Compare commits
320 Commits
temp_motio
...
temp-ghash
Author | SHA1 | Date | |
---|---|---|---|
58d6cbba6d | |||
295d0c52a2 | |||
e35a26fbef | |||
6654ec7de7 | |||
827ccc343f | |||
e6f7f36e40 | |||
e245a57640 | |||
68478aea01 | |||
b506f3d328 | |||
d9ef528d05 | |||
9f48aa45ad | |||
c5c2883ce0 | |||
32319dd106 | |||
2ef3c43c5d | |||
3d616ccba8 | |||
aac5485fca | |||
008da0ff5e | |||
3d7329950e | |||
4d74180b9f | |||
09dc470982 | |||
17f12fc71a | |||
9260c0c2ba | |||
48ef0501b7 | |||
e2d3e36ca7 | |||
c68322c7e5 | |||
e170d6be7f | |||
ecb6a6df52 | |||
ff7a46cfad | |||
4d043c99dc | |||
e78b03f9e9 | |||
ab85c5f980 | |||
851d7535d9 | |||
ddeb8c595f | |||
c58b5acefd | |||
79c106705a | |||
8690ea611e | |||
09e89f01a6 | |||
c74255181e | |||
2cdcb1c171 | |||
0e83b0854f | |||
284d294f2c | |||
c0ea3099c5 | |||
ef57051e9c | |||
8e95303414 | |||
c40205738b | |||
ba98e6148b | |||
42314b32f2 | |||
![]() |
6f17fb8630 | ||
![]() |
fc668df245 | ||
![]() |
49aa7b1261 | ||
1676fcded0 | |||
c40759e678 | |||
a09af2dc7b | |||
9ce738e0f6 | |||
a33b1ce500 | |||
![]() |
227aefc18b | ||
0d4cca6593 | |||
f1bad1d16b | |||
40a345a9c7 | |||
04e9a707f4 | |||
b318795c3b | |||
90b4131d16 | |||
57065a6df5 | |||
1c251d7cb6 | |||
72e812de7c | |||
ec8e0336a9 | |||
7ecb199d86 | |||
cb5aecdae9 | |||
91fde2891c | |||
cd7853be22 | |||
4e8092e2e4 | |||
f1917a2188 | |||
d6e180e75a | |||
74f7ef1240 | |||
e2fa6663d3 | |||
80192b5391 | |||
![]() |
f0c5ed39ee | ||
211a95b538 | |||
a1609791ca | |||
4faccf0a78 | |||
d979ac4cc9 | |||
5e241e3028 | |||
7119a0f67d | |||
3044e9fd31 | |||
b5b8599342 | |||
63c9f51133 | |||
c119187be0 | |||
63f62cd757 | |||
857c9e14f7 | |||
43f6ed908f | |||
6057548058 | |||
8be4d76204 | |||
9ddb624a88 | |||
8d752141ce | |||
e3d6269ec4 | |||
cdb0cf3ec7 | |||
aeda4dca77 | |||
a95b0e0e9d | |||
5e2835037a | |||
34d665a4a4 | |||
63dd554ff1 | |||
5a4b51992e | |||
845854959f | |||
2a305580b2 | |||
6b3a43ccb4 | |||
b6820c9522 | |||
e019d8fb8c | |||
e3fe56d9d1 | |||
72a2d22f03 | |||
5a69b93f57 | |||
973afa0172 | |||
f6c661a38f | |||
e807520a1e | |||
74b32a23f7 | |||
4addabaed8 | |||
2de34ba31d | |||
51188ecbf1 | |||
8e1ba0b805 | |||
1d6c025c42 | |||
037181cf1c | |||
27eb2b1017 | |||
e9406256d0 | |||
ae0ed5e9d5 | |||
![]() |
9affa8450a | ||
9d796df4f6 | |||
0d3555fe2e | |||
0f171d4a25 | |||
1cf1f48893 | |||
52e95ad3d3 | |||
d4aeec9204 | |||
9b3722b414 | |||
d8cef42a14 | |||
![]() |
a1e01fda24 | ||
e1fd7b9ca9 | |||
7e529c2a64 | |||
4ed6605d65 | |||
28c34d332f | |||
03efc37a6e | |||
7165d979ae | |||
3468038ed5 | |||
7fbf264c67 | |||
530034511c | |||
18f228d593 | |||
![]() |
a62392dea7 | ||
3ce4a58aa9 | |||
937ecaf77e | |||
da61c36f2a | |||
fc35b758ad | |||
e96d1c7965 | |||
0dcda51836 | |||
37fd262805 | |||
bd5ea70a75 | |||
01f21f8026 | |||
42d5df448c | |||
0119c63405 | |||
bcc4957877 | |||
0b79c5ed29 | |||
e1ce9220d6 | |||
3b57f075a8 | |||
e0ae59f5d8 | |||
aee4527101 | |||
ae3e37b899 | |||
364d934951 | |||
a1c6b73de7 | |||
5b833de521 | |||
c03dcc5421 | |||
810f8928d6 | |||
81b37f5e92 | |||
ecdbe3cc63 | |||
2689247f98 | |||
770dfead86 | |||
aab2da9e65 | |||
fbff0e68a4 | |||
5ca3f3d811 | |||
c55cf743cd | |||
94eb2647d5 | |||
b986f955e9 | |||
173c1133a8 | |||
fa823dc828 | |||
b1a92f2b3a | |||
532e29cd76 | |||
291152e127 | |||
6d63446710 | |||
53e3e46332 | |||
888ed6b7f1 | |||
099aaea447 | |||
6c23497185 | |||
1c707a2392 | |||
124b25cf9d | |||
a44a0cf443 | |||
b633c2857f | |||
3f7ea7489e | |||
bf57c91ead | |||
473d46263b | |||
05b2ab1109 | |||
9090d64544 | |||
d7cd8ff891 | |||
5b8af1d1f1 | |||
edfe2d6691 | |||
fd629d2fb8 | |||
644e2250ce | |||
d8e994b35f | |||
3efc0aca54 | |||
7f3dcbe17f | |||
e464cbae3b | |||
9cefd5612d | |||
eb0310950c | |||
1862991862 | |||
b9fe261255 | |||
91b23992ce | |||
208a917b73 | |||
52997272aa | |||
1e9348efdc | |||
424e5be046 | |||
a2d4c26aa2 | |||
b1ed12bfec | |||
1c81bcffde | |||
75a86d6a8e | |||
a1ac42f5eb | |||
4835fe06f1 | |||
![]() |
9326820a1b | ||
![]() |
e944af67f7 | ||
41d5ff6fe9 | |||
d3e16df4f1 | |||
1cbf748e0c | |||
0f42b8aee0 | |||
097aa852cf | |||
![]() |
54b824106b | ||
0bf0aa6625 | |||
0b51e7d991 | |||
38a60418f7 | |||
60ddaf045a | |||
02a496c61c | |||
7bac8348bf | |||
![]() |
7182677620 | ||
1b8a785d83 | |||
07562a4afb | |||
9e91313a97 | |||
6f36e1f872 | |||
efe4af8fcb | |||
a9d3f663d3 | |||
e2e414218b | |||
0d95b41f9e | |||
7823ca06da | |||
4fae3620d0 | |||
850bb80aef | |||
69e96509a6 | |||
f2bd6d73e6 | |||
6c44265bc9 | |||
34c3beb339 | |||
520fb5c8cd | |||
4ab47a7670 | |||
5893a3445e | |||
37b8153afe | |||
![]() |
7ca40c1061 | ||
![]() |
2205950274 | ||
6a33d13ae7 | |||
596eadf0e1 | |||
b3cc602adc | |||
f6748183a2 | |||
7dae8e54cc | |||
774e034d40 | |||
9c5995c062 | |||
b496819fcc | |||
b666593775 | |||
96d9801423 | |||
b4446b505f | |||
5114637967 | |||
8c2619a11a | |||
![]() |
939948c233 | ||
356afe0085 | |||
6a0a205cb4 | |||
af4d10703b | |||
102e18d05c | |||
2bd6de5bbb | |||
3438130a94 | |||
abc9c26ec8 | |||
a6803bf564 | |||
bb5e46f105 | |||
41564a402e | |||
ee37de75e6 | |||
867cd2048e | |||
b8b57d2da9 | |||
958c20872a | |||
![]() |
087c82e392 | ||
f167f434d9 | |||
8e0ab3d42f | |||
825892ae7a | |||
3560e36ee9 | |||
ec3c2d3be9 | |||
91e767c99c | |||
ab417f31f4 | |||
73a104b8e8 | |||
9f911f62dc | |||
6e844da9da | |||
0446c73c4a | |||
bc69eafa98 | |||
08687ee380 | |||
45d4fadebd | |||
7b0c327b94 | |||
9a83e112be | |||
3092e1031d | |||
af980a20a4 | |||
6c8f2049f6 | |||
cb9bd23d0c | |||
![]() |
e1b8ed8dd4 | ||
962f764d58 | |||
f8385de5ed | |||
![]() |
ffdeba49e6 | ||
![]() |
4f94947157 | ||
94549adec4 | |||
77a4d705c7 | |||
f808f36c12 | |||
b6f0c9e25a | |||
ecc9fe9945 | |||
4e3bc21492 | |||
88ae44a363 | |||
df587b03c3 | |||
1df3713365 | |||
23b42a5e69 |
@@ -53,7 +53,9 @@ if(NOT (${CMAKE_VERSION} VERSION_LESS 3.0))
|
||||
endif()
|
||||
|
||||
if(NOT EXECUTABLE_OUTPUT_PATH)
|
||||
set(FIRST_RUN "TRUE")
|
||||
set(FIRST_RUN TRUE)
|
||||
else()
|
||||
set(FIRST_RUN FALSE)
|
||||
endif()
|
||||
|
||||
# this starts out unset
|
||||
@@ -71,7 +73,6 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE NDEBU
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL NDEBUG)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO NDEBUG)
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Set policy
|
||||
|
||||
@@ -129,7 +130,7 @@ macro(option_defaults_init)
|
||||
set(${_var} ON)
|
||||
list(APPEND _init_vars "${_var}")
|
||||
endforeach()
|
||||
unset(_INC)
|
||||
unset(_var)
|
||||
endmacro()
|
||||
|
||||
# remove from namespace
|
||||
@@ -274,10 +275,6 @@ option(WITH_MOD_REMESH "Enable Remesh Modifier" ON)
|
||||
# mark_as_advanced(WITH_MOD_CLOTH_ELTOPO)
|
||||
option(WITH_MOD_OCEANSIM "Enable Ocean Modifier" OFF)
|
||||
|
||||
# Alembic
|
||||
option(WITH_ALEMBIC "Enable Alembic Support" OFF)
|
||||
option(WITH_HDF5 "Enable HDF5 Support for Alembic" OFF)
|
||||
|
||||
# Image format support
|
||||
option(WITH_OPENIMAGEIO "Enable OpenImageIO Support (http://www.openimageio.org)" ON)
|
||||
option(WITH_IMAGE_OPENEXR "Enable OpenEXR Support (http://www.openexr.com)" ${_init_IMAGE_OPENEXR})
|
||||
@@ -454,6 +451,7 @@ mark_as_advanced(WITH_CPP11)
|
||||
|
||||
# Dependency graph
|
||||
option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
|
||||
mark_as_advanced(WITH_LEGACY_DEPSGRAPH)
|
||||
|
||||
# avoid using again
|
||||
option_defaults_clear()
|
||||
@@ -644,26 +642,27 @@ if(NOT WITH_BOOST)
|
||||
|
||||
set_and_warn(WITH_CYCLES OFF)
|
||||
set_and_warn(WITH_AUDASPACE OFF)
|
||||
set_and_warn(WITH_ALEMBIC OFF)
|
||||
set_and_warn(WITH_INTERNATIONAL OFF)
|
||||
|
||||
set_and_warn(WITH_OPENAL OFF) # depends on AUDASPACE
|
||||
set_and_warn(WITH_GAMEENGINE OFF) # depends on AUDASPACE
|
||||
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_ALEMBIC OR WITH_INTERNATIONAL)
|
||||
elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL)
|
||||
# Keep enabled
|
||||
else()
|
||||
# Enabled but we don't need it
|
||||
set(WITH_BOOST OFF)
|
||||
endif()
|
||||
|
||||
# disable hdf5 if Alembic is disabled
|
||||
if(NOT WITH_ALEMBIC)
|
||||
set(WITH_HDF5 OFF)
|
||||
endif()
|
||||
|
||||
# auto enable openimageio for cycles
|
||||
if(WITH_CYCLES)
|
||||
set(WITH_OPENIMAGEIO ON)
|
||||
|
||||
# auto enable llvm for cycles_osl
|
||||
if(WITH_CYCLES_OSL)
|
||||
set(WITH_LLVM ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
else()
|
||||
set(WITH_CYCLES_OSL OFF)
|
||||
endif()
|
||||
|
||||
# auto enable openimageio linking dependencies
|
||||
@@ -672,11 +671,6 @@ if(WITH_OPENIMAGEIO)
|
||||
set(WITH_IMAGE_TIFF ON)
|
||||
endif()
|
||||
|
||||
# auto enable llvm for cycles_osl
|
||||
if(WITH_CYCLES_OSL)
|
||||
set(WITH_LLVM ON CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
# don't store paths to libs for portable distribution
|
||||
if(WITH_INSTALL_PORTABLE)
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
@@ -1085,19 +1079,6 @@ if(UNIX AND NOT APPLE)
|
||||
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--version-script='${CMAKE_SOURCE_DIR}/source/creator/blender.map'")
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
find_package_wrapper(Alembic)
|
||||
set(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARIES} ${BOOST_LIBRARIES})
|
||||
if(NOT ALEMBIC_HDF5_FOUND AND WITH_HDF5)
|
||||
message(STATUS "Alembic is compiled without HDF5 support, disabling HDF5 options")
|
||||
set(WITH_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_HDF5)
|
||||
find_package_wrapper(HDF5)
|
||||
endif()
|
||||
|
||||
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
||||
list(APPEND PLATFORM_LINKLIBS -lutil -lc -lm)
|
||||
|
||||
@@ -2184,12 +2165,6 @@ if(WITH_CYCLES)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
if(NOT WITH_BOOST)
|
||||
message(FATAL_ERROR "Alembic requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_ALEMBIC")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_INTERNATIONAL)
|
||||
if(NOT WITH_BOOST)
|
||||
message(FATAL_ERROR "Internationalization requires WITH_BOOST, the library may not have been found. Configure BOOST or disable WITH_INTERNATIONAL")
|
||||
@@ -2787,25 +2762,29 @@ include(build_files/cmake/packaging.cmake)
|
||||
# Print Final Configuration
|
||||
|
||||
if(FIRST_RUN)
|
||||
set(_config_msg "\n* Blender Configuration *")
|
||||
macro(info_cfg_option
|
||||
_setting)
|
||||
set(_msg " * ${_setting}")
|
||||
|
||||
set(_config_msg "\nBlender Configuration\n=====================")
|
||||
|
||||
function(info_cfg_option
|
||||
_setting
|
||||
)
|
||||
|
||||
set(_msg " - ${_setting}")
|
||||
string(LENGTH "${_msg}" _len)
|
||||
while("32" GREATER "${_len}")
|
||||
set(_msg "${_msg} ")
|
||||
math(EXPR _len "${_len} + 1")
|
||||
endwhile()
|
||||
|
||||
set(_config_msg "${_config_msg}\n${_msg}${${_setting}}")
|
||||
endmacro()
|
||||
set(_config_msg "${_config_msg}\n${_msg}${${_setting}}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
macro(info_cfg_text
|
||||
_text)
|
||||
set(_config_msg "${_config_msg}\n\n ${_text}")
|
||||
function(info_cfg_text
|
||||
_text
|
||||
)
|
||||
|
||||
|
||||
endmacro()
|
||||
set(_config_msg "${_config_msg}\n\n ${_text}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
message(STATUS "C Compiler: \"${CMAKE_C_COMPILER_ID}\"")
|
||||
message(STATUS "C++ Compiler: \"${CMAKE_CXX_COMPILER_ID}\"")
|
||||
|
88
GNUmakefile
88
GNUmakefile
@@ -43,6 +43,11 @@ ifndef BUILD_DIR
|
||||
BUILD_DIR:=$(shell dirname "$(BLENDER_DIR)")/build_$(OS_NCASE)
|
||||
endif
|
||||
|
||||
# Allow to use alternative binary (pypy3, etc)
|
||||
ifndef PYTHON
|
||||
PYTHON:=python3
|
||||
endif
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# additional targets for the build configuration
|
||||
@@ -76,18 +81,20 @@ endif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Get the number of cores for threaded build
|
||||
NPROCS:=1
|
||||
ifeq ($(OS), Linux)
|
||||
NPROCS:=$(shell nproc)
|
||||
endif
|
||||
ifeq ($(OS), Darwin)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f3)
|
||||
endif
|
||||
ifeq ($(OS), FreeBSD)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
|
||||
endif
|
||||
ifeq ($(OS), NetBSD)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
|
||||
ifndef NPROCS
|
||||
NPROCS:=1
|
||||
ifeq ($(OS), Linux)
|
||||
NPROCS:=$(shell nproc)
|
||||
endif
|
||||
ifeq ($(OS), Darwin)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f3)
|
||||
endif
|
||||
ifeq ($(OS), FreeBSD)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
|
||||
endif
|
||||
ifeq ($(OS), NetBSD)
|
||||
NPROCS:=$(shell sysctl -a | grep "hw.ncpu" | cut -d" " -f2 )
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
@@ -117,12 +124,12 @@ all: FORCE
|
||||
@echo
|
||||
@echo Configuring Blender ...
|
||||
|
||||
# if test ! -f $(BUILD_DIR)/CMakeCache.txt ; then \
|
||||
# $(CMAKE_CONFIG); \
|
||||
# fi
|
||||
# # if test ! -f $(BUILD_DIR)/CMakeCache.txt ; then \
|
||||
# # $(CMAKE_CONFIG); \
|
||||
# # fi
|
||||
|
||||
# do this always incase of failed initial build, could be smarter here...
|
||||
$(CMAKE_CONFIG)
|
||||
# # do this always incase of failed initial build, could be smarter here...
|
||||
@$(CMAKE_CONFIG)
|
||||
|
||||
@echo
|
||||
@echo Building Blender ...
|
||||
@@ -201,6 +208,12 @@ help: FORCE
|
||||
@echo " * tgz - create a compressed archive of the source code."
|
||||
@echo " * update - updates git and all submodules"
|
||||
@echo ""
|
||||
@echo "Environment Variables"
|
||||
@echo " * BUILD_CMAKE_ARGS - arguments passed to CMake."
|
||||
@echo " * BUILD_DIR - override default build path."
|
||||
@echo " * PYTHON - use this for the Python command (used for checking tools)."
|
||||
@echo " * NPROCS - number of processes to use building (auto-detect when omitted)."
|
||||
@echo ""
|
||||
@echo "Documentation Targets (not associated with building blender)"
|
||||
@echo " * doc_py - generate sphinx python api docs"
|
||||
@echo " * doc_doxy - generate doxygen C/C++ docs"
|
||||
@@ -210,6 +223,7 @@ help: FORCE
|
||||
@echo "Information"
|
||||
@echo " * help - this help message"
|
||||
@echo " * help_features - show a list of optional features when building"
|
||||
@echo ""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Packages
|
||||
@@ -233,21 +247,21 @@ test: FORCE
|
||||
|
||||
# run pep8 check check on scripts we distribute.
|
||||
test_pep8: FORCE
|
||||
python3 tests/python/pep8.py > test_pep8.log 2>&1
|
||||
$(PYTHON) tests/python/pep8.py > test_pep8.log 2>&1
|
||||
@echo "written: test_pep8.log"
|
||||
|
||||
# run some checks on our cmakefiles.
|
||||
test_cmake: FORCE
|
||||
python3 build_files/cmake/cmake_consistency_check.py > test_cmake_consistency.log 2>&1
|
||||
$(PYTHON) build_files/cmake/cmake_consistency_check.py > test_cmake_consistency.log 2>&1
|
||||
@echo "written: test_cmake_consistency.log"
|
||||
|
||||
# run deprecation tests, see if we have anything to remove.
|
||||
test_deprecated: FORCE
|
||||
python3 tests/check_deprecated.py
|
||||
$(PYTHON) tests/check_deprecated.py
|
||||
|
||||
test_style_c: FORCE
|
||||
# run our own checks on C/C++ style
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
|
||||
"$(BLENDER_DIR)/source/blender" \
|
||||
"$(BLENDER_DIR)/source/creator" \
|
||||
@@ -256,7 +270,7 @@ test_style_c: FORCE
|
||||
test_style_c_qtc: FORCE
|
||||
# run our own checks on C/C++ style
|
||||
USE_QTC_TASK=1 \
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
|
||||
"$(BLENDER_DIR)/source/blender" \
|
||||
"$(BLENDER_DIR)/source/creator" \
|
||||
@@ -268,7 +282,7 @@ test_style_c_qtc: FORCE
|
||||
|
||||
test_style_osl: FORCE
|
||||
# run our own checks on C/C++ style
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
|
||||
"$(BLENDER_DIR)/intern/cycles/kernel/shaders" \
|
||||
"$(BLENDER_DIR)/release/scripts/templates_osl"
|
||||
@@ -277,7 +291,7 @@ test_style_osl: FORCE
|
||||
test_style_osl_qtc: FORCE
|
||||
# run our own checks on C/C++ style
|
||||
USE_QTC_TASK=1 \
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_style_c.py" \
|
||||
"$(BLENDER_DIR)/intern/cycles/kernel/shaders" \
|
||||
"$(BLENDER_DIR)/release/scripts/templates_osl" \
|
||||
@@ -290,10 +304,10 @@ test_style_osl_qtc: FORCE
|
||||
#
|
||||
|
||||
project_qtcreator: FORCE
|
||||
python3 build_files/cmake/cmake_qtcreator_project.py "$(BUILD_DIR)"
|
||||
$(PYTHON) build_files/cmake/cmake_qtcreator_project.py "$(BUILD_DIR)"
|
||||
|
||||
project_netbeans: FORCE
|
||||
python3 build_files/cmake/cmake_netbeans_project.py "$(BUILD_DIR)"
|
||||
$(PYTHON) build_files/cmake/cmake_netbeans_project.py "$(BUILD_DIR)"
|
||||
|
||||
project_eclipse: FORCE
|
||||
cmake -G"Eclipse CDT4 - Unix Makefiles" -H"$(BLENDER_DIR)" -B"$(BUILD_DIR)"
|
||||
@@ -306,39 +320,39 @@ project_eclipse: FORCE
|
||||
check_cppcheck: FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
python3 "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py" 2> \
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py" 2> \
|
||||
"$(BLENDER_DIR)/check_cppcheck.txt"
|
||||
@echo "written: check_cppcheck.txt"
|
||||
|
||||
check_clang_array: FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
python3 "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_clang_array.py"
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_clang_array.py"
|
||||
|
||||
check_splint: FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
python3 "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py"
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_splint.py"
|
||||
|
||||
check_sparse: FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
python3 "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_sparse.py"
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_sparse.py"
|
||||
|
||||
check_smatch: FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
python3 "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_smatch.py"
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_smatch.py"
|
||||
|
||||
check_spelling_py: FORCE
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
|
||||
"$(BLENDER_DIR)/release/scripts"
|
||||
|
||||
check_spelling_c: FORCE
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
|
||||
"$(BLENDER_DIR)/source" \
|
||||
"$(BLENDER_DIR)/intern/cycles" \
|
||||
@@ -347,7 +361,7 @@ check_spelling_c: FORCE
|
||||
|
||||
check_spelling_c_qtc: FORCE
|
||||
cd "$(BUILD_DIR)" ; USE_QTC_TASK=1 \
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
|
||||
"$(BLENDER_DIR)/source" \
|
||||
"$(BLENDER_DIR)/intern/cycles" \
|
||||
@@ -358,7 +372,7 @@ check_spelling_c_qtc: FORCE
|
||||
|
||||
check_spelling_osl: FORCE
|
||||
cd "$(BUILD_DIR)" ;\
|
||||
PYTHONIOENCODING=utf_8 python3 \
|
||||
PYTHONIOENCODING=utf_8 $(PYTHON) \
|
||||
"$(BLENDER_DIR)/source/tools/check_source/check_spelling.py" \
|
||||
"$(BLENDER_DIR)/intern/cycles/kernel/shaders"
|
||||
|
||||
@@ -404,10 +418,10 @@ doc_dna: FORCE
|
||||
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
|
||||
|
||||
doc_man: FORCE
|
||||
python3 doc/manpage/blender.1.py "$(BUILD_DIR)/bin/blender"
|
||||
$(PYTHON) doc/manpage/blender.1.py "$(BUILD_DIR)/bin/blender"
|
||||
|
||||
help_features: FORCE
|
||||
@python3 -c \
|
||||
@$(PYTHON) -c \
|
||||
"import re; \
|
||||
print('\n'.join([ \
|
||||
w for l in open('"$(BLENDER_DIR)"/CMakeLists.txt', 'r').readlines() \
|
||||
|
16
SConstruct
16
SConstruct
@@ -817,13 +817,6 @@ if B.targets != ['cudakernels']:
|
||||
data_to_c_simple("release/datafiles/brushicons/fill.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/flatten.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/grab.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/hairadd.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/haircomb.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/haircut.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/hairlength.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/hairpuff.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/hairsmooth.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/hairweight.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/inflate.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/layer.png")
|
||||
data_to_c_simple("release/datafiles/brushicons/lighten.png")
|
||||
@@ -1307,6 +1300,15 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'linuxcross'):
|
||||
windlls = env.Install(dir=env['BF_INSTALLDIR'], source = dllsources)
|
||||
allinstall += windlls
|
||||
|
||||
# TODO(sergey): For unti we've got better way to deal with python binary
|
||||
if env['WITH_BF_PYTHON']:
|
||||
py_target = os.path.join(env['BF_INSTALLDIR'], VERSION, 'python', 'bin')
|
||||
if env['BF_DEBUG']:
|
||||
allinstall += env.Install(dir=py_target, source = ['${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}_d.dll'])
|
||||
else:
|
||||
allinstall += env.Install(dir=py_target, source = ['${BF_PYTHON_LIBPATH}/${BF_PYTHON_DLL}.dll'])
|
||||
|
||||
|
||||
if env['OURPLATFORM'] == 'win64-mingw':
|
||||
dllsources = []
|
||||
|
||||
|
@@ -28,8 +28,8 @@ getopt \
|
||||
--long source:,install:,tmp:,info:,threads:,help,no-sudo,with-all,with-opencollada,\
|
||||
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,\
|
||||
force-all,force-python,force-numpy,force-boost,force-ocio,force-oiio,force-llvm,force-osl,force-opencollada,\
|
||||
force-ffmpeg,force-alembic,\
|
||||
skip-python,skip-numpy,skip-boost,skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg,skip-opencollada,skip-alembic,\
|
||||
force-ffmpeg,\
|
||||
skip-python,skip-numpy,skip-boost,skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-ffmpeg,skip-opencollada,\
|
||||
required-numpy: \
|
||||
-- "$@" \
|
||||
)
|
||||
@@ -95,9 +95,6 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--with-opencollada
|
||||
Build and install the OpenCOLLADA libraries.
|
||||
|
||||
--with-alembic
|
||||
Build and install the Alembic library.
|
||||
|
||||
--ver-ocio=<ver>
|
||||
Force version of OCIO library.
|
||||
|
||||
@@ -147,9 +144,6 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--force-ffmpeg
|
||||
Force the rebuild of FFMpeg.
|
||||
|
||||
--force-alembic
|
||||
Force the rebuild of Alembic.
|
||||
|
||||
Note about the --force-foo options:
|
||||
* They obviously only have an effect if those libraries are built by this script
|
||||
(i.e. if there is no available and satisfactory package)!
|
||||
@@ -186,9 +180,6 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--skip-ffmpeg
|
||||
Unconditionally skip FFMpeg installation/building.
|
||||
|
||||
--skip-alembic
|
||||
Unconditionally skip Alembic installation/building.
|
||||
|
||||
--required-numpy
|
||||
Use this in case your distro features a valid python package, but no matching Numpy one.
|
||||
It will force compilation of both python and numpy\""
|
||||
@@ -273,11 +264,6 @@ MP3LAME_DEV=""
|
||||
OPENJPEG_USE=false
|
||||
OPENJPEG_DEV=""
|
||||
|
||||
ALEMBIC_VERSION="1.5.5"
|
||||
ALEMBIC_VERSION_MIN="1.5.5"
|
||||
ALEMBIC_FORCE_REBUILD=false
|
||||
ALEMBIC_SKIP=false
|
||||
|
||||
# Switch to english language, else some things (like check_package_DEB()) won't work!
|
||||
LANG_BACK=$LANG
|
||||
LANG=""
|
||||
@@ -437,9 +423,6 @@ while true; do
|
||||
--force-ffmpeg)
|
||||
FFMPEG_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--force-alembic)
|
||||
ALEMBIC_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--skip-python)
|
||||
PYTHON_SKIP=true; shift; continue
|
||||
;;
|
||||
@@ -470,9 +453,6 @@ while true; do
|
||||
--skip-ffmpeg)
|
||||
FFMPEG_SKIP=true; shift; continue
|
||||
;;
|
||||
--skip-alembic)
|
||||
ALEMBIC_SKIP=true; shift; continue
|
||||
;;
|
||||
--required-numpy)
|
||||
NUMPY_REQUIRED=true; shift; continue
|
||||
;;
|
||||
@@ -533,9 +513,6 @@ OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
|
||||
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
|
||||
FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
|
||||
|
||||
ALEMBIC_SOURCE=( "https://code.google.com/p/alembic/" )
|
||||
ALEMBIC_REPO_UID=( "1_05_05" )
|
||||
|
||||
|
||||
##### Generic Helpers #####
|
||||
|
||||
@@ -862,7 +839,6 @@ compile_Boost() {
|
||||
# Rebuild dependecies as well!
|
||||
OIIO_FORCE_REBUILD=true
|
||||
OSL_FORCE_REBUILD=true
|
||||
ALEMBIC_FORCE_REBUILD=true
|
||||
|
||||
prepare_opt
|
||||
|
||||
@@ -1730,165 +1706,6 @@ compile_FFmpeg() {
|
||||
fi
|
||||
}
|
||||
|
||||
#### Build ALEMBIC ####
|
||||
_init_alembic() {
|
||||
_src=$SRC/Alembic-$ALEMBIC_VERSION
|
||||
_hg=false
|
||||
_inst=$INST/alembic-$ALEMBIC_VERSION
|
||||
_inst_shortcut=$INST/alembic
|
||||
}
|
||||
|
||||
clean_alembic() {
|
||||
_init_alembic
|
||||
_clean
|
||||
}
|
||||
|
||||
compile_alembic() {
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
alembic_magic=1
|
||||
_init_alembic
|
||||
|
||||
# Clean install if needed!
|
||||
magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
if [ $? -eq 1 -o $ALEMBIC_FORCE_REBUILD == true ]; then
|
||||
clean_alembic
|
||||
fi
|
||||
|
||||
if [ ! -d $_inst ]; then
|
||||
INFO "Building Alembic-$ALEMBIC_VERSION"
|
||||
|
||||
prepare_opt
|
||||
|
||||
if [ ! -d $_src ]; then
|
||||
mkdir -p $SRC
|
||||
hg clone -u $ALEMBIC_REPO_UID $ALEMBIC_SOURCE $_src
|
||||
fi
|
||||
|
||||
cd $_src
|
||||
|
||||
# XXX Ugly patching hack!
|
||||
# Alembice cmake files are erratic, to say the least
|
||||
# have to manually disable a bunch of crap here
|
||||
cat << EOF | patch -p1
|
||||
--- a/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
|
||||
+++ b/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
|
||||
@@ -57,9 +57,9 @@
|
||||
${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} )
|
||||
SET( VERSION ${PROJECT_VERSION} )
|
||||
|
||||
-SET( ALEMBIC_NO_TESTS FALSE )
|
||||
-SET( ALEMBIC_NO_BOOTSTRAP FALSE )
|
||||
-SET( ALEMBIC_NO_OPENGL FALSE )
|
||||
+SET( ALEMBIC_NO_TESTS TRUE )
|
||||
+SET( ALEMBIC_NO_BOOTSTRAP TRUE )
|
||||
+SET( ALEMBIC_NO_OPENGL TRUE )
|
||||
|
||||
MESSAGE(STATUS "CMAKE SYSTEM NAME = ${CMAKE_SYSTEM_NAME}" )
|
||||
|
||||
@@ -306,15 +306,15 @@
|
||||
ENDIF()
|
||||
|
||||
# Include PyAlembic stuff
|
||||
-IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
|
||||
- MESSAGE(STATUS "Skipping Alembic Python bindings")
|
||||
-ELSE()
|
||||
- MESSAGE(STATUS "About to include Python cmake files")
|
||||
- ADD_SUBDIRECTORY( python )
|
||||
-ENDIF()
|
||||
+#IF(DEFINED USE_PYALEMBIC AND NOT USE_PYALEMBIC)
|
||||
+# MESSAGE(STATUS "Skipping Alembic Python bindings")
|
||||
+#ELSE()
|
||||
+# MESSAGE(STATUS "About to include Python cmake files")
|
||||
+# ADD_SUBDIRECTORY( python )
|
||||
+#ENDIF()
|
||||
|
||||
# Example code not supported
|
||||
-ADD_SUBDIRECTORY( examples )
|
||||
+#ADD_SUBDIRECTORY( examples )
|
||||
|
||||
# Uncomment to build python docs Makefile (requires Sphinx)
|
||||
# Run `make docs` from build root
|
||||
|
||||
EOF
|
||||
|
||||
cat << EOF | patch -p1
|
||||
--- a/lib/Alembic/Util/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
|
||||
+++ b/lib/Alembic/Util/CMakeLists.txt Thu Oct 16 15:03:27 2014 +0200
|
||||
@@ -65,7 +65,7 @@
|
||||
DESTINATION include/Alembic/Util
|
||||
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ )
|
||||
|
||||
-IF( NOT ALEMBIC_NO_TESTS )
|
||||
- ADD_SUBDIRECTORY( Tests )
|
||||
-ENDIF()
|
||||
+#IF( NOT ALEMBIC_NO_TESTS )
|
||||
+# ADD_SUBDIRECTORY( Tests )
|
||||
+#ENDIF()
|
||||
|
||||
EOF
|
||||
|
||||
cat << EOF | patch -p1
|
||||
--- a/python/CMakeLists.txt Mon Jul 28 10:09:21 2014 -0700
|
||||
+++ b/python/CMakeLists.txt Thu Oct 16 14:20:25 2014 +0200
|
||||
@@ -35,4 +35,4 @@
|
||||
|
||||
ADD_SUBDIRECTORY( PyAlembic )
|
||||
ADD_SUBDIRECTORY( PyAbcOpenGL )
|
||||
-ADD_SUBDIRECTORY( examples )
|
||||
+#ADD_SUBDIRECTORY( examples )
|
||||
|
||||
EOF
|
||||
|
||||
# Always refresh the whole build!
|
||||
# XXX 'build' directory is included in Alembic sources, don't touch that
|
||||
if [ -d blender_build ]; then
|
||||
rm -rf blender_build
|
||||
fi
|
||||
mkdir blender_build
|
||||
cd blender_build
|
||||
|
||||
# XXX Alembic cmake doesn't take these as options
|
||||
# XXX Alembic creates a subfolder itself ... rather than fix their
|
||||
# stupid build files, just expect this here by using $INST as prefix
|
||||
export ALEMBIC_INSTALL_PREFIX=$INST
|
||||
|
||||
cmake_d="-D CMAKE_BUILD_TYPE=Release"
|
||||
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$INST"
|
||||
cmake_d="$cmake_d -D BUILD_SHARED_LIBS=ON"
|
||||
cmake_d="$cmake_d -D BUILD_STATIC_LIBS=ON"
|
||||
cmake_d="$cmake_d -D USE_PYTHON=OFF"
|
||||
cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
|
||||
cmake_d="$cmakd_d -D ALEMBIC_PYTHON_INCLUDE_DIR=/use/include/python2.7" # XXX BAD
|
||||
cmake_d="$cmakd_d -D ALEMBIC_PYTHON_LIBRARY=/use/lib/python2.7" # XXX BAD
|
||||
cmake_d="$cmake_d -D USE_PYILMBASE=OFF"
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_HALF_LIB=$INST/openexr/lib/libHalf.la"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IEX_LIB=$INST/openexr/lib/libIex-2_1.la"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_ILMTHREAD_LIB=$INST/openexr/lib/libIlmThread-2_1.la"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_IMATH_LIB=$INST/openexr/lib/libImath-2_1.la"
|
||||
|
||||
cmake $cmake_d ../
|
||||
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
|
||||
cd $CWD
|
||||
INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
|
||||
else
|
||||
INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#### Install on DEB-like ####
|
||||
get_package_version_DEB() {
|
||||
@@ -1995,7 +1812,7 @@ install_DEB() {
|
||||
OGG_DEV="libogg-dev"
|
||||
THEORA_DEV="libtheora-dev"
|
||||
|
||||
_packages="gawk cmake cmake-curses-gui scons mercurial build-essential libjpeg-dev libpng-dev \
|
||||
_packages="gawk cmake cmake-curses-gui scons build-essential libjpeg-dev libpng-dev \
|
||||
libfreetype6-dev libx11-dev libxi-dev wget libsqlite3-dev libbz2-dev \
|
||||
libncurses5-dev libssl-dev liblzma-dev libreadline-dev $OPENJPEG_DEV \
|
||||
libopenal-dev libglew-dev libglewmx-dev yasm $THEORA_DEV $VORBIS_DEV $OGG_DEV \
|
||||
@@ -2175,8 +1992,7 @@ install_DEB() {
|
||||
if [ $? -eq 0 ]; then
|
||||
install_packages_DEB libboost-locale$boost_version-dev libboost-filesystem$boost_version-dev \
|
||||
libboost-regex$boost_version-dev libboost-system$boost_version-dev \
|
||||
libboost-thread$boost_version-dev libboost-python$boost_version-dev \
|
||||
libboost-program-options$boost_version-dev libboost-wave$boost_version-dev
|
||||
libboost-thread$boost_version-dev libboost-wave$boost_version-dev
|
||||
clean_Boost
|
||||
else
|
||||
compile_Boost
|
||||
@@ -2309,14 +2125,6 @@ install_DEB() {
|
||||
# fi
|
||||
compile_FFmpeg
|
||||
fi
|
||||
|
||||
if $ALEMBIC_SKIP; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
else
|
||||
install_packages_DEB libhdf5-dev
|
||||
install_packages_DEB libpython2.7-dev # XXX nasty hack, should be done better ...
|
||||
compile_alembic
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -3222,12 +3030,6 @@ print_info() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d $INST/alembic ]; then
|
||||
_1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
PRINT "Or even simpler, just run (in your blender-source dir):"
|
||||
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
|
||||
@@ -3297,13 +3099,6 @@ print_info() {
|
||||
PRINT "BF_FFMPEG_LIB = 'avformat avcodec swscale avutil avdevice `print_info_ffmpeglink`'"
|
||||
fi
|
||||
|
||||
if [ "$ALEMBIC_SKIP" = false ]; then
|
||||
PRINT "WITH_BF_ALEMBIC = True"
|
||||
if [ -d $INST/alembic ]; then
|
||||
PRINT "BF_ALEMBIC = '$INST/alembic'"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$WITH_ALL" = false ]; then
|
||||
PRINT "WITH_BF_3DMOUSE = False"
|
||||
# No libspacenav in official arch repos...
|
||||
|
@@ -166,19 +166,6 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||
# Ocean Simulation
|
||||
WITH_BF_OCEANSIM = True
|
||||
|
||||
# Alembic
|
||||
WITH_BF_HDF5 = False
|
||||
WITH_BF_ALEMBIC = True
|
||||
WITH_BF_STATICALEMBIC = True
|
||||
BF_ALEMBIC = '/opt/lib/alembic'
|
||||
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
|
||||
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
|
||||
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
|
||||
|
||||
# Compilation and optimization
|
||||
BF_DEBUG = False
|
||||
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
|
||||
|
@@ -166,19 +166,6 @@ BF_BOOST_LIBPATH = '${BF_BOOST}/lib'
|
||||
# Ocean Simulation
|
||||
WITH_BF_OCEANSIM = True
|
||||
|
||||
# Alembic
|
||||
WITH_BF_HDF5 = False
|
||||
WITH_BF_ALEMBIC = True
|
||||
WITH_BF_STATICALEMBIC = True
|
||||
BF_ALEMBIC = '/opt/lib/alembic'
|
||||
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
|
||||
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
|
||||
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
|
||||
|
||||
# Compilation and optimization
|
||||
BF_DEBUG = False
|
||||
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
|
||||
|
@@ -120,19 +120,6 @@ WITH_BF_FFTW3 = True
|
||||
WITH_BF_STATICFFTW3 = True
|
||||
WITH_BF_OCEANSIM = True
|
||||
|
||||
# Alembic
|
||||
WITH_BF_HDF5 = False
|
||||
WITH_BF_ALEMBIC = True
|
||||
WITH_BF_STATICALEMBIC = True
|
||||
BF_ALEMBIC = '/opt/lib/alembic'
|
||||
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
|
||||
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
|
||||
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
|
||||
|
||||
# Compilation and optimization
|
||||
BF_DEBUG = False
|
||||
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
|
||||
|
@@ -120,19 +120,6 @@ WITH_BF_FFTW3 = True
|
||||
WITH_BF_STATICFFTW3 = True
|
||||
WITH_BF_OCEANSIM = True
|
||||
|
||||
# Alembic
|
||||
WITH_BF_HDF5 = False
|
||||
WITH_BF_ALEMBIC = True
|
||||
WITH_BF_STATICALEMBIC = True
|
||||
BF_ALEMBIC = '/opt/lib/alembic'
|
||||
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
|
||||
BF_ALEMBIC_LIBPATH = '${BF_ALEMBIC}/lib/static'
|
||||
BF_ALEMBIC_LIB_STATIC = '${BF_ALEMBIC_LIBPATH}/libAlembicAbcGeom.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbc.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCollection.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreFactory.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcMaterial.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicOgawa.a ${BF_ALEMBIC_LIBPATH}/libAlembicAbcCoreAbstract.a ' + \
|
||||
'${BF_ALEMBIC_LIBPATH}/libAlembicUtil.a'
|
||||
|
||||
# Compilation and optimization
|
||||
BF_DEBUG = False
|
||||
REL_CCFLAGS = ['-DNDEBUG', '-O2', '-msse', '-msse2'] # C & C++
|
||||
|
@@ -1,103 +0,0 @@
|
||||
# - Find Alembic library
|
||||
# Find the native Alembic includes and library
|
||||
# This module defines
|
||||
# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers.
|
||||
# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
|
||||
# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
|
||||
# This can also be an environment variable.
|
||||
# ALEMBIC_FOUND, If false, do not try to use Alembic.
|
||||
# ALEMBIC_HDF5_FOUND, indicates whether Alembic supports HDF5
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2013 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
|
||||
SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_alembic_SEARCH_DIRS
|
||||
${ALEMBIC_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/alembic
|
||||
)
|
||||
|
||||
SET(_alembic_FIND_COMPONENTS
|
||||
AlembicAbc
|
||||
AlembicAbcCoreAbstract
|
||||
AlembicAbcGeom
|
||||
AlembicAbcCoreOgawa
|
||||
AlembicOgawa
|
||||
AlembicUtil
|
||||
)
|
||||
|
||||
FIND_PATH(ALEMBIC_INCLUDE_DIR
|
||||
NAMES
|
||||
Alembic/Abc/All.h
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
SET(_alembic_LIBRARIES)
|
||||
FOREACH(COMPONENT ${_alembic_FIND_COMPONENTS})
|
||||
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
|
||||
|
||||
FIND_LIBRARY(ALEMBIC_${UPPERCOMPONENT}_LIBRARY
|
||||
NAMES
|
||||
${COMPONENT}
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
lib/static
|
||||
)
|
||||
MARK_AS_ADVANCED(ALEMBIC_${UPPERCOMPONENT}_LIBRARY)
|
||||
LIST(APPEND _alembic_LIBRARIES "${ALEMBIC_${UPPERCOMPONENT}_LIBRARY}")
|
||||
ENDFOREACH()
|
||||
|
||||
# Sepcial handling of optional libraries
|
||||
FIND_LIBRARY(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY
|
||||
NAMES
|
||||
AlembicAbcCoreHDF5
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib
|
||||
lib/static
|
||||
)
|
||||
MARK_AS_ADVANCED(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY)
|
||||
IF(ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY)
|
||||
LIST(APPEND _alembic_LIBRARIES "${ALEMBIC_ALEMBICABCCOREHDF5_LIBRARY}")
|
||||
SET(ALEMBIC_HDF5_FOUND TRUE)
|
||||
ELSE()
|
||||
SET(ALEMBIC_HDF5_FOUND FALSE)
|
||||
ENDIF()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Alembic DEFAULT_MSG
|
||||
_alembic_LIBRARIES ALEMBIC_INCLUDE_DIR)
|
||||
|
||||
IF(ALEMBIC_FOUND)
|
||||
SET(ALEMBIC_LIBRARIES ${_alembic_LIBRARIES})
|
||||
SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
|
||||
ENDIF(ALEMBIC_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ALEMBIC_INCLUDE_DIR
|
||||
ALEMBIC_LIBRARIES
|
||||
)
|
@@ -1,75 +0,0 @@
|
||||
# - Find HDF5 library
|
||||
# Find the native hdf5 includes and library
|
||||
# This module defines
|
||||
# HDF5_INCLUDE_DIRS, where to find hdf5 headers.
|
||||
# HDF5_LIBRARIES, libraries to link against to use hdf5.
|
||||
# HDF5_ROOT_DIR, The base directory to search for hdf5.
|
||||
# This can also be an environment variable.
|
||||
# HDF5_FOUND, If false, do not try to use hdf5.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2013 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If HDF5_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
|
||||
SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_hdf5_SEARCH_DIRS
|
||||
${HDF5_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/hdf5
|
||||
)
|
||||
|
||||
SET(_hdf5_FIND_COMPONENTS
|
||||
hdf5
|
||||
hdf5_hl
|
||||
)
|
||||
|
||||
FIND_PATH(_hdf5_INCLUDE_DIRS
|
||||
NAMES
|
||||
hdf5.h
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
)
|
||||
|
||||
SET(_hdf5_LIBRARIES)
|
||||
FOREACH(COMPONENT ${_hdf5_FIND_COMPONENTS})
|
||||
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
|
||||
|
||||
FIND_LIBRARY(HDF5_${UPPERCOMPONENT}_LIBRARY
|
||||
NAMES
|
||||
${COMPONENT}
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
)
|
||||
MARK_AS_ADVANCED(HDF5_${UPPERCOMPONENT}_LIBRARY)
|
||||
LIST(APPEND _hdf5_LIBRARIES "${HDF5_${UPPERCOMPONENT}_LIBRARY}")
|
||||
ENDFOREACH()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(hdf5 DEFAULT_MSG
|
||||
_hdf5_LIBRARIES _hdf5_INCLUDE_DIRS)
|
||||
|
||||
IF(HDF5_FOUND)
|
||||
SET(HDF5_LIBRARIES ${_hdf5_LIBRARIES})
|
||||
SET(HDF5_INCLUDE_DIRS ${_hdf5_INCLUDE_DIRS})
|
||||
ENDIF(HDF5_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
HDF5_INCLUDE_DIRS
|
||||
HDF5_LIBRARIES
|
||||
)
|
@@ -59,7 +59,8 @@ FIND_LIBRARY(OPENIMAGEIO_LIBRARY
|
||||
FIND_FILE(OPENIMAGEIO_IDIFF
|
||||
NAMES
|
||||
idiff
|
||||
${OPENIMAGEIO_ROOT_DIR}
|
||||
HINTS
|
||||
${OPENIMAGEIO_ROOT_DIR}
|
||||
PATH_SUFFIXES
|
||||
bin
|
||||
)
|
||||
|
@@ -40,6 +40,7 @@ from project_info import (
|
||||
# is_py,
|
||||
cmake_advanced_info,
|
||||
cmake_compiler_defines,
|
||||
cmake_cache_var,
|
||||
project_name_get,
|
||||
)
|
||||
|
||||
@@ -71,6 +72,10 @@ def create_nb_project_main():
|
||||
# be tricky, get the project name from git if we can!
|
||||
PROJECT_NAME = project_name_get()
|
||||
|
||||
|
||||
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
|
||||
make_exe_basename = os.path.basename(make_exe)
|
||||
|
||||
# --------------- NB spesific
|
||||
defines = [("%s=%s" % cdef) if cdef[1] else cdef[0] for cdef in defines]
|
||||
defines += [cdef.replace("#define", "").strip() for cdef in cmake_compiler_defines()]
|
||||
@@ -131,9 +136,9 @@ def create_nb_project_main():
|
||||
f = open(join(PROJECT_DIR_NB, "configurations.xml"), 'w')
|
||||
|
||||
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
f.write('<configurationDescriptor version="94">\n')
|
||||
f.write('<configurationDescriptor version="95">\n')
|
||||
f.write(' <logicalFolder name="root" displayName="root" projectFiles="true" kind="ROOT">\n')
|
||||
f.write(' <df name="0" root="%s">\n' % SOURCE_DIR) # base_root_rel
|
||||
f.write(' <df root="%s" name="0">\n' % SOURCE_DIR) # base_root_rel
|
||||
|
||||
# write files!
|
||||
files_rel_local = [normpath(relpath(join(CMAKE_DIR, path), SOURCE_DIR)) for path in files_rel]
|
||||
@@ -185,16 +190,27 @@ def create_nb_project_main():
|
||||
|
||||
f.write(' <toolsSet>\n')
|
||||
f.write(' <compilerSet>default</compilerSet>\n')
|
||||
f.write(' <dependencyChecking>false</dependencyChecking>\n')
|
||||
f.write(' <rebuildPropChanged>false</rebuildPropChanged>\n')
|
||||
f.write(' </toolsSet>\n')
|
||||
f.write(' <dependencyChecking>false</dependencyChecking>\n')
|
||||
f.write(' <rebuildPropChanged>false</rebuildPropChanged>\n')
|
||||
f.write(' <codeAssistance>\n')
|
||||
f.write(' </codeAssistance>\n')
|
||||
f.write(' <makefileType>\n')
|
||||
|
||||
f.write(' <makeTool>\n')
|
||||
f.write(' <buildCommandWorkingDir>.</buildCommandWorkingDir>\n')
|
||||
f.write(' <buildCommand>${MAKE} -f Makefile</buildCommand>\n')
|
||||
f.write(' <cleanCommand>${MAKE} -f Makefile clean</cleanCommand>\n')
|
||||
|
||||
if make_exe_basename == "ninja":
|
||||
build_cmd = "ninja"
|
||||
clean_cmd = "ninja -t clean"
|
||||
else:
|
||||
build_cmd = "${MAKE} -f Makefile"
|
||||
clean_cmd = "${MAKE} -f Makefile clean"
|
||||
|
||||
f.write(' <buildCommand>%s</buildCommand>\n' % build_cmd)
|
||||
f.write(' <cleanCommand>%s</cleanCommand>\n' % clean_cmd)
|
||||
f.write(' <executablePath>./bin/blender</executablePath>\n')
|
||||
del build_cmd, clean_cmd
|
||||
|
||||
def write_toolinfo():
|
||||
f.write(' <incDir>\n')
|
||||
@@ -221,10 +237,11 @@ def create_nb_project_main():
|
||||
f.write(' \n')
|
||||
|
||||
for path in files_rel_local:
|
||||
is_c = path.endswith(".c")
|
||||
f.write(' <item path="%s"\n' % path)
|
||||
f.write(' ex="false"\n')
|
||||
f.write(' tool="1"\n')
|
||||
f.write(' flavor2="0">\n')
|
||||
f.write(' tool="%d"\n' % (0 if is_c else 1))
|
||||
f.write(' flavor2="%d">\n' % (3 if is_c else 0))
|
||||
f.write(' </item>\n')
|
||||
|
||||
f.write(' <runprofile version="9">\n')
|
||||
|
@@ -16,6 +16,7 @@ set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_FFTW3 OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_GAMEENGINE OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_FREESTYLE OFF CACHE BOOL "" FORCE)
|
||||
|
@@ -104,21 +104,31 @@ macro(file_list_suffix
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(target_link_libraries_optimized TARGET LIBS)
|
||||
function(target_link_libraries_optimized
|
||||
TARGET
|
||||
LIBS
|
||||
)
|
||||
|
||||
foreach(_LIB ${LIBS})
|
||||
target_link_libraries(${TARGET} optimized "${_LIB}")
|
||||
endforeach()
|
||||
unset(_LIB)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
function(target_link_libraries_debug
|
||||
TARGET
|
||||
LIBS
|
||||
)
|
||||
|
||||
macro(target_link_libraries_debug TARGET LIBS)
|
||||
foreach(_LIB ${LIBS})
|
||||
target_link_libraries(${TARGET} debug "${_LIB}")
|
||||
endforeach()
|
||||
unset(_LIB)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
function(target_link_libraries_decoupled
|
||||
target
|
||||
libraries_var
|
||||
)
|
||||
|
||||
macro(target_link_libraries_decoupled target libraries_var)
|
||||
if(NOT MSVC)
|
||||
target_link_libraries(${target} ${${libraries_var}})
|
||||
else()
|
||||
@@ -127,14 +137,15 @@ macro(target_link_libraries_decoupled target libraries_var)
|
||||
file_list_suffix(_libraries_debug "${${libraries_var}}" "_d")
|
||||
target_link_libraries_debug(${target} "${_libraries_debug}")
|
||||
target_link_libraries_optimized(${target} "${${libraries_var}}")
|
||||
unset(_libraries_debug)
|
||||
endif()
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# Nicer makefiles with -I/1/foo/ instead of -I/1/2/3/../../foo/
|
||||
# use it instead of include_directories()
|
||||
macro(blender_include_dirs
|
||||
includes)
|
||||
function(blender_include_dirs
|
||||
includes
|
||||
)
|
||||
|
||||
set(_ALL_INCS "")
|
||||
foreach(_INC ${ARGV})
|
||||
get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
|
||||
@@ -145,13 +156,12 @@ macro(blender_include_dirs
|
||||
##endif()
|
||||
endforeach()
|
||||
include_directories(${_ALL_INCS})
|
||||
unset(_INC)
|
||||
unset(_ABS_INC)
|
||||
unset(_ALL_INCS)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
function(blender_include_dirs_sys
|
||||
includes
|
||||
)
|
||||
|
||||
macro(blender_include_dirs_sys
|
||||
includes)
|
||||
set(_ALL_INCS "")
|
||||
foreach(_INC ${ARGV})
|
||||
get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
|
||||
@@ -161,13 +171,11 @@ macro(blender_include_dirs_sys
|
||||
##endif()
|
||||
endforeach()
|
||||
include_directories(SYSTEM ${_ALL_INCS})
|
||||
unset(_INC)
|
||||
unset(_ABS_INC)
|
||||
unset(_ALL_INCS)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
macro(blender_source_group
|
||||
sources)
|
||||
function(blender_source_group
|
||||
sources
|
||||
)
|
||||
|
||||
# Group by location on disk
|
||||
source_group("Source Files" FILES CMakeLists.txt)
|
||||
@@ -177,23 +185,23 @@ macro(blender_source_group
|
||||
if((${_SRC_EXT} MATCHES ".h") OR
|
||||
(${_SRC_EXT} MATCHES ".hpp") OR
|
||||
(${_SRC_EXT} MATCHES ".hh"))
|
||||
source_group("Header Files" FILES ${_SRC})
|
||||
else()
|
||||
source_group("Source Files" FILES ${_SRC})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
unset(_SRC)
|
||||
unset(_SRC_EXT)
|
||||
endmacro()
|
||||
set(GROUP_ID "Header Files")
|
||||
else()
|
||||
set(GROUP_ID "Source Files")
|
||||
endif()
|
||||
source_group("${GROUP_ID}" FILES ${_SRC})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
# only MSVC uses SOURCE_GROUP
|
||||
macro(blender_add_lib_nolist
|
||||
function(blender_add_lib_nolist
|
||||
name
|
||||
sources
|
||||
includes
|
||||
includes_sys)
|
||||
includes_sys
|
||||
)
|
||||
|
||||
# message(STATUS "Configuring library ${name}")
|
||||
|
||||
@@ -213,22 +221,24 @@ macro(blender_add_lib_nolist
|
||||
# Not for system includes because they can resolve to the same path
|
||||
# list_assert_duplicates("${includes_sys}")
|
||||
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(blender_add_lib
|
||||
function(blender_add_lib
|
||||
name
|
||||
sources
|
||||
includes
|
||||
includes_sys)
|
||||
includes_sys
|
||||
)
|
||||
|
||||
blender_add_lib_nolist(${name} "${sources}" "${includes}" "${includes_sys}")
|
||||
|
||||
set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name})
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(SETUP_LIBDIRS)
|
||||
function(SETUP_LIBDIRS)
|
||||
|
||||
link_directories(${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${FREETYPE_LIBPATH})
|
||||
|
||||
if(WITH_PYTHON) # AND NOT WITH_PYTHON_MODULE # WIN32 needs
|
||||
@@ -288,24 +298,27 @@ macro(SETUP_LIBDIRS)
|
||||
if(WIN32 AND NOT UNIX)
|
||||
link_directories(${PTHREADS_LIBPATH})
|
||||
endif()
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
macro(setup_liblinks
|
||||
target)
|
||||
function(setup_liblinks
|
||||
target
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}" PARENT_SCOPE)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}" PARENT_SCOPE)
|
||||
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}" PARENT_SCOPE)
|
||||
|
||||
target_link_libraries(${target}
|
||||
${PNG_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${FREETYPE_LIBRARY})
|
||||
target_link_libraries(
|
||||
${target}
|
||||
${PNG_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${FREETYPE_LIBRARY}
|
||||
)
|
||||
|
||||
# since we are using the local libs for python when compiling msvc projects, we need to add _d when compiling debug versions
|
||||
if(WITH_PYTHON) # AND NOT WITH_PYTHON_MODULE # WIN32 needs
|
||||
@@ -402,11 +415,13 @@ macro(setup_liblinks
|
||||
unset(EXPAT_LIB_DEBUG)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${target}
|
||||
${OPENCOLLADA_LIBRARIES}
|
||||
${PCRE_LIBRARIES}
|
||||
${XML2_LIBRARIES}
|
||||
${EXPAT_LIB})
|
||||
target_link_libraries(
|
||||
${target}
|
||||
${OPENCOLLADA_LIBRARIES}
|
||||
${PCRE_LIBRARIES}
|
||||
${XML2_LIBRARIES}
|
||||
${EXPAT_LIB}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(WITH_MEM_JEMALLOC)
|
||||
@@ -421,12 +436,6 @@ macro(setup_liblinks
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(${target} ${LLVM_LIBRARY})
|
||||
endif()
|
||||
if(WITH_ALEMBIC)
|
||||
target_link_libraries(${target} ${ALEMBIC_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_HDF5)
|
||||
target_link_libraries(${target} ${HDF5_LIBRARIES})
|
||||
endif()
|
||||
if(WIN32 AND NOT UNIX)
|
||||
target_link_libraries(${target} ${PTHREADS_LIBRARIES})
|
||||
endif()
|
||||
@@ -442,9 +451,11 @@ macro(setup_liblinks
|
||||
${BLENDER_GL_LIBRARIES})
|
||||
|
||||
target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(SETUP_BLENDER_SORTED_LIBS)
|
||||
|
||||
macro(SETUP_BLENDER_SORTED_LIBS)
|
||||
get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS)
|
||||
|
||||
list(APPEND BLENDER_LINK_LIBS
|
||||
@@ -504,7 +515,6 @@ macro(SETUP_BLENDER_SORTED_LIBS)
|
||||
bf_editor_object
|
||||
bf_editor_armature
|
||||
bf_editor_physics
|
||||
bf_editor_hair
|
||||
bf_editor_render
|
||||
bf_editor_screen
|
||||
bf_editor_sculpt_paint
|
||||
@@ -568,8 +578,6 @@ macro(SETUP_BLENDER_SORTED_LIBS)
|
||||
ge_videotex
|
||||
bf_dna
|
||||
bf_blenfont
|
||||
bf_pointcache_alembic
|
||||
bf_pointcache
|
||||
bf_intern_audaspace
|
||||
bf_intern_mikktspace
|
||||
bf_intern_dualcon
|
||||
@@ -683,14 +691,12 @@ macro(SETUP_BLENDER_SORTED_LIBS)
|
||||
message(STATUS "Blender Skipping: (${REM_MSG})")
|
||||
endif()
|
||||
|
||||
unset(SEARCHLIB)
|
||||
unset(SORTLIB)
|
||||
unset(REMLIB)
|
||||
unset(REM_MSG)
|
||||
|
||||
set(BLENDER_SORTED_LIBS ${BLENDER_SORTED_LIBS} PARENT_SCOPE)
|
||||
|
||||
# for top-level tests
|
||||
set_property(GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP ${BLENDER_SORTED_LIBS})
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
macro(TEST_SSE_SUPPORT
|
||||
_sse_flags
|
||||
@@ -912,19 +918,22 @@ endmacro()
|
||||
|
||||
# utility macro
|
||||
macro(remove_cc_flag
|
||||
flag)
|
||||
_flag)
|
||||
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
foreach(flag ${ARGV})
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
endforeach()
|
||||
unset(flag)
|
||||
|
||||
endmacro()
|
||||
|
||||
@@ -938,28 +947,34 @@ endmacro()
|
||||
macro(remove_strict_flags)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
remove_cc_flag("-Wstrict-prototypes")
|
||||
remove_cc_flag("-Wmissing-prototypes")
|
||||
remove_cc_flag("-Wunused-parameter")
|
||||
remove_cc_flag("-Wunused-macros")
|
||||
remove_cc_flag("-Wwrite-strings")
|
||||
remove_cc_flag("-Wredundant-decls")
|
||||
remove_cc_flag("-Wundef")
|
||||
remove_cc_flag("-Wshadow")
|
||||
remove_cc_flag("-Wdouble-promotion")
|
||||
remove_cc_flag("-Wold-style-definition")
|
||||
remove_cc_flag("-Werror=[^ ]+")
|
||||
remove_cc_flag("-Werror")
|
||||
remove_cc_flag(
|
||||
"-Wstrict-prototypes"
|
||||
"-Wmissing-prototypes"
|
||||
"-Wmissing-format-attribute"
|
||||
"-Wunused-local-typedefs"
|
||||
"-Wunused-macros"
|
||||
"-Wunused-parameter"
|
||||
"-Wwrite-strings"
|
||||
"-Wredundant-decls"
|
||||
"-Wundef"
|
||||
"-Wshadow"
|
||||
"-Wdouble-promotion"
|
||||
"-Wold-style-definition"
|
||||
"-Werror=[^ ]+"
|
||||
"-Werror"
|
||||
)
|
||||
|
||||
# negate flags implied by '-Wall'
|
||||
add_cc_flag("${CC_REMOVE_STRICT_FLAGS}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
remove_cc_flag("-Wunused-parameter")
|
||||
remove_cc_flag("-Wunused-variable")
|
||||
remove_cc_flag("-Werror=[^ ]+")
|
||||
remove_cc_flag("-Werror")
|
||||
remove_cc_flag(
|
||||
"-Wunused-parameter"
|
||||
"-Wunused-variable"
|
||||
"-Werror=[^ ]+"
|
||||
"-Werror"
|
||||
)
|
||||
|
||||
# negate flags implied by '-Wall'
|
||||
add_cc_flag("${CC_REMOVE_STRICT_FLAGS}")
|
||||
@@ -973,11 +988,15 @@ endmacro()
|
||||
|
||||
macro(remove_extra_strict_flags)
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
remove_cc_flag("-Wunused-parameter")
|
||||
remove_cc_flag(
|
||||
"-Wunused-parameter"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
remove_cc_flag("-Wunused-parameter")
|
||||
remove_cc_flag(
|
||||
"-Wunused-parameter"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@@ -1013,37 +1032,39 @@ macro(remove_strict_flags_file
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(ADD_CHECK_C_COMPILER_FLAG
|
||||
function(ADD_CHECK_C_COMPILER_FLAG
|
||||
_CFLAGS
|
||||
_CACHE_VAR
|
||||
_FLAG)
|
||||
_FLAG
|
||||
)
|
||||
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
CHECK_C_COMPILER_FLAG("${_FLAG}" "${_CACHE_VAR}")
|
||||
if(${_CACHE_VAR})
|
||||
# message(STATUS "Using CFLAG: ${_FLAG}")
|
||||
set(${_CFLAGS} "${${_CFLAGS}} ${_FLAG}")
|
||||
set(${_CFLAGS} "${${_CFLAGS}} ${_FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Unsupported CFLAG: ${_FLAG}")
|
||||
endif()
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
macro(ADD_CHECK_CXX_COMPILER_FLAG
|
||||
function(ADD_CHECK_CXX_COMPILER_FLAG
|
||||
_CXXFLAGS
|
||||
_CACHE_VAR
|
||||
_FLAG)
|
||||
_FLAG
|
||||
)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("${_FLAG}" "${_CACHE_VAR}")
|
||||
if(${_CACHE_VAR})
|
||||
# message(STATUS "Using CXXFLAG: ${_FLAG}")
|
||||
set(${_CXXFLAGS} "${${_CXXFLAGS}} ${_FLAG}")
|
||||
set(${_CXXFLAGS} "${${_CXXFLAGS}} ${_FLAG}" PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "Unsupported CXXFLAG: ${_FLAG}")
|
||||
endif()
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
function(get_blender_version)
|
||||
# extracts header vars and defines them in the parent scope:
|
||||
@@ -1193,7 +1214,7 @@ endmacro()
|
||||
# pair of macros to allow libraries to be specify files to install, but to
|
||||
# only install them at the end so the directories don't get cleared with
|
||||
# the files in them. used by cycles to install addon.
|
||||
macro(delayed_install
|
||||
function(delayed_install
|
||||
base
|
||||
files
|
||||
destination)
|
||||
@@ -1206,8 +1227,7 @@ macro(delayed_install
|
||||
endif()
|
||||
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
|
||||
endforeach()
|
||||
unset(f)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
|
||||
# does not get expanded in calling but is preserved
|
||||
@@ -1226,16 +1246,17 @@ function(delayed_do_install
|
||||
list(GET destinations ${i} d)
|
||||
install(FILES ${f} DESTINATION ${targetdir}/${d})
|
||||
endforeach()
|
||||
unset(f)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
macro(data_to_c
|
||||
file_from file_to
|
||||
list_to_add)
|
||||
function(data_to_c
|
||||
file_from file_to
|
||||
list_to_add
|
||||
)
|
||||
|
||||
list(APPEND ${list_to_add} ${file_to})
|
||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
||||
|
||||
get_filename_component(_file_to_path ${file_to} PATH)
|
||||
|
||||
@@ -1246,21 +1267,21 @@ macro(data_to_c
|
||||
DEPENDS ${file_from} datatoc)
|
||||
|
||||
set_source_files_properties(${file_to} PROPERTIES GENERATED TRUE)
|
||||
|
||||
unset(_file_to_path)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
|
||||
# same as above but generates the var name and output automatic.
|
||||
macro(data_to_c_simple
|
||||
file_from
|
||||
list_to_add)
|
||||
function(data_to_c_simple
|
||||
file_from
|
||||
list_to_add
|
||||
)
|
||||
|
||||
# remove ../'s
|
||||
get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH)
|
||||
get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c REALPATH)
|
||||
|
||||
list(APPEND ${list_to_add} ${_file_to})
|
||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
||||
|
||||
get_filename_component(_file_to_path ${_file_to} PATH)
|
||||
|
||||
@@ -1271,17 +1292,13 @@ macro(data_to_c_simple
|
||||
DEPENDS ${_file_from} datatoc)
|
||||
|
||||
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
||||
|
||||
unset(_file_from)
|
||||
unset(_file_to)
|
||||
unset(_file_to_path)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# macro for converting pixmap directory to a png and then a c file
|
||||
macro(data_to_c_simple_icons
|
||||
path_from
|
||||
list_to_add
|
||||
)
|
||||
function(data_to_c_simple_icons
|
||||
path_from
|
||||
list_to_add
|
||||
)
|
||||
|
||||
# Conversion steps
|
||||
# path_from -> _file_from -> _file_to
|
||||
@@ -1293,6 +1310,7 @@ macro(data_to_c_simple_icons
|
||||
get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${path_from}.png.c REALPATH)
|
||||
|
||||
list(APPEND ${list_to_add} ${_file_to})
|
||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
||||
|
||||
get_filename_component(_file_to_path ${_file_to} PATH)
|
||||
|
||||
@@ -1314,27 +1332,22 @@ macro(data_to_c_simple_icons
|
||||
)
|
||||
|
||||
set_source_files_properties(${_file_from} ${_file_to} PROPERTIES GENERATED TRUE)
|
||||
|
||||
unset(_path_from_abs)
|
||||
unset(_file_from)
|
||||
unset(_file_to)
|
||||
unset(_file_to_path)
|
||||
unset(_icon_files)
|
||||
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# XXX Not used for now...
|
||||
macro(svg_to_png
|
||||
file_from
|
||||
file_to
|
||||
dpi
|
||||
list_to_add)
|
||||
function(svg_to_png
|
||||
file_from
|
||||
file_to
|
||||
dpi
|
||||
list_to_add
|
||||
)
|
||||
|
||||
# remove ../'s
|
||||
get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH)
|
||||
get_filename_component(_file_to ${CMAKE_CURRENT_SOURCE_DIR}/${file_to} REALPATH)
|
||||
|
||||
list(APPEND ${list_to_add} ${_file_to})
|
||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
||||
|
||||
find_program(INKSCAPE_EXE inkscape)
|
||||
mark_as_advanced(INKSCAPE_EXE)
|
||||
@@ -1357,15 +1370,12 @@ macro(svg_to_png
|
||||
else()
|
||||
message(WARNING "Inkscape not found, could not re-generate ${_file_to} from ${_file_from}!")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
unset(_file_from)
|
||||
unset(_file_to)
|
||||
|
||||
endmacro()
|
||||
|
||||
macro(msgfmt_simple
|
||||
file_from
|
||||
list_to_add)
|
||||
function(msgfmt_simple
|
||||
file_from
|
||||
list_to_add
|
||||
)
|
||||
|
||||
# remove ../'s
|
||||
get_filename_component(_file_from_we ${file_from} NAME_WE)
|
||||
@@ -1374,6 +1384,7 @@ macro(msgfmt_simple
|
||||
get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${_file_from_we}.mo REALPATH)
|
||||
|
||||
list(APPEND ${list_to_add} ${_file_to})
|
||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
||||
|
||||
get_filename_component(_file_to_path ${_file_to} PATH)
|
||||
|
||||
@@ -1384,15 +1395,11 @@ macro(msgfmt_simple
|
||||
DEPENDS msgfmt ${_file_from})
|
||||
|
||||
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
||||
endfunction()
|
||||
|
||||
unset(_file_from_we)
|
||||
unset(_file_from)
|
||||
unset(_file_to)
|
||||
unset(_file_to_path)
|
||||
endmacro()
|
||||
|
||||
macro(find_python_package
|
||||
package)
|
||||
function(find_python_package
|
||||
package
|
||||
)
|
||||
|
||||
string(TOUPPER ${package} _upper_package)
|
||||
|
||||
@@ -1430,25 +1437,17 @@ macro(find_python_package
|
||||
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', "
|
||||
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', "
|
||||
"WITH_PYTHON_INSTALL_${_upper_package} option will be ignored when installing python")
|
||||
set(WITH_PYTHON_INSTALL_${_upper_package} OFF)
|
||||
set(WITH_PYTHON_INSTALL_${_upper_package} OFF PARENT_SCOPE)
|
||||
else()
|
||||
message(STATUS "${package} found at '${PYTHON_${_upper_package}_PATH}'")
|
||||
endif()
|
||||
|
||||
unset(_PY_VER_SPLIT)
|
||||
unset(_PY_VER_MAJOR)
|
||||
endif()
|
||||
|
||||
unset(_upper_package)
|
||||
endmacro()
|
||||
endfunction()
|
||||
|
||||
# like Python's 'print(dir())'
|
||||
macro(print_all_vars)
|
||||
function(print_all_vars)
|
||||
get_cmake_property(_vars VARIABLES)
|
||||
foreach(_var ${_vars})
|
||||
message("${_var}=${${_var}}")
|
||||
endforeach()
|
||||
unset(_vars)
|
||||
unset(_var)
|
||||
endmacro()
|
||||
|
||||
endfunction()
|
||||
|
@@ -130,7 +130,7 @@ def is_project_file(filename):
|
||||
|
||||
|
||||
def cmake_advanced_info():
|
||||
""" Extracr includes and defines from cmake.
|
||||
""" Extract includes and defines from cmake.
|
||||
"""
|
||||
|
||||
make_exe = cmake_cache_var("CMAKE_MAKE_PROGRAM")
|
||||
|
@@ -52,9 +52,9 @@ BF_OPENEXR = '/usr'
|
||||
# BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR ${BF_OPENEXR}/include'
|
||||
|
||||
BF_OPENEXR_INC = '${BF_OPENEXR}/include/OpenEXR'
|
||||
BF_OPENEXR_LIB = 'Half IlmImf-2_1 Iex-2_1 Imath-2_1 '
|
||||
BF_OPENEXR_LIB = 'Half IlmImf Iex Imath '
|
||||
BF_OPENEXR_LIB_STATIC = '${BF_OPENEXR}/lib/libHalf.a ${BF_OPENEXR}/lib/libIlmImf.a ${BF_OPENEXR}/lib/libIex.a ${BF_OPENEXR}/lib/libImath.a ${BF_OPENEXR}/lib/libIlmThread.a'
|
||||
BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
|
||||
# BF_OPENEXR_LIBPATH = '${BF_OPENEXR}/lib'
|
||||
|
||||
|
||||
WITH_BF_DDS = True
|
||||
@@ -206,7 +206,7 @@ WITH_BF_CYCLES = WITH_BF_OIIO and WITH_BF_BOOST
|
||||
|
||||
WITH_BF_CYCLES_CUDA_BINARIES = False
|
||||
BF_CYCLES_CUDA_NVCC = '/usr/local/cuda/bin/nvcc'
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50']
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
|
||||
|
||||
WITH_BF_OPENMP = True
|
||||
|
||||
@@ -226,19 +226,6 @@ BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
|
||||
#Freestyle
|
||||
WITH_BF_FREESTYLE = True
|
||||
|
||||
# HDF5
|
||||
WITH_BF_HDF5 = True
|
||||
BF_HDF5 = '/usr'
|
||||
BF_HDF5_LIB = 'hdf5 hdf5_hl'
|
||||
BF_HDF5_LIBPATH='${BF_HDF5}/lib'
|
||||
|
||||
# Alembic
|
||||
WITH_BF_ALEMBIC = True
|
||||
BF_ALEMBIC = '/opt/lib/alembic'
|
||||
BF_ALEMBIC_LIB = 'AlembicAbcGeom AlembicAbc AlembicAbcCollection AlembicAbcCoreFactory AlembicAbcCoreHDF5 AlembicAbcCoreAbstract AlembicAbcCoreOgawa AlembicAbcMaterial AlembicOgawa AlembicUtil'
|
||||
BF_ALEMBIC_INC = '${BF_ALEMBIC}/include'
|
||||
BF_ALEMBIC_LIBPATH='${BF_ALEMBIC}/lib/static'
|
||||
|
||||
##
|
||||
CC = 'gcc'
|
||||
CXX = 'g++'
|
||||
|
@@ -145,7 +145,7 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
|
||||
WITH_BF_CYCLES = True
|
||||
WITH_BF_CYCLES_CUDA_BINARIES = False
|
||||
BF_CYCLES_CUDA_NVCC = "" # Path to the NVIDIA CUDA compiler
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50']
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
|
||||
|
||||
WITH_BF_OIIO = True
|
||||
BF_OIIO = LIBDIR + '/openimageio'
|
||||
|
@@ -144,7 +144,7 @@ BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib/opencollada'
|
||||
WITH_BF_CYCLES = True
|
||||
WITH_BF_CYCLES_CUDA_BINARIES = False
|
||||
BF_CYCLES_CUDA_NVCC = "" # Path to the NVIDIA CUDA compiler
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50']
|
||||
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_20', 'sm_21', 'sm_30', 'sm_35', 'sm_50', 'sm_52']
|
||||
|
||||
WITH_BF_OIIO = True
|
||||
BF_OIIO = LIBDIR + '/openimageio'
|
||||
|
@@ -204,20 +204,10 @@ def setup_staticlibs(lenv):
|
||||
libincs += Split(lenv['BF_OIIO_LIBPATH'])
|
||||
if lenv['WITH_BF_STATICOIIO']:
|
||||
statlibs += Split(lenv['BF_OIIO_LIB_STATIC'])
|
||||
|
||||
if lenv['WITH_BF_HDF5']:
|
||||
libincs += Split(lenv['BF_HDF5_LIBPATH'])
|
||||
|
||||
if lenv['WITH_BF_ALEMBIC']:
|
||||
libincs += Split(lenv['BF_ALEMBIC_LIBPATH'])
|
||||
if lenv['WITH_BF_STATICALEMBIC']:
|
||||
statlibs += Split(lenv['BF_ALEMBIC_LIB_STATIC'])
|
||||
|
||||
if lenv['WITH_BF_OPENEXR']:
|
||||
libincs += Split(lenv['BF_OPENEXR_LIBPATH'])
|
||||
if lenv['WITH_BF_STATICOPENEXR']:
|
||||
statlibs += Split(lenv['BF_OPENEXR_LIB_STATIC'])
|
||||
|
||||
if lenv['WITH_BF_ZLIB'] and lenv['WITH_BF_STATICZLIB']:
|
||||
statlibs += Split(lenv['BF_ZLIB_LIB_STATIC'])
|
||||
|
||||
@@ -293,16 +283,8 @@ def setup_syslibs(lenv):
|
||||
if not lenv['WITH_BF_STATICOCIO']:
|
||||
syslibs += Split(lenv['BF_OCIO_LIB'])
|
||||
|
||||
if lenv['WITH_BF_HDF5']:
|
||||
syslibs += Split(lenv['BF_HDF5_LIB'])
|
||||
|
||||
if lenv['WITH_BF_ALEMBIC']:
|
||||
if not lenv['WITH_BF_STATICALEMBIC']:
|
||||
syslibs += Split(lenv['BF_ALEMBIC_LIB'])
|
||||
|
||||
if lenv['WITH_BF_OPENEXR'] and not lenv['WITH_BF_STATICOPENEXR']:
|
||||
syslibs += Split(lenv['BF_OPENEXR_LIB'])
|
||||
|
||||
if lenv['WITH_BF_ZLIB'] and not lenv['WITH_BF_STATICZLIB']:
|
||||
syslibs += Split(lenv['BF_ZLIB_LIB'])
|
||||
if lenv['WITH_BF_TIFF'] and not lenv['WITH_BF_STATICTIFF']:
|
||||
@@ -390,23 +372,7 @@ def propose_priorities():
|
||||
def creator(env):
|
||||
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
|
||||
|
||||
incs = ['#/intern/guardedalloc',
|
||||
'#/source/blender/blenlib',
|
||||
'#/source/blender/blenkernel',
|
||||
'#/source/blender/depsgraph',
|
||||
'#/source/blender/editors/include',
|
||||
'#/source/blender/blenloader',
|
||||
'#/source/blender/imbuf',
|
||||
'#/source/blender/renderconverter',
|
||||
'#/source/blender/render/extern/include',
|
||||
'#/source/blender/windowmanager',
|
||||
'#/source/blender/makesdna',
|
||||
'#/source/blender/makesrna',
|
||||
'#/source/blender/pointcache',
|
||||
'#/source/gameengine/BlenderRoutines',
|
||||
'#/extern/glew/include',
|
||||
'#/source/blender/gpu',
|
||||
env['BF_OPENGL_INC']]
|
||||
incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/depsgraph', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
|
||||
|
||||
defs = []
|
||||
|
||||
@@ -798,7 +764,7 @@ def AppIt(target=None, source=None, env=None):
|
||||
commands.getoutput(cmd)
|
||||
cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
|
||||
commands.getoutput(cmd)
|
||||
cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/kernel/geom %s/util/util_color.h %s/util/util_half.h %s/util/util_math.h %s/util/util_math_fast.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, croot, croot, croot, cinstalldir)
|
||||
cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/kernel/geom %s/kernel/split %s/kernel/kernels %s/util/util_color.h %s/util/util_half.h %s/util/util_math.h %s/util/util_math_fast.h %s/util/util_transform.h %s/util/util_types.h %s/util/util_atomic.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, croot, cinstalldir)
|
||||
commands.getoutput(cmd)
|
||||
cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
|
||||
commands.getoutput(cmd)
|
||||
|
@@ -182,8 +182,7 @@ def validate_arguments(args, bc):
|
||||
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_INTERNATIONAL', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
|
||||
'WITH_BF_LIBMV', 'WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS',
|
||||
'WITH_BF_CYCLES_OSL', 'WITH_BF_STATICOSL', 'BF_OSL', 'BF_OSL_INC', 'BF_OSL_LIB', 'BF_OSL_LIBPATH', 'BF_OSL_LIB_STATIC', 'BF_OSL_COMPILER',
|
||||
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS',
|
||||
'WITH_BF_ALEMBIC', 'BF_ALEMBIC', 'BF_ALEMBIC_INC', 'BF_ALEMBIC_LIB', 'BF_ALEMBIC_LIBPATH',
|
||||
'WITH_BF_LLVM', 'WITH_BF_STATICLLVM', 'BF_LLVM', 'BF_LLVM_LIB', 'BF_LLVM_LIBPATH', 'BF_LLVM_LIB_STATIC', 'BF_PROGRAM_LINKFLAGS'
|
||||
]
|
||||
|
||||
# Have options here that scons expects to be lists
|
||||
@@ -582,19 +581,6 @@ def read_opts(env, cfg, args):
|
||||
(BoolVariable('WITH_BF_LIBMV_SCHUR_SPECIALIZATIONS', 'Enable fixed-size schur specializations', True)),
|
||||
|
||||
(BoolVariable('WITH_BF_COMPOSITOR', 'Enable the tile based nodal compositor', True)),
|
||||
|
||||
(BoolVariable('WITH_BF_HDF5', 'Use HDF5 if true', False)),
|
||||
('BF_HDF5', 'HDF5 base path', ''),
|
||||
('BF_HDF5_LIB', 'HDF5 library', ''),
|
||||
('BF_HDF5_LIBPATH', 'HDF5 library path', ''),
|
||||
|
||||
(BoolVariable('WITH_BF_ALEMBIC', 'Use Alembic if true', False)),
|
||||
(BoolVariable('WITH_BF_STATICALEMBIC', 'Staticly link to Alembic', False)),
|
||||
('BF_ALEMBIC', 'Alembic base path', ''),
|
||||
('BF_ALEMBIC_INC', 'Alembic include path', ''),
|
||||
('BF_ALEMBIC_LIB', 'Alembic library', ''),
|
||||
('BF_ALEMBIC_LIB_STATIC', 'Alembic static libraries', ''),
|
||||
('BF_ALEMBIC_LIBPATH', 'Alembic library path', ''),
|
||||
) # end of opts.AddOptions()
|
||||
|
||||
localopts.AddVariables(
|
||||
|
47
doc/python_api/rst/bge.app.rst
Normal file
47
doc/python_api/rst/bge.app.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
Application Data (bge.app)
|
||||
==========================
|
||||
|
||||
Module to access application values that remain unchanged during runtime.
|
||||
|
||||
.. module:: bge.app
|
||||
|
||||
.. data:: version
|
||||
|
||||
The Blender/BGE version as a tuple of 3 ints, eg. (2, 75, 1).
|
||||
|
||||
.. note:: Version tuples can be compared simply with (in)equality symbols;
|
||||
for example, ``(2, 74, 5) <= (2, 75, 0)`` returns True (lexical order).
|
||||
|
||||
:type: tuple of three ints
|
||||
|
||||
.. data:: version_string
|
||||
|
||||
The Blender/BGE version formatted as a string, eg. "2.75 (sub 1)".
|
||||
|
||||
:type: str
|
||||
|
||||
.. data:: version_char
|
||||
|
||||
The Blender/BGE version character (for minor releases).
|
||||
|
||||
:type: str
|
||||
|
||||
.. data:: has_texture_ffmpeg
|
||||
|
||||
True if the BGE has been built with FFmpeg support, enabling use of :class:`~bge.texture.ImageFFmpeg` and :class:`~bge.texture.VideoFFmpeg`.
|
||||
|
||||
:type: bool
|
||||
|
||||
.. data:: has_joystick
|
||||
|
||||
True if the BGE has been built with joystick support.
|
||||
|
||||
:type: bool
|
||||
|
||||
.. data:: has_physics
|
||||
|
||||
True if the BGE has been built with physics support.
|
||||
|
||||
:type: bool
|
||||
|
@@ -4,75 +4,84 @@ Physics Constraints (bge.constraints)
|
||||
|
||||
.. module:: bge.constraints
|
||||
|
||||
.. literalinclude:: ../examples/bge.constraints.py
|
||||
:language: rest
|
||||
:lines: 2-4
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
.. include:: ../examples/bge.constraints.py
|
||||
:start-line: 1
|
||||
:end-line: 4
|
||||
|
||||
.. literalinclude:: ../examples/bge.constraints.py
|
||||
:lines: 6-
|
||||
|
||||
.. function:: createConstraint(physicsid_1, physicsid_2, constraint_type, pivot_X, pivot_y, pivot_z, axis_x, axis_y, axis_z, flag)
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. function:: createConstraint( \
|
||||
physicsid_1, physicsid_2, constraint_type, \
|
||||
pivot_x=0.0, pivot_y=0.0, pivot_z=0.0, \
|
||||
axis_x=0.0, axis_y=0.0, axis_z=0.0, flag=0)
|
||||
|
||||
Creates a constraint.
|
||||
|
||||
Constraints types:
|
||||
:arg physicsid_1: The physics id of the first object in constraint.
|
||||
:type physicsid_1: int
|
||||
|
||||
:arg physicsid_2: The physics id of the second object in constraint.
|
||||
:type physicsid_2: int
|
||||
|
||||
:arg constraint_type: The type of the constraint, one of...
|
||||
|
||||
- :class:`POINTTOPOINT_CONSTRAINT`
|
||||
- :class:`LINEHINGE_CONSTRAINT`
|
||||
- :class:`ANGULAR_CONSTRAINT`
|
||||
- :class:`CONETWIST_CONSTRAINT`
|
||||
- :class:`VEHICLE_CONSTRAINT`
|
||||
- :class:`GENERIC_6DOF_CONSTRAINT`
|
||||
- :class:`GENERIC_6DOF_CONSTRAINT`
|
||||
|
||||
:arg physicsid_1: the physics id of the first object in constraint.
|
||||
:type physicsid_1: int
|
||||
:type constraint_type: int
|
||||
|
||||
:arg physicsid_2: the physics id of the second object in constraint.
|
||||
:type physicsid_2: int
|
||||
:arg pivot_x: Pivot X position. (optional)
|
||||
:type pivot_x: float
|
||||
|
||||
:arg constrainttype: the type of the constraint.
|
||||
:type constrainttype: int
|
||||
:arg pivot_y: Pivot Y position. (optional)
|
||||
:type pivot_y: float
|
||||
|
||||
:arg pivot_X: pivot X position (optional).
|
||||
:type pivot_X: float
|
||||
:arg pivot_z: Pivot Z position. (optional)
|
||||
:type pivot_z: float
|
||||
|
||||
:arg pivot_Y: pivot Y position (optional).
|
||||
:type pivot_Y: float
|
||||
:arg axis_x: X axis angle in degrees. (optional)
|
||||
:type axis_x: float
|
||||
|
||||
:arg pivot_Z: pivot Z position (optional).
|
||||
:type pivot_Z: float
|
||||
:arg axis_y: Y axis angle in degrees. (optional)
|
||||
:type axis_y: float
|
||||
|
||||
:arg axis_X: X axis angle in degrees (optional).
|
||||
:type axis_X: float
|
||||
:arg axis_z: Z axis angle in degrees. (optional)
|
||||
:type axis_z: float
|
||||
|
||||
:arg axis_Y: Y axis angle in degrees (optional).
|
||||
:type axis_Y: float
|
||||
|
||||
:arg axis_Z: Z axis angle in degrees (optional).
|
||||
:type axis_Z: float
|
||||
|
||||
:arg flag: 128 to disable collision between linked bodies (optional).
|
||||
:arg flag: 128 to disable collision between linked bodies. (optional)
|
||||
:type flag: int
|
||||
|
||||
:return: a constraint wrapper.
|
||||
:rtype: :class:`bge.types.KX_ConstraintWrapper`
|
||||
|
||||
.. attribute:: error
|
||||
|
||||
Symbolic constant string that indicates error.
|
||||
:return: A constraint wrapper.
|
||||
:rtype: :class:`~bge.types.KX_ConstraintWrapper`
|
||||
|
||||
.. function:: exportBulletFile(filename)
|
||||
|
||||
export a .bullet file
|
||||
Exports a file representing the dynamics world (usually using ``.bullet`` extension).
|
||||
|
||||
:arg filename: File name
|
||||
:type filename: string
|
||||
See `Bullet binary serialization <http://bulletphysics.org/mediawiki-1.5.8/index.php/Bullet_binary_serialization>`__.
|
||||
|
||||
:arg filename: File path.
|
||||
:type filename: str
|
||||
|
||||
.. function:: getAppliedImpulse(constraintId)
|
||||
|
||||
:arg constraintId: The id of the constraint.
|
||||
:type constraintId: int
|
||||
|
||||
:return: the most recent applied impulse.
|
||||
:return: The most recent applied impulse.
|
||||
:rtype: float
|
||||
|
||||
.. function:: getVehicleConstraint(constraintId)
|
||||
@@ -80,16 +89,16 @@ Physics Constraints (bge.constraints)
|
||||
:arg constraintId: The id of the vehicle constraint.
|
||||
:type constraintId: int
|
||||
|
||||
:return: a vehicle constraint object.
|
||||
:rtype: :class:`bge.types.KX_VehicleWrapper`
|
||||
:return: A vehicle constraint object.
|
||||
:rtype: :class:`~bge.types.KX_VehicleWrapper`
|
||||
|
||||
.. function:: getCharacter(gameobj)
|
||||
|
||||
:arg gameobj: The game object with the character physics.
|
||||
:type gameobj: :class:`bge.types.KX_GameObject`
|
||||
:type gameobj: :class:`~bge.types.KX_GameObject`
|
||||
|
||||
:return: character wrapper
|
||||
:rtype: :class:`bge.types.KX_CharacterWrapper`
|
||||
:return: Character wrapper.
|
||||
:rtype: :class:`~bge.types.KX_CharacterWrapper`
|
||||
|
||||
.. function:: removeConstraint(constraintId)
|
||||
|
||||
@@ -143,7 +152,8 @@ Physics Constraints (bge.constraints)
|
||||
|
||||
Sets the debug mode.
|
||||
|
||||
Debug modes:
|
||||
:arg mode: The new debug mode.
|
||||
|
||||
- :class:`DBG_NODEBUG`
|
||||
- :class:`DBG_DRAWWIREFRAME`
|
||||
- :class:`DBG_DRAWAABB`
|
||||
@@ -159,7 +169,6 @@ Physics Constraints (bge.constraints)
|
||||
- :class:`DBG_DRAWCONSTRAINTLIMITS`
|
||||
- :class:`DBG_FASTWIREFRAME`
|
||||
|
||||
:arg mode: The new debug mode.
|
||||
:type mode: int
|
||||
|
||||
.. function:: setGravity(x, y, z)
|
||||
@@ -178,7 +187,8 @@ Physics Constraints (bge.constraints)
|
||||
.. function:: setLinearAirDamping(damping)
|
||||
|
||||
.. note::
|
||||
Not implemented.
|
||||
|
||||
Not implemented
|
||||
|
||||
Sets the linear air damping for rigidbodies.
|
||||
|
||||
@@ -238,144 +248,111 @@ Physics Constraints (bge.constraints)
|
||||
|
||||
.. function:: setUseEpa(epa)
|
||||
|
||||
Not implemented.
|
||||
.. note::
|
||||
|
||||
Not implemented
|
||||
|
||||
|
||||
Constants
|
||||
+++++++++
|
||||
|
||||
.. attribute:: error
|
||||
|
||||
Symbolic constant string that indicates error.
|
||||
|
||||
:type: str
|
||||
|
||||
|
||||
Debug Mode Constants
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Debug mode to be used with :func:`setDebugMode`.
|
||||
|
||||
|
||||
.. data:: DBG_NODEBUG
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
No debug.
|
||||
|
||||
.. data:: DBG_DRAWWIREFRAME
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw wireframe in debug.
|
||||
|
||||
.. data:: DBG_DRAWAABB
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw Axis Aligned Bounding Box in debug.
|
||||
|
||||
.. data:: DBG_DRAWFREATURESTEXT
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw freatures text in debug.
|
||||
Draw features text in debug.
|
||||
|
||||
.. data:: DBG_DRAWCONTACTPOINTS
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw contact points in debug.
|
||||
|
||||
.. data:: DBG_NOHELPTEXT
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Debug without help text.
|
||||
|
||||
.. data:: DBG_DRAWTEXT
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw text in debug.
|
||||
|
||||
.. data:: DBG_PROFILETIMINGS
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw profile timings in debug.
|
||||
|
||||
.. data:: DBG_ENABLESATCOMPARISION
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Enable sat comparision in debug.
|
||||
|
||||
.. data:: DBG_DISABLEBULLETLCP
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Disable Bullet LCP.
|
||||
|
||||
.. data:: DBG_ENABLECCD
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Enable Continous Colision Detection in debug.
|
||||
Enable Continous Collision Detection in debug.
|
||||
|
||||
.. data:: DBG_DRAWCONSTRAINTS
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw constraints in debug.
|
||||
|
||||
.. data:: DBG_DRAWCONSTRAINTLIMITS
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw constraint limits in debug.
|
||||
|
||||
.. data:: DBG_FASTWIREFRAME
|
||||
|
||||
.. note::
|
||||
Debug mode to be used with function :class:`setDebugMode`
|
||||
|
||||
Draw a fast wireframe in debug.
|
||||
|
||||
.. data:: POINTTOPOINT_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
Create Constraint Constants
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Constraint type to be used with :func:`createConstraint`.
|
||||
|
||||
|
||||
.. data:: POINTTOPOINT_CONSTRAINT
|
||||
|
||||
.. to do
|
||||
|
||||
.. data:: LINEHINGE_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
|
||||
.. to do
|
||||
|
||||
.. data:: ANGULAR_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
|
||||
.. to do
|
||||
|
||||
.. data:: CONETWIST_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
|
||||
.. to do
|
||||
|
||||
.. data:: VEHICLE_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
|
||||
.. to do
|
||||
|
||||
.. data:: GENERIC_6DOF_CONSTRAINT
|
||||
|
||||
.. note::
|
||||
Constraint type to be used with function :class:`createConstraint`
|
||||
|
||||
.. to do
|
||||
|
||||
|
@@ -894,6 +894,8 @@ Various
|
||||
2D Filter
|
||||
---------
|
||||
|
||||
.. _Two-D-FilterActuator-mode:
|
||||
|
||||
.. data:: RAS_2DFILTER_BLUR
|
||||
|
||||
:value: 2
|
||||
@@ -1288,5 +1290,3 @@ See :class:`bge.types.KX_StateActuator.operation`
|
||||
Add bits to state mask
|
||||
|
||||
:value: 3
|
||||
|
||||
.. _Two-D-FilterActuator-mode:
|
||||
|
@@ -218,6 +218,8 @@ When the texture object is deleted, the new texture is deleted and the old textu
|
||||
|
||||
background color
|
||||
|
||||
:type: int or float list [r, g, b, a] in [0.0, 255.0]
|
||||
|
||||
.. attribute:: capsize
|
||||
|
||||
size of render area
|
||||
@@ -315,6 +317,8 @@ When the texture object is deleted, the new texture is deleted and the old textu
|
||||
|
||||
background color
|
||||
|
||||
:type: int or float list [r, g, b, a] in [0.0, 255.0]
|
||||
|
||||
.. attribute:: capsize
|
||||
|
||||
size of render area
|
||||
|
@@ -7,11 +7,66 @@ base class --- :class:`PyObjectPlus`
|
||||
|
||||
.. class:: KX_BlenderMaterial(PyObjectPlus)
|
||||
|
||||
KX_BlenderMaterial
|
||||
This is the interface to materials in the game engine.
|
||||
|
||||
Materials define the render state to be applied to mesh objects.
|
||||
|
||||
The example below shows a simple GLSL shader setup allowing to dynamically mix two texture channels
|
||||
in a material. All materials of the object executing this script should have two textures using
|
||||
separate UV maps in the two first texture channels.
|
||||
|
||||
The code works for both Multitexture and GLSL rendering modes.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from bge import logic
|
||||
|
||||
vertex_shader = """
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// simple projection of the vertex position to view space
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
// coordinate of the 1st texture channel
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
// coordinate of the 2nd texture channel
|
||||
gl_TexCoord[1] = gl_MultiTexCoord1;
|
||||
}
|
||||
"""
|
||||
|
||||
fragment_shader ="""
|
||||
|
||||
uniform sampler2D texture_0;
|
||||
uniform sampler2D texture_1;
|
||||
uniform float factor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 color_0 = texture2D(texture_0, gl_TexCoord[0].st);
|
||||
vec4 color_1 = texture2D(texture_1, gl_TexCoord[1].st);
|
||||
gl_FragColor = mix(color_0, color_1, factor);
|
||||
}
|
||||
"""
|
||||
|
||||
object = logic.getCurrentController().owner
|
||||
|
||||
for mesh in object.meshes:
|
||||
for material in mesh.materials:
|
||||
shader = material.getShader()
|
||||
if shader is not None:
|
||||
if not shader.isValid():
|
||||
shader.setSource(vertex_shader, fragment_shader, True)
|
||||
|
||||
# get the first texture channel of the material
|
||||
shader.setSampler('texture_0', 0)
|
||||
# get the second texture channel of the material
|
||||
shader.setSampler('texture_1', 1)
|
||||
# pass another uniform to the shader
|
||||
shader.setUniform1f('factor', 0.3)
|
||||
|
||||
.. attribute:: shader
|
||||
|
||||
The materials shader.
|
||||
The material's shader.
|
||||
|
||||
:type: :class:`BL_Shader`
|
||||
|
||||
@@ -38,35 +93,37 @@ base class --- :class:`PyObjectPlus`
|
||||
|
||||
Set the pixel color arithmetic functions.
|
||||
|
||||
:arg src: Specifies how the red, green, blue, and alpha source blending factors are computed.
|
||||
:type src: Value in...
|
||||
:arg src: Specifies how the red, green, blue, and alpha source blending factors are computed, one of...
|
||||
|
||||
* :data:`~bgl.GL_ZERO`
|
||||
* :data:`~bgl.GL_ONE`
|
||||
* :data:`~bgl.GL_SRC_COLOR`
|
||||
* :data:`~bgl.GL_ONE_MINUS_SRC_COLOR`
|
||||
* :data:`~bgl.GL_DST_COLOR`
|
||||
* :data:`~bgl.GL_ONE_MINUS_DST_COLOR`
|
||||
* :data:`~bgl.GL_SRC_ALPHA`
|
||||
* :data:`~bgl.GL_ONE_MINUS_SRC_ALPHA`
|
||||
* :data:`~bgl.GL_DST_ALPHA`
|
||||
* :data:`~bgl.GL_ONE_MINUS_DST_ALPHA`
|
||||
* :data:`~bgl.GL_SRC_ALPHA_SATURATE`
|
||||
|
||||
:type src: int
|
||||
|
||||
* GL_ZERO,
|
||||
* GL_ONE,
|
||||
* GL_SRC_COLOR,
|
||||
* GL_ONE_MINUS_SRC_COLOR,
|
||||
* GL_DST_COLOR,
|
||||
* GL_ONE_MINUS_DST_COLOR,
|
||||
* GL_SRC_ALPHA,
|
||||
* GL_ONE_MINUS_SRC_ALPHA,
|
||||
* GL_DST_ALPHA,
|
||||
* GL_ONE_MINUS_DST_ALPHA,
|
||||
* GL_SRC_ALPHA_SATURATE
|
||||
|
||||
:arg dest: Specifies how the red, green, blue, and alpha destination blending factors are computed.
|
||||
:type dest: Value in...
|
||||
|
||||
* GL_ZERO
|
||||
* GL_ONE
|
||||
* GL_SRC_COLOR
|
||||
* GL_ONE_MINUS_SRC_COLOR
|
||||
* GL_DST_COLOR
|
||||
* GL_ONE_MINUS_DST_COLOR
|
||||
* GL_SRC_ALPHA
|
||||
* GL_ONE_MINUS_SRC_ALPHA
|
||||
* GL_DST_ALPHA
|
||||
* GL_ONE_MINUS_DST_ALPHA
|
||||
* GL_SRC_ALPHA_SATURATE
|
||||
:arg dest: Specifies how the red, green, blue, and alpha destination blending factors are computed, one of...
|
||||
|
||||
* :data:`~bgl.GL_ZERO`
|
||||
* :data:`~bgl.GL_ONE`
|
||||
* :data:`~bgl.GL_SRC_COLOR`
|
||||
* :data:`~bgl.GL_ONE_MINUS_SRC_COLOR`
|
||||
* :data:`~bgl.GL_DST_COLOR`
|
||||
* :data:`~bgl.GL_ONE_MINUS_DST_COLOR`
|
||||
* :data:`~bgl.GL_SRC_ALPHA`
|
||||
* :data:`~bgl.GL_ONE_MINUS_SRC_ALPHA`
|
||||
* :data:`~bgl.GL_DST_ALPHA`
|
||||
* :data:`~bgl.GL_ONE_MINUS_DST_ALPHA`
|
||||
* :data:`~bgl.GL_SRC_ALPHA_SATURATE`
|
||||
|
||||
:type dest: int
|
||||
|
||||
.. method:: getMaterialIndex()
|
||||
|
||||
|
@@ -139,6 +139,29 @@ base class --- :class:`SCA_IObject`
|
||||
|
||||
A value of 0.0 disables this option (rather then setting it stationary).
|
||||
|
||||
.. attribute:: angularVelocityMin
|
||||
|
||||
Enforces the object keeps rotating at a minimum velocity. A value of 0.0 disables this.
|
||||
|
||||
:type: non-negative float
|
||||
|
||||
.. note::
|
||||
|
||||
Applies to dynamic and rigid body objects only.
|
||||
While objects are stationary the minimum velocity will not be applied.
|
||||
|
||||
|
||||
.. attribute:: angularVelocityMax
|
||||
|
||||
Clamp the maximum angular velocity to prevent objects rotating beyond a set speed.
|
||||
A value of 0.0 disables clamping; it does not stop rotation.
|
||||
|
||||
:type: non-negative float
|
||||
|
||||
.. note::
|
||||
|
||||
Applies to dynamic and rigid body objects only.
|
||||
|
||||
.. attribute:: localInertia
|
||||
|
||||
the object's inertia vector in local coordinates. Read only.
|
||||
|
@@ -1,250 +0,0 @@
|
||||
KX_PolygonMaterial(PyObjectPlus)
|
||||
================================
|
||||
|
||||
.. module:: bge.types
|
||||
|
||||
base class --- :class:`PyObjectPlus`
|
||||
|
||||
.. class:: KX_PolygonMaterial(PyObjectPlus)
|
||||
|
||||
This is the interface to materials in the game engine.
|
||||
|
||||
Materials define the render state to be applied to mesh objects.
|
||||
|
||||
.. warning::
|
||||
|
||||
Some of the methods/variables are CObjects. If you mix these up, you will crash blender.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from bge import logic
|
||||
|
||||
vertex_shader = """
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// original vertex position, no changes
|
||||
gl_Position = ftransform();
|
||||
// coordinate of the 1st texture channel
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
// coordinate of the 2nd texture channel
|
||||
gl_TexCoord[1] = gl_MultiTexCoord1;
|
||||
}
|
||||
"""
|
||||
|
||||
fragment_shader ="""
|
||||
|
||||
uniform sampler2D color_0;
|
||||
uniform sampler2D color_1;
|
||||
uniform float factor;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
vec4 color_0 = texture2D(color_0, gl_TexCoord[0].st);
|
||||
vec4 color_1 = texture2D(color_1, gl_TexCoord[1].st);
|
||||
gl_FragColor = mix(color_0, color_1, factor);
|
||||
}
|
||||
"""
|
||||
|
||||
object = logic.getCurrentController().owner
|
||||
object = cont.owner
|
||||
for mesh in object.meshes:
|
||||
for material in mesh.materials:
|
||||
shader = material.getShader()
|
||||
if shader != None:
|
||||
if not shader.isValid():
|
||||
shader.setSource(vertex_shader, fragment_shader, True)
|
||||
|
||||
# get the first texture channel of the material
|
||||
shader.setSampler('color_0', 0)
|
||||
# get the second texture channel of the material
|
||||
shader.setSampler('color_1', 1)
|
||||
# pass another uniform to the shader
|
||||
shader.setUniform1f('factor', 0.3)
|
||||
|
||||
|
||||
.. attribute:: texture
|
||||
|
||||
Texture name.
|
||||
|
||||
:type: string (read-only)
|
||||
|
||||
.. attribute:: gl_texture
|
||||
|
||||
OpenGL texture handle (eg for glBindTexture(GL_TEXTURE_2D, gl_texture).
|
||||
|
||||
:type: integer (read-only)
|
||||
|
||||
.. attribute:: material
|
||||
|
||||
Material name.
|
||||
|
||||
:type: string (read-only)
|
||||
|
||||
.. attribute:: tface
|
||||
|
||||
Texture face properties.
|
||||
|
||||
:type: CObject (read-only)
|
||||
|
||||
.. attribute:: tile
|
||||
|
||||
Texture is tiling.
|
||||
|
||||
:type: boolean
|
||||
|
||||
.. attribute:: tilexrep
|
||||
|
||||
Number of tile repetitions in x direction.
|
||||
|
||||
:type: integer
|
||||
|
||||
.. attribute:: tileyrep
|
||||
|
||||
Number of tile repetitions in y direction.
|
||||
|
||||
:type: integer
|
||||
|
||||
.. attribute:: drawingmode
|
||||
|
||||
Drawing mode for the material.
|
||||
- 2 (drawingmode & 4) Textured
|
||||
- 4 (drawingmode & 16) Light
|
||||
- 14 (drawingmode & 16384) 3d Polygon Text.
|
||||
|
||||
:type: bitfield
|
||||
|
||||
.. attribute:: transparent
|
||||
|
||||
This material is transparent. All meshes with this
|
||||
material will be rendered after non transparent meshes from back
|
||||
to front.
|
||||
|
||||
:type: boolean
|
||||
|
||||
.. attribute:: zsort
|
||||
|
||||
Transparent polygons in meshes with this material will be sorted back to
|
||||
front before rendering.
|
||||
Non-Transparent polygons will be sorted front to back before rendering.
|
||||
|
||||
:type: boolean
|
||||
|
||||
.. attribute:: diffuse
|
||||
|
||||
The diffuse color of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0].
|
||||
|
||||
:type: list [r, g, b]
|
||||
|
||||
.. attribute:: specular
|
||||
|
||||
The specular color of the material. black = [0.0, 0.0, 0.0] white = [1.0, 1.0, 1.0].
|
||||
|
||||
:type: list [r, g, b]
|
||||
|
||||
.. attribute:: shininess
|
||||
|
||||
The shininess (specular exponent) of the material. 0.0 <= shininess <= 128.0.
|
||||
|
||||
:type: float
|
||||
|
||||
.. attribute:: specularity
|
||||
|
||||
The amount of specular of the material. 0.0 <= specularity <= 1.0.
|
||||
|
||||
:type: float
|
||||
|
||||
.. method:: updateTexture(tface, rasty)
|
||||
|
||||
Updates a realtime animation.
|
||||
|
||||
:arg tface: Texture face (eg mat.tface)
|
||||
:type tface: CObject
|
||||
:arg rasty: Rasterizer
|
||||
:type rasty: CObject
|
||||
|
||||
.. method:: setTexture(tface)
|
||||
|
||||
Sets texture render state.
|
||||
|
||||
:arg tface: Texture face
|
||||
:type tface: CObject
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
mat.setTexture(mat.tface)
|
||||
|
||||
.. method:: activate(rasty, cachingInfo)
|
||||
|
||||
Sets material parameters for this object for rendering.
|
||||
|
||||
Material Parameters set:
|
||||
|
||||
#. Texture
|
||||
#. Backface culling
|
||||
#. Line drawing
|
||||
#. Specular Colour
|
||||
#. Shininess
|
||||
#. Diffuse Colour
|
||||
#. Polygon Offset.
|
||||
|
||||
:arg rasty: Rasterizer instance.
|
||||
:type rasty: CObject
|
||||
:arg cachingInfo: Material cache instance.
|
||||
:type cachingInfo: CObject
|
||||
|
||||
.. method:: setCustomMaterial(material)
|
||||
|
||||
Sets the material state setup object.
|
||||
|
||||
Using this method, you can extend or completely replace the gameengine material
|
||||
to do your own advanced multipass effects.
|
||||
|
||||
Use this method to register your material class. Instead of the normal material,
|
||||
your class's activate method will be called just before rendering the mesh.
|
||||
This should setup the texture, material, and any other state you would like.
|
||||
It should return True to render the mesh, or False if you are finished. You should
|
||||
clean up any state Blender does not set before returning False.
|
||||
|
||||
Activate Method Definition:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def activate(self, rasty, cachingInfo, material):
|
||||
|
||||
:arg material: The material object.
|
||||
:type material: instance
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class PyMaterial:
|
||||
def __init__(self):
|
||||
self.pass_no = -1
|
||||
|
||||
def activate(self, rasty, cachingInfo, material):
|
||||
# Activate the material here.
|
||||
#
|
||||
# The activate method will be called until it returns False.
|
||||
# Every time the activate method returns True the mesh will
|
||||
# be rendered.
|
||||
#
|
||||
# rasty is a CObject for passing to material.updateTexture()
|
||||
# and material.activate()
|
||||
# cachingInfo is a CObject for passing to material.activate()
|
||||
# material is the KX_PolygonMaterial instance this material
|
||||
# was added to
|
||||
|
||||
# default material properties:
|
||||
self.pass_no += 1
|
||||
if self.pass_no == 0:
|
||||
material.activate(rasty, cachingInfo)
|
||||
# Return True to do this pass
|
||||
return True
|
||||
|
||||
# clean up and return False to finish.
|
||||
self.pass_no = -1
|
||||
return False
|
||||
|
||||
# Create a new Python Material and pass it to the renderer.
|
||||
mat.setCustomMaterial(PyMaterial())
|
||||
|
@@ -7,7 +7,7 @@ base class --- :class:`SCA_IActuator`
|
||||
|
||||
.. class:: SCA_2DFilterActuator(SCA_IActuator)
|
||||
|
||||
Create, enable and disable 2D filters
|
||||
Create, enable and disable 2D filters.
|
||||
|
||||
The following properties don't have an immediate effect.
|
||||
You must active the actuator to get the result.
|
||||
@@ -29,7 +29,7 @@ base class --- :class:`SCA_IActuator`
|
||||
|
||||
.. attribute:: mode
|
||||
|
||||
Type of 2D filter, use one of :ref:`these constants <Two-D-FilterActuator-mode>`
|
||||
Type of 2D filter, use one of :ref:`these constants <Two-D-FilterActuator-mode>`.
|
||||
|
||||
:type: integer
|
||||
|
||||
|
@@ -121,7 +121,7 @@ Here are some more complex examples:
|
||||
bpy.context.scene.render.layers["RenderLayer"].samples
|
||||
|
||||
# access to the current weight paint brush size
|
||||
bpy.context.tool_settings.weight_paint.brush.size
|
||||
bpy.context.tool_settings.weight_paint.brush.size
|
||||
|
||||
# check if the window is fullscreen
|
||||
bpy.context.window.screen.show_fullscreen
|
||||
@@ -141,15 +141,16 @@ When starting out scripting you will often run into the problem where you're not
|
||||
|
||||
There are a few ways to do this.
|
||||
|
||||
- Use the Python console's auto-complete to inspect properties. *This can be hit-and-miss but has the advantage
|
||||
- Use the Python console's auto-complete to inspect properties.
|
||||
*This can be hit-and-miss but has the advantage
|
||||
that you can easily see the values of properties and assign them to interactively see the results.*
|
||||
|
||||
- Copy the Data-Path from the user interface. *Explained further in :ref:`Copy Data Path <info_data_path_copy>`*
|
||||
|
||||
- Using the documentation to follow references. *Explained further in :ref:`Indirect Data Access <info_data_path_indirect>`*
|
||||
- Copy the Data-Path from the user interface.
|
||||
*Explained further in :ref:`Copy Data Path <info_data_path_copy>`*
|
||||
- Using the documentation to follow references.
|
||||
*Explained further in :ref:`Indirect Data Access <info_data_path_indirect>`*
|
||||
|
||||
|
||||
.. _info_data_path_copy
|
||||
.. _info_data_path_copy:
|
||||
|
||||
Copy Data Path
|
||||
--------------
|
||||
@@ -172,7 +173,8 @@ you won't be doing collection look-ups on every access and typically you'll want
|
||||
then access each :class:`bpy.types.ID` instance by name.
|
||||
|
||||
|
||||
Type in the ID path into a Python console :mod:`bpy.context.active_object`. Include the trailing dot and don't hit "enter", yet.
|
||||
Type in the ID path into a Python console :mod:`bpy.context.active_object`.
|
||||
Include the trailing dot and don't hit "enter", yet.
|
||||
|
||||
Now right-click on the button and select **Copy Data Path**, then paste the result into the console.
|
||||
|
||||
@@ -191,7 +193,7 @@ Hit "enter" and you'll get the current value of 1. Now try changing the value to
|
||||
You can see the value update in the Subdivision-Surface modifier's UI as well as the cube.
|
||||
|
||||
|
||||
.. _info_data_path_indirect
|
||||
.. _info_data_path_indirect:
|
||||
|
||||
Indirect Data Access
|
||||
--------------------
|
||||
@@ -201,32 +203,24 @@ For this example we'll go over something more involved, showing the steps to acc
|
||||
Lets say we want to access the texture of a brush via Python, to adjust its ``contrast`` for example.
|
||||
|
||||
- Start in the default scene and enable 'Sculpt' mode from the 3D-View header.
|
||||
|
||||
- From the toolbar expand the **Texture** panel and add a new texture.
|
||||
|
||||
*Notice the texture button its self doesn't have very useful links (you can check the tool-tips).*
|
||||
|
||||
- The contrast setting isn't exposed in the sculpt toolbar, so view the texture in the properties panel...
|
||||
|
||||
- In the properties button select the Texture context.
|
||||
|
||||
- Select the Brush icon to show the brush texture.
|
||||
|
||||
- Expand the **Colors** panel to locate the **Contrast** button.
|
||||
|
||||
- Right click on the contrast button and select **Online Python Reference** This takes you to ``bpy.types.Texture.contrast``
|
||||
|
||||
- Now we can see that ``contrast`` is a property of texture, so next we'll check on how to access the texture from the brush.
|
||||
|
||||
- Expand the *Colors* panel to locate the *Contrast* button.
|
||||
- Right click on the contrast button and select **Online Python Reference**
|
||||
This takes you to ``bpy.types.Texture.contrast``
|
||||
- Now we can see that ``contrast`` is a property of texture,
|
||||
so next we'll check on how to access the texture from the brush.
|
||||
- Check on the **References** at the bottom of the page, sometimes there are many references, and it may take
|
||||
some guess work to find the right one, but in this case its obviously ``Brush.texture``.
|
||||
|
||||
*Now we know that the texture can be accessed from* ``bpy.data.brushes["BrushName"].texture``
|
||||
*but normally you won't want to access the brush by name, so we'll see now to access the active brush instead.*
|
||||
|
||||
- So the next step is to check on where brushes are accessed from via the **References**.
|
||||
In this case there is simply ``bpy.context.brush`` which is all we need.
|
||||
|
||||
|
||||
Now you can use the Python console to form the nested properties needed to access brush textures contrast,
|
||||
logically we now know.
|
||||
@@ -282,7 +276,8 @@ are interested to check on the source code.
|
||||
|
||||
.. note::
|
||||
|
||||
Not all operators can be called usefully from Python, for more on this see :ref:`using operators <using_operators>`.
|
||||
Not all operators can be called usefully from Python,
|
||||
for more on this see :ref:`using operators <using_operators>`.
|
||||
|
||||
|
||||
Info View
|
||||
@@ -294,7 +289,8 @@ This is located above the file-menu which can be dragged down to display its con
|
||||
Select the **Script** screen that comes default with Blender to see its output.
|
||||
You can perform some actions and see them show up - delete a vertex for example.
|
||||
|
||||
Each entry can be selected (Right-Mouse-Button), then copied :kbd:`Control-C`, usually to paste in the text editor or python console.
|
||||
Each entry can be selected (Right-Mouse-Button),
|
||||
then copied :kbd:`Control-C`, usually to paste in the text editor or python console.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@@ -1,16 +1,20 @@
|
||||
|
||||
*************
|
||||
Best Practice
|
||||
*************
|
||||
|
||||
When writing your own scripts python is great for new developers to pick up and become productive, but you can also pick up odd habits or at least write scripts that are not easy for others to understand.
|
||||
When writing your own scripts python is great for new developers to pick up and become productive,
|
||||
but you can also pick up odd habits or at least write scripts that are not easy for others to understand.
|
||||
|
||||
For your own work this is of course fine, but if you want to collaborate with others or have your work included with blender there are practices we encourage.
|
||||
For your own work this is of course fine,
|
||||
but if you want to collaborate with others or have your work included with blender there are practices we encourage.
|
||||
|
||||
|
||||
Style Conventions
|
||||
=================
|
||||
|
||||
For Blender/Python development we have chosen to follow python suggested style guide to avoid mixing styles amongst our own scripts and make it easier to use python scripts from other projects.
|
||||
For Blender/Python development we have chosen to follow python suggested style guide to avoid mixing styles
|
||||
amongst our own scripts and make it easier to use python scripts from other projects.
|
||||
|
||||
Using our style guide for your own scripts makes it easier if you eventually want to contribute them to blender.
|
||||
|
||||
@@ -18,22 +22,17 @@ This style guide is known as pep8 and can be found `here <http://www.python.org/
|
||||
|
||||
A brief listing of pep8 criteria.
|
||||
|
||||
* camel caps for class names: MyClass
|
||||
|
||||
* all lower case underscore separated module names: my_module
|
||||
|
||||
* indentation of 4 spaces (no tabs)
|
||||
|
||||
* spaces around operators. ``1 + 1``, not ``1+1``
|
||||
|
||||
* only use explicit imports, (no importing '*')
|
||||
|
||||
* don't use single line: ``if val: body``, separate onto 2 lines instead.
|
||||
- camel caps for class names: MyClass
|
||||
- all lower case underscore separated module names: my_module
|
||||
- indentation of 4 spaces (no tabs)
|
||||
- spaces around operators. ``1 + 1``, not ``1+1``
|
||||
- only use explicit imports, (no importing ``*``)
|
||||
- don't use single line: ``if val: body``, separate onto 2 lines instead.
|
||||
|
||||
|
||||
As well as pep8 we have other conventions used for blender python scripts.
|
||||
|
||||
* Use single quotes for enums, and double quotes for strings.
|
||||
- Use single quotes for enums, and double quotes for strings.
|
||||
|
||||
Both are of course strings but in our internal API enums are unique items from a limited set. eg.
|
||||
|
||||
@@ -42,9 +41,11 @@ As well as pep8 we have other conventions used for blender python scripts.
|
||||
bpy.context.scene.render.image_settings.file_format = 'PNG'
|
||||
bpy.context.scene.render.filepath = "//render_out"
|
||||
|
||||
* pep8 also defines that lines should not exceed 79 characters, we felt this is too restrictive so this is optional per script.
|
||||
- pep8 also defines that lines should not exceed 79 characters,
|
||||
we felt this is too restrictive so this is optional per script.
|
||||
|
||||
Periodically we run checks for pep8 compliance on blender scripts, for scripts to be included in this check add this line as a comment at the top of the script.
|
||||
Periodically we run checks for pep8 compliance on blender scripts,
|
||||
for scripts to be included in this check add this line as a comment at the top of the script.
|
||||
|
||||
``# <pep8 compliant>``
|
||||
|
||||
@@ -58,72 +59,75 @@ User Interface Layout
|
||||
|
||||
Some notes to keep in mind when writing UI layouts:
|
||||
|
||||
* UI code is quite simple. Layout declarations are there to easily create a decent layout.
|
||||
- UI code is quite simple. Layout declarations are there to easily create a decent layout.
|
||||
|
||||
General rule here: If you need more code for the layout declaration,
|
||||
then for the actual properties, you do it wrong.
|
||||
|
||||
General rule here: If you need more code for the layout declaration, then for the actual properties, you do it wrong.
|
||||
|
||||
Example layouts:
|
||||
|
||||
* layout()
|
||||
- layout()
|
||||
|
||||
The basic layout is a simple Top -> Bottom layout.
|
||||
|
||||
The basic layout is a simple Top -> Bottom layout.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
layout.prop()
|
||||
layout.prop()
|
||||
layout.prop()
|
||||
layout.prop()
|
||||
|
||||
* layout.row()
|
||||
- layout.row()
|
||||
|
||||
Use row(), when you want more than 1 property in one line.
|
||||
|
||||
Use row(), when you want more than 1 property in one line.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
row = layout.row()
|
||||
row.prop()
|
||||
row.prop()
|
||||
|
||||
* layout.column()
|
||||
row = layout.row()
|
||||
row.prop()
|
||||
row.prop()
|
||||
|
||||
- layout.column()
|
||||
|
||||
Use column(), when you want your properties in a column.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
col = layout.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
* layout.split()
|
||||
col = layout.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
This can be used to create more complex layouts. For example you can split the layout and create two column() layouts next to each other.
|
||||
- layout.split()
|
||||
|
||||
This can be used to create more complex layouts.
|
||||
For example you can split the layout and create two column() layouts next to each other.
|
||||
Don't use split, when you simply want two properties in a row. Use row() for that.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
col = split.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
col = split.column()
|
||||
col.prop()
|
||||
col.prop()
|
||||
|
||||
Declaration names:
|
||||
|
||||
Try to only use these variable names for layout declarations:
|
||||
|
||||
* row for a row() layout
|
||||
* col for a column() layout
|
||||
* split for a split() layout
|
||||
* flow for a column_flow() layout
|
||||
* sub for a sub layout (a column inside a column for example)
|
||||
- row for a row() layout
|
||||
- col for a column() layout
|
||||
- split for a split() layout
|
||||
- flow for a column_flow() layout
|
||||
- sub for a sub layout (a column inside a column for example)
|
||||
|
||||
|
||||
Script Efficiency
|
||||
=================
|
||||
|
||||
|
||||
List Manipulation (General Python Tips)
|
||||
---------------------------------------
|
||||
|
||||
@@ -133,7 +137,8 @@ Searching for list items
|
||||
|
||||
In Python there are some handy list functions that save you having to search through the list.
|
||||
|
||||
Even though you're not looping on the list data **python is**, so you need to be aware of functions that will slow down your script by searching the whole list.
|
||||
Even though you're not looping on the list data **python is**,
|
||||
so you need to be aware of functions that will slow down your script by searching the whole list.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -145,11 +150,16 @@ Even though you're not looping on the list data **python is**, so you need to be
|
||||
|
||||
Modifying Lists
|
||||
^^^^^^^^^^^^^^^
|
||||
In python we can add and remove from a list, this is slower when the list length is modified, especially at the start of the list, since all the data after the index of modification needs to be moved up or down 1 place.
|
||||
In python we can add and remove from a list, this is slower when the list length is modified,
|
||||
especially at the start of the list, since all the data after the index of
|
||||
modification needs to be moved up or down 1 place.
|
||||
|
||||
The most simple way to add onto the end of the list is to use ``my_list.append(list_item)`` or ``my_list.extend(some_list)`` and the fastest way to remove an item is ``my_list.pop()`` or ``del my_list[-1]``.
|
||||
The most simple way to add onto the end of the list is to use
|
||||
``my_list.append(list_item)`` or ``my_list.extend(some_list)`` and the fastest way to
|
||||
remove an item is ``my_list.pop()`` or ``del my_list[-1]``.
|
||||
|
||||
To use an index you can use ``my_list.insert(index, list_item)`` or ``list.pop(index)`` for list removal, but these are slower.
|
||||
To use an index you can use ``my_list.insert(index, list_item)`` or ``list.pop(index)``
|
||||
for list removal, but these are slower.
|
||||
|
||||
Sometimes its faster (but more memory hungry) to just rebuild the list.
|
||||
|
||||
@@ -193,7 +203,8 @@ Use...
|
||||
my_list.extend([a, b, c...])
|
||||
|
||||
|
||||
Note that insert can be used when needed, but it is slower than append especially when inserting at the start of a long list.
|
||||
Note that insert can be used when needed,
|
||||
but it is slower than append especially when inserting at the start of a long list.
|
||||
|
||||
This example shows a very sub-optimal way of making a reversed list.
|
||||
|
||||
@@ -205,7 +216,8 @@ This example shows a very sub-optimal way of making a reversed list.
|
||||
reverse_list.insert(0, list_item)
|
||||
|
||||
|
||||
Python provides more convenient ways to reverse a list using the slice method, but you may want to time this before relying on it too much:
|
||||
Python provides more convenient ways to reverse a list using the slice method,
|
||||
but you may want to time this before relying on it too much:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
@@ -220,7 +232,8 @@ Use ``my_list.pop(index)`` rather than ``my_list.remove(list_item)``
|
||||
|
||||
This requires you to have the index of the list item but is faster since ``remove()`` will search the list.
|
||||
|
||||
Here is an example of how to remove items in 1 loop, removing the last items first, which is faster (as explained above).
|
||||
Here is an example of how to remove items in 1 loop,
|
||||
removing the last items first, which is faster (as explained above).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -232,7 +245,9 @@ Here is an example of how to remove items in 1 loop, removing the last items fir
|
||||
my_list.pop(list_index)
|
||||
|
||||
|
||||
This example shows a fast way of removing items, for use in cases where you can alter the list order without breaking the scripts functionality. This works by swapping 2 list items, so the item you remove is always last.
|
||||
This example shows a fast way of removing items,
|
||||
for use in cases where you can alter the list order without breaking the scripts functionality.
|
||||
This works by swapping 2 list items, so the item you remove is always last.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -251,7 +266,9 @@ When removing many items in a large list this can provide a good speedup.
|
||||
Avoid Copying Lists
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When passing a list/dictionary to a function, it is faster to have the function modify the list rather than returning a new list so python doesn't have to duplicate the list in memory.
|
||||
When passing a list/dictionary to a function,
|
||||
it is faster to have the function modify the list rather than returning
|
||||
a new list so python doesn't have to duplicate the list in memory.
|
||||
|
||||
Functions that modify a list in-place are more efficient than functions that create new lists.
|
||||
|
||||
@@ -296,20 +313,26 @@ Python’s string joining function. To join a list of strings
|
||||
>>> file.write(" ".join([str1, str2, str3, "\n"]))
|
||||
|
||||
|
||||
join is fastest on many strings, `string formatting <http://docs.python.org/py3k/library/string.html#string-formatting>`_ is quite fast too (better for converting data types). String arithmetic is slowest.
|
||||
join is fastest on many strings,
|
||||
`string formatting <http://docs.python.org/py3k/library/string.html#string-formatting>`__
|
||||
is quite fast too (better for converting data types). String arithmetic is slowest.
|
||||
|
||||
|
||||
Parsing Strings (Import/Exporting)
|
||||
----------------------------------
|
||||
|
||||
Since many file formats are ASCII, the way you parse/export strings can make a large difference in how fast your script runs.
|
||||
Since many file formats are ASCII,
|
||||
the way you parse/export strings can make a large difference in how fast your script runs.
|
||||
|
||||
There are a few ways to parse strings when importing them into Blender.
|
||||
|
||||
|
||||
Parsing Numbers
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Use ``float(string)`` rather than ``eval(string)``, if you know the value will be an int then ``int(string)``, float() will work for an int too but it's faster to read ints with int().
|
||||
Use ``float(string)`` rather than ``eval(string)``, if you know the value will be an int then ``int(string)``,
|
||||
float() will work for an int too but it's faster to read ints with int().
|
||||
|
||||
|
||||
Checking String Start/End
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -322,7 +345,8 @@ Use...
|
||||
|
||||
>>> if line.startswith("vert "):
|
||||
|
||||
Using ``startswith()`` is slightly faster (approx 5%) and also avoids a possible error with the slice length not matching the string length.
|
||||
Using ``startswith()`` is slightly faster (approx 5%) and also avoids a possible
|
||||
error with the slice length not matching the string length.
|
||||
|
||||
my_string.endswith("foo_bar") can be used for line endings too.
|
||||
|
||||
@@ -336,15 +360,19 @@ Use try/except Sparingly
|
||||
|
||||
The **try** statement is useful to save time writing error checking code.
|
||||
|
||||
However **try** is significantly slower than an **if** since an exception has to be set each time, so avoid using **try** in areas of your code that execute in a loop and runs many times.
|
||||
However **try** is significantly slower than an **if** since an exception has to be set each time,
|
||||
so avoid using **try** in areas of your code that execute in a loop and runs many times.
|
||||
|
||||
There are cases where using **try** is faster than checking whether the condition will raise an error, so it is worth experimenting.
|
||||
There are cases where using **try** is faster than checking whether the condition will raise an error,
|
||||
so it is worth experimenting.
|
||||
|
||||
|
||||
Value Comparison
|
||||
----------------
|
||||
|
||||
Python has two ways to compare values ``a == b`` and ``a is b``, the difference is that ``==`` may run the objects comparison function ``__cmp__()`` whereas ``is`` compares identity, that both variables reference the same item in memory.
|
||||
Python has two ways to compare values ``a == b`` and ``a is b``,
|
||||
the difference is that ``==`` may run the objects comparison function ``__cmp__()`` whereas ``is`` compares identity,
|
||||
that both variables reference the same item in memory.
|
||||
|
||||
In cases where you know you are checking for the same value which is referenced from multiple places, ``is`` is faster.
|
||||
|
||||
@@ -362,3 +390,4 @@ While developing a script it's good to time it to be aware of any changes in per
|
||||
# do something...
|
||||
|
||||
print("My Script Finished: %.4f sec" % time.time() - time_start)
|
||||
|
||||
|
@@ -1,18 +1,25 @@
|
||||
|
||||
.. _info_overview:
|
||||
|
||||
*******************
|
||||
Python API Overview
|
||||
*******************
|
||||
|
||||
This document is to give an understanding of how python and blender fit together, covering some of the functionality that isn't obvious from reading the API reference and example scripts.
|
||||
This document is to give an understanding of how Python and Blender fit together,
|
||||
covering some of the functionality that isn't obvious from reading the API reference and example scripts.
|
||||
|
||||
|
||||
Python in Blender
|
||||
=================
|
||||
|
||||
Blender embeds a python interpreter which is started with blender and stays active. This interpreter runs scripts to draw the user interface and is used for some of Blender's internal tools too.
|
||||
Blender embeds a Python interpreter which is started with Blender and stays active.
|
||||
This interpreter runs scripts to draw the user interface and is used for some of Blender's internal tools too.
|
||||
|
||||
This is a typical python environment so tutorials on how to write python scripts will work running the scripts in blender too. Blender provides the :mod:`bpy` module to the python interpreter. This module can be imported in a script and gives access to blender data, classes, and functions. Scripts that deal with blender data will need to import this module.
|
||||
This is a typical Python environment so tutorials on how to write Python scripts
|
||||
will work running the scripts in Blender too.
|
||||
Blender provides the :mod:`bpy` module to the Python interpreter.
|
||||
This module can be imported in a script and gives access to Blender data, classes, and functions.
|
||||
Scripts that deal with Blender data will need to import this module.
|
||||
|
||||
Here is a simple example of moving a vertex of the object named **Cube**:
|
||||
|
||||
@@ -21,84 +28,96 @@ Here is a simple example of moving a vertex of the object named **Cube**:
|
||||
import bpy
|
||||
bpy.data.objects["Cube"].data.vertices[0].co.x += 1.0
|
||||
|
||||
This modifies Blender's internal data directly. When you run this in the interactive console you will see the 3D viewport update.
|
||||
This modifies Blender's internal data directly.
|
||||
When you run this in the interactive console you will see the 3D viewport update.
|
||||
|
||||
|
||||
The Default Environment
|
||||
=======================
|
||||
|
||||
When developing your own scripts it may help to understand how blender sets up its python environment. Many python scripts come bundled with blender and can be used as a reference because they use the same API that script authors write tools in. Typical usage for scripts include: user interface, import/export, scene manipulation, automation, defining your own toolset and customization.
|
||||
When developing your own scripts it may help to understand how Blender sets up its Python environment.
|
||||
Many Python scripts come bundled with Blender and can be used as a reference
|
||||
because they use the same API that script authors write tools in.
|
||||
Typical usage for scripts include: user interface, import/export,
|
||||
scene manipulation, automation, defining your own toolset and customization.
|
||||
|
||||
On startup blender scans the ``scripts/startup/`` directory for python modules and imports them. The exact location of this directory depends on your installation. `See the directory layout docs <http://wiki.blender.org/index.php/Doc:2.6/Manual/Introduction/Installing_Blender/DirectoryLayout>`_
|
||||
On startup Blender scans the ``scripts/startup/`` directory for Python modules and imports them.
|
||||
The exact location of this directory depends on your installation.
|
||||
`See the directory layout docs
|
||||
<https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`__
|
||||
|
||||
|
||||
Script Loading
|
||||
==============
|
||||
|
||||
This may seem obvious but it's important to note the difference between executing a script directly or importing it as a module.
|
||||
This may seem obvious but it's important to note the difference
|
||||
between executing a script directly or importing it as a module.
|
||||
|
||||
Scripts that extend blender - define classes that exist beyond the scripts execution, this makes future access to these classes (to unregister for example) more difficult than importing as a module where class instance is kept in the module and can be accessed by importing that module later on.
|
||||
Scripts that extend Blender - define classes that exist beyond the scripts execution,
|
||||
this makes future access to these classes (to unregister for example)
|
||||
more difficult than importing as a module where class instance is kept
|
||||
in the module and can be accessed by importing that module later on.
|
||||
|
||||
For this reason it's preferable to only use directly execute scripts that don't extend blender by registering classes.
|
||||
For this reason it's preferable to only use directly execute scripts that don't extend Blender by registering classes.
|
||||
|
||||
|
||||
Here are some ways to run scripts directly in blender.
|
||||
Here are some ways to run scripts directly in Blender.
|
||||
|
||||
* Loaded in the text editor and press **Run Script**.
|
||||
- Loaded in the text editor and press **Run Script**.
|
||||
- Typed or pasted into the interactive console.
|
||||
- Execute a Python file from the command line with Blender, eg:
|
||||
|
||||
* Typed or pasted into the interactive console.
|
||||
.. code-block:: sh
|
||||
|
||||
* Execute a python file from the command line with blender, eg:
|
||||
|
||||
``blender --python /home/me/my_script.py``
|
||||
blender --python /home/me/my_script.py
|
||||
|
||||
|
||||
To run as modules:
|
||||
|
||||
* The obvious way, ``import some_module`` command from the text window or interactive console.
|
||||
|
||||
* Open as a text block and tick "Register" option, this will load with the blend file.
|
||||
|
||||
* copy into one of the directories ``scripts/startup``, where they will be automatically imported on startup.
|
||||
|
||||
* define as an addon, enabling the addon will load it as a python module.
|
||||
- The obvious way, ``import some_module`` command from the text window or interactive console.
|
||||
- Open as a text block and tick "Register" option, this will load with the blend file.
|
||||
- copy into one of the directories ``scripts/startup``, where they will be automatically imported on startup.
|
||||
- define as an addon, enabling the addon will load it as a Python module.
|
||||
|
||||
|
||||
Addons
|
||||
------
|
||||
|
||||
Some of blenders functionality is best kept optional, alongside scripts loaded at startup we have addons which are kept in their own directory ``scripts/addons``, and only load on startup if selected from the user preferences.
|
||||
Some of Blenders functionality is best kept optional,
|
||||
alongside scripts loaded at startup we have addons which are kept in their own directory ``scripts/addons``,
|
||||
and only load on startup if selected from the user preferences.
|
||||
|
||||
The only difference between addons and built-in python modules is that addons must contain a **bl_info** variable which blender uses to read metadata such as name, author, category and URL.
|
||||
The only difference between addons and built-in Python modules is that addons must contain a ``bl_info``
|
||||
variable which Blender uses to read metadata such as name, author, category and URL.
|
||||
|
||||
The user preferences addon listing uses **bl_info** to display information about each addon.
|
||||
|
||||
`See Addons <http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons>`_ for details on the **bl_info** dictionary.
|
||||
`See Addons <http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons>`__
|
||||
for details on the ``bl_info`` dictionary.
|
||||
|
||||
|
||||
Integration through Classes
|
||||
===========================
|
||||
|
||||
Running python scripts in the text editor is useful for testing but you’ll want to extend blender to make tools accessible like other built-in functionality.
|
||||
Running Python scripts in the text editor is useful for testing but you'll
|
||||
want to extend Blender to make tools accessible like other built-in functionality.
|
||||
|
||||
The blender python api allows integration for:
|
||||
The Blender Python api allows integration for:
|
||||
|
||||
* :class:`bpy.types.Panel`
|
||||
|
||||
* :class:`bpy.types.Menu`
|
||||
|
||||
* :class:`bpy.types.Operator`
|
||||
|
||||
* :class:`bpy.types.PropertyGroup`
|
||||
|
||||
* :class:`bpy.types.KeyingSet`
|
||||
|
||||
* :class:`bpy.types.RenderEngine`
|
||||
- :class:`bpy.types.Panel`
|
||||
- :class:`bpy.types.Menu`
|
||||
- :class:`bpy.types.Operator`
|
||||
- :class:`bpy.types.PropertyGroup`
|
||||
- :class:`bpy.types.KeyingSet`
|
||||
- :class:`bpy.types.RenderEngine`
|
||||
|
||||
|
||||
This is intentionally limited. Currently, for more advanced features such as mesh modifiers, object types, or shader nodes, C/C++ must be used.
|
||||
This is intentionally limited. Currently, for more advanced features such as mesh modifiers,
|
||||
object types, or shader nodes, C/C++ must be used.
|
||||
|
||||
For python intergration Blender defines methods which are common to all types. This works by creating a python subclass of a Blender class which contains variables and functions specified by the parent class which are pre-defined to interface with Blender.
|
||||
For Python integration Blender defines methods which are common to all types.
|
||||
This works by creating a Python subclass of a Blender class which contains variables and functions
|
||||
specified by the parent class which are pre-defined to interface with Blender.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -115,15 +134,20 @@ For example:
|
||||
|
||||
bpy.utils.register_class(SimpleOperator)
|
||||
|
||||
First note that we subclass a member of :mod:`bpy.types`, this is common for all classes which can be integrated with blender and used so we know if this is an Operator and not a Panel when registering.
|
||||
First note that we subclass a member of :mod:`bpy.types`,
|
||||
this is common for all classes which can be integrated with Blender and
|
||||
used so we know if this is an Operator and not a Panel when registering.
|
||||
|
||||
Both class properties start with a **bl_** prefix. This is a convention used to distinguish blender properties from those you add yourself.
|
||||
Both class properties start with a ``bl_`` prefix.
|
||||
This is a convention used to distinguish Blender properties from those you add yourself.
|
||||
|
||||
Next see the execute function, which takes an instance of the operator and the current context. A common prefix is not used for functions.
|
||||
Next see the execute function, which takes an instance of the operator and the current context.
|
||||
A common prefix is not used for functions.
|
||||
|
||||
Lastly the register function is called, this takes the class and loads it into blender. See `Class Registration`_.
|
||||
Lastly the register function is called, this takes the class and loads it into Blender. See `Class Registration`_.
|
||||
|
||||
Regarding inheritance, blender doesn't impose restrictions on the kinds of class inheritance used, the registration checks will use attributes and functions defined in parent classes.
|
||||
Regarding inheritance, Blender doesn't impose restrictions on the kinds of class inheritance used,
|
||||
the registration checks will use attributes and functions defined in parent classes.
|
||||
|
||||
class mix-in example:
|
||||
|
||||
@@ -141,11 +165,20 @@ class mix-in example:
|
||||
|
||||
bpy.utils.register_class(SimpleOperator)
|
||||
|
||||
Notice these classes don't define an ``__init__(self)`` function. While ``__init__()`` and ``__del__()`` will be called if defined, the class instances lifetime only spans the execution. So a panel for example will have a new instance for every redraw, for this reason there is rarely a cause to store variables in the panel instance. Instead, persistent variables should be stored in Blenders data so that the state can be restored when blender is restarted.
|
||||
Notice these classes don't define an ``__init__(self)`` function.
|
||||
While ``__init__()`` and ``__del__()`` will be called if defined,
|
||||
the class instances lifetime only spans the execution.
|
||||
So a panel for example will have a new instance for every redraw,
|
||||
for this reason there is rarely a cause to store variables in the panel instance.
|
||||
Instead, persistent variables should be stored in Blenders
|
||||
ata so that the state can be restored when Blender is restarted.
|
||||
|
||||
.. note:: Modal operators are an exception, keeping their instance variable as blender runs, see modal operator template.
|
||||
.. note::
|
||||
|
||||
So once the class is registered with blender, instancing the class and calling the functions is left up to blender. In fact you cannot instance these classes from the script as you would expect with most python API's.
|
||||
Modal operators are an exception, keeping their instance variable as Blender runs, see modal operator template.
|
||||
|
||||
So once the class is registered with Blender, instancing the class and calling the functions is left up to Blender.
|
||||
In fact you cannot instance these classes from the script as you would expect with most Python API's.
|
||||
|
||||
To run operators you can call them through the operator api, eg:
|
||||
|
||||
@@ -154,7 +187,8 @@ To run operators you can call them through the operator api, eg:
|
||||
import bpy
|
||||
bpy.ops.object.simple_operator()
|
||||
|
||||
User interface classes are given a context in which to draw, buttons window, file header, toolbar etc, then they are drawn when that area is displayed so they are never called by python scripts directly.
|
||||
User interface classes are given a context in which to draw, buttons window, file header, toolbar etc,
|
||||
then they are drawn when that area is displayed so they are never called by Python scripts directly.
|
||||
|
||||
|
||||
Registration
|
||||
@@ -164,9 +198,10 @@ Registration
|
||||
Module Registration
|
||||
-------------------
|
||||
|
||||
Blender modules loaded at startup require ``register()`` and ``unregister()`` functions. These are the *only* functions that blender calls from your code, which is otherwise a regular python module.
|
||||
Blender modules loaded at startup require ``register()`` and ``unregister()`` functions.
|
||||
These are the *only* functions that Blender calls from your code, which is otherwise a regular Python module.
|
||||
|
||||
A simple blender/python module can look like this:
|
||||
A simple Blender/Python module can look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -184,12 +219,16 @@ A simple blender/python module can look like this:
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
|
||||
These functions usually appear at the bottom of the script containing class registration sometimes adding menu items. You can also use them for internal purposes setting up data for your own tools but take care since register won't re-run when a new blend file is loaded.
|
||||
These functions usually appear at the bottom of the script containing class registration sometimes adding menu items.
|
||||
You can also use them for internal purposes setting up data for your own tools but take care
|
||||
since register won't re-run when a new blend file is loaded.
|
||||
|
||||
The register/unregister calls are used so it's possible to toggle addons and reload scripts while blender runs.
|
||||
If the register calls were placed in the body of the script, registration would be called on import, meaning there would be no distinction between importing a module or loading its classes into blender.
|
||||
The register/unregister calls are used so it's possible to toggle addons and reload scripts while Blender runs.
|
||||
If the register calls were placed in the body of the script, registration would be called on import,
|
||||
meaning there would be no distinction between importing a module or loading its classes into Blender.
|
||||
|
||||
This becomes problematic when a script imports classes from another module making it difficult to manage which classes are being loaded and when.
|
||||
This becomes problematic when a script imports classes from another module
|
||||
making it difficult to manage which classes are being loaded and when.
|
||||
|
||||
The last 2 lines are only for testing:
|
||||
|
||||
@@ -199,19 +238,24 @@ The last 2 lines are only for testing:
|
||||
register()
|
||||
|
||||
This allows the script to be run directly in the text editor to test changes.
|
||||
This ``register()`` call won't run when the script is imported as a module since ``__main__`` is reserved for direct execution.
|
||||
This ``register()`` call won't run when the script is imported as a module
|
||||
since ``__main__`` is reserved for direct execution.
|
||||
|
||||
|
||||
Class Registration
|
||||
------------------
|
||||
|
||||
Registering a class with blender results in the class definition being loaded into blender, where it becomes available alongside existing functionality.
|
||||
Registering a class with Blender results in the class definition being loaded into Blender,
|
||||
where it becomes available alongside existing functionality.
|
||||
|
||||
Once this class is loaded you can access it from :mod:`bpy.types`, using the bl_idname rather than the classes original name.
|
||||
Once this class is loaded you can access it from :mod:`bpy.types`,
|
||||
using the bl_idname rather than the classes original name.
|
||||
|
||||
When loading a class, blender performs sanity checks making sure all required properties and functions are found, that properties have the correct type, and that functions have the right number of arguments.
|
||||
When loading a class, Blender performs sanity checks making sure all required properties and functions are found,
|
||||
that properties have the correct type, and that functions have the right number of arguments.
|
||||
|
||||
Mostly you will not need concern yourself with this but if there is a problem with the class definition it will be raised on registering:
|
||||
Mostly you will not need concern yourself with this but if there is a problem
|
||||
with the class definition it will be raised on registering:
|
||||
|
||||
Using the function arguments ``def execute(self, context, spam)``, will raise an exception:
|
||||
|
||||
@@ -225,9 +269,13 @@ Using ``bl_idname = 1`` will raise.
|
||||
Multiple-Classes
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Loading classes into blender is described above, for simple cases calling :mod:`bpy.utils.register_class` (SomeClass) is sufficient, but when there are many classes or a packages submodule has its own classes it can be tedious to list them all for registration.
|
||||
Loading classes into Blender is described above,
|
||||
for simple cases calling :mod:`bpy.utils.register_class` (SomeClass) is sufficient,
|
||||
but when there are many classes or a packages submodule has its own
|
||||
classes it can be tedious to list them all for registration.
|
||||
|
||||
For more convenient loading/unloading :mod:`bpy.utils.register_module` (module) and :mod:`bpy.utils.unregister_module` (module) functions exist.
|
||||
For more convenient loading/unloading :mod:`bpy.utils.register_module` (module)
|
||||
and :mod:`bpy.utils.unregister_module` (module) functions exist.
|
||||
|
||||
A script which defines many of its own operators, panels menus etc. you only need to write:
|
||||
|
||||
@@ -239,13 +287,19 @@ A script which defines many of its own operators, panels menus etc. you only nee
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
||||
|
||||
Internally blender collects subclasses on registrable types, storing them by the module in which they are defined. By passing the module name to :mod:`bpy.utils.register_module` blender can register all classes created by this module and its submodules.
|
||||
Internally Blender collects subclasses on registrable types, storing them by the module in which they are defined.
|
||||
By passing the module name to :mod:`bpy.utils.register_module`
|
||||
Blender can register all classes created by this module and its submodules.
|
||||
|
||||
|
||||
Inter Classes Dependencies
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When customizing blender you may want to group your own settings together, after all, they will likely have to co-exist with other scripts. To group these properties classes need to be defined, for groups within groups or collections within groups you can find yourself having to deal with order of registration/unregistration.
|
||||
When customizing Blender you may want to group your own settings together,
|
||||
after all, they will likely have to co-exist with other scripts.
|
||||
To group these properties classes need to be defined,
|
||||
for groups within groups or collections within groups
|
||||
you can find yourself having to deal with order of registration/unregistration.
|
||||
|
||||
Custom properties groups are themselves classes which need to be registered.
|
||||
|
||||
@@ -311,7 +365,9 @@ Say you want to store material settings for a custom engine.
|
||||
Manipulating Classes
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Properties can be added and removed as blender runs, normally happens on register or unregister but for some special cases it may be useful to modify types as the script runs.
|
||||
Properties can be added and removed as Blender runs,
|
||||
normally happens on register or unregister but for some
|
||||
special cases it may be useful to modify types as the script runs.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -341,7 +397,8 @@ This works just as well for PropertyGroup subclasses you define yourself.
|
||||
Dynamic Defined-Classes (Advanced)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In some cases the specifier for data may not be in blender, renderman shader definitions for example and it may be useful to define types and remove them on the fly.
|
||||
In some cases the specifier for data may not be in Blender,
|
||||
renderman shader definitions for example and it may be useful to define types and remove them on the fly.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -360,7 +417,8 @@ In some cases the specifier for data may not be in blender, renderman shader def
|
||||
|
||||
.. note::
|
||||
|
||||
Notice ``type()`` is called to define the class. This is an alternative syntax for class creation in python, better suited to constructing classes dynamically.
|
||||
``type()`` is called to define the class.
|
||||
This is an alternative syntax for class creation in Python, better suited to constructing classes dynamically.
|
||||
|
||||
|
||||
Calling these operators:
|
||||
|
@@ -1,3 +1,4 @@
|
||||
|
||||
.. _info_quickstart:
|
||||
|
||||
***********************
|
||||
@@ -32,13 +33,15 @@ The Blender/Python API **can't** (yet)...
|
||||
Before Starting
|
||||
===============
|
||||
|
||||
This document isn't intended to fully cover each topic. Rather, its purpose is to familiarize you with Blender Python API.
|
||||
This document isn't intended to fully cover each topic.
|
||||
Rather, its purpose is to familiarize you with Blender Python API.
|
||||
|
||||
|
||||
A quick list of helpful things to know before starting:
|
||||
|
||||
- Blender uses Python 3.x; some online documentation still assumes 2.x.
|
||||
- The interactive console is great for testing one-liners, It also has autocompletion so you can inspect the API quickly.
|
||||
- The interactive console is great for testing one-liners.
|
||||
It also has autocompletion so you can inspect the API quickly.
|
||||
- Button tool tips show Python attributes and operator names.
|
||||
- Right clicking on buttons and menu items directly links to API documentation.
|
||||
- For more examples, the text menu has a templates section where some example operators can be found.
|
||||
@@ -51,15 +54,19 @@ A quick list of helpful things to know before starting:
|
||||
Running Scripts
|
||||
---------------
|
||||
|
||||
The two most common ways to execute Python scripts are using the built-in text editor or entering commands in the Python console.
|
||||
The two most common ways to execute Python scripts are using the built-in
|
||||
text editor or entering commands in the Python console.
|
||||
|
||||
Both the **Text Editor** and **Python Console** are space types you can select from the view header.
|
||||
Both the *Text Editor* and *Python Console* are space types you can select from the view header.
|
||||
|
||||
Rather then manually configuring your spaces for Python development, you may prefer to use the **Scripting** screen, included default with Blender, accessible from the top headers screen selector.
|
||||
Rather then manually configuring your spaces for Python development,
|
||||
you may prefer to use the *Scripting* screen, included default with Blender,
|
||||
accessible from the top headers screen selector.
|
||||
|
||||
From the text editor you can open ``.py`` files or paste then from the clipboard, then test using **Run Script**.
|
||||
From the text editor you can open ``.py`` files or paste then from the clipboard, then test using *Run Script*.
|
||||
|
||||
The Python Console is typically used for typing in snippets and for testing to get immediate feedback, but can also have entire scripts pasted into it.
|
||||
The Python Console is typically used for typing in snippets and for testing to get immediate feedback,
|
||||
but can also have entire scripts pasted into it.
|
||||
|
||||
Scripts can also run from the command line with Blender but to learn Blender/Python this isn't essential.
|
||||
|
||||
@@ -73,9 +80,11 @@ Data Access
|
||||
Accessing DataBlocks
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Python accesses Blender's data in the same way as the animation system and user interface; this implies that any setting that can be changed via a button can also be changed from Python.
|
||||
Python accesses Blender's data in the same way as the animation system and user interface;
|
||||
this implies that any setting that can be changed via a button can also be changed from Python.
|
||||
|
||||
Accessing data from the currently loaded blend file is done with the module :mod:`bpy.data`. This gives access to library data. For example:
|
||||
Accessing data from the currently loaded blend file is done with the module :mod:`bpy.data`.
|
||||
This gives access to library data. For example:
|
||||
|
||||
>>> bpy.data.objects
|
||||
<bpy_collection[3], BlendDataObjects>
|
||||
@@ -92,7 +101,8 @@ About Collections
|
||||
|
||||
You'll notice that an index as well as a string can be used to access members of the collection.
|
||||
|
||||
Unlike Python's dictionaries, both methods are acceptable; however, the index of a member may change while running Blender.
|
||||
Unlike Python's dictionaries, both methods are acceptable;
|
||||
however, the index of a member may change while running Blender.
|
||||
|
||||
>>> list(bpy.data.objects)
|
||||
[bpy.data.objects["Cube"], bpy.data.objects["Plane"]]
|
||||
@@ -107,7 +117,10 @@ Unlike Python's dictionaries, both methods are acceptable; however, the index of
|
||||
Accessing Attributes
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Once you have a data block, such as a material, object, groups etc., its attributes can be accessed much like you would change a setting using the graphical interface. In fact, the tooltip for each button also displays the Python attribute which can help in finding what settings to change in a script.
|
||||
Once you have a data block, such as a material, object, groups etc.,
|
||||
its attributes can be accessed much like you would change a setting using the graphical interface.
|
||||
In fact, the tooltip for each button also displays the Python attribute
|
||||
which can help in finding what settings to change in a script.
|
||||
|
||||
>>> bpy.data.objects[0].name
|
||||
'Camera'
|
||||
@@ -119,7 +132,8 @@ Once you have a data block, such as a material, object, groups etc., its attribu
|
||||
bpy.data.materials['MyMaterial']
|
||||
|
||||
|
||||
For testing what data to access it's useful to use the "Console", which is its own space type. This supports auto-complete, giving you a fast way to dig into different data in your file.
|
||||
For testing what data to access it's useful to use the "Console", which is its own space type.
|
||||
This supports auto-complete, giving you a fast way to dig into different data in your file.
|
||||
|
||||
Example of a data path that can be quickly found via the console:
|
||||
|
||||
@@ -132,7 +146,8 @@ Example of a data path that can be quickly found via the console:
|
||||
Data Creation/Removal
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Those of you familiar with other Python API's may be surprised that new datablocks in the bpy API can't be created by calling the class:
|
||||
Those of you familiar with other Python API's may be surprised that
|
||||
new datablocks in the bpy API can't be created by calling the class:
|
||||
|
||||
>>> bpy.types.Mesh()
|
||||
Traceback (most recent call last):
|
||||
@@ -141,7 +156,8 @@ Those of you familiar with other Python API's may be surprised that new databloc
|
||||
|
||||
|
||||
This is an intentional part of the API design.
|
||||
The Blender/Python API can't create Blender data that exists outside the main Blender database (accessed through :mod:`bpy.data`), because this data is managed by Blender (save/load/undo/append... etc).
|
||||
The Blender/Python API can't create Blender data that exists outside the main Blender database
|
||||
(accessed through :mod:`bpy.data`), because this data is managed by Blender (save/load/undo/append... etc).
|
||||
|
||||
Data is added and removed via methods on the collections in :mod:`bpy.data`, eg:
|
||||
|
||||
@@ -155,8 +171,10 @@ Data is added and removed via methods on the collections in :mod:`bpy.data`, eg:
|
||||
Custom Properties
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
Python can access properties on any datablock that has an ID (data that can be linked in and accessed from :mod:`bpy.data`.
|
||||
When assigning a property, you can make up your own names, these will be created when needed or overwritten if they exist.
|
||||
Python can access properties on any datablock that has an ID
|
||||
(data that can be linked in and accessed from :mod:`bpy.data`.
|
||||
When assigning a property, you can make up your own names,
|
||||
these will be created when needed or overwritten if they exist.
|
||||
|
||||
This data is saved with the blend file and copied with objects.
|
||||
|
||||
@@ -192,8 +210,10 @@ These properties are valid outside of Python. They can be animated by curves or
|
||||
Context
|
||||
-------
|
||||
|
||||
While it's useful to be able to access data directly by name or as a list, it's more common to operate on the user's selection.
|
||||
The context is always available from ``bpy.context`` and can be used to get the active object, scene, tool settings along with many other attributes.
|
||||
While it's useful to be able to access data directly by name or as a list,
|
||||
it's more common to operate on the user's selection.
|
||||
The context is always available from ``bpy.context`` and can be used to get the active object, scene,
|
||||
tool settings along with many other attributes.
|
||||
|
||||
Common-use cases:
|
||||
|
||||
@@ -201,7 +221,9 @@ Common-use cases:
|
||||
>>> bpy.context.selected_objects
|
||||
>>> bpy.context.visible_bones
|
||||
|
||||
Note that the context is read-only. These values cannot be modified directly, though they may be changed by running API functions or by using the data API.
|
||||
Note that the context is read-only.
|
||||
These values cannot be modified directly,
|
||||
though they may be changed by running API functions or by using the data API.
|
||||
|
||||
So ``bpy.context.object = obj`` will raise an error.
|
||||
|
||||
@@ -209,7 +231,8 @@ But ``bpy.context.scene.objects.active = obj`` will work as expected.
|
||||
|
||||
|
||||
The context attributes change depending on where they are accessed.
|
||||
The 3D view has different context members than the console, so take care when accessing context attributes that the user state is known.
|
||||
The 3D view has different context members than the console,
|
||||
so take care when accessing context attributes that the user state is known.
|
||||
|
||||
See :mod:`bpy.context` API reference.
|
||||
|
||||
@@ -217,7 +240,9 @@ See :mod:`bpy.context` API reference.
|
||||
Operators (Tools)
|
||||
-----------------
|
||||
|
||||
Operators are tools generally accessed by the user from buttons, menu items or key shortcuts. From the user perspective they are a tool but Python can run these with its own settings through the :mod:`bpy.ops` module.
|
||||
Operators are tools generally accessed by the user from buttons, menu items or key shortcuts.
|
||||
From the user perspective they are a tool but Python can run these with its own settings
|
||||
through the :mod:`bpy.ops` module.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -230,14 +255,16 @@ Examples:
|
||||
|
||||
.. note::
|
||||
|
||||
The menu item: :menuselection:`Help --> Operator Cheat Sheet` gives a list of all operators and their default values in Python syntax, along with the generated docs.
|
||||
The menu item: :menuselection:`Help --> Operator Cheat Sheet`
|
||||
gives a list of all operators and their default values in Python syntax, along with the generated docs.
|
||||
This is a good way to get an overview of all Blender's operators.
|
||||
|
||||
|
||||
Operator Poll()
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Many operators have a "poll" function which may check that the mouse is in a valid area or that the object is in the correct mode (Edit Mode, Weight Paint etc).
|
||||
Many operators have a "poll" function which may check that the cursor
|
||||
is in a valid area or that the object is in the correct mode (Edit Mode, Weight Paint etc).
|
||||
When an operator's poll function fails within Python, an exception is raised.
|
||||
|
||||
For example, calling ``bpy.ops.view3d.render_border()`` from the console raises the following error:
|
||||
@@ -248,7 +275,8 @@ For example, calling ``bpy.ops.view3d.render_border()`` from the console raises
|
||||
|
||||
In this case the context must be the 3d view with an active camera.
|
||||
|
||||
To avoid using try/except clauses wherever operators are called you can call the operators own .poll() function to check if it can run in the current context.
|
||||
To avoid using try/except clauses wherever operators are called you can call the operators
|
||||
own ``poll()`` function to check if it can run in the current context.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -275,7 +303,8 @@ Example Operator
|
||||
|
||||
.. literalinclude:: ../../../release/scripts/templates_py/operator_simple.py
|
||||
|
||||
Once this script runs, ``SimpleOperator`` is registered with Blender and can be called from the operator search popup or added to the toolbar.
|
||||
Once this script runs, ``SimpleOperator`` is registered with Blender
|
||||
and can be called from the operator search popup or added to the toolbar.
|
||||
|
||||
To run the script:
|
||||
|
||||
@@ -285,19 +314,23 @@ To run the script:
|
||||
#. Click the button labeled ``New`` and the confirmation pop up in order to create a new text block.
|
||||
#. Press :kbd:`Ctrl-V` to paste the code into the text panel (the upper left frame).
|
||||
#. Click on the button **Run Script**.
|
||||
#. Move your mouse into the 3D view, press spacebar for the operator search menu, and type "Simple".
|
||||
#. Move your cursor into the 3D view, press spacebar for the operator search menu, and type "Simple".
|
||||
#. Click on the "Simple Operator" item found in search.
|
||||
|
||||
|
||||
.. seealso:: The class members with the ``bl_`` prefix are documented in the API
|
||||
reference :class:`bpy.types.Operator`
|
||||
|
||||
.. note:: The output from the ``main`` function is sent to the terminal; in order to see this, be sure to :ref:`use the terminal <use_the_terminal>`.
|
||||
.. note::
|
||||
|
||||
The output from the ``main`` function is sent to the terminal;
|
||||
in order to see this, be sure to :ref:`use the terminal <use_the_terminal>`.
|
||||
|
||||
Example Panel
|
||||
-------------
|
||||
|
||||
Panels register themselves as a class, like an operator. Notice the extra ``bl_`` variables used to set the context they display in.
|
||||
Panels register themselves as a class, like an operator.
|
||||
Notice the extra ``bl_`` variables used to set the context they display in.
|
||||
|
||||
.. literalinclude:: ../../../release/scripts/templates_py/ui_panel_simple.py
|
||||
|
||||
@@ -334,7 +367,8 @@ Blender's Python API can be split up into 3 categories.
|
||||
Native Types
|
||||
------------
|
||||
|
||||
In simple cases returning a number or a string as a custom type would be cumbersome, so these are accessed as normal Python types.
|
||||
In simple cases returning a number or a string as a custom type would be cumbersome,
|
||||
so these are accessed as normal Python types.
|
||||
|
||||
- Blender float/int/boolean -> float/int/boolean
|
||||
- Blender enumerator -> string
|
||||
@@ -359,7 +393,8 @@ Used for Blender datablocks and collections: :class:`bpy.types.bpy_struct`
|
||||
|
||||
For data that contains its own attributes groups/meshes/bones/scenes... etc.
|
||||
|
||||
There are 2 main types that wrap Blenders data, one for datablocks (known internally as ``bpy_struct``), another for properties.
|
||||
There are 2 main types that wrap Blenders data, one for datablocks
|
||||
(known internally as ``bpy_struct``), another for properties.
|
||||
|
||||
>>> bpy.context.object
|
||||
bpy.data.objects['Cube']
|
||||
@@ -375,7 +410,9 @@ Mathutils Types
|
||||
|
||||
Used for vectors, quaternion, eulers, matrix and color types, accessible from :mod:`mathutils`
|
||||
|
||||
Some attributes such as :class:`bpy.types.Object.location`, :class:`bpy.types.PoseBone.rotation_euler` and :class:`bpy.types.Scene.cursor_location` can be accessed as special math types which can be used together and manipulated in various useful ways.
|
||||
Some attributes such as :class:`bpy.types.Object.location`,
|
||||
:class:`bpy.types.PoseBone.rotation_euler` and :class:`bpy.types.Scene.cursor_location`
|
||||
can be accessed as special math types which can be used together and manipulated in various useful ways.
|
||||
|
||||
Example of a matrix, vector multiplication:
|
||||
|
||||
@@ -410,7 +447,9 @@ Animation
|
||||
|
||||
There are 2 ways to add keyframes through Python.
|
||||
|
||||
The first is through key properties directly, which is similar to inserting a keyframe from the button as a user. You can also manually create the curves and keyframe data, then set the path to the property. Here are examples of both methods.
|
||||
The first is through key properties directly, which is similar to inserting a keyframe from the button as a user.
|
||||
You can also manually create the curves and keyframe data, then set the path to the property.
|
||||
Here are examples of both methods.
|
||||
|
||||
Both examples insert a keyframe on the active object's Z axis.
|
||||
|
||||
|
@@ -1,10 +1,12 @@
|
||||
|
||||
***************
|
||||
Tips and Tricks
|
||||
***************
|
||||
|
||||
Here are various suggestions that you might find useful when writing scripts.
|
||||
|
||||
Some of these are just python features that scripters may not have thought to use with blender, others are blender specific.
|
||||
Some of these are just Python features that scripters may not have thought to use with Blender,
|
||||
others are Blender specific.
|
||||
|
||||
|
||||
.. _use_the_terminal:
|
||||
@@ -12,18 +14,21 @@ Some of these are just python features that scripters may not have thought to us
|
||||
Use The Terminal
|
||||
================
|
||||
|
||||
When writing python scripts, it's useful to have a terminal open, this is not the built-in python console but a terminal application which is used to start blender.
|
||||
When writing Python scripts, it's useful to have a terminal open,
|
||||
this is not the built-in Python console but a terminal application which is used to start Blender.
|
||||
|
||||
There are 3 main uses for the terminal, these are:
|
||||
|
||||
* You can see the output of ``print()`` as your script runs, which is useful to view debug info.
|
||||
|
||||
* The error trace-back is printed in full to the terminal which won't always generate an error popup in blender's user interface (depending on how the script is executed).
|
||||
|
||||
* If the script runs for too long or you accidentally enter an infinite loop, Ctrl+C in the terminal (Ctrl+Break on Windows) will quit the script early.
|
||||
- You can see the output of ``print()`` as your script runs, which is useful to view debug info.
|
||||
- The error trace-back is printed in full to the terminal which won't always generate an error popup in
|
||||
Blender's user interface (depending on how the script is executed).
|
||||
- If the script runs for too long or you accidentally enter an infinite loop,
|
||||
:kbd:`Ctrl-C` in the terminal (:kbd:`Ctrl-Break` on Windows) will quit the script early.
|
||||
|
||||
.. note::
|
||||
For Linux and OSX users this means starting the terminal first, then running blender from within it. On Windows the terminal can be enabled from the help menu.
|
||||
|
||||
For Linux and OSX users this means starting the terminal first, then running Blender from within it.
|
||||
On Windows the terminal can be enabled from the help menu.
|
||||
|
||||
|
||||
Interface Tricks
|
||||
@@ -33,43 +38,56 @@ Interface Tricks
|
||||
Access Operator Commands
|
||||
------------------------
|
||||
|
||||
You may have noticed that the tooltip for menu items and buttons includes the ``bpy.ops``... command to run that button, a handy (hidden) feature is that you can press Ctrl+C over any menu item/button to copy this command into the clipboard.
|
||||
You may have noticed that the tooltip for menu items and buttons includes the ``bpy.ops.[...])`` command
|
||||
to run that button, a handy (hidden) feature is that you can press :kbd:`Ctrl-C` over
|
||||
any menu item/button to copy this command into the clipboard.
|
||||
|
||||
|
||||
Access Data Path
|
||||
----------------
|
||||
|
||||
To find the path from an :class:`ID` datablock to its setting isn't always so simple since it may be nested away. To get this quickly you can right click on the setting and select select **Copy Data Path**,
|
||||
To find the path from an :class:`ID` datablock to its setting isn't always so simple since it may be nested away.
|
||||
To get this quickly you can right click on the setting and select select **Copy Data Path**,
|
||||
if this can't be generated, only the property name is copied.
|
||||
|
||||
.. note::
|
||||
|
||||
This uses the same method for creating the animation path used by :class:`bpy.types.FCurve.data_path` and :class:`bpy.types.DriverTarget.data_path` drivers.
|
||||
This uses the same method for creating the animation path used by
|
||||
:class:`bpy.types.FCurve.data_path` and
|
||||
:class:`bpy.types.DriverTarget.data_path` drivers.
|
||||
|
||||
|
||||
.. _info_show_all_operators
|
||||
.. _info_show_all_operators:
|
||||
|
||||
Show All Operators
|
||||
==================
|
||||
|
||||
While blender logs operators in the Info space, this only reports operators with the ``REGISTER`` option enabeld so as not to flood the Info view with calls to ``bpy.ops.view3d.smoothview`` and ``bpy.ops.view3d.zoom``.
|
||||
While Blender logs operators in the Info space,
|
||||
this only reports operators with the ``REGISTER`` option enabeld so as not to flood the *Info* view
|
||||
with calls to ``bpy.ops.view3d.smoothview`` and ``bpy.ops.view3d.zoom``.
|
||||
|
||||
However, for testing it can be useful to see **every** operator called in a terminal, do this by enabling the debug option either by passing the ``--debug-wm`` argument when starting blender or by setting :mod:`bpy.app.debug_wm` to True while blender is running.
|
||||
However, for testing it can be useful to see **every** operator called in a terminal,
|
||||
do this by enabling the debug option either by passing the ``--debug-wm`` argument when starting Blender
|
||||
or by setting :mod:`bpy.app.debug_wm` to ``True`` while Blender is running.
|
||||
|
||||
|
||||
Use an External Editor
|
||||
======================
|
||||
|
||||
Blenders text editor is fine for small changes and writing tests but its not full featured, for larger projects you'll probably want to use a standalone editor or python IDE.
|
||||
Blenders text editor is fine for small changes and writing tests but its not full featured,
|
||||
for larger projects you'll probably want to use a standalone editor or Python IDE.
|
||||
|
||||
Editing a text file externally and having the same text open in blender does work but isn't that optimal so here are 2 ways you can easily use an external file from blender.
|
||||
Editing a text file externally and having the same text open in Blender does work but isn't that optimal
|
||||
so here are 2 ways you can easily use an external file from Blender.
|
||||
|
||||
Using the following examples you'll still need textblock in Blender to execute,
|
||||
but reference an external file rather then including it directly.
|
||||
|
||||
Using the following examples you'll still need textblock in blender to execute, but reference an external file rather then including it directly.
|
||||
|
||||
Executing External Scripts
|
||||
--------------------------
|
||||
|
||||
This is the equivalent to running the script directly, referencing a scripts path from a 2 line textblock.
|
||||
This is the equivalent to running the script directly, referencing a scripts path from a 2 line text-block.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -102,12 +120,17 @@ This example shows loading a script in as a module and executing a module functi
|
||||
myscript.main()
|
||||
|
||||
|
||||
Notice that the script is reloaded every time, this forces use of the modified version, otherwise the cached one in ``sys.modules`` would be used until blender was restarted.
|
||||
Notice that the script is reloaded every time, this forces use of the modified version,
|
||||
otherwise the cached one in ``sys.modules`` would be used until Blender was restarted.
|
||||
|
||||
The important difference between this and executing the script directly is it has to call a function in the module, in this case ``main()`` but it can be any function, an advantage with this is you can pass arguments to the function from this small script which is often useful for testing different settings quickly.
|
||||
The important difference between this and executing the script directly is it
|
||||
has to call a function in the module, in this case ``main()`` but it can be any function,
|
||||
an advantage with this is you can pass arguments to the function from this
|
||||
small script which is often useful for testing different settings quickly.
|
||||
|
||||
The other issue with this is the script has to be in pythons module search path.
|
||||
While this is not best practice - for testing you can extend the search path, this example adds the current blend files directory to the search path, then loads the script as a module.
|
||||
The other issue with this is the script has to be in Pythons module search path.
|
||||
While this is not best practice - for testing you can extend the search path,
|
||||
this example adds the current blend files directory to the search path, then loads the script as a module.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -128,71 +151,86 @@ While this is not best practice - for testing you can extend the search path, th
|
||||
Don't Use Blender!
|
||||
==================
|
||||
|
||||
While developing your own scripts blenders interface can get in the way, manually reloading, running the scripts, opening file import etc. adds overhead.
|
||||
While developing your own scripts Blenders interface can get in the way,
|
||||
manually reloading, running the scripts, opening file import etc. adds overhead.
|
||||
|
||||
For scripts that are not interactive it can end up being more efficient not to use blenders interface at all and instead execute the script on the command line.
|
||||
For scripts that are not interactive it can end up being more efficient not to use
|
||||
Blenders interface at all and instead execute the script on the command line.
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: sh
|
||||
|
||||
blender --background --python myscript.py
|
||||
|
||||
|
||||
You might want to run this with a blend file so the script has some data to operate on.
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: sh
|
||||
|
||||
blender myscene.blend --background --python myscript.py
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Depending on your setup you might have to enter the full path to the blender executable.
|
||||
Depending on your setup you might have to enter the full path to the Blender executable.
|
||||
|
||||
|
||||
Once the script is running properly in background mode, you'll want to check the output of the script, this depends completely on the task at hand however here are some suggestions.
|
||||
Once the script is running properly in background mode, you'll want to check the output of the script,
|
||||
this depends completely on the task at hand however here are some suggestions.
|
||||
|
||||
* render the output to an image, use an image viewer and keep writing over the same image each time.
|
||||
|
||||
* save a new blend file, or export the file using one of blenders exporters.
|
||||
|
||||
* if the results can be displayed as text - print them or write them to a file.
|
||||
- render the output to an image, use an image viewer and keep writing over the same image each time.
|
||||
- save a new blend file, or export the file using one of Blenders exporters.
|
||||
- if the results can be displayed as text - print them or write them to a file.
|
||||
|
||||
|
||||
This can take a little time to setup, but it can be well worth the effort to reduce the time it takes to test changes - you can even have blender running the script ever few seconds with a viewer updating the results, so no need to leave your text editor to see changes.
|
||||
While this can take a little time to setup, it can be well worth the effort
|
||||
to reduce the time it takes to test changes - you can even have
|
||||
Blender running the script every few seconds with a viewer updating the results,
|
||||
so no need to leave your text editor to see changes.
|
||||
|
||||
|
||||
Use External Tools
|
||||
==================
|
||||
|
||||
When there are no readily available python modules to perform specific tasks it's worth keeping in mind you may be able to have python execute an external command on your data and read the result back in.
|
||||
When there are no readily available Python modules to perform specific tasks it's
|
||||
worth keeping in mind you may be able to have Python execute an external command
|
||||
on your data and read the result back in.
|
||||
|
||||
Using external programs adds an extra dependency and may limit who can use the script but to quickly setup your own custom pipeline or writing one-off scripts this can be handy.
|
||||
Using external programs adds an extra dependency and may limit who can use the script
|
||||
but to quickly setup your own custom pipeline or writing one-off scripts this can be handy.
|
||||
|
||||
Examples include:
|
||||
|
||||
* Run The Gimp in batch mode to execute custom scripts for advanced image processing.
|
||||
|
||||
* Write out 3D models to use external mesh manipulation tools and read back in the results.
|
||||
|
||||
* Convert files into recognizable formats before reading.
|
||||
- Run The Gimp in batch mode to execute custom scripts for advanced image processing.
|
||||
- Write out 3D models to use external mesh manipulation tools and read back in the results.
|
||||
- Convert files into recognizable formats before reading.
|
||||
|
||||
|
||||
Bundled Python & Extensions
|
||||
===========================
|
||||
|
||||
The Blender releases distributed from blender.org include a complete python installation on all platforms, this has the disadvantage that any extensions you have installed in your systems python wont be found by blender.
|
||||
The Blender releases distributed from blender.org include a complete Python installation on all platforms,
|
||||
this has the disadvantage that any extensions you have installed in your systems Python wont be found by Blender.
|
||||
|
||||
There are 2 ways around this:
|
||||
|
||||
* remove blender python sub-directory, blender will then fallback on the systems python and use that instead **python version must match the one that blender comes with**.
|
||||
- remove Blender Python sub-directory, Blender will then fallback on the systems Python and use that instead
|
||||
.. warning::
|
||||
|
||||
* copy the extensions into blender's python sub-directory so blender can access them, you could also copy the entire python installation into blenders sub-directory, replacing the one blender comes with. This works as long as the python versions match and the paths are created in the same relative locations. Doing this has the advantage that you can redistribute this bundle to others with blender and/or the game player, including any extensions you rely on.
|
||||
The Python version must match the one that Blender comes with.
|
||||
|
||||
- copy the extensions into Blender's Python sub-directory so Blender can access them,
|
||||
you could also copy the entire Python installation into Blenders sub-directory,
|
||||
replacing the one Blender comes with.
|
||||
This works as long as the Python versions match and the paths are created in the same relative locations.
|
||||
Doing this has the advantage that you can redistribute this bundle to others with Blender and/or the game player,
|
||||
including any extensions you rely on.
|
||||
|
||||
|
||||
Drop Into a Python Interpreter in Your Script
|
||||
=============================================
|
||||
|
||||
In the middle of a script you may want to inspect some variables, run some function and generally dig about to see whats going on.
|
||||
In the middle of a script you may want to inspect some variables,
|
||||
run some function and generally dig about to see whats going on.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -217,10 +255,13 @@ The next example is an equivalent single line version of the script above which
|
||||
__import__('code').interact(local=dict(globals(), **locals()))
|
||||
|
||||
|
||||
``code.interact`` can be added at any line in the script and will pause the script an launch an interactive interpreter in the terminal, when you're done you can quit the interpreter and the script will continue execution.
|
||||
``code.interact`` can be added at any line in the script
|
||||
and will pause the script an launch an interactive interpreter in the terminal,
|
||||
when you're done you can quit the interpreter and the script will continue execution.
|
||||
|
||||
|
||||
If you have **IPython** installed you can use their ``embed()`` function which will implicitly use the current namespace, this has autocomplete and some useful features that the standard python eval-loop doesn't have.
|
||||
If you have **IPython** installed you can use its ``embed()`` function which uses the current namespace.
|
||||
The IPython prompt has auto-complete and some useful features that the standard Python eval-loop doesn't have.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -228,7 +269,7 @@ If you have **IPython** installed you can use their ``embed()`` function which w
|
||||
IPython.embed()
|
||||
|
||||
|
||||
Admittedly this highlights the lack of any python debugging support built into blender, but its still handy to know.
|
||||
Admittedly this highlights the lack of any Python debugging support built into Blender, but its still handy to know.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -242,27 +283,32 @@ Advanced
|
||||
Blender as a module
|
||||
-------------------
|
||||
|
||||
From a python perspective it's nicer to have everything as an extension which lets the python script combine many components.
|
||||
From a Python perspective it's nicer to have everything as an extension
|
||||
which lets the Python script combine many components.
|
||||
|
||||
Advantages include:
|
||||
|
||||
* you can use external editors/IDE's with blenders python API and execute scripts within the IDE (step over code, inspect variables as the script runs).
|
||||
|
||||
* editors/IDE's can auto complete blender modules & variables.
|
||||
|
||||
* existing scripts can import blender API's without having to run inside blender.
|
||||
- you can use external editors/IDE's with Blenders Python API and execute scripts within the IDE
|
||||
(step over code, inspect variables as the script runs).
|
||||
- editors/IDE's can auto complete Blender modules & variables.
|
||||
- existing scripts can import Blender API's without having to run inside Blender.
|
||||
|
||||
|
||||
This is marked advanced because to run blender as a python module requires a special build option.
|
||||
This is marked advanced because to run Blender as a Python module requires a special build option.
|
||||
|
||||
For instructions on building see `Building blender as a python module <http://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
|
||||
For instructions on building see
|
||||
`Building Blender as a Python module <http://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule>`_
|
||||
|
||||
|
||||
Python Safety (Build Option)
|
||||
----------------------------
|
||||
|
||||
Since it's possible to access data which has been removed (see Gotcha's), this can be hard to track down the cause of crashes.
|
||||
Since it's possible to access data which has been removed (see Gotcha's),
|
||||
this can be hard to track down the cause of crashes.
|
||||
|
||||
To raise python exceptions on accessing freed data (rather then crashing), enable the CMake build option WITH_PYTHON_SAFETY.
|
||||
To raise Python exceptions on accessing freed data (rather then crashing),
|
||||
enable the CMake build option WITH_PYTHON_SAFETY.
|
||||
|
||||
This enables data tracking which makes data access about 2x slower
|
||||
which is why the option isn't enabled in release builds.
|
||||
|
||||
This enables data tracking which makes data access about 2x slower which is why the option is not enabled in release builds.
|
||||
|
@@ -208,6 +208,7 @@ The objects should move as before.
|
||||
|
||||
*Keep this addon open in Blender for the next step - Installing.*
|
||||
|
||||
|
||||
Install The Addon
|
||||
-----------------
|
||||
|
||||
@@ -221,10 +222,11 @@ restrictions that apply to Python modules and end with a ``.py`` extension.
|
||||
|
||||
Once the file is on disk, you can install it as you would for an addon downloaded online.
|
||||
|
||||
Open the user **File -> User Preferences**, Select the **Addon** section, press **Install Addon...** and select the file.
|
||||
Open the user :menuselection:`File -> User Preferences`,
|
||||
Select the *Addon* section, press *Install Addon...* and select the file.
|
||||
|
||||
Now the addon will be listed and you can enable it by pressing the check-box, if you want it to be enabled on restart,
|
||||
press **Save as Default**.
|
||||
Now the addon will be listed and you can enable it by pressing the check-box,
|
||||
if you want it to be enabled on restart, press *Save as Default*.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -238,7 +240,7 @@ press **Save as Default**.
|
||||
print(addon_utils.paths())
|
||||
|
||||
More is written on this topic here:
|
||||
`Directory Layout <http://wiki.blender.org/index.php/Doc:2.6/Manual/Introduction/Installing_Blender/DirectoryLayout>`_
|
||||
`Directory Layout <https://www.blender.org/manual/getting_started/installing_blender/directorylayout.html>`_
|
||||
|
||||
|
||||
Your Second Addon
|
||||
|
@@ -234,6 +234,7 @@ else:
|
||||
EXCLUDE_MODULES = [
|
||||
"aud",
|
||||
"bge",
|
||||
"bge.app"
|
||||
"bge.constraints",
|
||||
"bge.events",
|
||||
"bge.logic",
|
||||
@@ -1669,6 +1670,7 @@ def write_rst_contents(basepath):
|
||||
fw(" bge.texture.rst\n\n")
|
||||
fw(" bge.events.rst\n\n")
|
||||
fw(" bge.constraints.rst\n\n")
|
||||
fw(" bge.app.rst\n\n")
|
||||
|
||||
# rna generated change log
|
||||
fw(title_string("API Info", "=", double=True))
|
||||
@@ -1825,6 +1827,7 @@ def copy_handwritten_rsts(basepath):
|
||||
"bge.texture",
|
||||
"bge.events",
|
||||
"bge.constraints",
|
||||
"bge.app",
|
||||
"bgl", # "Blender OpenGl wrapper"
|
||||
"gpu", # "GPU Shader Module"
|
||||
|
||||
|
7
extern/gtest/CMakeLists.txt
vendored
7
extern/gtest/CMakeLists.txt
vendored
@@ -21,6 +21,13 @@
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
# avoid noisy warnings
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
remove_cc_flag(
|
||||
"-Wmissing-declarations"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(INC
|
||||
.
|
||||
include
|
||||
|
@@ -33,16 +33,7 @@
|
||||
#include "AUD_Space.h"
|
||||
|
||||
#include <cstring>
|
||||
#ifdef _MSC_VER
|
||||
#if (_MSC_VER <= 1500)
|
||||
typedef short int16_t;
|
||||
typedef int int32_t;
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
typedef void (*AUD_convert_f)(data_t* target, data_t* source, int length);
|
||||
|
||||
|
@@ -44,8 +44,7 @@ AUD_Sequencer::AUD_Sequencer(AUD_Specs specs, float fps, bool muted) :
|
||||
m_distance_model(AUD_DISTANCE_MODEL_INVERSE_CLAMPED),
|
||||
m_volume(1, 1.0f),
|
||||
m_location(3),
|
||||
m_orientation(4),
|
||||
m_recursive(false)
|
||||
m_orientation(4)
|
||||
{
|
||||
AUD_Quaternion q;
|
||||
m_orientation.write(q.get());
|
||||
|
@@ -201,8 +201,6 @@ public:
|
||||
* \param entry The entry to remove.
|
||||
*/
|
||||
void remove(boost::shared_ptr<AUD_SequencerEntry> entry);
|
||||
|
||||
bool m_recursive;
|
||||
};
|
||||
|
||||
#endif //__AUD_SEQUENCER_H__
|
||||
|
@@ -78,9 +78,6 @@ AUD_Specs AUD_SequencerReader::getSpecs() const
|
||||
|
||||
void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
{
|
||||
if (m_sequence->m_recursive)
|
||||
return;
|
||||
|
||||
AUD_MutexLock lock(*m_sequence);
|
||||
|
||||
if(m_sequence->m_status != m_status)
|
||||
@@ -195,9 +192,7 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
v2 -= v;
|
||||
m_device.setListenerVelocity(v2 * m_sequence->m_fps);
|
||||
|
||||
m_sequence->m_recursive = true;
|
||||
m_device.read(reinterpret_cast<data_t*>(buffer + specs.channels * pos), len);
|
||||
m_sequence->m_recursive = false;
|
||||
|
||||
pos += len;
|
||||
time += float(len) / float(specs.rate);
|
||||
|
@@ -96,12 +96,6 @@ macro(cycles_target_link_libraries target)
|
||||
${CMAKE_DL_LIBS}
|
||||
${PLATFORM_LINKLIBS}
|
||||
)
|
||||
if(WITH_ALEMBIC)
|
||||
target_link_libraries(
|
||||
${target}
|
||||
${ALEMBIC_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Application build targets
|
||||
@@ -112,23 +106,6 @@ if(WITH_CYCLES_STANDALONE)
|
||||
cycles_xml.cpp
|
||||
cycles_xml.h
|
||||
)
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
list(APPEND SRC
|
||||
cycles_alembic.cpp
|
||||
cycles_alembic.h
|
||||
)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
include_directories(
|
||||
SYSTEM
|
||||
${ALEMBIC_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_HDF5)
|
||||
add_definitions(-DWITH_HDF5)
|
||||
endif()
|
||||
|
||||
add_executable(cycles ${SRC})
|
||||
cycles_target_link_libraries(cycles)
|
||||
|
||||
|
@@ -1,426 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <Alembic/AbcCoreOgawa/ReadWrite.h>
|
||||
#ifdef WITH_HDF5
|
||||
#include <Alembic/AbcCoreHDF5/ReadWrite.h>
|
||||
#endif
|
||||
#include <Alembic/Abc/IArchive.h>
|
||||
#include <Alembic/Abc/IObject.h>
|
||||
#include <Alembic/Abc/ISampleSelector.h>
|
||||
#include <Alembic/Abc/ICompoundProperty.h>
|
||||
#include <Alembic/Abc/IScalarProperty.h>
|
||||
#include <Alembic/Abc/IArrayProperty.h>
|
||||
#include <Alembic/Abc/ArchiveInfo.h>
|
||||
#include <Alembic/AbcGeom/IPolyMesh.h>
|
||||
|
||||
#include "camera.h"
|
||||
#include "film.h"
|
||||
#include "graph.h"
|
||||
#include "integrator.h"
|
||||
#include "light.h"
|
||||
#include "mesh.h"
|
||||
#include "nodes.h"
|
||||
#include "object.h"
|
||||
#include "shader.h"
|
||||
#include "scene.h"
|
||||
|
||||
#include "subd_mesh.h"
|
||||
#include "subd_patch.h"
|
||||
#include "subd_split.h"
|
||||
|
||||
#include "util_debug.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_path.h"
|
||||
#include "util_transform.h"
|
||||
#include "util_xml.h"
|
||||
|
||||
#include "cycles_alembic.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace Alembic;
|
||||
using namespace Abc;
|
||||
using namespace AbcGeom;
|
||||
|
||||
#define ABC_SAFE_CALL_BEGIN \
|
||||
try {
|
||||
|
||||
#define ABC_SAFE_CALL_END \
|
||||
} \
|
||||
catch (Alembic::Util::Exception e) { \
|
||||
printf("%s", e.what()); \
|
||||
}
|
||||
|
||||
|
||||
/* File */
|
||||
|
||||
static const std::string g_sep(";");
|
||||
|
||||
static void visitProperties(std::stringstream &ss, ICompoundProperty, std::string &);
|
||||
|
||||
template <class PROP>
|
||||
static void visitSimpleArrayProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
|
||||
{
|
||||
std::string ptype = "ArrayProperty ";
|
||||
size_t asize = 0;
|
||||
|
||||
AbcA::ArraySamplePtr samp;
|
||||
index_t maxSamples = iProp.getNumSamples();
|
||||
for (index_t i = 0 ; i < maxSamples; ++i) {
|
||||
iProp.get(samp, ISampleSelector( i ));
|
||||
asize = samp->size();
|
||||
};
|
||||
|
||||
std::string mdstring = "interpretation=";
|
||||
mdstring += iProp.getMetaData().get("interpretation");
|
||||
|
||||
std::stringstream dtype;
|
||||
dtype << "datatype=";
|
||||
dtype << iProp.getDataType();
|
||||
|
||||
std::stringstream asizestr;
|
||||
asizestr << ";arraysize=";
|
||||
asizestr << asize;
|
||||
|
||||
mdstring += g_sep;
|
||||
|
||||
mdstring += dtype.str();
|
||||
|
||||
mdstring += asizestr.str();
|
||||
|
||||
ss << iIndent << " " << ptype << "name=" << iProp.getName()
|
||||
<< g_sep << mdstring << g_sep << "numsamps="
|
||||
<< iProp.getNumSamples() << std::endl;
|
||||
}
|
||||
|
||||
template <class PROP>
|
||||
static void visitSimpleScalarProperty(std::stringstream &ss, PROP iProp, const std::string &iIndent)
|
||||
{
|
||||
std::string ptype = "ScalarProperty ";
|
||||
size_t asize = 0;
|
||||
|
||||
const AbcA::DataType &dt = iProp.getDataType();
|
||||
const Alembic::Util ::uint8_t extent = dt.getExtent();
|
||||
Alembic::Util::Dimensions dims(extent);
|
||||
AbcA::ArraySamplePtr samp = AbcA::AllocateArraySample( dt, dims );
|
||||
index_t maxSamples = iProp.getNumSamples();
|
||||
for (index_t i = 0 ; i < maxSamples; ++i) {
|
||||
iProp.get(const_cast<void*>(samp->getData()), ISampleSelector( i ));
|
||||
asize = samp->size();
|
||||
};
|
||||
|
||||
std::string mdstring = "interpretation=";
|
||||
mdstring += iProp.getMetaData().get("interpretation");
|
||||
|
||||
std::stringstream dtype;
|
||||
dtype << "datatype=";
|
||||
dtype << dt;
|
||||
|
||||
std::stringstream asizestr;
|
||||
asizestr << ";arraysize=";
|
||||
asizestr << asize;
|
||||
|
||||
mdstring += g_sep;
|
||||
|
||||
mdstring += dtype.str();
|
||||
|
||||
mdstring += asizestr.str();
|
||||
|
||||
ss << iIndent << " " << ptype << "name=" << iProp.getName()
|
||||
<< g_sep << mdstring << g_sep << "numsamps="
|
||||
<< iProp.getNumSamples() << std::endl;
|
||||
}
|
||||
|
||||
static void visitCompoundProperty(std::stringstream &ss, ICompoundProperty iProp, std::string &ioIndent)
|
||||
{
|
||||
std::string oldIndent = ioIndent;
|
||||
ioIndent += " ";
|
||||
|
||||
std::string interp = "schema=";
|
||||
interp += iProp.getMetaData().get("schema");
|
||||
|
||||
ss << ioIndent << "CompoundProperty " << "name=" << iProp.getName()
|
||||
<< g_sep << interp << std::endl;
|
||||
|
||||
visitProperties(ss, iProp, ioIndent);
|
||||
|
||||
ioIndent = oldIndent;
|
||||
}
|
||||
|
||||
static void visitProperties(std::stringstream &ss, ICompoundProperty iParent, std::string &ioIndent )
|
||||
{
|
||||
std::string oldIndent = ioIndent;
|
||||
for (size_t i = 0 ; i < iParent.getNumProperties() ; i++) {
|
||||
PropertyHeader header = iParent.getPropertyHeader(i);
|
||||
|
||||
if (header.isCompound()) {
|
||||
visitCompoundProperty(ss, ICompoundProperty(iParent, header.getName()), ioIndent);
|
||||
}
|
||||
else if (header.isScalar()) {
|
||||
visitSimpleScalarProperty(ss, IScalarProperty(iParent, header.getName()), ioIndent);
|
||||
}
|
||||
else {
|
||||
assert(header.isArray());
|
||||
visitSimpleArrayProperty(ss, IArrayProperty(iParent, header.getName()), ioIndent);
|
||||
}
|
||||
}
|
||||
|
||||
ioIndent = oldIndent;
|
||||
}
|
||||
|
||||
static void visitObject(std::stringstream &ss, IObject iObj, std::string iIndent, AbcArchiveInfoLevel info_level)
|
||||
{
|
||||
// Object has a name, a full name, some meta data,
|
||||
// and then it has a compound property full of properties.
|
||||
std::string path = iObj.getFullName();
|
||||
|
||||
if (iObj.isInstanceRoot()) {
|
||||
if (path != "/") {
|
||||
ss << "Object " << "name=" << path
|
||||
<< " [Instance " << iObj.instanceSourcePath() << "]"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else if (iObj.isInstanceDescendant()) {
|
||||
/* skip non-root instances to avoid repetition */
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (path != "/") {
|
||||
ss << "Object " << "name=" << path << std::endl;
|
||||
}
|
||||
|
||||
if (info_level >= ABC_INFO_PROPERTIES) {
|
||||
// Get the properties.
|
||||
ICompoundProperty props = iObj.getProperties();
|
||||
visitProperties(ss, props, iIndent);
|
||||
}
|
||||
|
||||
// now the child objects
|
||||
for (size_t i = 0 ; i < iObj.getNumChildren() ; i++) {
|
||||
visitObject(ss, IObject(iObj, iObj.getChildHeader(i).getName()), iIndent, info_level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string abc_archive_info(IArchive &archive, AbcArchiveInfoLevel info_level)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "Alembic Archive Info for "
|
||||
<< Alembic::AbcCoreAbstract::GetLibraryVersion()
|
||||
<< std::endl;;
|
||||
|
||||
std::string appName;
|
||||
std::string libraryVersionString;
|
||||
Alembic::Util::uint32_t libraryVersion;
|
||||
std::string whenWritten;
|
||||
std::string userDescription;
|
||||
GetArchiveInfo(archive,
|
||||
appName,
|
||||
libraryVersionString,
|
||||
libraryVersion,
|
||||
whenWritten,
|
||||
userDescription);
|
||||
|
||||
if (appName != "") {
|
||||
ss << " file written by: " << appName << std::endl;
|
||||
ss << " using Alembic : " << libraryVersionString << std::endl;
|
||||
ss << " written on : " << whenWritten << std::endl;
|
||||
ss << " user description : " << userDescription << std::endl;
|
||||
ss << std::endl;
|
||||
}
|
||||
else {
|
||||
// ss << argv[1] << std::endl;
|
||||
ss << " (file doesn't have any ArchiveInfo)"
|
||||
<< std::endl;
|
||||
ss << std::endl;
|
||||
}
|
||||
|
||||
if (info_level >= ABC_INFO_OBJECTS)
|
||||
visitObject(ss, archive.getTop(), "", info_level);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
struct AbcReadState {
|
||||
Scene *scene; /* scene pointer */
|
||||
float time;
|
||||
Transform tfm; /* current transform state */
|
||||
bool smooth; /* smooth normal state */
|
||||
int shader; /* current shader */
|
||||
string base; /* base path to current file*/
|
||||
float dicing_rate; /* current dicing rate */
|
||||
Mesh::DisplacementMethod displacement_method;
|
||||
};
|
||||
|
||||
static ISampleSelector get_sample_selector(const AbcReadState &state)
|
||||
{
|
||||
return ISampleSelector(state.time, ISampleSelector::kFloorIndex);
|
||||
}
|
||||
|
||||
static Mesh *add_mesh(Scene *scene, const Transform& tfm)
|
||||
{
|
||||
/* create mesh */
|
||||
Mesh *mesh = new Mesh();
|
||||
scene->meshes.push_back(mesh);
|
||||
|
||||
/* create object*/
|
||||
Object *object = new Object();
|
||||
object->mesh = mesh;
|
||||
object->tfm = tfm;
|
||||
scene->objects.push_back(object);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
static void read_mesh(const AbcReadState &state, IPolyMesh object)
|
||||
{
|
||||
/* add mesh */
|
||||
Mesh *mesh = add_mesh(state.scene, state.tfm);
|
||||
mesh->used_shaders.push_back(state.shader);
|
||||
|
||||
/* read state */
|
||||
int shader = state.shader;
|
||||
bool smooth = state.smooth;
|
||||
|
||||
mesh->displacement_method = state.displacement_method;
|
||||
|
||||
ISampleSelector ss = get_sample_selector(state);
|
||||
IPolyMeshSchema schema = object.getSchema();
|
||||
|
||||
IPolyMeshSchema::Sample sample;
|
||||
schema.get(sample, ss);
|
||||
|
||||
int totverts = sample.getPositions()->size();
|
||||
int totfaces = sample.getFaceCounts()->size();
|
||||
const V3f *P = sample.getPositions()->get();
|
||||
const int32_t *verts = sample.getFaceIndices()->get();
|
||||
const int32_t *nverts = sample.getFaceCounts()->get();
|
||||
|
||||
/* create vertices */
|
||||
mesh->verts.reserve(totverts);
|
||||
for(int i = 0; i < totverts; i++) {
|
||||
mesh->verts.push_back(make_float3(P[i].x, P[i].y, P[i].z));
|
||||
}
|
||||
|
||||
/* create triangles */
|
||||
int index_offset = 0;
|
||||
|
||||
for(int i = 0; i < totfaces; i++) {
|
||||
int n = nverts[i];
|
||||
/* XXX TODO only supports tris and quads atm,
|
||||
* need a proper tessellation algorithm in cycles.
|
||||
*/
|
||||
if (n > 4) {
|
||||
printf("%d-sided face found, only triangles and quads are supported currently", n);
|
||||
n = 4;
|
||||
}
|
||||
|
||||
for(int j = 0; j < n-2; j++) {
|
||||
int v0 = verts[index_offset];
|
||||
int v1 = verts[index_offset + j + 1];
|
||||
int v2 = verts[index_offset + j + 2];
|
||||
|
||||
assert(v0 < (int)totverts);
|
||||
assert(v1 < (int)totverts);
|
||||
assert(v2 < (int)totverts);
|
||||
|
||||
mesh->add_triangle(v0, v1, v2, shader, smooth);
|
||||
}
|
||||
|
||||
index_offset += n;
|
||||
}
|
||||
|
||||
/* temporary for test compatibility */
|
||||
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
|
||||
}
|
||||
|
||||
static void read_object(const AbcReadState &state, IObject object)
|
||||
{
|
||||
for (int i = 0; i < object.getNumChildren(); ++i) {
|
||||
IObject child = object.getChild(i);
|
||||
const MetaData &metadata = child.getMetaData();
|
||||
|
||||
if (IPolyMeshSchema::matches(metadata)) {
|
||||
read_mesh(state, IPolyMesh(child, kWrapExisting));
|
||||
}
|
||||
else {
|
||||
read_object(state, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_archive(Scene *scene, IArchive archive, const char *filepath)
|
||||
{
|
||||
AbcReadState state;
|
||||
|
||||
state.scene = scene;
|
||||
state.time = 0.0f; // TODO
|
||||
state.tfm = transform_identity();
|
||||
state.shader = scene->default_surface;
|
||||
state.smooth = false;
|
||||
state.dicing_rate = 0.1f;
|
||||
state.base = path_dirname(filepath);
|
||||
|
||||
read_object(state, archive.getTop());
|
||||
|
||||
scene->params.bvh_type = SceneParams::BVH_STATIC;
|
||||
}
|
||||
|
||||
void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
|
||||
{
|
||||
IArchive archive;
|
||||
ABC_SAFE_CALL_BEGIN
|
||||
archive = IArchive(AbcCoreOgawa::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
|
||||
ABC_SAFE_CALL_END
|
||||
|
||||
if (archive) {
|
||||
if (info_level >= ABC_INFO_BASIC)
|
||||
printf("%s", abc_archive_info(archive, info_level).c_str());
|
||||
|
||||
read_archive(scene, archive, filepath);
|
||||
}
|
||||
}
|
||||
|
||||
void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level)
|
||||
{
|
||||
#ifdef WITH_HDF5
|
||||
IArchive archive;
|
||||
ABC_SAFE_CALL_BEGIN
|
||||
archive = IArchive(AbcCoreHDF5::ReadArchive(), filepath, ErrorHandler::kThrowPolicy);
|
||||
ABC_SAFE_CALL_END
|
||||
|
||||
if (archive) {
|
||||
if (info_level >= ABC_INFO_BASIC)
|
||||
printf("%s", abc_archive_info(archive, info_level).c_str());
|
||||
|
||||
read_archive(scene, archive, filepath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __CYCLES_ALEMBIC_H__
|
||||
#define __CYCLES_ALEMBIC_H__
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class Scene;
|
||||
|
||||
enum AbcArchiveInfoLevel {
|
||||
ABC_INFO_NONE = 0,
|
||||
ABC_INFO_BASIC,
|
||||
ABC_INFO_OBJECTS,
|
||||
ABC_INFO_PROPERTIES,
|
||||
};
|
||||
|
||||
void abc_read_ogawa_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
|
||||
void abc_read_hdf5_file(Scene *scene, const char *filepath, AbcArchiveInfoLevel info_level = ABC_INFO_NONE);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __CYCLES_XML_H__ */
|
@@ -38,23 +38,13 @@
|
||||
#endif
|
||||
|
||||
#include "cycles_xml.h"
|
||||
#ifdef WITH_ALEMBIC
|
||||
#include "cycles_alembic.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
enum FileType {
|
||||
FILETYPE_XML = 0,
|
||||
FILETYPE_ABC_HDF5,
|
||||
FILETYPE_ABC_OGAWA,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
Session *session;
|
||||
Scene *scene;
|
||||
string filepath;
|
||||
FileType filetype;
|
||||
int width, height;
|
||||
SceneParams scene_params;
|
||||
SessionParams session_params;
|
||||
@@ -131,22 +121,8 @@ static void scene_init()
|
||||
{
|
||||
options.scene = new Scene(options.scene_params, options.session_params.device);
|
||||
|
||||
/* Read file */
|
||||
switch (options.filetype) {
|
||||
case FILETYPE_XML:
|
||||
xml_read_file(options.scene, options.filepath.c_str());
|
||||
break;
|
||||
#ifdef WITH_ALEMBIC
|
||||
case FILETYPE_ABC_OGAWA:
|
||||
abc_read_ogawa_file(options.scene, options.filepath.c_str());
|
||||
break;
|
||||
case FILETYPE_ABC_HDF5:
|
||||
abc_read_hdf5_file(options.scene, options.filepath.c_str());
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* Read XML */
|
||||
xml_read_file(options.scene, options.filepath.c_str());
|
||||
|
||||
/* Camera width/height override? */
|
||||
if(!(options.width == 0 || options.height == 0)) {
|
||||
@@ -380,16 +356,6 @@ static void options_parse(int argc, const char **argv)
|
||||
/* shading system */
|
||||
string ssname = "svm";
|
||||
|
||||
/* input file type */
|
||||
string filetypes = "auto, xml";
|
||||
#ifdef WITH_ALEMBIC
|
||||
filetypes += ", alembic_ogawa";
|
||||
#ifdef WITH_HDF5
|
||||
filetypes += ", alembic_hdf5";
|
||||
#endif
|
||||
#endif
|
||||
string filetype = "auto";
|
||||
|
||||
/* parse options */
|
||||
ArgParse ap;
|
||||
bool help = false, debug = false;
|
||||
@@ -405,7 +371,6 @@ static void options_parse(int argc, const char **argv)
|
||||
"--quiet", &options.quiet, "In background mode, don't print progress messages",
|
||||
"--samples %d", &options.session_params.samples, "Number of samples to render",
|
||||
"--output %s", &options.session_params.output_path, "File path to write output image",
|
||||
"--filetype %s", &filetype, ("File type: " + filetypes).c_str(),
|
||||
"--threads %d", &options.session_params.threads, "CPU Rendering Threads",
|
||||
"--width %d", &options.width, "Window width in pixel",
|
||||
"--height %d", &options.height, "Window height in pixel",
|
||||
@@ -451,21 +416,6 @@ static void options_parse(int argc, const char **argv)
|
||||
else if(ssname == "svm")
|
||||
options.scene_params.shadingsystem = SHADINGSYSTEM_SVM;
|
||||
|
||||
if(filetype == "auto") {
|
||||
string extension = options.filepath.substr(options.filepath.find_last_of(".") + 1);
|
||||
|
||||
if (extension == "xml")
|
||||
options.filetype = FILETYPE_XML;
|
||||
else if (extension == "abc")
|
||||
options.filetype = FILETYPE_ABC_OGAWA;
|
||||
}
|
||||
else if(filetype == "xml")
|
||||
options.filetype = FILETYPE_XML;
|
||||
else if(filetype == "alembic_ogawa")
|
||||
options.filetype = FILETYPE_ABC_OGAWA;
|
||||
else if(filetype == "alembic_hdf5")
|
||||
options.filetype = FILETYPE_ABC_HDF5;
|
||||
|
||||
#ifndef WITH_CYCLES_STANDALONE_GUI
|
||||
options.session_params.background = true;
|
||||
#endif
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include "background.h"
|
||||
#include "camera.h"
|
||||
#include "film.h"
|
||||
#include "graph.h"
|
||||
@@ -42,9 +43,6 @@
|
||||
#include "util_xml.h"
|
||||
|
||||
#include "cycles_xml.h"
|
||||
#ifdef WITH_ALEMBIC
|
||||
#include "cycles_alembic.h"
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
@@ -853,6 +851,15 @@ static void xml_read_shader(const XMLReadState& state, pugi::xml_node node)
|
||||
|
||||
static void xml_read_background(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
/* Background Settings */
|
||||
Background *bg = state.scene->background;
|
||||
|
||||
xml_read_float(&bg->ao_distance, node, "ao_distance");
|
||||
xml_read_float(&bg->ao_factor, node, "ao_factor");
|
||||
|
||||
xml_read_bool(&bg->transparent, node, "transparent");
|
||||
|
||||
/* Background Shader */
|
||||
Shader *shader = state.scene->shaders[state.scene->default_background];
|
||||
|
||||
xml_read_bool(&shader->heterogeneous_volume, node, "heterogeneous_volume");
|
||||
@@ -899,6 +906,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
|
||||
|
||||
/* read vertices and polygons, RIB style */
|
||||
vector<float3> P;
|
||||
vector<float> UV;
|
||||
vector<int> verts, nverts;
|
||||
|
||||
xml_read_float3_array(P, node, "P");
|
||||
@@ -970,6 +978,31 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node)
|
||||
|
||||
index_offset += nverts[i];
|
||||
}
|
||||
|
||||
if(xml_read_float_array(UV, node, "UV")) {
|
||||
ustring name = ustring("UVMap");
|
||||
Attribute *attr = mesh->attributes.add(ATTR_STD_UV, name);
|
||||
float3 *fdata = attr->data_float3();
|
||||
|
||||
/* loop over the triangles */
|
||||
index_offset = 0;
|
||||
for(size_t i = 0; i < nverts.size(); i++) {
|
||||
for(int j = 0; j < nverts[i]-2; j++) {
|
||||
int v0 = verts[index_offset];
|
||||
int v1 = verts[index_offset + j + 1];
|
||||
int v2 = verts[index_offset + j + 2];
|
||||
|
||||
assert(v0*2+1 < (int)UV.size());
|
||||
assert(v1*2+1 < (int)UV.size());
|
||||
assert(v2*2+1 < (int)UV.size());
|
||||
|
||||
fdata[0] = make_float3(UV[v0*2], UV[v0*2+1], 0.0);
|
||||
fdata[1] = make_float3(UV[v1*2], UV[v1*2+1], 0.0);
|
||||
fdata[2] = make_float3(UV[v2*2], UV[v2*2+1], 0.0);
|
||||
fdata += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* temporary for test compatibility */
|
||||
@@ -1155,25 +1188,6 @@ static void xml_read_state(XMLReadState& state, pugi::xml_node node)
|
||||
state.displacement_method = Mesh::DISPLACE_BOTH;
|
||||
}
|
||||
|
||||
/* Alembic */
|
||||
static void xml_read_alembic(const XMLReadState& state, pugi::xml_node node)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
string filepath;
|
||||
|
||||
if(xml_read_string(&filepath, node, "file")) {
|
||||
filepath = path_join(state.base, filepath);
|
||||
|
||||
if(xml_equal_string(node, "type", "hdf5"))
|
||||
abc_read_hdf5_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
|
||||
else if(xml_equal_string(node, "type", "ogawa"))
|
||||
abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC);
|
||||
else
|
||||
abc_read_ogawa_file(state.scene, filepath.c_str(), ABC_INFO_BASIC); /* default */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Scene */
|
||||
|
||||
static void xml_read_include(const XMLReadState& state, const string& src);
|
||||
@@ -1223,9 +1237,6 @@ static void xml_read_scene(const XMLReadState& state, pugi::xml_node scene_node)
|
||||
if(xml_read_string(&src, node, "src"))
|
||||
xml_read_include(state, src);
|
||||
}
|
||||
else if(string_iequals(node.name(), "alembic")) {
|
||||
xml_read_alembic(state, node);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
|
||||
}
|
||||
|
@@ -31,12 +31,10 @@ set(SRC
|
||||
blender_session.cpp
|
||||
blender_shader.cpp
|
||||
blender_sync.cpp
|
||||
blender_texture.cpp
|
||||
|
||||
CCL_api.h
|
||||
blender_sync.h
|
||||
blender_session.h
|
||||
blender_texture.h
|
||||
blender_util.h
|
||||
)
|
||||
|
||||
|
@@ -463,12 +463,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
description="Use BVH spatial splits: longer builder time, faster render",
|
||||
default=False,
|
||||
)
|
||||
cls.debug_use_triangle_storage = BoolProperty(
|
||||
name="Use Triangle Storage",
|
||||
description="use special storage with aligned triangle coordinates for faster "
|
||||
"intesection check in expense of higher memory usage",
|
||||
default=True,
|
||||
)
|
||||
cls.use_cache = BoolProperty(
|
||||
name="Cache BVH",
|
||||
description="Cache last built BVH to disk for faster re-render if no geometry changed",
|
||||
@@ -517,19 +511,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
),
|
||||
)
|
||||
|
||||
cls.use_camera_cull = BoolProperty(
|
||||
name="Use Camera Cull",
|
||||
description="Allow objects to be culled based on the camera frustum",
|
||||
default=False,
|
||||
)
|
||||
|
||||
cls.camera_cull_margin = FloatProperty(
|
||||
name="Camera Cull Margin",
|
||||
description="Margin for the camera space culling",
|
||||
default=0.1,
|
||||
min=0.0, max=5.0
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Scene.cycles
|
||||
@@ -909,12 +890,6 @@ class CyclesObjectBlurSettings(bpy.types.PropertyGroup):
|
||||
default=1,
|
||||
)
|
||||
|
||||
cls.use_camera_cull = BoolProperty(
|
||||
name="Use Camera Cull",
|
||||
description="Allow this object and it's duplicators to be culled by camera space culling",
|
||||
default=False,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Object.cycles
|
||||
|
@@ -322,11 +322,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
|
||||
subsub.enabled = not rd.use_border
|
||||
subsub.prop(rd, "use_save_buffers")
|
||||
|
||||
sub.prop(cscene, "use_camera_cull")
|
||||
subsub = col.column()
|
||||
subsub.active = cscene.use_camera_cull
|
||||
subsub.prop(cscene, "camera_cull_margin")
|
||||
|
||||
col = split.column(align=True)
|
||||
|
||||
col.label(text="Viewport:")
|
||||
@@ -344,7 +339,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
|
||||
|
||||
col.label(text="Acceleration structure:")
|
||||
col.prop(cscene, "debug_use_spatial_splits")
|
||||
col.prop(cscene, "debug_use_triangle_storage")
|
||||
|
||||
|
||||
class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
|
||||
@@ -437,6 +431,9 @@ class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
|
||||
col.prop(rl, "use_pass_emit", text="Emission")
|
||||
col.prop(rl, "use_pass_environment")
|
||||
|
||||
if hasattr(rd, "debug_pass_type"):
|
||||
layout.prop(rd, "debug_pass_type")
|
||||
|
||||
|
||||
class CyclesRender_PT_views(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Views"
|
||||
@@ -650,7 +647,13 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return CyclesButtonsPanel.poll(context) and ob and ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}
|
||||
if CyclesButtonsPanel.poll(context) and ob:
|
||||
if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META'}:
|
||||
return True
|
||||
if ob.dupli_type == 'GROUP' and ob.dupli_group:
|
||||
return True
|
||||
# TODO(sergey): More duplicator types here?
|
||||
return False
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
@@ -684,8 +687,8 @@ class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
|
||||
sub.prop(cob, "motion_steps", text="Steps")
|
||||
|
||||
|
||||
class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Cycles Settings"
|
||||
class CyclesObject_PT_ray_visibility(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Ray Visibility"
|
||||
bl_context = "object"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@@ -693,17 +696,15 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
|
||||
def poll(cls, context):
|
||||
ob = context.object
|
||||
return (CyclesButtonsPanel.poll(context) and
|
||||
ob and ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'} or
|
||||
ob and ob.dupli_type == 'GROUP' and ob.dupli_group)
|
||||
ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LAMP'}) or
|
||||
(ob.dupli_type == 'GROUP' and ob.dupli_group)))
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
ob = context.object
|
||||
cob = ob.cycles
|
||||
visibility = ob.cycles_visibility
|
||||
|
||||
layout.label(text="Ray Visibility:")
|
||||
flow = layout.column_flow()
|
||||
|
||||
flow.prop(visibility, "camera")
|
||||
@@ -715,9 +716,6 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel):
|
||||
if ob.type != 'LAMP':
|
||||
flow.prop(visibility, "shadow")
|
||||
|
||||
layout.label(text="Performance:")
|
||||
layout.prop(cob, "use_camera_cull")
|
||||
|
||||
|
||||
class CYCLES_OT_use_shading_nodes(Operator):
|
||||
"""Enable nodes on a material, world or lamp"""
|
||||
@@ -1227,8 +1225,7 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
node = context.texture_node
|
||||
# TODO(sergey): perform a faster/nicer check?
|
||||
return node and hasattr(node, 'texture_mapping') and CyclesButtonsPanel.poll(context)
|
||||
return node and CyclesButtonsPanel.poll(context)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@@ -1452,8 +1449,7 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
rd = scene.render
|
||||
rd = context.scene.render
|
||||
|
||||
layout.active = rd.use_simplify
|
||||
split = layout.split()
|
||||
@@ -1533,7 +1529,6 @@ def get_panels():
|
||||
"DATA_PT_curve_texture_space",
|
||||
"DATA_PT_mball_texture_space",
|
||||
"DATA_PT_vertex_groups",
|
||||
"DATA_PT_face_maps",
|
||||
"DATA_PT_shape_keys",
|
||||
"DATA_PT_uv_texture",
|
||||
"DATA_PT_vertex_colors",
|
||||
|
@@ -207,19 +207,34 @@ static void blender_camera_from_object(BlenderCamera *bcam, BL::RenderEngine b_e
|
||||
}
|
||||
}
|
||||
|
||||
static Transform blender_camera_matrix(const Transform& tfm, CameraType type)
|
||||
static Transform blender_camera_matrix(const Transform& tfm,
|
||||
const CameraType type,
|
||||
const PanoramaType panorama_type)
|
||||
{
|
||||
Transform result;
|
||||
|
||||
if(type == CAMERA_PANORAMA) {
|
||||
/* make it so environment camera needs to be pointed in the direction
|
||||
* of the positive x-axis to match an environment texture, this way
|
||||
* it is looking at the center of the texture */
|
||||
result = tfm *
|
||||
make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
if(panorama_type == PANORAMA_MIRRORBALL) {
|
||||
/* Mirror ball camera is looking into the negative Y direction
|
||||
* which matches texture mirror ball mapping.
|
||||
*/
|
||||
result = tfm *
|
||||
make_transform(1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
else {
|
||||
/* Make it so environment camera needs to be pointed in the direction
|
||||
* of the positive x-axis to match an environment texture, this way
|
||||
* it is looking at the center of the texture
|
||||
*/
|
||||
result = tfm *
|
||||
make_transform( 0.0f, -1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
-1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* note the blender camera points along the negative z-axis */
|
||||
@@ -365,7 +380,9 @@ static void blender_camera_sync(Camera *cam, BlenderCamera *bcam, int width, int
|
||||
cam->bladesrotation = bcam->aperturerotation;
|
||||
|
||||
/* transform */
|
||||
cam->matrix = blender_camera_matrix(bcam->matrix, bcam->type);
|
||||
cam->matrix = blender_camera_matrix(bcam->matrix,
|
||||
bcam->type,
|
||||
bcam->panorama_type);
|
||||
cam->motion.pre = cam->matrix;
|
||||
cam->motion.post = cam->matrix;
|
||||
cam->use_motion = false;
|
||||
@@ -424,7 +441,7 @@ void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
|
||||
BL::Array<float, 16> b_ob_matrix;
|
||||
b_engine.camera_model_matrix(b_ob, b_ob_matrix);
|
||||
Transform tfm = get_transform(b_ob_matrix);
|
||||
tfm = blender_camera_matrix(tfm, cam->type);
|
||||
tfm = blender_camera_matrix(tfm, cam->type, cam->panorama_type);
|
||||
|
||||
if(tfm != cam->matrix) {
|
||||
VLOG(1) << "Camera " << b_ob.name() << " motion detected.";
|
||||
|
@@ -37,14 +37,15 @@ void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, floa
|
||||
void interp_weights(float t, float data[4]);
|
||||
float shaperadius(float shape, float root, float tip, float time);
|
||||
void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData);
|
||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num);
|
||||
bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num);
|
||||
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background);
|
||||
void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData);
|
||||
void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData,
|
||||
float3 RotCam, bool is_ortho);
|
||||
void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution);
|
||||
void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata);
|
||||
void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol);
|
||||
void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata);
|
||||
void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol);
|
||||
|
||||
ParticleCurveData::ParticleCurveData()
|
||||
{
|
||||
@@ -118,330 +119,206 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl
|
||||
curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t);
|
||||
}
|
||||
|
||||
static void ObtainCacheParticleData(Mesh *mesh, BL::Object b_ob, BL::ParticleSystem b_psys, const Transform &itfm,
|
||||
ParticleCurveData *CData, bool background)
|
||||
bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
|
||||
{
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
|
||||
int shader = mesh->used_shaders[mi];
|
||||
int draw_step = background ? b_part.render_step() : b_part.draw_step();
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
int curvenum = 0;
|
||||
int keyno = 0;
|
||||
|
||||
if(totcurves == 0)
|
||||
return;
|
||||
if(!(mesh && b_mesh && b_ob && CData))
|
||||
return false;
|
||||
|
||||
int ren_step = (1 << draw_step) + 1;
|
||||
if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
|
||||
ren_step += b_part.kink_extra_steps();
|
||||
Transform tfm = get_transform(b_ob->matrix_world());
|
||||
Transform itfm = transform_quick_inverse(tfm);
|
||||
|
||||
PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
|
||||
|
||||
int keyno = CData->curvekey_co.size();
|
||||
int curvenum = CData->curve_keynum.size();
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
CData->psys_firstcurve.push_back(curvenum);
|
||||
CData->psys_curvenum.push_back(totcurves);
|
||||
CData->psys_shader.push_back(shader);
|
||||
if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
|
||||
int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
|
||||
int shader = mesh->used_shaders[mi];
|
||||
int draw_step = background ? b_part.render_step() : b_part.draw_step();
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
|
||||
float radius = get_float(cpsys, "radius_scale") * 0.5f;
|
||||
|
||||
CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
|
||||
CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
|
||||
CData->psys_shape.push_back(get_float(cpsys, "shape"));
|
||||
CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
|
||||
CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
|
||||
CData->curve_length.reserve(CData->curve_length.size() + num_add);
|
||||
CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
|
||||
CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
|
||||
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
int keynum = 0;
|
||||
CData->curve_firstkey.push_back(keyno);
|
||||
|
||||
float curve_length = 0.0f;
|
||||
float3 pcKey;
|
||||
for(int step_no = 0; step_no < ren_step; step_no++) {
|
||||
float nco[3];
|
||||
b_psys.co_hair(b_ob, pa_no, step_no, nco);
|
||||
float3 cKey = make_float3(nco[0], nco[1], nco[2]);
|
||||
cKey = transform_point(&itfm, cKey);
|
||||
if(step_no > 0) {
|
||||
float step_length = len(cKey - pcKey);
|
||||
if(step_length == 0.0f)
|
||||
if(totcurves == 0)
|
||||
continue;
|
||||
curve_length += step_length;
|
||||
|
||||
int ren_step = (1 << draw_step) + 1;
|
||||
if(b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
|
||||
ren_step += b_part.kink_extra_steps();
|
||||
|
||||
PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
|
||||
|
||||
CData->psys_firstcurve.push_back(curvenum);
|
||||
CData->psys_curvenum.push_back(totcurves);
|
||||
CData->psys_shader.push_back(shader);
|
||||
|
||||
float radius = get_float(cpsys, "radius_scale") * 0.5f;
|
||||
|
||||
CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
|
||||
CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
|
||||
CData->psys_shape.push_back(get_float(cpsys, "shape"));
|
||||
CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_firstkey.reserve(CData->curve_firstkey.size() + num_add);
|
||||
CData->curve_keynum.reserve(CData->curve_keynum.size() + num_add);
|
||||
CData->curve_length.reserve(CData->curve_length.size() + num_add);
|
||||
CData->curvekey_co.reserve(CData->curvekey_co.size() + num_add*ren_step);
|
||||
CData->curvekey_time.reserve(CData->curvekey_time.size() + num_add*ren_step);
|
||||
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
int keynum = 0;
|
||||
CData->curve_firstkey.push_back(keyno);
|
||||
|
||||
float curve_length = 0.0f;
|
||||
float3 pcKey;
|
||||
for(int step_no = 0; step_no < ren_step; step_no++) {
|
||||
float nco[3];
|
||||
b_psys.co_hair(*b_ob, pa_no, step_no, nco);
|
||||
float3 cKey = make_float3(nco[0], nco[1], nco[2]);
|
||||
cKey = transform_point(&itfm, cKey);
|
||||
if(step_no > 0) {
|
||||
float step_length = len(cKey - pcKey);
|
||||
if(step_length == 0.0f)
|
||||
continue;
|
||||
curve_length += step_length;
|
||||
}
|
||||
CData->curvekey_co.push_back(cKey);
|
||||
CData->curvekey_time.push_back(curve_length);
|
||||
pcKey = cKey;
|
||||
keynum++;
|
||||
}
|
||||
keyno += keynum;
|
||||
|
||||
CData->curve_keynum.push_back(keynum);
|
||||
CData->curve_length.push_back(curve_length);
|
||||
curvenum++;
|
||||
}
|
||||
}
|
||||
CData->curvekey_co.push_back(cKey);
|
||||
CData->curvekey_time.push_back(curve_length);
|
||||
pcKey = cKey;
|
||||
keynum++;
|
||||
}
|
||||
keyno += keynum;
|
||||
|
||||
CData->curve_keynum.push_back(keynum);
|
||||
CData->curve_length.push_back(curve_length);
|
||||
curvenum++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ObtainCacheParticleUV(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
|
||||
ParticleCurveData *CData, bool background, int uv_num)
|
||||
{
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
|
||||
if(totcurves == 0)
|
||||
return;
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
|
||||
|
||||
BL::ParticleSystem::particles_iterator b_pa;
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add UVs */
|
||||
BL::Mesh::tessface_uv_textures_iterator l;
|
||||
b_mesh.tessface_uv_textures.begin(l);
|
||||
|
||||
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh.tessface_uv_textures.length())
|
||||
b_psys.uv_on_emitter(b_psmd, *b_pa, pa_no, uv_num, &uv.x);
|
||||
CData->curve_uv.push_back(uv);
|
||||
|
||||
if(pa_no < totparts && b_pa != b_psys.particles.end())
|
||||
++b_pa;
|
||||
}
|
||||
}
|
||||
|
||||
static void ObtainCacheParticleVcol(Mesh * /*mesh*/, BL::Object /*b_ob*/, BL::Mesh b_mesh, BL::ParticleSystem b_psys, BL::ParticleSystemModifier b_psmd,
|
||||
ParticleCurveData *CData, bool background, int vcol_num)
|
||||
{
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
|
||||
if(totcurves == 0)
|
||||
return;
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
|
||||
|
||||
BL::ParticleSystem::particles_iterator b_pa;
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add vertex colors */
|
||||
BL::Mesh::tessface_vertex_colors_iterator l;
|
||||
b_mesh.tessface_vertex_colors.begin(l);
|
||||
|
||||
float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh.tessface_vertex_colors.length())
|
||||
b_psys.mcol_on_emitter(b_psmd, *b_pa, pa_no, vcol_num, &vcol.x);
|
||||
CData->curve_vcol.push_back(vcol);
|
||||
|
||||
if(pa_no < totparts && b_pa != b_psys.particles.end())
|
||||
++b_pa;
|
||||
}
|
||||
}
|
||||
|
||||
/* A little bit of templated code here to avoid much duplication for parent/child strands:
|
||||
* Most attributes are the same for both types, but some are handled slightly differently.
|
||||
* These attributes are handled by templated utility functions that automatically get selected by type.
|
||||
*/
|
||||
template <typename StrandsT>
|
||||
struct StrandsTraits;
|
||||
|
||||
template<>
|
||||
struct StrandsTraits<BL::Strands>
|
||||
{
|
||||
typedef BL::StrandsCurve curve_t;
|
||||
typedef BL::StrandsVertex vertex_t;
|
||||
|
||||
static float3 get_location(BL::Strands b_strands, int index)
|
||||
{
|
||||
float *co = (b_strands.has_motion_state())? b_strands.motion_state[index].location() : b_strands.vertices[index].location();
|
||||
return make_float3(co[0], co[1], co[2]);
|
||||
}
|
||||
static float3 get_uv(BL::Strands /*b_strands*/, int /*index*/, int /*uv_num*/)
|
||||
{
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
static float3 get_vcol(BL::Strands /*b_strands*/, int /*index*/, int /*vcol_num*/)
|
||||
{
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct StrandsTraits<BL::StrandsChildren>
|
||||
{
|
||||
typedef BL::StrandsChildCurve curve_t;
|
||||
typedef BL::StrandsChildVertex vertex_t;
|
||||
|
||||
static float3 get_location(BL::StrandsChildren b_strands, int index)
|
||||
{
|
||||
float *co = b_strands.vertices[index].location();
|
||||
return make_float3(co[0], co[1], co[2]);
|
||||
}
|
||||
static float3 get_uv(BL::StrandsChildren b_strands, int index, int uv_num)
|
||||
{
|
||||
if (uv_num < b_strands.num_curve_uv_layers()) {
|
||||
size_t offset = uv_num * b_strands.curves.length();
|
||||
float *uv = b_strands.curve_uvs[offset + index].uv();
|
||||
return make_float3(uv[0], uv[1], 0.0f);
|
||||
}
|
||||
else
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
static float3 get_vcol(BL::StrandsChildren b_strands, int index, int vcol_num)
|
||||
{
|
||||
if (vcol_num < b_strands.num_curve_vcol_layers()) {
|
||||
size_t offset = vcol_num * b_strands.curves.length();
|
||||
float *vcol = b_strands.curve_vcols[offset + index].vcol();
|
||||
return make_float3(vcol[0], vcol[1], vcol[2]);
|
||||
}
|
||||
else
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename StrandsT>
|
||||
static bool ObtainCacheStrandsData(Mesh *mesh, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem b_psys, StrandsT b_strands, const Transform &/*itfm*/,
|
||||
ParticleCurveData *CData, bool /*background*/)
|
||||
{
|
||||
typedef StrandsTraits<StrandsT> traits;
|
||||
typedef typename traits::curve_t CurveT;
|
||||
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
PointerRNA cpsys = RNA_pointer_get(&b_part.ptr, "cycles");
|
||||
|
||||
int mi = clamp(b_part.material()-1, 0, mesh->used_shaders.size()-1);
|
||||
int shader = mesh->used_shaders[mi];
|
||||
|
||||
int totcurves = b_strands.curves.length();
|
||||
int totvert = b_strands.vertices.length();
|
||||
|
||||
int keyno = CData->curvekey_co.size();
|
||||
int curvenum = CData->curve_keynum.size();
|
||||
|
||||
CData->psys_firstcurve.push_back(curvenum);
|
||||
CData->psys_curvenum.push_back(totcurves);
|
||||
CData->psys_shader.push_back(shader);
|
||||
|
||||
float radius = get_float(cpsys, "radius_scale") * 0.5f;
|
||||
|
||||
CData->psys_rootradius.push_back(radius * get_float(cpsys, "root_width"));
|
||||
CData->psys_tipradius.push_back(radius * get_float(cpsys, "tip_width"));
|
||||
CData->psys_shape.push_back(get_float(cpsys, "shape"));
|
||||
CData->psys_closetip.push_back(get_boolean(cpsys, "use_closetip"));
|
||||
|
||||
CData->curve_firstkey.reserve(CData->curve_firstkey.size() + totcurves);
|
||||
CData->curve_keynum.reserve(CData->curve_keynum.size() + totcurves);
|
||||
CData->curve_length.reserve(CData->curve_length.size() + totcurves);
|
||||
CData->curvekey_co.reserve(CData->curvekey_co.size() + totvert);
|
||||
CData->curvekey_time.reserve(CData->curvekey_time.size() + totvert);
|
||||
|
||||
int icurve = 0;
|
||||
int ivert = 0;
|
||||
for(; icurve < totcurves; ++icurve) {
|
||||
CurveT b_curve = b_strands.curves[icurve];
|
||||
int numverts = b_curve.size();
|
||||
int showverts = b_curve.render_size();
|
||||
int usedverts = 0;
|
||||
CData->curve_firstkey.push_back(keyno);
|
||||
|
||||
float curve_length = 0.0f;
|
||||
float3 pcKey;
|
||||
for(int cvert = 0; cvert < showverts; ++cvert) {
|
||||
float3 cKey = traits::get_location(b_strands, ivert + cvert);
|
||||
|
||||
if(cvert > 0) {
|
||||
float step_length = len(cKey - pcKey);
|
||||
if(step_length == 0.0f)
|
||||
continue;
|
||||
curve_length += step_length;
|
||||
}
|
||||
CData->curvekey_co.push_back(cKey);
|
||||
CData->curvekey_time.push_back(curve_length);
|
||||
pcKey = cKey;
|
||||
usedverts++;
|
||||
}
|
||||
keyno += usedverts;
|
||||
ivert += numverts;
|
||||
|
||||
CData->curve_keynum.push_back(usedverts);
|
||||
CData->curve_length.push_back(curve_length);
|
||||
curvenum++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename StrandsT>
|
||||
static bool ObtainCacheStrandsUV(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
|
||||
ParticleCurveData *CData, bool /*background*/, int uv_num)
|
||||
bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
|
||||
{
|
||||
typedef StrandsTraits<StrandsT> traits;
|
||||
|
||||
// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
if(!(mesh && b_mesh && b_ob && CData))
|
||||
return false;
|
||||
|
||||
int totcurves = b_strands.curves.length();
|
||||
CData->curve_uv.clear();
|
||||
|
||||
CData->curve_uv.reserve(CData->curve_uv.size() + totcurves);
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
int icurve = 0;
|
||||
for(; icurve < totcurves; ++icurve) {
|
||||
CData->curve_uv.push_back(traits::get_uv(b_strands, icurve, uv_num));
|
||||
if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
|
||||
if(totcurves == 0)
|
||||
continue;
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_uv.reserve(CData->curve_uv.size() + num_add);
|
||||
|
||||
BL::ParticleSystem::particles_iterator b_pa;
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add UVs */
|
||||
BL::Mesh::tessface_uv_textures_iterator l;
|
||||
b_mesh->tessface_uv_textures.begin(l);
|
||||
|
||||
float3 uv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh->tessface_uv_textures.length())
|
||||
b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x);
|
||||
CData->curve_uv.push_back(uv);
|
||||
|
||||
if(pa_no < totparts && b_pa != b_psys.particles.end())
|
||||
++b_pa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename StrandsT>
|
||||
static bool ObtainCacheStrandsVcol(Mesh * /*mesh*/, BL::Scene /*b_scene*/, BL::Object /*b_parent*/, BL::DupliObject /*b_dupli_ob*/, BL::ParticleSystem /*b_psys*/, StrandsT b_strands,
|
||||
ParticleCurveData *CData, bool /*background*/, int vcol_num)
|
||||
bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
|
||||
{
|
||||
typedef StrandsTraits<StrandsT> traits;
|
||||
|
||||
// BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
int totcurves = b_strands.curves.length();
|
||||
|
||||
CData->curve_vcol.reserve(CData->curve_vcol.size() + totcurves);
|
||||
|
||||
int icurve = 0;
|
||||
for(; icurve < totcurves; ++icurve) {
|
||||
CData->curve_vcol.push_back(traits::get_vcol(b_strands, icurve, vcol_num));
|
||||
if(!(mesh && b_mesh && b_ob && CData))
|
||||
return false;
|
||||
|
||||
CData->curve_vcol.clear();
|
||||
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) {
|
||||
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (background ? b_mod->show_render() : b_mod->show_viewport())) {
|
||||
BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
|
||||
int totparts = b_psys.particles.length();
|
||||
int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f);
|
||||
int totcurves = totchild;
|
||||
|
||||
if(b_part.child_type() == 0)
|
||||
totcurves += totparts;
|
||||
|
||||
if(totcurves == 0)
|
||||
continue;
|
||||
|
||||
int pa_no = 0;
|
||||
if(!(b_part.child_type() == 0))
|
||||
pa_no = totparts;
|
||||
|
||||
int num_add = (totparts+totchild - pa_no);
|
||||
CData->curve_vcol.reserve(CData->curve_vcol.size() + num_add);
|
||||
|
||||
BL::ParticleSystem::particles_iterator b_pa;
|
||||
b_psys.particles.begin(b_pa);
|
||||
for(; pa_no < totparts+totchild; pa_no++) {
|
||||
/* Add vertex colors */
|
||||
BL::Mesh::tessface_vertex_colors_iterator l;
|
||||
b_mesh->tessface_vertex_colors.begin(l);
|
||||
|
||||
float3 vcol = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(b_mesh->tessface_vertex_colors.length())
|
||||
b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
|
||||
CData->curve_vcol.push_back(vcol);
|
||||
|
||||
if(pa_no < totparts && b_pa != b_psys.particles.end())
|
||||
++b_pa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -873,39 +750,6 @@ void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol,
|
||||
}
|
||||
}
|
||||
|
||||
void ExportCurveUV(Mesh *mesh, ParticleCurveData *CData, ustring name, bool active_render, int primitive, int vert_offset, int resol)
|
||||
{
|
||||
AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
||||
Attribute *attr_uv;
|
||||
|
||||
if(primitive == CURVE_TRIANGLES) {
|
||||
if(active_render)
|
||||
attr_uv = mesh->attributes.add(std, name);
|
||||
else
|
||||
attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
|
||||
|
||||
float3 *uv = attr_uv->data_float3();
|
||||
|
||||
ExportCurveTriangleUV(CData, vert_offset, resol, uv);
|
||||
}
|
||||
else {
|
||||
if(active_render)
|
||||
attr_uv = mesh->curve_attributes.add(std, name);
|
||||
else
|
||||
attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
|
||||
|
||||
float3 *uv = attr_uv->data_float3();
|
||||
|
||||
if(uv) {
|
||||
size_t i = 0;
|
||||
|
||||
for(size_t curve = 0; curve < CData->curve_uv.size(); curve++)
|
||||
if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
|
||||
uv[i++] = CData->curve_uv[curve];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata)
|
||||
{
|
||||
if(cdata == NULL)
|
||||
@@ -938,31 +782,6 @@ void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int reso
|
||||
}
|
||||
}
|
||||
|
||||
void ExportCurveVcol(Mesh *mesh, ParticleCurveData *CData, ustring name, int primitive, int vert_offset, int resol)
|
||||
{
|
||||
if(primitive == CURVE_TRIANGLES) {
|
||||
Attribute *attr_vcol = mesh->attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
|
||||
|
||||
uchar4 *cdata = attr_vcol->data_uchar4();
|
||||
|
||||
ExportCurveTriangleVcol(CData, vert_offset, resol, cdata);
|
||||
}
|
||||
else {
|
||||
Attribute *attr_vcol = mesh->curve_attributes.add(name, TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
|
||||
|
||||
float3 *fdata = attr_vcol->data_float3();
|
||||
|
||||
if(fdata) {
|
||||
size_t i = 0;
|
||||
|
||||
for(size_t curve = 0; curve < CData->curve_vcol.size(); curve++)
|
||||
if(!(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f))
|
||||
fdata[i++] = color_srgb_to_scene_linear(CData->curve_vcol[curve]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Hair Curve Sync */
|
||||
|
||||
void BlenderSync::sync_curve_settings()
|
||||
@@ -1037,61 +856,8 @@ void BlenderSync::sync_curve_settings()
|
||||
curve_system_manager->tag_update(scene);
|
||||
}
|
||||
|
||||
struct CurvesPSysData {
|
||||
CurvesPSysData(BL::ParticleSystemModifier b_psmd=PointerRNA_NULL, BL::ParticleSystem b_psys=PointerRNA_NULL,
|
||||
BL::Strands b_strands=PointerRNA_NULL, BL::StrandsChildren b_strands_children=PointerRNA_NULL) :
|
||||
b_psmd(b_psmd), b_psys(b_psys), b_strands(b_strands), b_strands_children(b_strands_children)
|
||||
{}
|
||||
|
||||
BL::ParticleSystemModifier b_psmd;
|
||||
BL::ParticleSystem b_psys;
|
||||
BL::Strands b_strands;
|
||||
BL::StrandsChildren b_strands_children;
|
||||
};
|
||||
|
||||
static void curves_get_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::Scene b_scene, BL::Object b_ob, BL::Object b_parent, BL::DupliObject b_dupli_ob, bool preview)
|
||||
void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index)
|
||||
{
|
||||
BL::Object::modifiers_iterator b_mod;
|
||||
for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) {
|
||||
if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && (preview ? b_mod->show_viewport() : b_mod->show_render())) {
|
||||
BL::ParticleSystemModifier b_psmd((const PointerRNA)b_mod->ptr);
|
||||
BL::ParticleSystem b_psys((const PointerRNA)b_psmd.particle_system().ptr);
|
||||
BL::ParticleSettings b_part((const PointerRNA)b_psys.settings().ptr);
|
||||
|
||||
if((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) {
|
||||
int settings = preview ? 1 : 2;
|
||||
|
||||
BL::StrandsChildren b_strands_children = PointerRNA_NULL;
|
||||
BL::Strands b_strands = PointerRNA_NULL;
|
||||
|
||||
if (b_dupli_ob && b_parent) {
|
||||
b_strands_children = b_dupli_ob.strands_children_new(b_scene, b_parent, b_psys, settings);
|
||||
if (!b_strands_children)
|
||||
b_strands = b_dupli_ob.strands_new(b_scene, b_parent, b_psys, settings);
|
||||
}
|
||||
|
||||
b_psys_list.push_back(CurvesPSysData(b_psmd, b_psys, b_strands, b_strands_children));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void curves_free_psys_data(std::vector<CurvesPSysData> &b_psys_list, BL::DupliObject b_dupli_ob)
|
||||
{
|
||||
/* free temporary strands data */
|
||||
for (int i = 0; i < b_psys_list.size(); ++i) {
|
||||
CurvesPSysData &psys_data = b_psys_list[i];
|
||||
if (psys_data.b_strands)
|
||||
b_dupli_ob.strands_free(psys_data.b_strands);
|
||||
if (psys_data.b_strands_children)
|
||||
b_dupli_ob.strands_children_free(psys_data.b_strands_children);
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index, BL::DupliObject b_dupli_ob)
|
||||
{
|
||||
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
|
||||
|
||||
if(!motion) {
|
||||
/* Clear stored curve data */
|
||||
mesh->curve_keys.clear();
|
||||
@@ -1122,46 +888,27 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent,
|
||||
if(!preview)
|
||||
set_resolution(&b_ob, &b_scene, true);
|
||||
|
||||
Transform tfm = get_transform(b_ob.matrix_world());
|
||||
Transform itfm = transform_quick_inverse(tfm);
|
||||
|
||||
/* obtain camera parameters */
|
||||
float3 RotCam;
|
||||
Camera *camera = scene->camera;
|
||||
if(camera->type == CAMERA_ORTHOGRAPHIC) {
|
||||
Transform &ctfm = camera->matrix;
|
||||
RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
|
||||
}
|
||||
else {
|
||||
Transform &ctfm = camera->matrix;
|
||||
RotCam = transform_point(&itfm, make_float3(ctfm.x.w, ctfm.y.w, ctfm.z.w));
|
||||
}
|
||||
bool is_ortho_camera = camera->type == CAMERA_ORTHOGRAPHIC;
|
||||
|
||||
std::vector<CurvesPSysData> b_psys_list;
|
||||
curves_get_psys_data(b_psys_list, b_scene, b_ob, b_parent, b_dupli_ob, preview);
|
||||
|
||||
for (int i = 0; i < b_psys_list.size(); ++i) {
|
||||
CurvesPSysData &psys_data = b_psys_list[i];
|
||||
if (psys_data.b_strands_children)
|
||||
/* use child strands cache */
|
||||
ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
|
||||
itfm, &CData, !preview);
|
||||
else if (psys_data.b_strands)
|
||||
/* use parent strands cache */
|
||||
ObtainCacheStrandsData(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
|
||||
itfm, &CData, !preview);
|
||||
else {
|
||||
/* use object data */
|
||||
ObtainCacheParticleData(mesh, b_ob, psys_data.b_psys,
|
||||
itfm, &CData, !preview);
|
||||
}
|
||||
}
|
||||
ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview);
|
||||
|
||||
/* add hair geometry to mesh */
|
||||
if(primitive == CURVE_TRIANGLES) {
|
||||
if(triangle_method == CURVE_CAMERA_TRIANGLES) {
|
||||
ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho_camera);
|
||||
/* obtain camera parameters */
|
||||
float3 RotCam;
|
||||
Camera *camera = scene->camera;
|
||||
Transform &ctfm = camera->matrix;
|
||||
if(camera->type == CAMERA_ORTHOGRAPHIC) {
|
||||
RotCam = -make_float3(ctfm.x.z, ctfm.y.z, ctfm.z.z);
|
||||
}
|
||||
else {
|
||||
Transform tfm = get_transform(b_ob.matrix_world());
|
||||
Transform itfm = transform_quick_inverse(tfm);
|
||||
RotCam = transform_point(&itfm, make_float3(ctfm.x.w,
|
||||
ctfm.y.w,
|
||||
ctfm.z.w));
|
||||
}
|
||||
bool is_ortho = camera->type == CAMERA_ORTHOGRAPHIC;
|
||||
ExportCurveTrianglePlanes(mesh, &CData, RotCam, is_ortho);
|
||||
}
|
||||
else {
|
||||
ExportCurveTriangleGeometry(mesh, &CData, resolution);
|
||||
@@ -1208,31 +955,33 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent,
|
||||
int vcol_num = 0;
|
||||
|
||||
for(b_mesh.tessface_vertex_colors.begin(l); l != b_mesh.tessface_vertex_colors.end(); ++l, vcol_num++) {
|
||||
ustring name = ustring(l->name().c_str());
|
||||
|
||||
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
|
||||
continue;
|
||||
|
||||
CData.curve_vcol.clear();
|
||||
ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num);
|
||||
|
||||
for (int i = 0; i < b_psys_list.size(); ++i) {
|
||||
CurvesPSysData &psys_data = b_psys_list[i];
|
||||
if (psys_data.b_strands_children)
|
||||
/* use child strands cache */
|
||||
ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
|
||||
&CData, !preview, vcol_num);
|
||||
else if (psys_data.b_strands)
|
||||
/* use parent strands cache */
|
||||
ObtainCacheStrandsVcol(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
|
||||
&CData, !preview, vcol_num);
|
||||
else {
|
||||
/* use object data */
|
||||
ObtainCacheParticleVcol(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
|
||||
&CData, !preview, vcol_num);
|
||||
if(primitive == CURVE_TRIANGLES) {
|
||||
Attribute *attr_vcol = mesh->attributes.add(
|
||||
ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
|
||||
|
||||
uchar4 *cdata = attr_vcol->data_uchar4();
|
||||
|
||||
ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata);
|
||||
}
|
||||
else {
|
||||
Attribute *attr_vcol = mesh->curve_attributes.add(
|
||||
ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE);
|
||||
|
||||
float3 *fdata = attr_vcol->data_float3();
|
||||
|
||||
if(fdata) {
|
||||
size_t i = 0;
|
||||
|
||||
for(size_t curve = 0; curve < CData.curve_vcol.size(); curve++)
|
||||
if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
|
||||
fdata[i++] = color_srgb_to_scene_linear(CData.curve_vcol[curve]);
|
||||
}
|
||||
}
|
||||
|
||||
ExportCurveVcol(mesh, &CData, name, primitive, tri_num * 3, used_res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,37 +992,45 @@ void BlenderSync::sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent,
|
||||
|
||||
for(b_mesh.tessface_uv_textures.begin(l); l != b_mesh.tessface_uv_textures.end(); ++l, uv_num++) {
|
||||
bool active_render = l->active_render();
|
||||
AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE;
|
||||
ustring name = ustring(l->name().c_str());
|
||||
|
||||
/* UV map */
|
||||
if(!(mesh->need_attribute(scene, name) || (active_render && mesh->need_attribute(scene, ATTR_STD_UV))))
|
||||
continue;
|
||||
|
||||
CData.curve_uv.clear();
|
||||
|
||||
for (int i = 0; i < b_psys_list.size(); ++i) {
|
||||
CurvesPSysData &psys_data = b_psys_list[i];
|
||||
if (psys_data.b_strands_children)
|
||||
/* use child strands cache */
|
||||
ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands_children,
|
||||
&CData, !preview, uv_num);
|
||||
else if (psys_data.b_strands)
|
||||
/* use parent strands cache */
|
||||
ObtainCacheStrandsUV(mesh, b_scene, b_parent, b_dupli_ob, psys_data.b_psys, psys_data.b_strands,
|
||||
&CData, !preview, uv_num);
|
||||
if(mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) {
|
||||
Attribute *attr_uv;
|
||||
|
||||
ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num);
|
||||
|
||||
if(primitive == CURVE_TRIANGLES) {
|
||||
if(active_render)
|
||||
attr_uv = mesh->attributes.add(std, name);
|
||||
else
|
||||
attr_uv = mesh->attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
|
||||
|
||||
float3 *uv = attr_uv->data_float3();
|
||||
|
||||
ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv);
|
||||
}
|
||||
else {
|
||||
/* use object data */
|
||||
ObtainCacheParticleUV(mesh, b_ob, b_mesh, psys_data.b_psys, psys_data.b_psmd,
|
||||
&CData, !preview, uv_num);
|
||||
if(active_render)
|
||||
attr_uv = mesh->curve_attributes.add(std, name);
|
||||
else
|
||||
attr_uv = mesh->curve_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE);
|
||||
|
||||
float3 *uv = attr_uv->data_float3();
|
||||
|
||||
if(uv) {
|
||||
size_t i = 0;
|
||||
|
||||
for(size_t curve = 0; curve < CData.curve_uv.size(); curve++)
|
||||
if(!(CData.curve_keynum[curve] <= 1 || CData.curve_length[curve] == 0.0f))
|
||||
uv[i++] = CData.curve_uv[curve];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExportCurveUV(mesh, &CData, name, active_render, primitive, tri_num * 3, used_res);
|
||||
}
|
||||
}
|
||||
|
||||
curves_free_psys_data(b_psys_list, b_dupli_ob);
|
||||
|
||||
if(!preview)
|
||||
set_resolution(&b_ob, &b_scene, false);
|
||||
|
||||
|
@@ -229,13 +229,7 @@ static void mikk_compute_tangents(BL::Mesh b_mesh, BL::MeshTextureFaceLayer *b_l
|
||||
|
||||
/* Create Volume Attribute */
|
||||
|
||||
static void create_mesh_volume_attribute(BL::Object b_ob,
|
||||
Mesh *mesh,
|
||||
ImageManager *image_manager,
|
||||
AttributeStandard std,
|
||||
float frame,
|
||||
AttributeStandard special_std = ATTR_STD_NONE,
|
||||
bool from_alpha = false)
|
||||
static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManager *image_manager, AttributeStandard std, float frame)
|
||||
{
|
||||
BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
|
||||
|
||||
@@ -246,35 +240,17 @@ static void create_mesh_volume_attribute(BL::Object b_ob,
|
||||
VoxelAttribute *volume_data = attr->data_voxel();
|
||||
bool is_float, is_linear;
|
||||
bool animated = false;
|
||||
AttributeStandard data_attr = (special_std == ATTR_STD_NONE) ? std : special_std;
|
||||
|
||||
volume_data->manager = image_manager;
|
||||
volume_data->slot = image_manager->add_image(Attribute::standard_name(data_attr),
|
||||
volume_data->slot = image_manager->add_image(Attribute::standard_name(std),
|
||||
b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true);
|
||||
volume_data->from_alpha = from_alpha;
|
||||
}
|
||||
|
||||
static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame)
|
||||
{
|
||||
/* for smoke volume rendering */
|
||||
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY)) {
|
||||
/* Special case: we re-map density to A channel of Color texture
|
||||
* if both attributes are requested.
|
||||
*/
|
||||
AttributeStandard special_std = ATTR_STD_VOLUME_DENSITY;
|
||||
bool from_alpha = false;
|
||||
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR)) {
|
||||
special_std = ATTR_STD_VOLUME_COLOR;
|
||||
from_alpha = true;
|
||||
}
|
||||
create_mesh_volume_attribute(b_ob,
|
||||
mesh,
|
||||
scene->image_manager,
|
||||
ATTR_STD_VOLUME_DENSITY,
|
||||
frame,
|
||||
special_std,
|
||||
from_alpha);
|
||||
}
|
||||
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_DENSITY))
|
||||
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_DENSITY, frame);
|
||||
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_COLOR))
|
||||
create_mesh_volume_attribute(b_ob, mesh, scene->image_manager, ATTR_STD_VOLUME_COLOR, frame);
|
||||
if(mesh->need_attribute(scene, ATTR_STD_VOLUME_FLAME))
|
||||
@@ -446,52 +422,6 @@ static void attr_create_pointiness(Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
/* Create vertex custom attributes. */
|
||||
static void attr_create_vertex_properties(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh b_mesh)
|
||||
{
|
||||
{
|
||||
BL::Mesh::vertex_layers_float_iterator l;
|
||||
for(b_mesh.vertex_layers_float.begin(l); l != b_mesh.vertex_layers_float.end(); ++l) {
|
||||
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
|
||||
continue;
|
||||
|
||||
Attribute *attr = mesh->attributes.add(
|
||||
ustring(l->name().c_str()), TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
|
||||
|
||||
BL::MeshVertexFloatPropertyLayer::data_iterator d;
|
||||
float *data = attr->data_float();
|
||||
size_t i = 0;
|
||||
|
||||
for(l->data.begin(d); d != l->data.end(); ++d, ++i) {
|
||||
*data = d->value();
|
||||
data += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
BL::Mesh::vertex_layers_int_iterator l;
|
||||
for(b_mesh.vertex_layers_int.begin(l); l != b_mesh.vertex_layers_int.end(); ++l) {
|
||||
if(!mesh->need_attribute(scene, ustring(l->name().c_str())))
|
||||
continue;
|
||||
|
||||
Attribute *attr = mesh->attributes.add(
|
||||
ustring(l->name().c_str()), TypeDesc::TypeFloat, ATTR_ELEMENT_VERTEX);
|
||||
|
||||
BL::MeshVertexIntPropertyLayer::data_iterator d;
|
||||
float *data = attr->data_float();
|
||||
size_t i = 0;
|
||||
|
||||
for(l->data.begin(d); d != l->data.end(); ++d, ++i) {
|
||||
*data = (float)d->value();
|
||||
data += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create Mesh */
|
||||
|
||||
static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<uint>& used_shaders)
|
||||
@@ -598,7 +528,6 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
|
||||
*/
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, nverts);
|
||||
attr_create_uv_map(scene, mesh, b_mesh, nverts);
|
||||
attr_create_vertex_properties(scene, mesh, b_mesh);
|
||||
|
||||
/* for volume objects, create a matrix to transform from object space to
|
||||
* mesh texture space. this does not work with deformations but that can
|
||||
@@ -658,10 +587,8 @@ static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerR
|
||||
|
||||
/* Sync */
|
||||
|
||||
Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob)
|
||||
Mesh *BlenderSync::sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris)
|
||||
{
|
||||
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
|
||||
|
||||
/* When viewport display is not needed during render we can force some
|
||||
* caches to be releases from blender side in order to reduce peak memory
|
||||
* footprint during synchronization process.
|
||||
@@ -672,6 +599,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide
|
||||
|
||||
/* test if we can instance or if the object is modified */
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
|
||||
BL::Material material_override = render_layer.material_override;
|
||||
|
||||
/* find shader indices */
|
||||
@@ -702,24 +630,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide
|
||||
}
|
||||
Mesh *mesh;
|
||||
|
||||
bool need_update;
|
||||
BL::CacheLibrary b_cachelib = b_parent.cache_library();
|
||||
bool use_dupli_override = b_dupli_ob && b_cachelib &&
|
||||
(b_cachelib.source_mode() == BL::CacheLibrary::source_mode_CACHE ||
|
||||
b_cachelib.display_mode() == BL::CacheLibrary::display_mode_RESULT);
|
||||
if (use_dupli_override) {
|
||||
/* if a dupli override (cached data) is used, identify the mesh by object and parent together,
|
||||
* so that individual per-dupli overrides are possible.
|
||||
*/
|
||||
MeshKey key = MeshKey(b_parent, b_ob);
|
||||
need_update = mesh_map.sync(&mesh, b_ob, b_parent, key);
|
||||
}
|
||||
else {
|
||||
BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data;
|
||||
need_update = mesh_map.sync(&mesh, key);
|
||||
}
|
||||
|
||||
if(!need_update) {
|
||||
if(!mesh_map.sync(&mesh, key)) {
|
||||
/* if transform was applied to mesh, need full update */
|
||||
if(object_updated && mesh->transform_applied);
|
||||
/* test if shaders changed, these can be object level so mesh
|
||||
@@ -770,9 +681,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide
|
||||
b_ob.update_from_editmode();
|
||||
|
||||
bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED);
|
||||
BL::Mesh b_mesh = (use_dupli_override)?
|
||||
dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, need_undeformed):
|
||||
object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
|
||||
BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed);
|
||||
|
||||
if(b_mesh) {
|
||||
if(render_layer.use_surfaces && !hide_tris) {
|
||||
@@ -785,10 +694,10 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide
|
||||
}
|
||||
|
||||
if(render_layer.use_hair)
|
||||
sync_curves(mesh, b_mesh, b_parent, false, 0, b_dupli_ob);
|
||||
sync_curves(mesh, b_mesh, b_ob, false);
|
||||
|
||||
if(can_free_caches) {
|
||||
b_ob.cache_release(false);
|
||||
b_ob.cache_release();
|
||||
}
|
||||
|
||||
/* free derived mesh */
|
||||
@@ -831,9 +740,8 @@ Mesh *BlenderSync::sync_mesh(BL::Object b_parent, bool object_updated, bool hide
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob)
|
||||
void BlenderSync::sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time)
|
||||
{
|
||||
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
|
||||
/* ensure we only sync instanced meshes once */
|
||||
Mesh *mesh = object->mesh;
|
||||
|
||||
@@ -892,9 +800,7 @@ void BlenderSync::sync_mesh_motion(BL::Object b_parent, Object *object, float mo
|
||||
|
||||
if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||
/* get derived mesh */
|
||||
b_mesh = (b_dupli_ob && b_parent)?
|
||||
dupli_to_mesh(b_data, b_scene, b_parent, b_dupli_ob, !preview, false):
|
||||
object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
|
||||
b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false);
|
||||
}
|
||||
|
||||
if(!b_mesh) {
|
||||
@@ -984,7 +890,7 @@ void BlenderSync::sync_mesh_motion(BL::Object b_parent, Object *object, float mo
|
||||
|
||||
/* hair motion */
|
||||
if(numkeys)
|
||||
sync_curves(mesh, b_mesh, b_parent, true, time_index, b_dupli_ob);
|
||||
sync_curves(mesh, b_mesh, b_ob, true, time_index);
|
||||
|
||||
/* free derived mesh */
|
||||
b_data.meshes.remove(b_mesh);
|
||||
|
@@ -234,53 +234,8 @@ void BlenderSync::sync_background_light(bool use_portal)
|
||||
|
||||
/* Object */
|
||||
|
||||
static bool object_boundbox_clip(Scene *scene,
|
||||
BL::Object b_ob,
|
||||
Transform& tfm,
|
||||
float margin)
|
||||
{
|
||||
Camera *cam = scene->camera;
|
||||
Transform& worldtondc = cam->worldtondc;
|
||||
BL::Array<float, 24> boundbox = b_ob.bound_box();
|
||||
float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
|
||||
bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
bool all_behind = true;
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
float3 p = make_float3(boundbox[3 * i + 0],
|
||||
boundbox[3 * i + 1],
|
||||
boundbox[3 * i + 2]);
|
||||
p = transform_point(&tfm, p);
|
||||
p = transform_point(&worldtondc, p);
|
||||
if(p.z >= -margin) {
|
||||
all_behind = false;
|
||||
}
|
||||
p /= p.z;
|
||||
bb_min = min(bb_min, p);
|
||||
bb_max = max(bb_max, p);
|
||||
}
|
||||
if(!all_behind) {
|
||||
if(bb_min.x >= 1.0f + margin ||
|
||||
bb_min.y >= 1.0f + margin ||
|
||||
bb_max.x <= -margin ||
|
||||
bb_max.y <= -margin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BL::DupliObject b_dupli_ob,
|
||||
Transform& tfm,
|
||||
uint layer_flag,
|
||||
float motion_time,
|
||||
bool hide_tris,
|
||||
bool use_camera_cull,
|
||||
float camera_cull_margin,
|
||||
bool *use_portal)
|
||||
Object *BlenderSync::sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
|
||||
Transform& tfm, uint layer_flag, float motion_time, bool hide_tris, bool *use_portal)
|
||||
{
|
||||
BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent);
|
||||
bool motion = motion_time != 0.0f;
|
||||
@@ -298,11 +253,6 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
if(!object_is_mesh(b_ob))
|
||||
return NULL;
|
||||
|
||||
/* Perform camera space culling. */
|
||||
if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* key to lookup object */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob);
|
||||
Object *object;
|
||||
@@ -311,7 +261,9 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
if(motion) {
|
||||
object = object_map.find(key);
|
||||
|
||||
if(object && (scene->need_motion() == Scene::MOTION_PASS || object_use_motion(b_ob))) {
|
||||
if(object && (scene->need_motion() == Scene::MOTION_PASS ||
|
||||
object_use_motion(b_parent, b_ob)))
|
||||
{
|
||||
/* object transformation */
|
||||
if(tfm != object->tfm) {
|
||||
VLOG(1) << "Object " << b_ob.name() << " motion detected.";
|
||||
@@ -327,7 +279,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
|
||||
/* mesh deformation */
|
||||
if(object->mesh)
|
||||
sync_mesh_motion(b_parent, object, motion_time, b_dupli_ob);
|
||||
sync_mesh_motion(b_ob, object, motion_time);
|
||||
}
|
||||
|
||||
return object;
|
||||
@@ -342,10 +294,7 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0;
|
||||
|
||||
/* mesh sync */
|
||||
if (b_dupli_ob)
|
||||
object->mesh = sync_mesh(b_parent, object_updated, hide_tris, b_dupli_ob);
|
||||
else
|
||||
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
|
||||
object->mesh = sync_mesh(b_ob, object_updated, hide_tris);
|
||||
|
||||
/* special case not tracked by object update flags */
|
||||
|
||||
@@ -395,8 +344,8 @@ Object *BlenderSync::sync_object(BL::Object b_parent,
|
||||
|
||||
mesh->use_motion_blur = false;
|
||||
|
||||
if(object_use_motion(b_ob)) {
|
||||
if(object_use_deform_motion(b_ob)) {
|
||||
if(object_use_motion(b_parent, b_ob)) {
|
||||
if(object_use_deform_motion(b_parent, b_ob)) {
|
||||
mesh->motion_steps = object_motion_steps(b_ob);
|
||||
mesh->use_motion_blur = true;
|
||||
}
|
||||
@@ -531,15 +480,6 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
|
||||
mesh_motion_synced.clear();
|
||||
}
|
||||
|
||||
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||
bool allow_camera_cull = scene->camera->type != CAMERA_PANORAMA &&
|
||||
!b_scene.render().use_multiview() &&
|
||||
get_boolean(cscene, "use_camera_cull");
|
||||
float camera_cull_margin = 0.0f;
|
||||
if(allow_camera_cull) {
|
||||
camera_cull_margin = get_float(cscene, "camera_cull_margin");
|
||||
}
|
||||
|
||||
/* object loop */
|
||||
BL::Scene::object_bases_iterator b_base;
|
||||
BL::Scene b_sce = b_scene;
|
||||
@@ -562,12 +502,6 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
|
||||
if(!hide) {
|
||||
progress.set_sync_status("Synchronizing object", b_ob.name());
|
||||
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull");
|
||||
if(use_camera_cull) {
|
||||
/* Need to have proper projection matrix. */
|
||||
scene->camera->update();
|
||||
}
|
||||
if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) {
|
||||
/* dupli objects */
|
||||
b_ob.dupli_list_create(b_scene, dupli_settings);
|
||||
@@ -587,16 +521,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
|
||||
BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id();
|
||||
|
||||
/* sync object and mesh or light data */
|
||||
Object *object = sync_object(b_ob,
|
||||
persistent_id.data,
|
||||
*b_dup,
|
||||
tfm,
|
||||
ob_layer,
|
||||
motion_time,
|
||||
hide_tris,
|
||||
use_camera_cull,
|
||||
camera_cull_margin,
|
||||
&use_portal);
|
||||
Object *object = sync_object(b_ob, persistent_id.data, *b_dup, tfm, ob_layer, motion_time, hide_tris, &use_portal);
|
||||
|
||||
/* sync possible particle data, note particle_id
|
||||
* starts counting at 1, first is dummy particle */
|
||||
@@ -616,16 +541,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, float motion_time)
|
||||
if(!object_render_hide(b_ob, true, true, hide_tris)) {
|
||||
/* object itself */
|
||||
Transform tfm = get_transform(b_ob.matrix_world());
|
||||
sync_object(b_ob,
|
||||
NULL,
|
||||
PointerRNA_NULL,
|
||||
tfm,
|
||||
ob_layer,
|
||||
motion_time,
|
||||
hide_tris,
|
||||
use_camera_cull,
|
||||
camera_cull_margin,
|
||||
&use_portal);
|
||||
sync_object(b_ob, NULL, PointerRNA_NULL, tfm, ob_layer, motion_time, hide_tris, &use_portal);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "util_color.h"
|
||||
#include "util_foreach.h"
|
||||
#include "util_function.h"
|
||||
#include "util_logging.h"
|
||||
#include "util_progress.h"
|
||||
#include "util_time.h"
|
||||
|
||||
@@ -100,8 +101,7 @@ void BlenderSession::create_session()
|
||||
start_resize_time = 0.0;
|
||||
|
||||
/* create scene */
|
||||
bool free_data_after_update = background && !scene_params.persistent_data;
|
||||
scene = new Scene(scene_params, session_params.device, free_data_after_update);
|
||||
scene = new Scene(scene_params, session_params.device);
|
||||
|
||||
/* setup callbacks for builtin image support */
|
||||
scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7);
|
||||
@@ -272,6 +272,10 @@ static PassType get_pass_type(BL::RenderPass b_pass)
|
||||
{
|
||||
if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSAL_STEPS)
|
||||
return PASS_BVH_TRAVERSAL_STEPS;
|
||||
if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSED_INSTANCES)
|
||||
return PASS_BVH_TRAVERSED_INSTANCES;
|
||||
if(b_pass.debug_type() == BL::RenderPass::debug_type_RAY_BOUNCES)
|
||||
return PASS_RAY_BOUNCES;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -409,7 +413,6 @@ void BlenderSession::render()
|
||||
/* set callback to write out render results */
|
||||
session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
|
||||
session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1);
|
||||
session->clear_database_cb = function_bind(&BlenderSession::clear_blender_database, this);
|
||||
|
||||
/* get buffer parameters */
|
||||
SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
|
||||
@@ -441,6 +444,7 @@ void BlenderSession::render()
|
||||
Pass::add(PASS_COMBINED, passes);
|
||||
#ifdef WITH_CYCLES_DEBUG
|
||||
Pass::add(PASS_BVH_TRAVERSAL_STEPS, passes);
|
||||
/* Pass::add(PASS_RAY_BOUNCES, passes); */
|
||||
#endif
|
||||
|
||||
if(session_params.device.advanced_shading) {
|
||||
@@ -499,10 +503,14 @@ void BlenderSession::render()
|
||||
break;
|
||||
}
|
||||
|
||||
double total_time, render_time;
|
||||
session->progress.get_time(total_time, render_time);
|
||||
VLOG(1) << "Total render time: " << total_time;
|
||||
VLOG(1) << "Render time (without synchronization): " << render_time;
|
||||
|
||||
/* clear callback */
|
||||
session->write_render_tile_cb = function_null;
|
||||
session->update_render_tile_cb = function_null;
|
||||
session->clear_database_cb = function_null;
|
||||
|
||||
/* free all memory used (host and device), so we wouldn't leave render
|
||||
* engine with extra memory allocated
|
||||
@@ -1004,18 +1012,6 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti
|
||||
|
||||
is_float = true;
|
||||
}
|
||||
else {
|
||||
/* TODO(sergey): Check we're indeed in shader node tree. */
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
|
||||
BL::Node b_node(ptr);
|
||||
if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
|
||||
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
|
||||
channels = 4;
|
||||
width = height = depth = b_point_density_node.resolution();
|
||||
is_float = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels)
|
||||
@@ -1158,41 +1154,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void
|
||||
|
||||
fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
|
||||
}
|
||||
else {
|
||||
/* TODO(sergey): Check we're indeed in shader node tree. */
|
||||
PointerRNA ptr;
|
||||
RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
|
||||
BL::Node b_node(ptr);
|
||||
if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
|
||||
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
|
||||
int length;
|
||||
b_point_density_node.calc_point_density(b_scene, &length, &pixels);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlenderSession::clear_blender_database()
|
||||
{
|
||||
const bool is_interface_locked = b_engine.render() &&
|
||||
b_engine.render().use_lock_interface();
|
||||
const bool can_free_database = BlenderSession::headless || is_interface_locked;
|
||||
if(!can_free_database) {
|
||||
/* Database might be used by the interface, can not free it at all. */
|
||||
return;
|
||||
}
|
||||
for(BL::Scene b_sce = b_scene; b_sce; b_sce = b_sce.background_set()) {
|
||||
BL::Scene::object_bases_iterator b_base;
|
||||
for(b_sce.object_bases.begin(b_base);
|
||||
b_base != b_sce.object_bases.end();
|
||||
++b_base)
|
||||
{
|
||||
BL::Object b_ob = b_base->object();
|
||||
b_ob.cache_release(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
@@ -109,8 +109,6 @@ protected:
|
||||
void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels);
|
||||
bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels);
|
||||
bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels);
|
||||
|
||||
void clear_blender_database();
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include "scene.h"
|
||||
#include "shader.h"
|
||||
|
||||
#include "blender_texture.h"
|
||||
#include "blender_sync.h"
|
||||
#include "blender_util.h"
|
||||
|
||||
@@ -737,34 +736,6 @@ static ShaderNode *add_node(Scene *scene,
|
||||
uvm->from_dupli = b_uvmap_node.from_dupli();
|
||||
node = uvm;
|
||||
}
|
||||
else if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
|
||||
BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
|
||||
PointDensityTextureNode *point_density = new PointDensityTextureNode();
|
||||
point_density->filename = b_point_density_node.name();
|
||||
point_density->space =
|
||||
PointDensityTextureNode::space_enum[(int)b_point_density_node.space()];
|
||||
point_density->interpolation =
|
||||
(InterpolationType)b_point_density_node.interpolation();
|
||||
point_density->builtin_data = b_point_density_node.ptr.data;
|
||||
|
||||
/* Transformation form world space to texture space. */
|
||||
BL::Object b_ob(b_point_density_node.object());
|
||||
if(b_ob) {
|
||||
float3 loc, size;
|
||||
point_density_texture_space(b_point_density_node, loc, size);
|
||||
point_density->tfm =
|
||||
transform_translate(-loc) * transform_scale(size) *
|
||||
transform_inverse(get_transform(b_ob.matrix_world()));
|
||||
}
|
||||
|
||||
/* TODO(sergey): Use more proper update flag. */
|
||||
if(true) {
|
||||
scene->image_manager->tag_reload_image(point_density->filename,
|
||||
point_density->builtin_data,
|
||||
point_density->interpolation);
|
||||
}
|
||||
node = point_density;
|
||||
}
|
||||
|
||||
if(node)
|
||||
graph->add(node);
|
||||
|
@@ -435,8 +435,6 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene, bool background, bo
|
||||
params.use_qbvh = false;
|
||||
}
|
||||
|
||||
params.use_bvh_triangle_storage = RNA_boolean_get(&cscene, "debug_use_triangle_storage");
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
|
@@ -83,22 +83,13 @@ private:
|
||||
void sync_curve_settings();
|
||||
|
||||
void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree);
|
||||
Mesh *sync_mesh(BL::Object b_parent, bool object_updated, bool hide_tris, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
|
||||
void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_parent, bool motion, int time_index = 0, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
|
||||
Object *sync_object(BL::Object b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BL::DupliObject b_dupli_ob,
|
||||
Transform& tfm,
|
||||
uint layer_flag,
|
||||
float motion_time,
|
||||
bool hide_tris,
|
||||
bool use_camera_cull,
|
||||
float camera_cull_margin,
|
||||
bool *use_portal);
|
||||
Mesh *sync_mesh(BL::Object b_ob, bool object_updated, bool hide_tris);
|
||||
void sync_curves(Mesh *mesh, BL::Mesh b_mesh, BL::Object b_ob, bool motion, int time_index = 0);
|
||||
Object *sync_object(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject b_dupli_ob,
|
||||
Transform& tfm, uint layer_flag, float motion_time, bool hide_tris, bool *use_portal);
|
||||
void sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object b_ob, Transform& tfm, bool *use_portal);
|
||||
void sync_background_light(bool use_portal);
|
||||
void sync_mesh_motion(BL::Object b_parent, Object *object, float motion_time, BL::DupliObject b_dupli_ob = PointerRNA_NULL);
|
||||
|
||||
void sync_mesh_motion(BL::Object b_ob, Object *object, float motion_time);
|
||||
void sync_camera_motion(BL::Object b_ob, float motion_time);
|
||||
|
||||
/* particles */
|
||||
@@ -120,7 +111,7 @@ private:
|
||||
|
||||
id_map<void*, Shader> shader_map;
|
||||
id_map<ObjectKey, Object> object_map;
|
||||
id_map<MeshKey, Mesh> mesh_map;
|
||||
id_map<void*, Mesh> mesh_map;
|
||||
id_map<ObjectKey, Light> light_map;
|
||||
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
||||
set<Mesh*> mesh_synced;
|
||||
|
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2015 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "blender_texture.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
/* Point density helpers. */
|
||||
|
||||
static void density_texture_space_invert(float3& loc,
|
||||
float3& size)
|
||||
{
|
||||
if(size.x != 0.0f) size.x = 0.5f/size.x;
|
||||
if(size.y != 0.0f) size.y = 0.5f/size.y;
|
||||
if(size.z != 0.0f) size.z = 0.5f/size.z;
|
||||
|
||||
loc = loc*size - make_float3(0.5f, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
static void density_object_texture_space(BL::Object b_ob,
|
||||
float radius,
|
||||
float3& loc,
|
||||
float3& size)
|
||||
{
|
||||
if(b_ob.type() == BL::Object::type_MESH) {
|
||||
BL::Mesh b_mesh(b_ob.data());
|
||||
loc = get_float3(b_mesh.texspace_location());
|
||||
size = get_float3(b_mesh.texspace_size());
|
||||
}
|
||||
else {
|
||||
/* TODO(sergey): Not supported currently. */
|
||||
}
|
||||
/* Adjust texture space to include density points on the boundaries. */
|
||||
size = size + make_float3(radius, radius, radius);
|
||||
density_texture_space_invert(loc, size);
|
||||
}
|
||||
|
||||
static void density_particle_system_texture_space(
|
||||
BL::Object b_ob,
|
||||
BL::ParticleSystem b_particle_system,
|
||||
float radius,
|
||||
float3& loc,
|
||||
float3& size)
|
||||
{
|
||||
if(b_particle_system.settings().type() == BL::ParticleSettings::type_HAIR) {
|
||||
/* TODO(sergey): Not supported currently. */
|
||||
return;
|
||||
}
|
||||
Transform tfm = get_transform(b_ob.matrix_world());
|
||||
Transform itfm = transform_inverse(tfm);
|
||||
float3 min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX),
|
||||
max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
float3 particle_size = make_float3(radius, radius, radius);
|
||||
for(int i = 0; i < b_particle_system.particles.length(); ++i) {
|
||||
BL::Particle particle = b_particle_system.particles[i];
|
||||
float3 location = get_float3(particle.location());
|
||||
location = transform_point(&itfm, location);
|
||||
min = ccl::min(min, location - particle_size);
|
||||
max = ccl::max(max, location + particle_size);
|
||||
}
|
||||
/* Calculate texture space from the particle bounds. */
|
||||
loc = (min + max) * 0.5f;
|
||||
size = (max - min) * 0.5f;
|
||||
density_texture_space_invert(loc, size);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
|
||||
float3& loc,
|
||||
float3& size)
|
||||
{
|
||||
/* Fallback values. */
|
||||
loc = make_float3(0.0f, 0.0f, 0.0f);
|
||||
size = make_float3(0.0f, 0.0f, 0.0f);
|
||||
BL::Object b_ob(b_point_density_node.object());
|
||||
if(!b_ob) {
|
||||
return;
|
||||
}
|
||||
if(b_point_density_node.point_source() ==
|
||||
BL::ShaderNodeTexPointDensity::point_source_PARTICLE_SYSTEM)
|
||||
{
|
||||
BL::ParticleSystem b_particle_system(
|
||||
b_point_density_node.particle_system());
|
||||
if(b_particle_system) {
|
||||
density_particle_system_texture_space(b_ob,
|
||||
b_particle_system,
|
||||
b_point_density_node.radius(),
|
||||
loc,
|
||||
size);
|
||||
}
|
||||
}
|
||||
else {
|
||||
density_object_texture_space(b_ob,
|
||||
b_point_density_node.radius(),
|
||||
loc,
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2015 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __BLENDER_TEXTURE_H__
|
||||
#define __BLENDER_TEXTURE_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "blender_sync.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
void point_density_texture_space(BL::ShaderNodeTexPointDensity b_point_density_node,
|
||||
float3& loc,
|
||||
float3& size);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __BLENDER_TEXTURE_H__ */
|
@@ -52,18 +52,6 @@ static inline BL::Mesh object_to_mesh(BL::BlendData data, BL::Object object, BL:
|
||||
return me;
|
||||
}
|
||||
|
||||
static inline BL::Mesh dupli_to_mesh(BL::BlendData data, BL::Scene scene, BL::Object parent, BL::DupliObject dob, bool render, bool calc_undeformed)
|
||||
{
|
||||
BL::Mesh me = data.meshes.new_from_dupli(scene, parent, dob, (render)? 2: 1, false, calc_undeformed);
|
||||
if ((bool)me) {
|
||||
if (me.use_auto_smooth()) {
|
||||
me.calc_normals_split();
|
||||
}
|
||||
me.calc_tessface(true);
|
||||
}
|
||||
return me;
|
||||
}
|
||||
|
||||
static inline void colorramp_to_array(BL::ColorRamp ramp, float4 *data, int size)
|
||||
{
|
||||
for(int i = 0; i < size; i++) {
|
||||
@@ -366,11 +354,20 @@ static inline void mesh_texture_space(BL::Mesh b_mesh, float3& loc, float3& size
|
||||
}
|
||||
|
||||
/* object used for motion blur */
|
||||
static inline bool object_use_motion(BL::Object b_ob)
|
||||
static inline bool object_use_motion(BL::Object b_parent, BL::Object b_ob)
|
||||
{
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
bool use_motion = get_boolean(cobject, "use_motion_blur");
|
||||
|
||||
/* If motion blur is enabled for the object we also check
|
||||
* whether it's enabled for the parent object as well.
|
||||
*
|
||||
* This way we can control motion blur from the dupligroup
|
||||
* duplicator much easier.
|
||||
*/
|
||||
if(use_motion && b_parent.ptr.data != b_ob.ptr.data) {
|
||||
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
|
||||
use_motion &= get_boolean(parent_cobject, "use_motion_blur");
|
||||
}
|
||||
return use_motion;
|
||||
}
|
||||
|
||||
@@ -387,11 +384,20 @@ static inline uint object_motion_steps(BL::Object b_ob)
|
||||
}
|
||||
|
||||
/* object uses deformation motion blur */
|
||||
static inline bool object_use_deform_motion(BL::Object b_ob)
|
||||
static inline bool object_use_deform_motion(BL::Object b_parent, BL::Object b_ob)
|
||||
{
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
bool use_deform_motion = get_boolean(cobject, "use_deform_motion");
|
||||
|
||||
/* If motion blur is enabled for the object we also check
|
||||
* whether it's enabled for the parent object as well.
|
||||
*
|
||||
* This way we can control motion blur from the dupligroup
|
||||
* duplicator much easier.
|
||||
*/
|
||||
if(use_deform_motion && b_parent.ptr.data != b_ob.ptr.data) {
|
||||
PointerRNA parent_cobject = RNA_pointer_get(&b_parent.ptr, "cycles");
|
||||
use_deform_motion &= get_boolean(parent_cobject, "use_deform_motion");
|
||||
}
|
||||
return use_deform_motion;
|
||||
}
|
||||
|
||||
@@ -580,36 +586,6 @@ struct ObjectKey {
|
||||
}
|
||||
};
|
||||
|
||||
/* Mesh Key */
|
||||
|
||||
struct MeshKey {
|
||||
void *parent;
|
||||
void *mesh;
|
||||
|
||||
MeshKey(void *mesh_)
|
||||
: parent(NULL), mesh(mesh_)
|
||||
{
|
||||
}
|
||||
|
||||
MeshKey(void *parent_, void *mesh_)
|
||||
: parent(parent_), mesh(mesh_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const MeshKey& k) const
|
||||
{
|
||||
if(mesh < k.mesh) {
|
||||
return true;
|
||||
}
|
||||
else if(mesh == k.mesh) {
|
||||
return parent < k.parent;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/* Particle System Key */
|
||||
|
||||
struct ParticleSystemKey {
|
||||
|
@@ -190,11 +190,12 @@ void BVH::build(Progress& progress)
|
||||
}
|
||||
|
||||
/* build nodes */
|
||||
vector<int> prim_type;
|
||||
vector<int> prim_index;
|
||||
vector<int> prim_object;
|
||||
|
||||
BVHBuild bvh_build(objects, prim_type, prim_index, prim_object, params, progress);
|
||||
BVHBuild bvh_build(objects,
|
||||
pack.prim_type,
|
||||
pack.prim_index,
|
||||
pack.prim_object,
|
||||
params,
|
||||
progress);
|
||||
BVHNode *root = bvh_build.run();
|
||||
|
||||
if(progress.get_cancel()) {
|
||||
@@ -202,14 +203,6 @@ void BVH::build(Progress& progress)
|
||||
return;
|
||||
}
|
||||
|
||||
/* todo: get rid of this copy */
|
||||
pack.prim_type = prim_type;
|
||||
pack.prim_index = prim_index;
|
||||
pack.prim_object = prim_object;
|
||||
prim_type.free_memory();
|
||||
prim_index.free_memory();
|
||||
prim_object.free_memory();
|
||||
|
||||
/* compute SAH */
|
||||
if(!params.top_level)
|
||||
pack.SAH = root->computeSubtreeSAHCost(params);
|
||||
@@ -285,33 +278,27 @@ void BVH::pack_triangle(int idx, float4 woop[3])
|
||||
|
||||
void BVH::pack_primitives()
|
||||
{
|
||||
const int nsize = TRI_NODE_SIZE;
|
||||
const bool use_triangle_storage = params.use_triangle_storage;
|
||||
int nsize = TRI_NODE_SIZE;
|
||||
size_t tidx_size = pack.prim_index.size();
|
||||
|
||||
pack.tri_woop.clear();
|
||||
if (use_triangle_storage) {
|
||||
pack.tri_woop.resize(tidx_size * nsize);
|
||||
}
|
||||
else {
|
||||
pack.tri_woop.resize(0);
|
||||
}
|
||||
pack.tri_woop.resize(tidx_size * nsize);
|
||||
pack.prim_visibility.clear();
|
||||
pack.prim_visibility.resize(tidx_size);
|
||||
|
||||
for(unsigned int i = 0; i < tidx_size; i++) {
|
||||
if(pack.prim_index[i] != -1) {
|
||||
if(use_triangle_storage) {
|
||||
float4 woop[3];
|
||||
if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
|
||||
pack_triangle(i, woop);
|
||||
}
|
||||
else {
|
||||
/* Avoid use of uninitialized memory. */
|
||||
memset(&woop, 0, sizeof(woop));
|
||||
}
|
||||
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
|
||||
float4 woop[3];
|
||||
|
||||
if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) {
|
||||
pack_triangle(i, woop);
|
||||
}
|
||||
else {
|
||||
/* Avoid use of uninitialized memory. */
|
||||
memset(&woop, 0, sizeof(woop));
|
||||
}
|
||||
|
||||
memcpy(&pack.tri_woop[i * nsize], woop, sizeof(float4)*3);
|
||||
|
||||
int tob = pack.prim_object[i];
|
||||
Object *ob = objects[tob];
|
||||
@@ -321,9 +308,7 @@ void BVH::pack_primitives()
|
||||
pack.prim_visibility[i] |= PATH_RAY_CURVE;
|
||||
}
|
||||
else {
|
||||
if(use_triangle_storage) {
|
||||
memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
|
||||
}
|
||||
memset(&pack.tri_woop[i * nsize], 0, sizeof(float4)*3);
|
||||
pack.prim_visibility[i] = 0;
|
||||
}
|
||||
}
|
||||
|
@@ -65,15 +65,18 @@ public:
|
||||
/* Constructor / Destructor */
|
||||
|
||||
BVHBuild::BVHBuild(const vector<Object*>& objects_,
|
||||
vector<int>& prim_type_, vector<int>& prim_index_, vector<int>& prim_object_,
|
||||
const BVHParams& params_, Progress& progress_)
|
||||
: objects(objects_),
|
||||
prim_type(prim_type_),
|
||||
prim_index(prim_index_),
|
||||
prim_object(prim_object_),
|
||||
params(params_),
|
||||
progress(progress_),
|
||||
progress_start_time(0.0)
|
||||
array<int>& prim_type_,
|
||||
array<int>& prim_index_,
|
||||
array<int>& prim_object_,
|
||||
const BVHParams& params_,
|
||||
Progress& progress_)
|
||||
: objects(objects_),
|
||||
prim_type(prim_type_),
|
||||
prim_index(prim_index_),
|
||||
prim_object(prim_object_),
|
||||
params(params_),
|
||||
progress(progress_),
|
||||
progress_start_time(0.0)
|
||||
{
|
||||
spatial_min_overlap = 0.0f;
|
||||
}
|
||||
@@ -446,18 +449,10 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start,
|
||||
return new LeafNode(bounds, 0, 0, 0);
|
||||
}
|
||||
else if(num == 1) {
|
||||
if(start == prim_index.size()) {
|
||||
assert(params.use_spatial_split);
|
||||
|
||||
prim_type.push_back(ref->prim_type());
|
||||
prim_index.push_back(ref->prim_index());
|
||||
prim_object.push_back(ref->prim_object());
|
||||
}
|
||||
else {
|
||||
prim_type[start] = ref->prim_type();
|
||||
prim_index[start] = ref->prim_index();
|
||||
prim_object[start] = ref->prim_object();
|
||||
}
|
||||
assert(start < prim_type.size());
|
||||
prim_type[start] = ref->prim_type();
|
||||
prim_index[start] = ref->prim_index();
|
||||
prim_object[start] = ref->prim_object();
|
||||
|
||||
uint visibility = objects[ref->prim_object()]->visibility;
|
||||
return new LeafNode(ref->bounds(), visibility, start, start+1);
|
||||
@@ -484,17 +479,9 @@ BVHNode *BVHBuild::create_primitive_leaf_node(const int *p_type,
|
||||
int num)
|
||||
{
|
||||
for(int i = 0; i < num; ++i) {
|
||||
if(start + i == prim_index.size()) {
|
||||
assert(params.use_spatial_split);
|
||||
prim_type.push_back(p_type[i]);
|
||||
prim_index.push_back(p_index[i]);
|
||||
prim_object.push_back(p_object[i]);
|
||||
}
|
||||
else {
|
||||
prim_type[start + i] = p_type[i];
|
||||
prim_index[start + i] = p_index[i];
|
||||
prim_object[start + i] = p_object[i];
|
||||
}
|
||||
prim_type[start + i] = p_type[i];
|
||||
prim_index[start + i] = p_index[i];
|
||||
prim_object[start + i] = p_object[i];
|
||||
}
|
||||
return new LeafNode(bounds, visibility, start, start + num);
|
||||
}
|
||||
@@ -535,6 +522,19 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range)
|
||||
}
|
||||
}
|
||||
|
||||
/* Extend an array when needed. */
|
||||
if(prim_type.size() < range.end()) {
|
||||
assert(params.use_spatial_split);
|
||||
/* TODO(sergey): We might want to look into different policies of
|
||||
* re-allocation here, so on the one hand we would not do as much
|
||||
* re-allocations and on the other hand will have small memory
|
||||
* overhead.
|
||||
*/
|
||||
prim_type.resize(range.end());
|
||||
prim_index.resize(range.end());
|
||||
prim_object.resize(range.end());
|
||||
}
|
||||
|
||||
/* Create leaf nodes for every existing primitive. */
|
||||
BVHNode *leaves[PRIMITIVE_NUM_TOTAL + 1] = {NULL};
|
||||
int num_leaves = 0;
|
||||
|
@@ -42,13 +42,12 @@ class BVHBuild
|
||||
{
|
||||
public:
|
||||
/* Constructor/Destructor */
|
||||
BVHBuild(
|
||||
const vector<Object*>& objects,
|
||||
vector<int>& prim_type,
|
||||
vector<int>& prim_index,
|
||||
vector<int>& prim_object,
|
||||
const BVHParams& params,
|
||||
Progress& progress);
|
||||
BVHBuild(const vector<Object*>& objects,
|
||||
array<int>& prim_type,
|
||||
array<int>& prim_index,
|
||||
array<int>& prim_object,
|
||||
const BVHParams& params,
|
||||
Progress& progress);
|
||||
~BVHBuild();
|
||||
|
||||
BVHNode *run();
|
||||
@@ -99,9 +98,9 @@ protected:
|
||||
int num_original_references;
|
||||
|
||||
/* output primitive indexes and objects */
|
||||
vector<int>& prim_type;
|
||||
vector<int>& prim_index;
|
||||
vector<int>& prim_object;
|
||||
array<int>& prim_type;
|
||||
array<int>& prim_index;
|
||||
array<int>& prim_object;
|
||||
|
||||
/* build parameters */
|
||||
BVHParams params;
|
||||
|
@@ -49,9 +49,6 @@ public:
|
||||
/* QBVH */
|
||||
bool use_qbvh;
|
||||
|
||||
/* Use pre-aligned tringle storage for faster lookup. */
|
||||
bool use_triangle_storage;
|
||||
|
||||
/* fixed parameters */
|
||||
enum {
|
||||
MAX_DEPTH = 64,
|
||||
@@ -76,7 +73,6 @@ public:
|
||||
top_level = false;
|
||||
use_cache = false;
|
||||
use_qbvh = false;
|
||||
use_triangle_storage = true;
|
||||
}
|
||||
|
||||
/* SAH costs */
|
||||
|
@@ -30,7 +30,7 @@ if(NOT CYCLES_STANDALONE_REPOSITORY)
|
||||
set(GLEW_INCLUDE_DIR "${GLEW_INCLUDE_PATH}")
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_STANDALONE)
|
||||
if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
|
||||
set(CYCLES_APP_GLEW_LIBRARY ${BLENDER_GLEW_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
@@ -1122,14 +1122,20 @@ void device_cuda_info(vector<DeviceInfo>& devices)
|
||||
}
|
||||
|
||||
vector<DeviceInfo> display_devices;
|
||||
|
||||
|
||||
for(int num = 0; num < count; num++) {
|
||||
char name[256];
|
||||
int attr;
|
||||
|
||||
|
||||
if(cuDeviceGetName(name, 256, num) != CUDA_SUCCESS)
|
||||
continue;
|
||||
|
||||
int major, minor;
|
||||
cuDeviceComputeCapability(&major, &minor, num);
|
||||
if(major < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DeviceInfo info;
|
||||
|
||||
info.type = DEVICE_CUDA;
|
||||
@@ -1137,8 +1143,6 @@ void device_cuda_info(vector<DeviceInfo>& devices)
|
||||
info.id = string_printf("CUDA_%d", num);
|
||||
info.num = num;
|
||||
|
||||
int major, minor;
|
||||
cuDeviceComputeCapability(&major, &minor, num);
|
||||
info.advanced_shading = (major >= 2);
|
||||
info.extended_images = (major >= 3);
|
||||
info.pack_images = false;
|
||||
|
@@ -62,7 +62,17 @@ CCL_NAMESPACE_BEGIN
|
||||
*/
|
||||
#define DATA_ALLOCATION_MEM_FACTOR 5000000 //5MB
|
||||
|
||||
static cl_device_type opencl_device_type()
|
||||
struct OpenCLPlatformDevice {
|
||||
OpenCLPlatformDevice(cl_platform_id platform_id,
|
||||
cl_device_id device_id)
|
||||
: platform_id(platform_id), device_id(device_id) {}
|
||||
cl_platform_id platform_id;
|
||||
cl_device_id device_id;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
cl_device_type opencl_device_type()
|
||||
{
|
||||
char *device = getenv("CYCLES_OPENCL_TEST");
|
||||
|
||||
@@ -82,12 +92,12 @@ static cl_device_type opencl_device_type()
|
||||
return CL_DEVICE_TYPE_ALL;
|
||||
}
|
||||
|
||||
static bool opencl_kernel_use_debug()
|
||||
bool opencl_kernel_use_debug()
|
||||
{
|
||||
return (getenv("CYCLES_OPENCL_DEBUG") != NULL);
|
||||
}
|
||||
|
||||
static bool opencl_kernel_use_advanced_shading(const string& platform)
|
||||
bool opencl_kernel_use_advanced_shading(const string& platform)
|
||||
{
|
||||
/* keep this in sync with kernel_types.h! */
|
||||
if(platform == "NVIDIA CUDA")
|
||||
@@ -102,6 +112,175 @@ static bool opencl_kernel_use_advanced_shading(const string& platform)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool opencl_kernel_use_split(const string& platform_name,
|
||||
const cl_device_type device_type)
|
||||
{
|
||||
if(getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST") != NULL) {
|
||||
return true;
|
||||
}
|
||||
/* TODO(sergey): Replace string lookups with more enum-like API,
|
||||
* similar to device/vendor checks blender's gpu.
|
||||
*/
|
||||
if(platform_name == "AMD Accelerated Parallel Processing" &&
|
||||
device_type == CL_DEVICE_TYPE_GPU)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool opencl_device_supported(const string& platform_name,
|
||||
const cl_device_id device_id)
|
||||
{
|
||||
cl_device_type device_type;
|
||||
clGetDeviceInfo(device_id,
|
||||
CL_DEVICE_TYPE,
|
||||
sizeof(cl_device_type),
|
||||
&device_type,
|
||||
NULL);
|
||||
if(platform_name == "AMD Accelerated Parallel Processing" &&
|
||||
device_type == CL_DEVICE_TYPE_GPU)
|
||||
{
|
||||
return true;;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool opencl_platform_version_check(cl_platform_id platform,
|
||||
string *error = NULL)
|
||||
{
|
||||
const int req_major = 1, req_minor = 1;
|
||||
int major, minor;
|
||||
char version[256];
|
||||
clGetPlatformInfo(platform,
|
||||
CL_PLATFORM_VERSION,
|
||||
sizeof(version),
|
||||
&version,
|
||||
NULL);
|
||||
if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
|
||||
if(error != NULL) {
|
||||
*error = string_printf("OpenCL: failed to parse platform version string (%s).", version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||
if(error != NULL) {
|
||||
*error = string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(error != NULL) {
|
||||
*error = "";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool opencl_device_version_check(cl_device_id device,
|
||||
string *error = NULL)
|
||||
{
|
||||
const int req_major = 1, req_minor = 1;
|
||||
int major, minor;
|
||||
char version[256];
|
||||
clGetDeviceInfo(device,
|
||||
CL_DEVICE_OPENCL_C_VERSION,
|
||||
sizeof(version),
|
||||
&version,
|
||||
NULL);
|
||||
if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
|
||||
if(error != NULL) {
|
||||
*error = string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||
if(error != NULL) {
|
||||
*error = string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(error != NULL) {
|
||||
*error = "";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void opencl_get_usable_devices(vector<OpenCLPlatformDevice> *usable_devices)
|
||||
{
|
||||
const bool force_all_platforms =
|
||||
(getenv("CYCLES_OPENCL_TEST") != NULL) ||
|
||||
(getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST")) != NULL;
|
||||
const cl_device_type device_type = opencl_device_type();
|
||||
|
||||
vector<cl_device_id> device_ids;
|
||||
cl_uint num_devices = 0;
|
||||
vector<cl_platform_id> platform_ids;
|
||||
cl_uint num_platforms = 0;
|
||||
|
||||
/* Number of the devices added to the device info list. */
|
||||
cl_uint num_added_devices = 0;
|
||||
|
||||
/* Get devices. */
|
||||
if(clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS ||
|
||||
num_platforms == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
platform_ids.resize(num_platforms);
|
||||
if(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL) != CL_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
/* Devices are numbered consecutively across platforms. */
|
||||
int num_base = 0;
|
||||
for(int platform = 0;
|
||||
platform < num_platforms;
|
||||
platform++, num_base += num_added_devices)
|
||||
{
|
||||
cl_platform_id platform_id = platform_ids[platform];
|
||||
num_devices = num_added_devices = 0;
|
||||
if(clGetDeviceIDs(platform_id,
|
||||
device_type,
|
||||
0,
|
||||
NULL,
|
||||
&num_devices) != CL_SUCCESS || num_devices == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
device_ids.resize(num_devices);
|
||||
if(clGetDeviceIDs(platform_id,
|
||||
device_type,
|
||||
num_devices,
|
||||
&device_ids[0],
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!opencl_platform_version_check(platform_ids[platform])) {
|
||||
continue;
|
||||
}
|
||||
char pname[256];
|
||||
clGetPlatformInfo(platform_id,
|
||||
CL_PLATFORM_NAME,
|
||||
sizeof(pname),
|
||||
&pname,
|
||||
NULL);
|
||||
string platform_name = pname;
|
||||
for(int num = 0; num < num_devices; num++) {
|
||||
cl_device_id device_id = device_ids[num];
|
||||
if(!opencl_device_version_check(device_id)) {
|
||||
continue;
|
||||
}
|
||||
if(force_all_platforms ||
|
||||
opencl_device_supported(platform_name, device_id))
|
||||
{
|
||||
usable_devices->push_back(OpenCLPlatformDevice(platform_id,
|
||||
device_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
/* thread safe cache for contexts and programs */
|
||||
class OpenCLCache
|
||||
{
|
||||
@@ -421,71 +600,19 @@ public:
|
||||
null_mem = 0;
|
||||
device_initialized = false;
|
||||
|
||||
/* setup platform */
|
||||
cl_uint num_platforms;
|
||||
|
||||
ciErr = clGetPlatformIDs(0, NULL, &num_platforms);
|
||||
if(opencl_error(ciErr))
|
||||
return;
|
||||
|
||||
if(num_platforms == 0) {
|
||||
opencl_error("OpenCL: no platforms found.");
|
||||
return;
|
||||
}
|
||||
|
||||
vector<cl_platform_id> platforms(num_platforms, NULL);
|
||||
|
||||
ciErr = clGetPlatformIDs(num_platforms, &platforms[0], NULL);
|
||||
if(opencl_error(ciErr)) {
|
||||
fprintf(stderr, "clGetPlatformIDs failed \n");
|
||||
return;
|
||||
}
|
||||
|
||||
int num_base = 0;
|
||||
int total_devices = 0;
|
||||
|
||||
for(int platform = 0; platform < num_platforms; platform++) {
|
||||
cl_uint num_devices;
|
||||
|
||||
if(opencl_error(clGetDeviceIDs(platforms[platform], opencl_device_type(), 0, NULL, &num_devices)))
|
||||
return;
|
||||
|
||||
total_devices += num_devices;
|
||||
|
||||
if(info.num - num_base >= num_devices) {
|
||||
/* num doesn't refer to a device in this platform */
|
||||
num_base += num_devices;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* device is in this platform */
|
||||
cpPlatform = platforms[platform];
|
||||
|
||||
/* get devices */
|
||||
vector<cl_device_id> device_ids(num_devices, NULL);
|
||||
|
||||
if(opencl_error(clGetDeviceIDs(cpPlatform, opencl_device_type(), num_devices, &device_ids[0], NULL))) {
|
||||
fprintf(stderr, "clGetDeviceIDs failed \n");
|
||||
return;
|
||||
}
|
||||
|
||||
cdDevice = device_ids[info.num - num_base];
|
||||
|
||||
char name[256];
|
||||
clGetPlatformInfo(cpPlatform, CL_PLATFORM_NAME, sizeof(name), &name, NULL);
|
||||
platform_name = name;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(total_devices == 0) {
|
||||
vector<OpenCLPlatformDevice> usable_devices;
|
||||
opencl_get_usable_devices(&usable_devices);
|
||||
if(usable_devices.size() == 0) {
|
||||
opencl_error("OpenCL: no devices found.");
|
||||
return;
|
||||
}
|
||||
else if(!cdDevice) {
|
||||
opencl_error("OpenCL: specified device not found.");
|
||||
return;
|
||||
}
|
||||
assert(info.num < usable_devices.size());
|
||||
OpenCLPlatformDevice& platform_device = usable_devices[info.num];
|
||||
cpPlatform = platform_device.platform_id;
|
||||
cdDevice = platform_device.device_id;
|
||||
char name[256];
|
||||
clGetPlatformInfo(cpPlatform, CL_PLATFORM_NAME, sizeof(name), &name, NULL);
|
||||
platform_name = name;
|
||||
|
||||
{
|
||||
/* try to use cached context */
|
||||
@@ -536,34 +663,15 @@ public:
|
||||
|
||||
bool opencl_version_check()
|
||||
{
|
||||
char version[256];
|
||||
|
||||
int major, minor, req_major = 1, req_minor = 1;
|
||||
|
||||
clGetPlatformInfo(cpPlatform, CL_PLATFORM_VERSION, sizeof(version), &version, NULL);
|
||||
|
||||
if(sscanf(version, "OpenCL %d.%d", &major, &minor) < 2) {
|
||||
opencl_error(string_printf("OpenCL: failed to parse platform version string (%s).", version));
|
||||
string error;
|
||||
if(!opencl_platform_version_check(cpPlatform, &error)) {
|
||||
opencl_error(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||
opencl_error(string_printf("OpenCL: platform version 1.1 or later required, found %d.%d", major, minor));
|
||||
if(!opencl_device_version_check(cdDevice, &error)) {
|
||||
opencl_error(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
clGetDeviceInfo(cdDevice, CL_DEVICE_OPENCL_C_VERSION, sizeof(version), &version, NULL);
|
||||
|
||||
if(sscanf(version, "OpenCL C %d.%d", &major, &minor) < 2) {
|
||||
opencl_error(string_printf("OpenCL: failed to parse OpenCL C version string (%s).", version));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!((major == req_major && minor >= req_minor) || (major > req_major))) {
|
||||
opencl_error(string_printf("OpenCL: C version 1.1 or later required, found %d.%d", major, minor));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3225,125 +3333,38 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
/* Returns true in case of successful detection of platform and device type,
|
||||
* else returns false.
|
||||
*/
|
||||
static bool get_platform_and_devicetype(const DeviceInfo info,
|
||||
string &platform_name,
|
||||
cl_device_type &device_type)
|
||||
{
|
||||
cl_platform_id platform_id;
|
||||
cl_device_id device_id;
|
||||
cl_uint num_platforms;
|
||||
cl_int ciErr;
|
||||
|
||||
/* TODO(sergey): Use some generic error print helper function/ */
|
||||
ciErr = clGetPlatformIDs(0, NULL, &num_platforms);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getPlatformIds. file - %s, line - %d\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(num_platforms == 0) {
|
||||
fprintf(stderr, "No OpenCL platforms found. file - %s, line - %d\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<cl_platform_id> platforms(num_platforms, NULL);
|
||||
|
||||
ciErr = clGetPlatformIDs(num_platforms, &platforms[0], NULL);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getPlatformIds. file - %s, line - %d\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
int num_base = 0;
|
||||
int total_devices = 0;
|
||||
|
||||
for(int platform = 0; platform < num_platforms; platform++) {
|
||||
cl_uint num_devices;
|
||||
|
||||
ciErr = clGetDeviceIDs(platforms[platform], opencl_device_type(), 0, NULL, &num_devices);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getDeviceIDs. file - %s, line - %d\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
total_devices += num_devices;
|
||||
|
||||
if(info.num - num_base >= num_devices) {
|
||||
/* num doesn't refer to a device in this platform */
|
||||
num_base += num_devices;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* device is in this platform */
|
||||
platform_id = platforms[platform];
|
||||
|
||||
/* get devices */
|
||||
vector<cl_device_id> device_ids(num_devices, NULL);
|
||||
|
||||
ciErr = clGetDeviceIDs(platform_id, opencl_device_type(), num_devices, &device_ids[0], NULL);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getDeviceIDs. file - %s, line - %d\n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
device_id = device_ids[info.num - num_base];
|
||||
|
||||
char name[256];
|
||||
ciErr = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME, sizeof(name), &name, NULL);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getPlatformIDs. file - %s, line - %d \n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
platform_name = name;
|
||||
|
||||
ciErr = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, NULL);
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
fprintf(stderr, "Can't getDeviceInfo. file - %s, line - %d \n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(total_devices == 0) {
|
||||
fprintf(stderr, "No devices found. file - %s, line - %d \n", __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Device *device_opencl_create(DeviceInfo& info, Stats &stats, bool background)
|
||||
{
|
||||
string platform_name;
|
||||
vector<OpenCLPlatformDevice> usable_devices;
|
||||
opencl_get_usable_devices(&usable_devices);
|
||||
assert(info.num < usable_devices.size());
|
||||
OpenCLPlatformDevice& platform_device = usable_devices[info.num];
|
||||
char name[256];
|
||||
if(clGetPlatformInfo(platform_device.platform_id,
|
||||
CL_PLATFORM_NAME,
|
||||
sizeof(name),
|
||||
&name,
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
VLOG(1) << "Failed to retrieve platform name, using mega kernel.";
|
||||
return new OpenCLDeviceMegaKernel(info, stats, background);
|
||||
}
|
||||
string platform_name = name;
|
||||
cl_device_type device_type;
|
||||
if(get_platform_and_devicetype(info, platform_name, device_type)) {
|
||||
const bool force_split_kernel =
|
||||
getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST") != NULL;
|
||||
/* TODO(sergey): Replace string lookups with more enum-like API,
|
||||
* similar to device/vendor checks blender's gpu.
|
||||
*/
|
||||
if(force_split_kernel ||
|
||||
(platform_name == "AMD Accelerated Parallel Processing" &&
|
||||
device_type == CL_DEVICE_TYPE_GPU))
|
||||
{
|
||||
/* If the device is an AMD GPU, take split kernel path. */
|
||||
VLOG(1) << "Using split kernel";
|
||||
info.use_split_kernel = true;
|
||||
return new OpenCLDeviceSplitKernel(info, stats, background);
|
||||
} else {
|
||||
/* For any other device, take megakernel path. */
|
||||
VLOG(1) << "Using mega kernel";
|
||||
return new OpenCLDeviceMegaKernel(info, stats, background);
|
||||
}
|
||||
if(clGetDeviceInfo(platform_device.device_id,
|
||||
CL_DEVICE_TYPE,
|
||||
sizeof(cl_device_type),
|
||||
&device_type,
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
VLOG(1) << "Failed to retrieve device type, using mega kernel,";
|
||||
return new OpenCLDeviceMegaKernel(info, stats, background);
|
||||
}
|
||||
if(opencl_kernel_use_split(platform_name, device_type)) {
|
||||
VLOG(1) << "Using split kernel.";
|
||||
return new OpenCLDeviceSplitKernel(info, stats, background);
|
||||
} else {
|
||||
/* If we can't retrieve platform and device type information for some
|
||||
* reason, we default to megakernel path.
|
||||
*/
|
||||
VLOG(1) << "Failed to retrieve platform or device, using mega kernel";
|
||||
VLOG(1) << "Using mega kernel.";
|
||||
return new OpenCLDeviceMegaKernel(info, stats, background);
|
||||
}
|
||||
}
|
||||
@@ -3365,73 +3386,56 @@ bool device_opencl_init(void)
|
||||
|
||||
void device_opencl_info(vector<DeviceInfo>& devices)
|
||||
{
|
||||
vector<cl_device_id> device_ids;
|
||||
cl_uint num_devices = 0;
|
||||
vector<cl_platform_id> platform_ids;
|
||||
cl_uint num_platforms = 0;
|
||||
|
||||
/* get devices */
|
||||
if(clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS || num_platforms == 0)
|
||||
return;
|
||||
|
||||
platform_ids.resize(num_platforms);
|
||||
|
||||
if(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL) != CL_SUCCESS)
|
||||
return;
|
||||
|
||||
/* devices are numbered consecutively across platforms */
|
||||
int num_base = 0;
|
||||
|
||||
const bool force_all_platforms =
|
||||
(getenv("CYCLES_OPENCL_TEST") != NULL) ||
|
||||
(getenv("CYCLES_OPENCL_SPLIT_KERNEL_TEST")) != NULL;
|
||||
|
||||
for(int platform = 0; platform < num_platforms; platform++, num_base += num_devices) {
|
||||
num_devices = 0;
|
||||
if(clGetDeviceIDs(platform_ids[platform], opencl_device_type(), 0, NULL, &num_devices) != CL_SUCCESS || num_devices == 0)
|
||||
vector<OpenCLPlatformDevice> usable_devices;
|
||||
opencl_get_usable_devices(&usable_devices);
|
||||
/* Devices are numbered consecutively across platforms. */
|
||||
int num_devices = 0;
|
||||
foreach(OpenCLPlatformDevice& platform_device, usable_devices) {
|
||||
cl_platform_id platform_id = platform_device.platform_id;
|
||||
cl_device_id device_id = platform_device.device_id;
|
||||
/* We always increment the device number, so there;s 1:1 mapping from
|
||||
* info.num to indexinside usable_devices vector.
|
||||
*/
|
||||
++num_devices;
|
||||
char platform_name[256];
|
||||
if(clGetPlatformInfo(platform_id,
|
||||
CL_PLATFORM_NAME,
|
||||
sizeof(platform_name),
|
||||
&platform_name,
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
|
||||
device_ids.resize(num_devices);
|
||||
|
||||
if(clGetDeviceIDs(platform_ids[platform], opencl_device_type(), num_devices, &device_ids[0], NULL) != CL_SUCCESS)
|
||||
continue;
|
||||
|
||||
char pname[256];
|
||||
clGetPlatformInfo(platform_ids[platform], CL_PLATFORM_NAME, sizeof(pname), &pname, NULL);
|
||||
string platform_name = pname;
|
||||
|
||||
/* add devices */
|
||||
for(int num = 0; num < num_devices; num++) {
|
||||
cl_device_id device_id = device_ids[num];
|
||||
char name[1024] = "\0";
|
||||
|
||||
cl_device_type device_type;
|
||||
clGetDeviceInfo(device_id, CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, NULL);
|
||||
|
||||
/* TODO(sergey): Make it an utility function to check whitelisted devices. */
|
||||
if(!(force_all_platforms ||
|
||||
(platform_name == "AMD Accelerated Parallel Processing" &&
|
||||
device_type == CL_DEVICE_TYPE_GPU)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if(clGetDeviceInfo(device_id, CL_DEVICE_NAME, sizeof(name), &name, NULL) != CL_SUCCESS)
|
||||
continue;
|
||||
|
||||
DeviceInfo info;
|
||||
|
||||
info.type = DEVICE_OPENCL;
|
||||
info.description = string_remove_trademark(string(name));
|
||||
info.num = num_base + num;
|
||||
info.id = string_printf("OPENCL_%d", info.num);
|
||||
/* we don't know if it's used for display, but assume it is */
|
||||
info.display_device = true;
|
||||
info.advanced_shading = opencl_kernel_use_advanced_shading(platform_name);
|
||||
info.pack_images = true;
|
||||
|
||||
devices.push_back(info);
|
||||
}
|
||||
char device_name[1024] = "\0";
|
||||
if(clGetDeviceInfo(device_id,
|
||||
CL_DEVICE_NAME,
|
||||
sizeof(device_name),
|
||||
&device_name,
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cl_device_type device_type;
|
||||
if(clGetDeviceInfo(device_id,
|
||||
CL_DEVICE_TYPE,
|
||||
sizeof(cl_device_type),
|
||||
&device_type,
|
||||
NULL) != CL_SUCCESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DeviceInfo info;
|
||||
info.type = DEVICE_OPENCL;
|
||||
info.description = string_remove_trademark(string(device_name));
|
||||
info.num = num_devices - 1;
|
||||
info.id = string_printf("OPENCL_%d", info.num);
|
||||
/* We don't know if it's used for display, but assume it is. */
|
||||
info.display_device = true;
|
||||
info.advanced_shading = opencl_kernel_use_advanced_shading(platform_name);
|
||||
info.pack_images = true;
|
||||
info.use_split_kernel = opencl_kernel_use_split(platform_name,
|
||||
device_type);
|
||||
devices.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3446,7 +3450,7 @@ string device_opencl_capabilities(void)
|
||||
if(num_platforms == 0) {
|
||||
return "No OpenCL platforms found\n";
|
||||
}
|
||||
result += string_printf("Number of platforms: %d\n", num_platforms);
|
||||
result += string_printf("Number of platforms: %u\n", num_platforms);
|
||||
|
||||
vector<cl_platform_id> platform_ids;
|
||||
platform_ids.resize(num_platforms);
|
||||
@@ -3467,7 +3471,7 @@ string device_opencl_capabilities(void)
|
||||
for (cl_uint platform = 0; platform < num_platforms; ++platform) {
|
||||
cl_platform_id platform_id = platform_ids[platform];
|
||||
|
||||
result += string_printf("Platform #%d\n", platform);
|
||||
result += string_printf("Platform #%u\n", platform);
|
||||
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Name", CL_PLATFORM_NAME);
|
||||
APPEND_PLATFORM_STRING_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR);
|
||||
@@ -3481,7 +3485,7 @@ string device_opencl_capabilities(void)
|
||||
0,
|
||||
NULL,
|
||||
&num_devices));
|
||||
result += string_printf("\tNumber of devices: %d\n", num_devices);
|
||||
result += string_printf("\tNumber of devices: %u\n", num_devices);
|
||||
|
||||
device_ids.resize(num_devices);
|
||||
opencl_assert(clGetDeviceIDs(platform_ids[platform],
|
||||
@@ -3492,7 +3496,7 @@ string device_opencl_capabilities(void)
|
||||
for (cl_uint device = 0; device < num_devices; ++device) {
|
||||
cl_device_id device_id = device_ids[device];
|
||||
|
||||
result += string_printf("\t\tDevice: #%d\n", device);
|
||||
result += string_printf("\t\tDevice: #%u\n", device);
|
||||
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Name", CL_DEVICE_NAME);
|
||||
APPEND_DEVICE_STRING_INFO(device_id, "Vendor", CL_DEVICE_VENDOR);
|
||||
|
@@ -47,6 +47,7 @@ set(SRC_HEADERS
|
||||
kernel_montecarlo.h
|
||||
kernel_passes.h
|
||||
kernel_path.h
|
||||
kernel_path_branched.h
|
||||
kernel_path_common.h
|
||||
kernel_path_state.h
|
||||
kernel_path_surface.h
|
||||
@@ -124,7 +125,6 @@ set(SRC_SVM_HEADERS
|
||||
svm/svm_value.h
|
||||
svm/svm_vector_transform.h
|
||||
svm/svm_voronoi.h
|
||||
svm/svm_voxel.h
|
||||
svm/svm_wave.h
|
||||
)
|
||||
|
||||
|
@@ -107,18 +107,9 @@ ccl_device int volume_absorption_setup(ShaderClosure *sc)
|
||||
|
||||
ccl_device float3 volume_phase_eval(const ShaderData *sd, const ShaderClosure *sc, float3 omega_in, float *pdf)
|
||||
{
|
||||
float3 eval;
|
||||
kernel_assert(sc->type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID);
|
||||
|
||||
switch(sc->type) {
|
||||
case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
|
||||
eval = volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
|
||||
break;
|
||||
default:
|
||||
eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
return eval;
|
||||
return volume_henyey_greenstein_eval_phase(sc, sd->I, omega_in, pdf);
|
||||
}
|
||||
|
||||
ccl_device int volume_phase_sample(const ShaderData *sd, const ShaderClosure *sc, float randu,
|
||||
|
@@ -76,6 +76,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
||||
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
isect->num_traversal_steps = 0;
|
||||
isect->num_traversed_instances = 0;
|
||||
#endif
|
||||
|
||||
#if defined(__KERNEL_SSE2__)
|
||||
@@ -362,6 +363,10 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg,
|
||||
traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
|
||||
|
||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
||||
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
isect->num_traversed_instances++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* FEATURE(BVH_INSTANCING) */
|
||||
|
@@ -80,6 +80,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
||||
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
isect->num_traversal_steps = 0;
|
||||
isect->num_traversed_instances = 0;
|
||||
#endif
|
||||
|
||||
ssef tnear(0.0f), tfar(ray->t);
|
||||
@@ -185,6 +186,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
||||
if(traverseChild == 0) {
|
||||
if(d1 < d0) {
|
||||
nodeAddr = c1;
|
||||
nodeDist = d1;
|
||||
++stackPtr;
|
||||
kernel_assert(stackPtr < BVH_QSTACK_SIZE);
|
||||
traversalStack[stackPtr].addr = c0;
|
||||
@@ -193,6 +195,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
||||
}
|
||||
else {
|
||||
nodeAddr = c0;
|
||||
nodeDist = d0;
|
||||
++stackPtr;
|
||||
kernel_assert(stackPtr < BVH_QSTACK_SIZE);
|
||||
traversalStack[stackPtr].addr = c1;
|
||||
@@ -377,6 +380,10 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
||||
traversalStack[stackPtr].dist = -FLT_MAX;
|
||||
|
||||
nodeAddr = kernel_tex_fetch(__object_node, object);
|
||||
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
isect->num_traversed_instances++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif /* FEATURE(BVH_INSTANCING) */
|
||||
|
@@ -95,10 +95,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg,
|
||||
do {
|
||||
/* Traverse internal nodes. */
|
||||
while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
isect->num_traversal_steps++;
|
||||
#endif
|
||||
|
||||
ssef dist;
|
||||
int traverseChild = qbvh_node_intersect(kg,
|
||||
tnear,
|
||||
|
@@ -49,16 +49,25 @@ typedef struct IsectPrecalc {
|
||||
float Sx, Sy, Sz;
|
||||
} IsectPrecalc;
|
||||
|
||||
/* Workaround for CUDA toolkit 6.5.16. */
|
||||
#if defined(__KERNEL_CPU__) || !defined(__KERNEL_EXPERIMENTAL__) || __CUDA_ARCH__ < 500
|
||||
#if defined(__KERNEL_CUDA__)
|
||||
# if (defined(i386) || defined(_M_IX86))
|
||||
# if __CUDA_ARCH__ > 500
|
||||
ccl_device_noinline
|
||||
# else
|
||||
# else /* __CUDA_ARCH__ > 500 */
|
||||
ccl_device_inline
|
||||
# endif
|
||||
#else
|
||||
# endif /* __CUDA_ARCH__ > 500 */
|
||||
# else /* (defined(i386) || defined(_M_IX86)) */
|
||||
# if defined(__KERNEL_EXPERIMENTAL__) && (__CUDA_ARCH__ >= 500)
|
||||
ccl_device_noinline
|
||||
#endif
|
||||
# else
|
||||
ccl_device_inline
|
||||
# endif
|
||||
# endif /* (defined(i386) || defined(_M_IX86)) */
|
||||
#elif defined(__KERNEL_OPENCL_APPLE__)
|
||||
ccl_device_noinline
|
||||
#else /* defined(__KERNEL_OPENCL_APPLE__) */
|
||||
ccl_device_inline
|
||||
#endif /* defined(__KERNEL_OPENCL_APPLE__) */
|
||||
void triangle_intersect_precalc(float3 dir,
|
||||
IsectPrecalc *isect_precalc)
|
||||
{
|
||||
@@ -110,19 +119,9 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg,
|
||||
const float Sz = isect_precalc->Sz;
|
||||
|
||||
/* Calculate vertices relative to ray origin. */
|
||||
float4 tri_a, tri_b, tri_c;
|
||||
if (kernel_data.bvh.use_tri_storage) {
|
||||
tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
|
||||
tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
|
||||
tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
}
|
||||
else {
|
||||
const int prim = kernel_tex_fetch(__prim_index, triAddr);
|
||||
const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
|
||||
tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
|
||||
tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
|
||||
}
|
||||
const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
|
||||
tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
|
||||
tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
|
||||
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
|
||||
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
|
||||
@@ -213,19 +212,9 @@ ccl_device_inline void triangle_intersect_subsurface(
|
||||
const float Sz = isect_precalc->Sz;
|
||||
|
||||
/* Calculate vertices relative to ray origin. */
|
||||
float4 tri_a, tri_b, tri_c;
|
||||
if (kernel_data.bvh.use_tri_storage) {
|
||||
tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
|
||||
tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
|
||||
tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
}
|
||||
else {
|
||||
const int prim = kernel_tex_fetch(__prim_index, triAddr);
|
||||
const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
|
||||
tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
|
||||
tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
|
||||
}
|
||||
const float4 tri_a = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0),
|
||||
tri_b = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1),
|
||||
tri_c = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
|
||||
const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z);
|
||||
const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z);
|
||||
const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z);
|
||||
@@ -338,19 +327,9 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
|
||||
|
||||
P = P + D*t;
|
||||
|
||||
float4 tri_a, tri_b, tri_c;
|
||||
if (kernel_data.bvh.use_tri_storage) {
|
||||
tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
|
||||
tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
|
||||
tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
|
||||
}
|
||||
else {
|
||||
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
|
||||
tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
|
||||
tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
|
||||
}
|
||||
const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
|
||||
tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
|
||||
tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
|
||||
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
|
||||
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
|
||||
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
|
||||
@@ -405,19 +384,9 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
|
||||
|
||||
P = P + D*t;
|
||||
|
||||
float4 tri_a, tri_b, tri_c;
|
||||
if (kernel_data.bvh.use_tri_storage) {
|
||||
tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
|
||||
tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1);
|
||||
tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
|
||||
}
|
||||
else {
|
||||
const int prim = kernel_tex_fetch(__prim_index, isect->prim);
|
||||
const float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
tri_a = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x));
|
||||
tri_b = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y));
|
||||
tri_c = kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z));
|
||||
}
|
||||
const float4 tri_a = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0),
|
||||
tri_b = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+1),
|
||||
tri_c = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+2);
|
||||
float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z);
|
||||
float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z);
|
||||
float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
|
||||
|
@@ -53,21 +53,17 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
|
||||
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
float4 r;
|
||||
int slot = id >> 1;
|
||||
if(sd->flag & SD_VOLUME_CUBIC)
|
||||
r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
else
|
||||
r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
|
||||
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
|
||||
#endif
|
||||
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
/* todo: support float textures to lower memory usage for single floats */
|
||||
if(id & 1)
|
||||
return r.w;
|
||||
else
|
||||
return average(float4_to_float3(r));
|
||||
return average(float4_to_float3(r));
|
||||
}
|
||||
|
||||
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
|
||||
@@ -77,20 +73,16 @@ ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *s
|
||||
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
float4 r;
|
||||
int slot = id >> 1;
|
||||
if(sd->flag & SD_VOLUME_CUBIC)
|
||||
r = kernel_tex_image_interp_3d_ex(slot, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
else
|
||||
r = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z);
|
||||
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
|
||||
#endif
|
||||
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
if(id & 1)
|
||||
return make_float3(r.w, r.w, r.w);
|
||||
else
|
||||
return float4_to_float3(r);
|
||||
return float4_to_float3(r);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -341,12 +341,12 @@ ccl_device_inline void path_radiance_reset_indirect(PathRadiance *L)
|
||||
|
||||
ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L)
|
||||
{
|
||||
float3 L_sum, L_direct, L_indirect;
|
||||
float clamp_direct = kernel_data.integrator.sample_clamp_direct;
|
||||
float clamp_indirect = kernel_data.integrator.sample_clamp_indirect;
|
||||
|
||||
float3 L_sum;
|
||||
/* Light Passes are used */
|
||||
#ifdef __PASSES__
|
||||
float3 L_direct, L_indirect;
|
||||
float clamp_direct = kernel_data.integrator.sample_clamp_direct;
|
||||
float clamp_indirect = kernel_data.integrator.sample_clamp_indirect;
|
||||
if(L->use_light_pass) {
|
||||
path_radiance_sum_indirect(L);
|
||||
|
||||
|
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
#if defined(__GNUC__) && defined(NDEBUG)
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
# pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#endif
|
||||
|
||||
/* Selective nodes compilation. */
|
||||
|
@@ -19,6 +19,8 @@ CCL_NAMESPACE_BEGIN
|
||||
ccl_device_inline void debug_data_init(DebugData *debug_data)
|
||||
{
|
||||
debug_data->num_bvh_traversal_steps = 0;
|
||||
debug_data->num_bvh_traversed_instances = 0;
|
||||
debug_data->num_ray_bounces = 0;
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
|
||||
@@ -33,6 +35,16 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
|
||||
sample,
|
||||
debug_data->num_bvh_traversal_steps);
|
||||
}
|
||||
if(flag & PASS_BVH_TRAVERSED_INSTANCES) {
|
||||
kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_instances,
|
||||
sample,
|
||||
debug_data->num_bvh_traversed_instances);
|
||||
}
|
||||
if(flag & PASS_RAY_BOUNCES) {
|
||||
kernel_write_pass_float(buffer + kernel_data.film.pass_ray_bounces,
|
||||
sample,
|
||||
debug_data->num_ray_bounces);
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -324,43 +324,6 @@ ccl_device void kernel_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
|
||||
{
|
||||
int num_samples = kernel_data.integrator.ao_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
|
||||
float3 ao_alpha = shader_bsdf_alpha(kg, sd);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng));
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = ccl_fetch(sd, time);
|
||||
#endif
|
||||
light_ray.dP = ccl_fetch(sd, dP);
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
|
||||
ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, Ray *ray, float3 *throughput)
|
||||
@@ -476,7 +439,9 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
if(state.flag & PATH_RAY_CAMERA) {
|
||||
debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
|
||||
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
|
||||
}
|
||||
debug_data.num_ray_bounces++;
|
||||
#endif
|
||||
|
||||
#ifdef __LAMP_MIS__
|
||||
@@ -706,444 +671,6 @@ ccl_device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample,
|
||||
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
|
||||
}
|
||||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
|
||||
/* branched path tracing: bounce off surface and integrate indirect light */
|
||||
ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg,
|
||||
RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust,
|
||||
PathState *state, PathRadiance *L)
|
||||
{
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
const ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
|
||||
|
||||
if(!CLOSURE_IS_BSDF(sc->type))
|
||||
continue;
|
||||
/* transparency is not handled here, but in outer loop */
|
||||
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
continue;
|
||||
|
||||
int num_samples;
|
||||
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
|
||||
num_samples = kernel_data.integrator.diffuse_samples;
|
||||
else if(CLOSURE_IS_BSDF_BSSRDF(sc->type))
|
||||
num_samples = 1;
|
||||
else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
num_samples = kernel_data.integrator.glossy_samples;
|
||||
else
|
||||
num_samples = kernel_data.integrator.transmission_samples;
|
||||
|
||||
num_samples = ceil_to_int(num_samples_adjust*num_samples);
|
||||
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
RNG bsdf_rng = cmj_hash(*rng, i);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
PathState ps = *state;
|
||||
float3 tp = throughput;
|
||||
Ray bsdf_ray;
|
||||
|
||||
if(!kernel_branched_path_surface_bounce(kg, &bsdf_rng, sd, sc, j, num_samples, &tp, &ps, L, &bsdf_ray))
|
||||
continue;
|
||||
|
||||
kernel_path_indirect(kg, rng, bsdf_ray, tp*num_samples_inv, num_samples, ps, L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(L);
|
||||
path_radiance_reset_indirect(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
PathRadiance *L,
|
||||
PathState *state,
|
||||
RNG *rng,
|
||||
Ray *ray,
|
||||
float3 throughput)
|
||||
{
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
|
||||
|
||||
if(!CLOSURE_IS_BSSRDF(sc->type))
|
||||
continue;
|
||||
|
||||
/* set up random number generator */
|
||||
uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb);
|
||||
int num_samples = kernel_data.integrator.subsurface_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
RNG bssrdf_rng = cmj_hash(*rng, i);
|
||||
|
||||
/* do subsurface scatter step with copy of shader data, this will
|
||||
* replace the BSSRDF with a diffuse BSDF closure */
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_branched_rng_2D(kg, &bssrdf_rng, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, true);
|
||||
#ifdef __VOLUME__
|
||||
Ray volume_ray = *ray;
|
||||
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
|
||||
ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
|
||||
#endif
|
||||
|
||||
/* compute lighting with the BSDF closure */
|
||||
for(int hit = 0; hit < num_hits; hit++) {
|
||||
PathState hit_state = *state;
|
||||
|
||||
path_state_branch(&hit_state, j, num_samples);
|
||||
|
||||
#ifdef __VOLUME__
|
||||
if(need_update_volume_stack) {
|
||||
/* Setup ray from previous surface point to the new one. */
|
||||
float3 P = ray_offset(bssrdf_sd[hit].P, -bssrdf_sd[hit].Ng);
|
||||
volume_ray.D = normalize_len(P - volume_ray.P,
|
||||
&volume_ray.t);
|
||||
|
||||
kernel_volume_stack_update_for_subsurface(
|
||||
kg,
|
||||
&volume_ray,
|
||||
hit_state.volume_stack);
|
||||
|
||||
/* Move volume ray forward. */
|
||||
volume_ray.P = P;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__EMISSION__) && defined(__BRANCHED_PATH__)
|
||||
/* direct light */
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
kernel_branched_path_surface_connect_light(kg, rng,
|
||||
&bssrdf_sd[hit], &hit_state, throughput, num_samples_inv, L, all);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* indirect light */
|
||||
kernel_branched_path_surface_indirect_light(kg, rng,
|
||||
&bssrdf_sd[hit], throughput, num_samples_inv,
|
||||
&hit_state, L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer)
|
||||
{
|
||||
/* initialize */
|
||||
PathRadiance L;
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float L_transparent = 0.0f;
|
||||
|
||||
path_radiance_init(&L, kernel_data.film.use_light_pass);
|
||||
|
||||
PathState state;
|
||||
path_state_init(kg, &state, rng, sample, &ray);
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
DebugData debug_data;
|
||||
debug_data_init(&debug_data);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f, extmax = 0.0f;
|
||||
uint lcg_state = 0;
|
||||
|
||||
if(kernel_data.bvh.have_curves) {
|
||||
if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) {
|
||||
float3 pixdiff = ray.dD.dx + ray.dD.dy;
|
||||
/*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
|
||||
difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
|
||||
extmax = kernel_data.curve.maximum_width;
|
||||
lcg_state = lcg_state_init(rng, &state, 0x51633e2d);
|
||||
}
|
||||
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
if(state.flag & PATH_RAY_CAMERA) {
|
||||
debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* volume attenuation, emission, scatter */
|
||||
if(state.volume_stack[0].shader != SHADER_NONE) {
|
||||
Ray volume_ray = ray;
|
||||
volume_ray.t = (hit)? isect.t: FLT_MAX;
|
||||
|
||||
bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
|
||||
|
||||
#ifdef __VOLUME_DECOUPLED__
|
||||
/* decoupled ray marching only supported on CPU */
|
||||
|
||||
/* cache steps along volume for repeated sampling */
|
||||
VolumeSegment volume_segment;
|
||||
ShaderData volume_sd;
|
||||
|
||||
shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
|
||||
kernel_volume_decoupled_record(kg, &state,
|
||||
&volume_ray, &volume_sd, &volume_segment, heterogeneous);
|
||||
|
||||
/* direct light sampling */
|
||||
if(volume_segment.closure_flag & SD_SCATTER) {
|
||||
volume_segment.sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
|
||||
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
|
||||
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
|
||||
throughput, &state, &L, all, &volume_ray, &volume_segment);
|
||||
|
||||
/* indirect light sampling */
|
||||
int num_samples = kernel_data.integrator.volume_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
/* workaround to fix correlation bug in T38710, can find better solution
|
||||
* in random number generator later, for now this is done here to not impact
|
||||
* performance of rendering without volumes */
|
||||
RNG tmp_rng = cmj_hash(*rng, state.rng_offset);
|
||||
|
||||
PathState ps = state;
|
||||
Ray pray = ray;
|
||||
float3 tp = throughput;
|
||||
|
||||
/* branch RNG state */
|
||||
path_state_branch(&ps, j, num_samples);
|
||||
|
||||
/* scatter sample. if we use distance sampling and take just one
|
||||
* sample for direct and indirect light, we could share this
|
||||
* computation, but makes code a bit complex */
|
||||
float rphase = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_PHASE);
|
||||
float rscatter = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_SCATTER_DISTANCE);
|
||||
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
&ps, &pray, &volume_sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
|
||||
kernel_path_indirect(kg, rng, pray, tp*num_samples_inv, num_samples, ps, &L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(&L);
|
||||
path_radiance_reset_indirect(&L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* emission and transmittance */
|
||||
if(volume_segment.closure_flag & SD_EMISSION)
|
||||
path_radiance_accum_emission(&L, throughput, volume_segment.accum_emission, state.bounce);
|
||||
throughput *= volume_segment.accum_transmittance;
|
||||
|
||||
/* free cached steps */
|
||||
kernel_volume_decoupled_free(kg, &volume_segment);
|
||||
#else
|
||||
/* GPU: no decoupled ray marching, scatter probalistically */
|
||||
int num_samples = kernel_data.integrator.volume_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
|
||||
/* todo: we should cache the shader evaluations from stepping
|
||||
* through the volume, for now we redo them multiple times */
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
PathState ps = state;
|
||||
Ray pray = ray;
|
||||
ShaderData volume_sd;
|
||||
float3 tp = throughput * num_samples_inv;
|
||||
|
||||
/* branch RNG state */
|
||||
path_state_branch(&ps, j, num_samples);
|
||||
|
||||
VolumeIntegrateResult result = kernel_volume_integrate(
|
||||
kg, &ps, &volume_sd, &volume_ray, &L, &tp, rng, heterogeneous);
|
||||
|
||||
#ifdef __VOLUME_SCATTER__
|
||||
if(result == VOLUME_PATH_SCATTERED) {
|
||||
/* todo: support equiangular, MIS and all light sampling.
|
||||
* alternatively get decoupled ray marching working on the GPU */
|
||||
kernel_path_volume_connect_light(kg, rng, &volume_sd, tp, &state, &L);
|
||||
|
||||
if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
|
||||
kernel_path_indirect(kg, rng, pray, tp, num_samples, ps, &L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(&L);
|
||||
path_radiance_reset_indirect(&L);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* todo: avoid this calculation using decoupled ray marching */
|
||||
kernel_volume_shadow(kg, &state, &volume_ray, &throughput);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!hit) {
|
||||
/* eval background shader if nothing hit */
|
||||
if(kernel_data.background.transparent) {
|
||||
L_transparent += average(throughput);
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &state, &ray);
|
||||
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce);
|
||||
shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_merge_closures(&sd);
|
||||
|
||||
/* holdout */
|
||||
#ifdef __HOLDOUT__
|
||||
if(sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) {
|
||||
if(kernel_data.background.transparent) {
|
||||
float3 holdout_weight;
|
||||
|
||||
if(sd.flag & SD_HOLDOUT_MASK)
|
||||
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
|
||||
else
|
||||
holdout_weight = shader_holdout_eval(kg, &sd);
|
||||
|
||||
/* any throughput is ok, should all be identical here */
|
||||
L_transparent += average(holdout_weight*throughput);
|
||||
}
|
||||
|
||||
if(sd.flag & SD_HOLDOUT_MASK)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* holdout mask objects do not write data passes */
|
||||
kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput);
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd.flag & SD_EMISSION) {
|
||||
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
|
||||
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* transparency termination */
|
||||
if(state.flag & PATH_RAY_TRANSPARENT) {
|
||||
/* path termination. this is a strange place to put the termination, it's
|
||||
* mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||
* shader evaluations, only need emission if we are going to terminate */
|
||||
float probability = path_state_terminate_probability(kg, &state, throughput);
|
||||
|
||||
if(probability == 0.0f) {
|
||||
break;
|
||||
}
|
||||
else if(probability != 1.0f) {
|
||||
float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE);
|
||||
|
||||
if(terminate >= probability)
|
||||
break;
|
||||
|
||||
throughput /= probability;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
kernel_branched_path_ao(kg, &sd, &L, &state, rng, throughput);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
kernel_branched_path_subsurface_scatter(kg, &sd, &L, &state,
|
||||
rng, &ray, throughput);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
|
||||
PathState hit_state = state;
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* direct light */
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
kernel_branched_path_surface_connect_light(kg, rng,
|
||||
&sd, &hit_state, throughput, 1.0f, &L, all);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* indirect light */
|
||||
kernel_branched_path_surface_indirect_light(kg, rng,
|
||||
&sd, throughput, 1.0f, &hit_state, &L);
|
||||
|
||||
/* continue in case of transparency */
|
||||
throughput *= shader_bsdf_transparency(kg, &sd);
|
||||
|
||||
if(is_zero(throughput))
|
||||
break;
|
||||
}
|
||||
|
||||
path_state_next(kg, &state, LABEL_TRANSPARENT);
|
||||
ray.P = ray_offset(sd.P, -sd.Ng);
|
||||
ray.t -= sd.ray_length; /* clipping works through transparent */
|
||||
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD.dx = -sd.dI.dx;
|
||||
ray.dD.dy = -sd.dI.dy;
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* enter/exit volume */
|
||||
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
|
||||
|
||||
kernel_write_light_passes(kg, buffer, &L, sample);
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample);
|
||||
#endif
|
||||
|
||||
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ccl_device void kernel_path_trace(KernelGlobals *kg,
|
||||
ccl_global float *buffer, ccl_global uint *rng_state,
|
||||
int sample, int x, int y, int offset, int stride)
|
||||
@@ -1175,38 +702,5 @@ ccl_device void kernel_path_trace(KernelGlobals *kg,
|
||||
path_rng_end(kg, rng_state, rng);
|
||||
}
|
||||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
|
||||
ccl_global float *buffer, ccl_global uint *rng_state,
|
||||
int sample, int x, int y, int offset, int stride)
|
||||
{
|
||||
/* buffer offset */
|
||||
int index = offset + x + y*stride;
|
||||
int pass_stride = kernel_data.film.pass_stride;
|
||||
|
||||
rng_state += index;
|
||||
buffer += index*pass_stride;
|
||||
|
||||
/* initialize random numbers and ray */
|
||||
RNG rng;
|
||||
Ray ray;
|
||||
|
||||
kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray);
|
||||
|
||||
/* integrate */
|
||||
float4 L;
|
||||
|
||||
if(ray.t != 0.0f)
|
||||
L = kernel_branched_path_integrate(kg, &rng, sample, ray, buffer);
|
||||
else
|
||||
L = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
/* accumulate result in output buffer */
|
||||
kernel_write_pass_float4(buffer, sample, L);
|
||||
|
||||
path_rng_end(kg, rng_state, rng);
|
||||
}
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
|
534
intern/cycles/kernel/kernel_path_branched.h
Normal file
534
intern/cycles/kernel/kernel_path_branched.h
Normal file
@@ -0,0 +1,534 @@
|
||||
/*
|
||||
* Copyright 2011-2013 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef __BRANCHED_PATH__
|
||||
|
||||
ccl_device void kernel_branched_path_ao(KernelGlobals *kg, ShaderData *sd, PathRadiance *L, PathState *state, RNG *rng, float3 throughput)
|
||||
{
|
||||
int num_samples = kernel_data.integrator.ao_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
float ao_factor = kernel_data.background.ao_factor;
|
||||
float3 ao_N;
|
||||
float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N);
|
||||
float3 ao_alpha = shader_bsdf_alpha(kg, sd);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
float bsdf_u, bsdf_v;
|
||||
path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_BSDF_U, &bsdf_u, &bsdf_v);
|
||||
|
||||
float3 ao_D;
|
||||
float ao_pdf;
|
||||
|
||||
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
|
||||
|
||||
if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) {
|
||||
Ray light_ray;
|
||||
float3 ao_shadow;
|
||||
|
||||
light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng));
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
#ifdef __OBJECT_MOTION__
|
||||
light_ray.time = ccl_fetch(sd, time);
|
||||
#endif
|
||||
light_ray.dP = ccl_fetch(sd, dP);
|
||||
light_ray.dD = differential3_zero();
|
||||
|
||||
if(!shadow_blocked(kg, state, &light_ray, &ao_shadow))
|
||||
path_radiance_accum_ao(L, throughput*num_samples_inv, ao_alpha, ao_bsdf, ao_shadow, state->bounce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* bounce off surface and integrate indirect light */
|
||||
ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGlobals *kg,
|
||||
RNG *rng, ShaderData *sd, float3 throughput, float num_samples_adjust,
|
||||
PathState *state, PathRadiance *L)
|
||||
{
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
const ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
|
||||
|
||||
if(!CLOSURE_IS_BSDF(sc->type))
|
||||
continue;
|
||||
/* transparency is not handled here, but in outer loop */
|
||||
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
|
||||
continue;
|
||||
|
||||
int num_samples;
|
||||
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
|
||||
num_samples = kernel_data.integrator.diffuse_samples;
|
||||
else if(CLOSURE_IS_BSDF_BSSRDF(sc->type))
|
||||
num_samples = 1;
|
||||
else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
num_samples = kernel_data.integrator.glossy_samples;
|
||||
else
|
||||
num_samples = kernel_data.integrator.transmission_samples;
|
||||
|
||||
num_samples = ceil_to_int(num_samples_adjust*num_samples);
|
||||
|
||||
float num_samples_inv = num_samples_adjust/num_samples;
|
||||
RNG bsdf_rng = cmj_hash(*rng, i);
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
PathState ps = *state;
|
||||
float3 tp = throughput;
|
||||
Ray bsdf_ray;
|
||||
|
||||
if(!kernel_branched_path_surface_bounce(kg, &bsdf_rng, sd, sc, j, num_samples, &tp, &ps, L, &bsdf_ray))
|
||||
continue;
|
||||
|
||||
kernel_path_indirect(kg, rng, bsdf_ray, tp*num_samples_inv, num_samples, ps, L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(L);
|
||||
path_radiance_reset_indirect(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
PathRadiance *L,
|
||||
PathState *state,
|
||||
RNG *rng,
|
||||
Ray *ray,
|
||||
float3 throughput)
|
||||
{
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = &ccl_fetch(sd, closure)[i];
|
||||
|
||||
if(!CLOSURE_IS_BSSRDF(sc->type))
|
||||
continue;
|
||||
|
||||
/* set up random number generator */
|
||||
uint lcg_state = lcg_state_init(rng, state, 0x68bc21eb);
|
||||
int num_samples = kernel_data.integrator.subsurface_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
RNG bssrdf_rng = cmj_hash(*rng, i);
|
||||
|
||||
/* do subsurface scatter step with copy of shader data, this will
|
||||
* replace the BSSRDF with a diffuse BSDF closure */
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
ShaderData bssrdf_sd[BSSRDF_MAX_HITS];
|
||||
float bssrdf_u, bssrdf_v;
|
||||
path_branched_rng_2D(kg, &bssrdf_rng, state, j, num_samples, PRNG_BSDF_U, &bssrdf_u, &bssrdf_v);
|
||||
int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, true);
|
||||
#ifdef __VOLUME__
|
||||
Ray volume_ray = *ray;
|
||||
bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
|
||||
ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME;
|
||||
#endif
|
||||
|
||||
/* compute lighting with the BSDF closure */
|
||||
for(int hit = 0; hit < num_hits; hit++) {
|
||||
PathState hit_state = *state;
|
||||
|
||||
path_state_branch(&hit_state, j, num_samples);
|
||||
|
||||
#ifdef __VOLUME__
|
||||
if(need_update_volume_stack) {
|
||||
/* Setup ray from previous surface point to the new one. */
|
||||
float3 P = ray_offset(bssrdf_sd[hit].P, -bssrdf_sd[hit].Ng);
|
||||
volume_ray.D = normalize_len(P - volume_ray.P,
|
||||
&volume_ray.t);
|
||||
|
||||
kernel_volume_stack_update_for_subsurface(
|
||||
kg,
|
||||
&volume_ray,
|
||||
hit_state.volume_stack);
|
||||
|
||||
/* Move volume ray forward. */
|
||||
volume_ray.P = P;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* direct light */
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
kernel_branched_path_surface_connect_light(kg, rng,
|
||||
&bssrdf_sd[hit], &hit_state, throughput, num_samples_inv, L, all);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* indirect light */
|
||||
kernel_branched_path_surface_indirect_light(kg, rng,
|
||||
&bssrdf_sd[hit], throughput, num_samples_inv,
|
||||
&hit_state, L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer)
|
||||
{
|
||||
/* initialize */
|
||||
PathRadiance L;
|
||||
float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
|
||||
float L_transparent = 0.0f;
|
||||
|
||||
path_radiance_init(&L, kernel_data.film.use_light_pass);
|
||||
|
||||
PathState state;
|
||||
path_state_init(kg, &state, rng, sample, &ray);
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
DebugData debug_data;
|
||||
debug_data_init(&debug_data);
|
||||
#endif
|
||||
|
||||
/* Main Loop
|
||||
* Here we only handle transparency intersections from the camera ray.
|
||||
* Indirect bounces are handled in kernel_branched_path_surface_indirect_light().
|
||||
*/
|
||||
for(;;) {
|
||||
/* intersect scene */
|
||||
Intersection isect;
|
||||
uint visibility = path_state_ray_visibility(kg, &state);
|
||||
|
||||
#ifdef __HAIR__
|
||||
float difl = 0.0f, extmax = 0.0f;
|
||||
uint lcg_state = 0;
|
||||
|
||||
if(kernel_data.bvh.have_curves) {
|
||||
if(kernel_data.cam.resolution == 1) {
|
||||
float3 pixdiff = ray.dD.dx + ray.dD.dy;
|
||||
/*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
|
||||
difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
|
||||
}
|
||||
|
||||
extmax = kernel_data.curve.maximum_width;
|
||||
lcg_state = lcg_state_init(rng, &state, 0x51633e2d);
|
||||
}
|
||||
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, &lcg_state, difl, extmax);
|
||||
#else
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect, NULL, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
debug_data.num_bvh_traversal_steps += isect.num_traversal_steps;
|
||||
debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
|
||||
debug_data.num_ray_bounces++;
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* volume attenuation, emission, scatter */
|
||||
if(state.volume_stack[0].shader != SHADER_NONE) {
|
||||
Ray volume_ray = ray;
|
||||
volume_ray.t = (hit)? isect.t: FLT_MAX;
|
||||
|
||||
bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
|
||||
|
||||
#ifdef __VOLUME_DECOUPLED__
|
||||
/* decoupled ray marching only supported on CPU */
|
||||
|
||||
/* cache steps along volume for repeated sampling */
|
||||
VolumeSegment volume_segment;
|
||||
ShaderData volume_sd;
|
||||
|
||||
shader_setup_from_volume(kg, &volume_sd, &volume_ray, state.bounce, state.transparent_bounce);
|
||||
kernel_volume_decoupled_record(kg, &state,
|
||||
&volume_ray, &volume_sd, &volume_segment, heterogeneous);
|
||||
|
||||
/* direct light sampling */
|
||||
if(volume_segment.closure_flag & SD_SCATTER) {
|
||||
volume_segment.sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
|
||||
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
|
||||
kernel_branched_path_volume_connect_light(kg, rng, &volume_sd,
|
||||
throughput, &state, &L, all, &volume_ray, &volume_segment);
|
||||
|
||||
/* indirect light sampling */
|
||||
int num_samples = kernel_data.integrator.volume_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
/* workaround to fix correlation bug in T38710, can find better solution
|
||||
* in random number generator later, for now this is done here to not impact
|
||||
* performance of rendering without volumes */
|
||||
RNG tmp_rng = cmj_hash(*rng, state.rng_offset);
|
||||
|
||||
PathState ps = state;
|
||||
Ray pray = ray;
|
||||
float3 tp = throughput;
|
||||
|
||||
/* branch RNG state */
|
||||
path_state_branch(&ps, j, num_samples);
|
||||
|
||||
/* scatter sample. if we use distance sampling and take just one
|
||||
* sample for direct and indirect light, we could share this
|
||||
* computation, but makes code a bit complex */
|
||||
float rphase = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_PHASE);
|
||||
float rscatter = path_state_rng_1D_for_decision(kg, &tmp_rng, &ps, PRNG_SCATTER_DISTANCE);
|
||||
|
||||
VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
|
||||
&ps, &pray, &volume_sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
|
||||
|
||||
(void)result;
|
||||
kernel_assert(result == VOLUME_PATH_SCATTERED);
|
||||
|
||||
if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
|
||||
kernel_path_indirect(kg, rng, pray, tp*num_samples_inv, num_samples, ps, &L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(&L);
|
||||
path_radiance_reset_indirect(&L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* emission and transmittance */
|
||||
if(volume_segment.closure_flag & SD_EMISSION)
|
||||
path_radiance_accum_emission(&L, throughput, volume_segment.accum_emission, state.bounce);
|
||||
throughput *= volume_segment.accum_transmittance;
|
||||
|
||||
/* free cached steps */
|
||||
kernel_volume_decoupled_free(kg, &volume_segment);
|
||||
#else
|
||||
/* GPU: no decoupled ray marching, scatter probalistically */
|
||||
int num_samples = kernel_data.integrator.volume_samples;
|
||||
float num_samples_inv = 1.0f/num_samples;
|
||||
|
||||
/* todo: we should cache the shader evaluations from stepping
|
||||
* through the volume, for now we redo them multiple times */
|
||||
|
||||
for(int j = 0; j < num_samples; j++) {
|
||||
PathState ps = state;
|
||||
Ray pray = ray;
|
||||
ShaderData volume_sd;
|
||||
float3 tp = throughput * num_samples_inv;
|
||||
|
||||
/* branch RNG state */
|
||||
path_state_branch(&ps, j, num_samples);
|
||||
|
||||
VolumeIntegrateResult result = kernel_volume_integrate(
|
||||
kg, &ps, &volume_sd, &volume_ray, &L, &tp, rng, heterogeneous);
|
||||
|
||||
#ifdef __VOLUME_SCATTER__
|
||||
if(result == VOLUME_PATH_SCATTERED) {
|
||||
/* todo: support equiangular, MIS and all light sampling.
|
||||
* alternatively get decoupled ray marching working on the GPU */
|
||||
kernel_path_volume_connect_light(kg, rng, &volume_sd, tp, &state, &L);
|
||||
|
||||
if(kernel_path_volume_bounce(kg, rng, &volume_sd, &tp, &ps, &L, &pray)) {
|
||||
kernel_path_indirect(kg, rng, pray, tp, num_samples, ps, &L);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
path_radiance_sum_indirect(&L);
|
||||
path_radiance_reset_indirect(&L);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* todo: avoid this calculation using decoupled ray marching */
|
||||
kernel_volume_shadow(kg, &state, &volume_ray, &throughput);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!hit) {
|
||||
/* eval background shader if nothing hit */
|
||||
if(kernel_data.background.transparent) {
|
||||
L_transparent += average(throughput);
|
||||
|
||||
#ifdef __PASSES__
|
||||
if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* sample background shader */
|
||||
float3 L_background = indirect_background(kg, &state, &ray);
|
||||
path_radiance_accum_background(&L, throughput, L_background, state.bounce);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup shading */
|
||||
ShaderData sd;
|
||||
shader_setup_from_ray(kg, &sd, &isect, &ray, state.bounce, state.transparent_bounce);
|
||||
shader_eval_surface(kg, &sd, 0.0f, state.flag, SHADER_CONTEXT_MAIN);
|
||||
shader_merge_closures(&sd);
|
||||
|
||||
/* holdout */
|
||||
#ifdef __HOLDOUT__
|
||||
if(sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) {
|
||||
if(kernel_data.background.transparent) {
|
||||
float3 holdout_weight;
|
||||
|
||||
if(sd.flag & SD_HOLDOUT_MASK)
|
||||
holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
|
||||
else
|
||||
holdout_weight = shader_holdout_eval(kg, &sd);
|
||||
|
||||
/* any throughput is ok, should all be identical here */
|
||||
L_transparent += average(holdout_weight*throughput);
|
||||
}
|
||||
|
||||
if(sd.flag & SD_HOLDOUT_MASK)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* holdout mask objects do not write data passes */
|
||||
kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput);
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* emission */
|
||||
if(sd.flag & SD_EMISSION) {
|
||||
float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
|
||||
path_radiance_accum_emission(&L, throughput, emission, state.bounce);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* transparency termination */
|
||||
if(state.flag & PATH_RAY_TRANSPARENT) {
|
||||
/* path termination. this is a strange place to put the termination, it's
|
||||
* mainly due to the mixed in MIS that we use. gives too many unneeded
|
||||
* shader evaluations, only need emission if we are going to terminate */
|
||||
float probability = path_state_terminate_probability(kg, &state, throughput);
|
||||
|
||||
if(probability == 0.0f) {
|
||||
break;
|
||||
}
|
||||
else if(probability != 1.0f) {
|
||||
float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE);
|
||||
|
||||
if(terminate >= probability)
|
||||
break;
|
||||
|
||||
throughput /= probability;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AO__
|
||||
/* ambient occlusion */
|
||||
if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
|
||||
kernel_branched_path_ao(kg, &sd, &L, &state, rng, throughput);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
/* bssrdf scatter to a different location on the same object */
|
||||
if(sd.flag & SD_BSSRDF) {
|
||||
kernel_branched_path_subsurface_scatter(kg, &sd, &L, &state,
|
||||
rng, &ray, throughput);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!(sd.flag & SD_HAS_ONLY_VOLUME)) {
|
||||
PathState hit_state = state;
|
||||
|
||||
#ifdef __EMISSION__
|
||||
/* direct light */
|
||||
if(kernel_data.integrator.use_direct_light) {
|
||||
bool all = kernel_data.integrator.sample_all_lights_direct;
|
||||
kernel_branched_path_surface_connect_light(kg, rng,
|
||||
&sd, &hit_state, throughput, 1.0f, &L, all);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* indirect light */
|
||||
kernel_branched_path_surface_indirect_light(kg, rng,
|
||||
&sd, throughput, 1.0f, &hit_state, &L);
|
||||
|
||||
/* continue in case of transparency */
|
||||
throughput *= shader_bsdf_transparency(kg, &sd);
|
||||
|
||||
if(is_zero(throughput))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update Path State */
|
||||
state.flag |= PATH_RAY_TRANSPARENT;
|
||||
state.transparent_bounce++;
|
||||
|
||||
ray.P = ray_offset(sd.P, -sd.Ng);
|
||||
ray.t -= sd.ray_length; /* clipping works through transparent */
|
||||
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
ray.dP = sd.dP;
|
||||
ray.dD.dx = -sd.dI.dx;
|
||||
ray.dD.dy = -sd.dI.dy;
|
||||
#endif
|
||||
|
||||
#ifdef __VOLUME__
|
||||
/* enter/exit volume */
|
||||
kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 L_sum = path_radiance_clamp_and_sum(kg, &L);
|
||||
|
||||
kernel_write_light_passes(kg, buffer, &L, sample);
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample);
|
||||
#endif
|
||||
|
||||
return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
|
||||
}
|
||||
|
||||
ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
|
||||
ccl_global float *buffer, ccl_global uint *rng_state,
|
||||
int sample, int x, int y, int offset, int stride)
|
||||
{
|
||||
/* buffer offset */
|
||||
int index = offset + x + y*stride;
|
||||
int pass_stride = kernel_data.film.pass_stride;
|
||||
|
||||
rng_state += index;
|
||||
buffer += index*pass_stride;
|
||||
|
||||
/* initialize random numbers and ray */
|
||||
RNG rng;
|
||||
Ray ray;
|
||||
|
||||
kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng, &ray);
|
||||
|
||||
/* integrate */
|
||||
float4 L;
|
||||
|
||||
if(ray.t != 0.0f)
|
||||
L = kernel_branched_path_integrate(kg, &rng, sample, ray, buffer);
|
||||
else
|
||||
L = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
/* accumulate result in output buffer */
|
||||
kernel_write_pass_float4(buffer, sample, L);
|
||||
|
||||
path_rng_end(kg, rng_state, rng);
|
||||
}
|
||||
|
||||
#endif /* __BRANCHED_PATH__ */
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -480,6 +480,7 @@ ccl_device void shader_merge_closures(ShaderData *sd)
|
||||
}
|
||||
|
||||
sd->num_closure--;
|
||||
kernel_assert(sd->num_closure >= 0);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
@@ -493,7 +494,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa
|
||||
{
|
||||
/* this is the veach one-sample model with balance heuristic, some pdf
|
||||
* factors drop out when using balance heuristic weighting */
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
if(i == skip_bsdf)
|
||||
continue;
|
||||
|
||||
@@ -598,7 +599,7 @@ ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *s
|
||||
|
||||
ccl_device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
|
||||
{
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSDF(sc->type))
|
||||
@@ -613,7 +614,7 @@ ccl_device float3 shader_bsdf_transparency(KernelGlobals *kg, ShaderData *sd)
|
||||
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID) // todo: make this work for osl
|
||||
@@ -637,7 +638,7 @@ ccl_device float3 shader_bsdf_diffuse(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
|
||||
@@ -651,7 +652,7 @@ ccl_device float3 shader_bsdf_glossy(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
|
||||
@@ -665,7 +666,7 @@ ccl_device float3 shader_bsdf_transmission(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
|
||||
@@ -679,7 +680,7 @@ ccl_device float3 shader_bsdf_subsurface(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSSRDF(sc->type) || CLOSURE_IS_BSDF_BSSRDF(sc->type))
|
||||
@@ -694,7 +695,7 @@ ccl_device float3 shader_bsdf_ao(KernelGlobals *kg, ShaderData *sd, float ao_fac
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float3 N = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
@@ -722,7 +723,7 @@ ccl_device float3 shader_bssrdf_sum(ShaderData *sd, float3 *N_, float *texture_b
|
||||
float3 N = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float texture_blur = 0.0f, weight_sum = 0.0f;
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BSSRDF(sc->type)) {
|
||||
@@ -828,7 +829,7 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int
|
||||
|
||||
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i< ccl_fetch(sd, num_closure); i++) {
|
||||
for(int i = 0; i < ccl_fetch(sd, num_closure); i++) {
|
||||
const ShaderClosure *sc = ccl_fetch_array(sd, closure, i);
|
||||
|
||||
if(CLOSURE_IS_BACKGROUND(sc->type))
|
||||
@@ -849,7 +850,7 @@ ccl_device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int
|
||||
ccl_device_inline void _shader_volume_phase_multi_eval(const ShaderData *sd, const float3 omega_in, float *pdf,
|
||||
int skip_phase, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight)
|
||||
{
|
||||
for(int i = 0; i< sd->num_closure; i++) {
|
||||
for(int i = 0; i < sd->num_closure; i++) {
|
||||
if(i == skip_phase)
|
||||
continue;
|
||||
|
||||
|
@@ -119,7 +119,9 @@ CCL_NAMESPACE_BEGIN
|
||||
# define __CAMERA_MOTION__
|
||||
# define __OBJECT_MOTION__
|
||||
# define __HAIR__
|
||||
//#define __TRANSPARENT_SHADOWS__
|
||||
# ifdef __KERNEL_EXPERIMENTAL__
|
||||
# define __TRANSPARENT_SHADOWS__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __KERNEL_OPENCL_INTEL_CPU__
|
||||
@@ -337,6 +339,8 @@ typedef enum PassType {
|
||||
PASS_LIGHT = (1 << 25), /* no real pass, used to force use_light_pass */
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
PASS_BVH_TRAVERSAL_STEPS = (1 << 26),
|
||||
PASS_BVH_TRAVERSED_INSTANCES = (1 << 27),
|
||||
PASS_RAY_BOUNCES = (1 << 28),
|
||||
#endif
|
||||
} PassType;
|
||||
|
||||
@@ -498,6 +502,7 @@ typedef ccl_addr_space struct Intersection {
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
int num_traversal_steps;
|
||||
int num_traversed_instances;
|
||||
#endif
|
||||
} Intersection;
|
||||
|
||||
@@ -848,7 +853,9 @@ typedef struct KernelFilm {
|
||||
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
int pass_bvh_traversal_steps;
|
||||
int pass_pad3, pass_pad4, pass_pad5;
|
||||
int pass_bvh_traversed_instances;
|
||||
int pass_ray_bounces;
|
||||
int pass_pad3;
|
||||
#endif
|
||||
} KernelFilm;
|
||||
|
||||
@@ -945,8 +952,7 @@ typedef struct KernelBVH {
|
||||
int have_curves;
|
||||
int have_instancing;
|
||||
int use_qbvh;
|
||||
int use_tri_storage;
|
||||
int pad1;
|
||||
int pad1, pad2;
|
||||
} KernelBVH;
|
||||
|
||||
typedef enum CurveFlag {
|
||||
@@ -988,6 +994,8 @@ typedef ccl_addr_space struct DebugData {
|
||||
// Total number of BVH node traversal steps and primitives intersections
|
||||
// for the camera rays.
|
||||
int num_bvh_traversal_steps;
|
||||
int num_bvh_traversed_instances;
|
||||
int num_ray_bounces;
|
||||
} DebugData;
|
||||
#endif
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "kernel_globals.h"
|
||||
#include "kernel_film.h"
|
||||
#include "kernel_path.h"
|
||||
#include "kernel_path_branched.h"
|
||||
#include "kernel_bake.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "../../kernel_globals.h"
|
||||
#include "../../kernel_film.h"
|
||||
#include "../../kernel_path.h"
|
||||
#include "../../kernel_path_branched.h"
|
||||
#include "../../kernel_bake.h"
|
||||
|
||||
/* device data taken from CUDA occupancy calculator */
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "../../kernel_film.h"
|
||||
#include "../../kernel_path.h"
|
||||
#include "../../kernel_path_branched.h"
|
||||
#include "../../kernel_bake.h"
|
||||
|
||||
#ifdef __COMPILE_ONLY_MEGAKERNEL__
|
||||
|
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
#if defined(__GNUC__) && defined(NDEBUG)
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
# pragma GCC diagnostic ignored "-Wuninitialized"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
@@ -249,7 +249,21 @@ point rotate (point p, float angle, point a, point b)
|
||||
{
|
||||
vector axis = normalize (b - a);
|
||||
float cosang, sinang;
|
||||
/* Older OSX has major issues with sincos() function,
|
||||
* it's likely a big in OSL or LLVM. For until we've
|
||||
* updated to new versions of this libraries we'll
|
||||
* use a workaround to prevent possible crashes on all
|
||||
* the platforms.
|
||||
*
|
||||
* Shouldn't be that bad because it's mainly used for
|
||||
* anisotropic shader where angle is usually constant.
|
||||
*/
|
||||
#if 0
|
||||
sincos (angle, sinang, cosang);
|
||||
#else
|
||||
sinang = sin (angle);
|
||||
cosang = cos (angle);
|
||||
#endif
|
||||
float cosang1 = 1.0 - cosang;
|
||||
float x = axis[0], y = axis[1], z = axis[2];
|
||||
matrix M = matrix (x * x + (1.0 - x * x) * cosang,
|
||||
|
@@ -123,7 +123,9 @@ ccl_device void kernel_scene_intersect(
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
if(state.flag & PATH_RAY_CAMERA) {
|
||||
debug_data->num_bvh_traversal_steps += isect->num_traversal_steps;
|
||||
debug_data->num_bvh_traversed_instances += isect->num_traversed_instances;
|
||||
}
|
||||
debug_data->num_ray_bounces++;
|
||||
#endif
|
||||
|
||||
if(!hit) {
|
||||
|
@@ -179,7 +179,6 @@ CCL_NAMESPACE_END
|
||||
#include "svm_checker.h"
|
||||
#include "svm_brick.h"
|
||||
#include "svm_vector_transform.h"
|
||||
#include "svm_voxel.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
@@ -391,9 +390,6 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade
|
||||
case NODE_TEX_BRICK:
|
||||
svm_node_tex_brick(kg, sd, stack, node, &offset);
|
||||
break;
|
||||
case NODE_TEX_VOXEL:
|
||||
svm_node_tex_voxel(kg, sd, stack, node, &offset);
|
||||
break;
|
||||
# endif /* __TEXTURES__ */
|
||||
# ifdef __EXTRA_NODES__
|
||||
case NODE_NORMAL:
|
||||
|
@@ -285,15 +285,17 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
|
||||
#endif
|
||||
|
||||
/* refraction */
|
||||
sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
|
||||
sc->weight = weight;
|
||||
sc->sample_weight = sample_weight;
|
||||
if(ccl_fetch(sd, num_closure) < MAX_CLOSURE) {
|
||||
sc = ccl_fetch_array(sd, closure, ccl_fetch(sd, num_closure));
|
||||
sc->weight = weight;
|
||||
sc->sample_weight = sample_weight;
|
||||
|
||||
sc = svm_node_closure_get_bsdf(sd, mix_weight*(1.0f - fresnel));
|
||||
sc = svm_node_closure_get_bsdf(sd, mix_weight*(1.0f - fresnel));
|
||||
|
||||
if(sc) {
|
||||
sc->N = N;
|
||||
svm_node_glass_setup(sd, sc, type, eta, roughness, true);
|
||||
if(sc) {
|
||||
sc->N = N;
|
||||
svm_node_glass_setup(sd, sc, type, eta, roughness, true);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@@ -125,8 +125,7 @@ typedef enum NodeType {
|
||||
NODE_TANGENT,
|
||||
NODE_NORMAL_MAP,
|
||||
NODE_HAIR_INFO,
|
||||
NODE_UVMAP,
|
||||
NODE_TEX_VOXEL,
|
||||
NODE_UVMAP
|
||||
} NodeType;
|
||||
|
||||
typedef enum NodeAttributeType {
|
||||
@@ -350,11 +349,6 @@ typedef enum NodeBumpOffset {
|
||||
NODE_BUMP_OFFSET_DY,
|
||||
} NodeBumpOffset;
|
||||
|
||||
typedef enum NodeTexVoxelSpace {
|
||||
NODE_TEX_VOXEL_SPACE_OBJECT = 0,
|
||||
NODE_TEX_VOXEL_SPACE_WORLD = 1,
|
||||
} NodeTexVoxelSpace;
|
||||
|
||||
typedef enum ShaderType {
|
||||
SHADER_TYPE_SURFACE,
|
||||
SHADER_TYPE_VOLUME,
|
||||
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2011-2015 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
float *stack,
|
||||
uint4 node,
|
||||
int *offset)
|
||||
{
|
||||
int id = node.y;
|
||||
uint co_offset, density_out_offset, color_out_offset, space;
|
||||
decode_node_uchar4(node.z, &co_offset, &density_out_offset, &color_out_offset, &space);
|
||||
float3 co = stack_load_float3(stack, co_offset);
|
||||
if(space == NODE_TEX_VOXEL_SPACE_OBJECT) {
|
||||
co = volume_normalized_position(kg, sd, co);
|
||||
}
|
||||
else {
|
||||
kernel_assert(space == NODE_TEX_VOXEL_SPACE_WORLD);
|
||||
Transform tfm;
|
||||
tfm.x = read_node_float(kg, offset);
|
||||
tfm.y = read_node_float(kg, offset);
|
||||
tfm.z = read_node_float(kg, offset);
|
||||
tfm.w = read_node_float(kg, offset);
|
||||
co = transform_point(&tfm, co);
|
||||
}
|
||||
if(co.x < 0.0f || co.y < 0.0f || co.z < 0.0f ||
|
||||
co.x > 1.0f || co.y > 1.0f || co.z > 1.0f)
|
||||
{
|
||||
if (stack_valid(density_out_offset))
|
||||
stack_store_float(stack, density_out_offset, 0.0f);
|
||||
if (stack_valid(color_out_offset))
|
||||
stack_store_float3(stack, color_out_offset, make_float3(0.0f, 0.0f, 0.0f));
|
||||
return;
|
||||
}
|
||||
#ifdef __KERNEL_GPU__
|
||||
float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
float4 r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z);
|
||||
#endif
|
||||
if (stack_valid(density_out_offset))
|
||||
stack_store_float(stack, density_out_offset, r.w);
|
||||
if (stack_valid(color_out_offset))
|
||||
stack_store_float3(stack, color_out_offset, make_float3(r.x, r.y, r.z));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
@@ -39,7 +39,6 @@ struct Transform;
|
||||
struct VoxelAttribute {
|
||||
ImageManager *manager;
|
||||
int slot;
|
||||
int from_alpha;
|
||||
};
|
||||
|
||||
/* Attribute
|
||||
|
@@ -197,6 +197,12 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int
|
||||
pixels[0] = f;
|
||||
}
|
||||
}
|
||||
else if(type == PASS_RAY_BOUNCES) {
|
||||
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
|
||||
float f = *in;
|
||||
pixels[0] = f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
for(int i = 0; i < size; i++, in += pass_stride, pixels++) {
|
||||
|
@@ -151,6 +151,14 @@ void Pass::add(PassType type, vector<Pass>& passes)
|
||||
pass.components = 1;
|
||||
pass.exposure = false;
|
||||
break;
|
||||
case PASS_BVH_TRAVERSED_INSTANCES:
|
||||
pass.components = 1;
|
||||
pass.exposure = false;
|
||||
break;
|
||||
case PASS_RAY_BOUNCES:
|
||||
pass.components = 1;
|
||||
pass.exposure = false;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -399,6 +407,12 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
case PASS_BVH_TRAVERSAL_STEPS:
|
||||
kfilm->pass_bvh_traversal_steps = kfilm->pass_stride;
|
||||
break;
|
||||
case PASS_BVH_TRAVERSED_INSTANCES:
|
||||
kfilm->pass_bvh_traversed_instances = kfilm->pass_stride;
|
||||
break;
|
||||
case PASS_RAY_BOUNCES:
|
||||
kfilm->pass_ray_bounces = kfilm->pass_stride;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PASS_NONE:
|
||||
|
@@ -419,6 +419,21 @@ void ShaderGraph::remove_unneeded_nodes()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
|
||||
BumpNode *bump = static_cast<BumpNode*>(node);
|
||||
|
||||
if(bump->outputs[0]->links.size()) {
|
||||
/* Height input not connected */
|
||||
/* ToDo: Strength zero? */
|
||||
if(!bump->inputs[0]->link) {
|
||||
vector<ShaderInput*> inputs = bump->outputs[0]->links;
|
||||
|
||||
relink(bump->inputs, inputs, NULL);
|
||||
removed[bump->id] = true;
|
||||
any_node_removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(node->special_type == SHADER_SPECIAL_TYPE_MIX_CLOSURE) {
|
||||
MixClosureNode *mix = static_cast<MixClosureNode*>(node);
|
||||
|
||||
@@ -560,7 +575,7 @@ void ShaderGraph::clean()
|
||||
else
|
||||
delete node;
|
||||
}
|
||||
|
||||
|
||||
nodes = newnodes;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user