Compare commits
245 Commits
tmp-workbe
...
2d
Author | SHA1 | Date | |
---|---|---|---|
eaa666b539 | |||
fced09c6a5 | |||
2d8bf2dffd | |||
6edd8bd98f | |||
e54fba5591 | |||
bf8597febe | |||
4dcaac6d33 | |||
d81c3bcfbb | |||
a985f558a6 | |||
ff4e04a293 | |||
71b451bb62 | |||
829d93ff06 | |||
049df7ef94 | |||
286fcb3a60 | |||
4927919613 | |||
e8b3bd15e8 | |||
da5e72eb01 | |||
cabc9506f9 | |||
709f67cbf0 | |||
9b779993f0 | |||
d82372aee3 | |||
811606a064 | |||
9cc4861e6f | |||
a1f044e9b9 | |||
c9b578eac8 | |||
b91ae8b14c | |||
95fcb41841 | |||
6b914a43ad | |||
b127654816 | |||
a12265f048 | |||
b464bbb689 | |||
03e580c98c | |||
ff5e8e6d53 | |||
b9a5f375a0 | |||
4e78822c28 | |||
3d2314fa49 | |||
![]() |
7aec5b0622 | ||
2b01964e6c | |||
83b6c8f2b1 | |||
f39ade9e00 | |||
9505af72d4 | |||
9e42b9827a | |||
9bbfade772 | |||
7475f7b0de | |||
![]() |
ffb0ecb498 | ||
2110e271f5 | |||
2bd71b49e7 | |||
![]() |
e9150ac317 | ||
32b33e91eb | |||
b03fb70eff | |||
f8713aae5e | |||
217e0a2ce6 | |||
84dab8b597 | |||
34449ba9a6 | |||
6f9828289f | |||
396413dedf | |||
146618fb22 | |||
120deaac5b | |||
64264a496d | |||
c8814fb610 | |||
9ce1135440 | |||
f21f1279fa | |||
2e4a1a70da | |||
95005bbe02 | |||
f420118335 | |||
1d1859c3c4 | |||
bff83ecee5 | |||
71c76d596c | |||
2053fc849e | |||
68c2650b03 | |||
c3a41a8002 | |||
c8c9965df2 | |||
5fabbedb04 | |||
c4f159cfcd | |||
81ee46da1a | |||
716d8436f0 | |||
64359f8998 | |||
fc5ef2452d | |||
2bd30272ea | |||
![]() |
5edb924e57 | ||
![]() |
8ad5241778 | ||
![]() |
83fa6a1b2a | ||
![]() |
c626301f19 | ||
64ca0f44cb | |||
5257257539 | |||
9578fe3068 | |||
2216699c64 | |||
8cc6623c18 | |||
180a68c1dc | |||
46abc6ce25 | |||
caaec3e0c5 | |||
a31859c754 | |||
8b4f1e41ea | |||
cf871ab967 | |||
9badd27fb7 | |||
b9718899fa | |||
deb90557ea | |||
869180548c | |||
75576a3001 | |||
![]() |
e43ccfb702 | ||
dfc959eed6 | |||
cfa235b89d | |||
a727692af7 | |||
ed80c887b7 | |||
97dbe235a2 | |||
8815f2f116 | |||
9ccdad8a21 | |||
57f6aa4d83 | |||
79032a8513 | |||
23775f3914 | |||
ac3324f197 | |||
012e41fc8b | |||
14427f5aaa | |||
a04d0de039 | |||
![]() |
1f7013fb90 | ||
b315678fea | |||
![]() |
07514def19 | ||
4fcc651435 | |||
a58592885c | |||
0c5a9a0e77 | |||
f18172b023 | |||
f8b8727873 | |||
2cf3ed13da | |||
e951e81b0f | |||
ec2e9a4352 | |||
c9d35ee07c | |||
1405787142 | |||
90a23dec46 | |||
0b2864382a | |||
544a0f2880 | |||
d29a079cb6 | |||
03b57d3973 | |||
fd1078e105 | |||
3435c9a2c1 | |||
afdc35b636 | |||
fe80b6ceac | |||
0a8fa07735 | |||
6b7756279f | |||
4311a32bc2 | |||
ace1b6a73a | |||
26e608d820 | |||
82ad1631e4 | |||
dd4a89e78d | |||
cb09485ff2 | |||
92d747b0c4 | |||
391bb6e9ba | |||
b6f640b953 | |||
4e93918b35 | |||
3b2a1ff716 | |||
75e61e5a6d | |||
c40d6ebceb | |||
430f71fce2 | |||
29a1d8b1d3 | |||
cdcbdf8ce4 | |||
5d74fa314b | |||
7c48196056 | |||
be921a04f2 | |||
dcb7b3f9f7 | |||
379814a118 | |||
60bd6804db | |||
1a15461612 | |||
3aa56608f7 | |||
f4031f2be2 | |||
66e4fdab68 | |||
cfe18c3b94 | |||
f756dc4812 | |||
5d4583683b | |||
d45098024e | |||
c37b837244 | |||
c0225aa573 | |||
49b9b0251b | |||
78647fbcc0 | |||
e1be275878 | |||
![]() |
bdd74e1e93 | ||
0a32ac02e9 | |||
1e0758333d | |||
9523b1478e | |||
ebd0e76088 | |||
9f6b19526d | |||
7475012e24 | |||
f2b24272dd | |||
da848b7440 | |||
423bbbbaae | |||
![]() |
3775615aea | ||
a21f1e81e0 | |||
87c13ac68c | |||
4710f3346a | |||
74d68e50d3 | |||
89dbad9085 | |||
834b966b41 | |||
d7ac659e02 | |||
9c341153a2 | |||
279a73e429 | |||
32a96b80a3 | |||
25ac6aa5e4 | |||
658ae5d63f | |||
![]() |
58e0aa36ea | ||
99ffe1153a | |||
6c483479b8 | |||
![]() |
c85c52f2ce | ||
d518550c46 | |||
aa2164da33 | |||
5730668dea | |||
8a20aec403 | |||
5400018106 | |||
6f1ab97c53 | |||
78f29c0467 | |||
0379ddac7d | |||
cf31c4ba18 | |||
a99e43b2b7 | |||
5abab0a41a | |||
a7f7b0b77e | |||
1edf520439 | |||
0e86c60c28 | |||
bb1e2a80e4 | |||
710e46cb2d | |||
cab1f1d9a2 | |||
7b615ca186 | |||
9dc0379dc0 | |||
f6296e502a | |||
fdd84d36ce | |||
b57db4b79e | |||
fc0dd5583c | |||
08e2885796 | |||
da1b6c4c02 | |||
d74c2b5c1f | |||
57dfec79f4 | |||
13f2df3c28 | |||
489b484b7b | |||
b42adab3a2 | |||
e729abb0e2 | |||
![]() |
74afc86d4b | ||
![]() |
ae44070341 | ||
![]() |
a9bb460766 | ||
974981a637 | |||
79927e730e | |||
990ed109f2 | |||
37848d1c8e | |||
12b26d21b0 | |||
6738ecb64e | |||
5b299e5999 | |||
9bce134e56 | |||
1bf6a880ab | |||
![]() |
a21bca0e20 | ||
b3bf46b78d |
@@ -685,7 +685,7 @@ if(WIN32 OR XCODE)
|
||||
option(IDE_GROUP_PROJECTS_IN_FOLDERS "Organize the projects according to source folder structure." ON)
|
||||
mark_as_advanced(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
|
||||
if (IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
if(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -31,7 +31,7 @@ ExternalProject_Add(external_python_site_packages
|
||||
CONFIGURE_COMMAND ${PIP_CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND ""
|
||||
PREFIX ${BUILD_DIR}/site_packages
|
||||
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install ${SITE_PACKAGES_EXTRA} cython==${CYTHON_VERSION} idna==${IDNA_VERSION} charset-normalizer==${CHARSET_NORMALIZER_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} zstandard==${ZSTANDARD_VERSION} --no-binary :all:
|
||||
INSTALL_COMMAND ${PYTHON_BINARY} -m pip install --no-cache-dir ${SITE_PACKAGES_EXTRA} cython==${CYTHON_VERSION} idna==${IDNA_VERSION} charset-normalizer==${CHARSET_NORMALIZER_VERSION} urllib3==${URLLIB3_VERSION} certifi==${CERTIFI_VERSION} requests==${REQUESTS_VERSION} zstandard==${ZSTANDARD_VERSION} --no-binary :all:
|
||||
)
|
||||
|
||||
if(USE_PIP_NUMPY)
|
||||
|
@@ -189,11 +189,11 @@ set(OSL_HASH 1abd7ce40481771a9fa937f19595d2f2)
|
||||
set(OSL_HASH_TYPE MD5)
|
||||
set(OSL_FILE OpenShadingLanguage-${OSL_VERSION}.tar.gz)
|
||||
|
||||
set(PYTHON_VERSION 3.9.7)
|
||||
set(PYTHON_SHORT_VERSION 3.9)
|
||||
set(PYTHON_SHORT_VERSION_NO_DOTS 39)
|
||||
set(PYTHON_VERSION 3.10.2)
|
||||
set(PYTHON_SHORT_VERSION 3.10)
|
||||
set(PYTHON_SHORT_VERSION_NO_DOTS 310)
|
||||
set(PYTHON_URI https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tar.xz)
|
||||
set(PYTHON_HASH fddb060b483bc01850a3f412eea1d954)
|
||||
set(PYTHON_HASH 14e8c22458ed7779a1957b26cde01db9)
|
||||
set(PYTHON_HASH_TYPE MD5)
|
||||
set(PYTHON_FILE Python-${PYTHON_VERSION}.tar.xz)
|
||||
|
||||
@@ -215,18 +215,20 @@ set(NANOVDB_HASH e7b9e863ec2f3b04ead171dec2322807)
|
||||
set(NANOVDB_HASH_TYPE MD5)
|
||||
set(NANOVDB_FILE nano-vdb-${NANOVDB_GIT_UID}.tar.gz)
|
||||
|
||||
set(IDNA_VERSION 3.2)
|
||||
set(CHARSET_NORMALIZER_VERSION 2.0.6)
|
||||
set(URLLIB3_VERSION 1.26.7)
|
||||
set(IDNA_VERSION 3.3)
|
||||
set(CHARSET_NORMALIZER_VERSION 2.0.10)
|
||||
set(URLLIB3_VERSION 1.26.8)
|
||||
set(CERTIFI_VERSION 2021.10.8)
|
||||
set(REQUESTS_VERSION 2.26.0)
|
||||
set(CYTHON_VERSION 0.29.24)
|
||||
set(ZSTANDARD_VERSION 0.15.2 )
|
||||
set(REQUESTS_VERSION 2.27.1)
|
||||
set(CYTHON_VERSION 0.29.26)
|
||||
# The version of the zstd library used to build the Python package should match ZSTD_VERSION defined below.
|
||||
# At this time of writing, 0.17.0 was already released, but built against zstd 1.5.1, while we use 1.5.0.
|
||||
set(ZSTANDARD_VERSION 0.16.0)
|
||||
|
||||
set(NUMPY_VERSION 1.21.2)
|
||||
set(NUMPY_SHORT_VERSION 1.21)
|
||||
set(NUMPY_VERSION 1.22.0)
|
||||
set(NUMPY_SHORT_VERSION 1.22)
|
||||
set(NUMPY_URI https://github.com/numpy/numpy/releases/download/v${NUMPY_VERSION}/numpy-${NUMPY_VERSION}.zip)
|
||||
set(NUMPY_HASH 5638d5dae3ca387be562912312db842e)
|
||||
set(NUMPY_HASH 252de134862a27bd66705d29622edbfe)
|
||||
set(NUMPY_HASH_TYPE MD5)
|
||||
set(NUMPY_FILE numpy-${NUMPY_VERSION}.zip)
|
||||
|
||||
|
@@ -379,27 +379,27 @@ USE_CXX11=true
|
||||
CLANG_FORMAT_VERSION_MIN="6.0"
|
||||
CLANG_FORMAT_VERSION_MEX="10.0"
|
||||
|
||||
PYTHON_VERSION="3.9.7"
|
||||
PYTHON_VERSION_SHORT="3.9"
|
||||
PYTHON_VERSION_MIN="3.7"
|
||||
PYTHON_VERSION_MEX="3.11"
|
||||
PYTHON_VERSION="3.10.2"
|
||||
PYTHON_VERSION_SHORT="3.10"
|
||||
PYTHON_VERSION_MIN="3.9"
|
||||
PYTHON_VERSION_MEX="3.12"
|
||||
PYTHON_VERSION_INSTALLED=$PYTHON_VERSION_SHORT
|
||||
PYTHON_FORCE_BUILD=false
|
||||
PYTHON_FORCE_REBUILD=false
|
||||
PYTHON_SKIP=false
|
||||
|
||||
# Additional Python modules.
|
||||
PYTHON_IDNA_VERSION="3.2"
|
||||
PYTHON_IDNA_VERSION="3.3"
|
||||
PYTHON_IDNA_VERSION_MIN="2.0"
|
||||
PYTHON_IDNA_VERSION_MEX="4.0"
|
||||
PYTHON_IDNA_NAME="idna"
|
||||
|
||||
PYTHON_CHARSET_NORMALIZER_VERSION="2.0.6"
|
||||
PYTHON_CHARSET_NORMALIZER_VERSION="2.0.10"
|
||||
PYTHON_CHARSET_NORMALIZER_VERSION_MIN="2.0.6"
|
||||
PYTHON_CHARSET_NORMALIZER_VERSION_MEX="2.1.0" # requests uses `charset_normalizer~=2.0.0`
|
||||
PYTHON_CHARSET_NORMALIZER_NAME="charset-normalizer"
|
||||
|
||||
PYTHON_URLLIB3_VERSION="1.26.7"
|
||||
PYTHON_URLLIB3_VERSION="1.26.8"
|
||||
PYTHON_URLLIB3_VERSION_MIN="1.0"
|
||||
PYTHON_URLLIB3_VERSION_MEX="2.0"
|
||||
PYTHON_URLLIB3_NAME="urllib3"
|
||||
@@ -409,17 +409,17 @@ PYTHON_CERTIFI_VERSION_MIN="2021.0"
|
||||
PYTHON_CERTIFI_VERSION_MEX="2023.0"
|
||||
PYTHON_CERTIFI_NAME="certifi"
|
||||
|
||||
PYTHON_REQUESTS_VERSION="2.23.0"
|
||||
PYTHON_REQUESTS_VERSION="2.27.1"
|
||||
PYTHON_REQUESTS_VERSION_MIN="2.0"
|
||||
PYTHON_REQUESTS_VERSION_MEX="3.0"
|
||||
PYTHON_REQUESTS_NAME="requests"
|
||||
|
||||
PYTHON_ZSTANDARD_VERSION="0.15.2"
|
||||
PYTHON_ZSTANDARD_VERSION="0.16.0"
|
||||
PYTHON_ZSTANDARD_VERSION_MIN="0.15.2"
|
||||
PYTHON_ZSTANDARD_VERSION_MEX="0.16.0"
|
||||
PYTHON_ZSTANDARD_VERSION_MEX="0.20.0"
|
||||
PYTHON_ZSTANDARD_NAME="zstandard"
|
||||
|
||||
PYTHON_NUMPY_VERSION="1.21.2"
|
||||
PYTHON_NUMPY_VERSION="1.22.0"
|
||||
PYTHON_NUMPY_VERSION_MIN="1.14"
|
||||
PYTHON_NUMPY_VERSION_MEX="2.0"
|
||||
PYTHON_NUMPY_NAME="numpy"
|
||||
@@ -499,7 +499,7 @@ LLVM_FORCE_REBUILD=false
|
||||
LLVM_SKIP=false
|
||||
|
||||
# OSL needs to be compiled for now!
|
||||
OSL_VERSION="1.11.14.1"
|
||||
OSL_VERSION="1.11.17.0"
|
||||
OSL_VERSION_SHORT="1.11"
|
||||
OSL_VERSION_MIN="1.11"
|
||||
OSL_VERSION_MEX="2.0"
|
||||
@@ -4036,14 +4036,14 @@ install_DEB() {
|
||||
INFO "Forced Python building, as requested..."
|
||||
_do_compile_python=true
|
||||
else
|
||||
check_package_version_ge_lt_DEB python3-dev $PYTHON_VERSION_MIN $PYTHON_VERSION_MEX
|
||||
check_package_version_ge_lt_DEB python${PYTHON_VERSION_SHORT}-dev $PYTHON_VERSION_MIN $PYTHON_VERSION_MEX
|
||||
if [ $? -eq 0 ]; then
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_DEB python3-dev` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
install_packages_DEB python3-dev
|
||||
install_packages_DEB python${PYTHON_VERSION_SHORT}-dev
|
||||
clean_Python
|
||||
PRINT ""
|
||||
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_DEB python${PYTHON_VERSION_SHORT}-dev` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
for module in "${PYTHON_MODULES_PACKAGES[@]}"
|
||||
do
|
||||
module=($module)
|
||||
@@ -4681,11 +4681,11 @@ install_RPM() {
|
||||
else
|
||||
check_package_version_ge_lt_RPM python3-devel $PYTHON_VERSION_MIN $PYTHON_VERSION_MEX
|
||||
if [ $? -eq 0 ]; then
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_RPM python3-devel` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
install_packages_RPM python3-devel
|
||||
clean_Python
|
||||
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_RPM python3-devel` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
for module in "${PYTHON_MODULES_PACKAGES[@]}"
|
||||
do
|
||||
module=($module)
|
||||
@@ -5224,12 +5224,12 @@ install_ARCH() {
|
||||
else
|
||||
check_package_version_ge_lt_ARCH python $PYTHON_VERSION_MIN $PYTHON_VERSION_MEX
|
||||
if [ $? -eq 0 ]; then
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_ARCH python` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
install_packages_ARCH python
|
||||
clean_Python
|
||||
PRINT ""
|
||||
|
||||
PYTHON_VERSION_INSTALLED=$(echo `get_package_version_ARCH python` | sed -r 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||
|
||||
for module in "${PYTHON_MODULES_PACKAGES[@]}"
|
||||
do
|
||||
module=($module)
|
||||
|
@@ -34,7 +34,7 @@ IF(NOT PYTHON_ROOT_DIR AND NOT $ENV{PYTHON_ROOT_DIR} STREQUAL "")
|
||||
SET(PYTHON_ROOT_DIR $ENV{PYTHON_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(PYTHON_VERSION 3.9 CACHE STRING "Python Version (major and minor only)")
|
||||
SET(PYTHON_VERSION 3.10 CACHE STRING "Python Version (major and minor only)")
|
||||
MARK_AS_ADVANCED(PYTHON_VERSION)
|
||||
|
||||
|
||||
|
@@ -1197,21 +1197,21 @@ endfunction()
|
||||
macro(openmp_delayload
|
||||
projectname
|
||||
)
|
||||
if(MSVC)
|
||||
if(WITH_OPENMP)
|
||||
if(MSVC_CLANG)
|
||||
set(OPENMP_DLL_NAME "libomp")
|
||||
elseif(MSVC_VERSION EQUAL 1800)
|
||||
set(OPENMP_DLL_NAME "vcomp120")
|
||||
else()
|
||||
set(OPENMP_DLL_NAME "vcomp140")
|
||||
endif()
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
if(MSVC)
|
||||
if(WITH_OPENMP)
|
||||
if(MSVC_CLANG)
|
||||
set(OPENMP_DLL_NAME "libomp")
|
||||
elseif(MSVC_VERSION EQUAL 1800)
|
||||
set(OPENMP_DLL_NAME "vcomp120")
|
||||
else()
|
||||
set(OPENMP_DLL_NAME "vcomp140")
|
||||
endif()
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_RELWITHDEBINFO " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
set_property(TARGET ${projectname} APPEND_STRING PROPERTY LINK_FLAGS_MINSIZEREL " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(set_and_warn_dependency
|
||||
|
@@ -128,25 +128,20 @@ if(WITH_CODEC_SNDFILE)
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
# we use precompiled libraries for py 3.9 and up by default
|
||||
set(PYTHON_VERSION 3.9)
|
||||
# Use precompiled libraries by default.
|
||||
set(PYTHON_VERSION 3.10)
|
||||
if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
|
||||
# normally cached but not since we include them with blender
|
||||
# Normally cached but not since we include them with blender.
|
||||
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}")
|
||||
set(PYTHON_EXECUTABLE "${LIBDIR}/python/bin/python${PYTHON_VERSION}")
|
||||
set(PYTHON_LIBRARY ${LIBDIR}/python/lib/libpython${PYTHON_VERSION}.a)
|
||||
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
|
||||
else()
|
||||
# module must be compiled against Python framework
|
||||
# Module must be compiled against Python framework.
|
||||
set(_py_framework "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}")
|
||||
|
||||
set(PYTHON_INCLUDE_DIR "${_py_framework}/include/python${PYTHON_VERSION}")
|
||||
set(PYTHON_EXECUTABLE "${_py_framework}/bin/python${PYTHON_VERSION}")
|
||||
set(PYTHON_LIBPATH "${_py_framework}/lib/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_LIBRARY python${PYTHON_VERSION})
|
||||
# set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
|
||||
|
||||
unset(_py_framework)
|
||||
endif()
|
||||
|
||||
|
@@ -109,9 +109,14 @@ if(NOT WITH_SYSTEM_FREETYPE)
|
||||
find_package_wrapper(Freetype REQUIRED)
|
||||
if(EXISTS ${LIBDIR})
|
||||
find_package_wrapper(Brotli REQUIRED)
|
||||
list(APPEND FREETYPE_LIBRARIES
|
||||
${BROTLI_LIBRARIES}
|
||||
)
|
||||
|
||||
# NOTE: This is done on WIN32 & APPLE but fails on some Linux systems.
|
||||
# See: https://devtalk.blender.org/t/22536
|
||||
# So `BROTLI_LIBRARIES` need to be added directly after `FREETYPE_LIBRARIES`.
|
||||
#
|
||||
# list(APPEND FREETYPE_LIBRARIES
|
||||
# ${BROTLI_LIBRARIES}
|
||||
# )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@@ -55,6 +55,10 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
message(WARNING "stripped pdb not supported with clang, disabling..")
|
||||
set(WITH_WINDOWS_STRIPPED_PDB OFF)
|
||||
endif()
|
||||
else()
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28.29921) # MSVC 2019 16.9.16
|
||||
message(FATAL_ERROR "Compiler is unsupported, MSVC 2019 16.9.16 or newer is required for building blender.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT WITH_PYTHON_MODULE)
|
||||
@@ -265,12 +269,6 @@ if(NOT DEFINED LIBDIR)
|
||||
elseif(MSVC_VERSION GREATER 1919)
|
||||
message(STATUS "Visual Studio 2019 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
elseif(MSVC_VERSION GREATER 1909)
|
||||
message(STATUS "Visual Studio 2017 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
elseif(MSVC_VERSION EQUAL 1900)
|
||||
message(STATUS "Visual Studio 2015 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
|
||||
@@ -465,7 +463,7 @@ if(WITH_JACK)
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
set(PYTHON_VERSION 3.9) # CACHE STRING)
|
||||
set(PYTHON_VERSION 3.10) # CACHE STRING)
|
||||
|
||||
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
|
||||
set(PYTHON_LIBRARY ${LIBDIR}/python/${_PYTHON_VERSION_NO_DOTS}/libs/python${_PYTHON_VERSION_NO_DOTS}.lib)
|
||||
|
@@ -3,9 +3,6 @@ echo No explicit msvc version requested, autodetecting version.
|
||||
call "%~dp0\detect_msvc2019.cmd"
|
||||
if %ERRORLEVEL% EQU 0 goto DetectionComplete
|
||||
|
||||
call "%~dp0\detect_msvc2017.cmd"
|
||||
if %ERRORLEVEL% EQU 0 goto DetectionComplete
|
||||
|
||||
call "%~dp0\detect_msvc2022.cmd"
|
||||
if %ERRORLEVEL% EQU 0 goto DetectionComplete
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
if "%BUILD_VS_YEAR%"=="2017" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
|
||||
|
||||
|
@@ -19,12 +19,6 @@ if "%WITH_PYDEBUG%"=="1" (
|
||||
set PYDEBUG_CMAKE_ARGS=-DWINDOWS_PYTHON_DEBUG=On
|
||||
)
|
||||
|
||||
if "%BUILD_VS_YEAR%"=="2017" (
|
||||
set BUILD_GENERATOR_POST=%WINDOWS_ARCH%
|
||||
) else (
|
||||
set BUILD_PLATFORM_SELECT=-A %MSBUILD_PLATFORM%
|
||||
)
|
||||
|
||||
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%BUILD_GENERATOR_POST%" %BUILD_PLATFORM_SELECT% %TESTS_CMAKE_ARGS% %CLANG_CMAKE_ARGS% %ASAN_CMAKE_ARGS% %PYDEBUG_CMAKE_ARGS%
|
||||
|
||||
if NOT EXIST %BUILD_DIR%\nul (
|
||||
|
@@ -37,15 +37,9 @@ set LLVM_DIR=
|
||||
:DetectionComplete
|
||||
set CC=%LLVM_DIR%\bin\clang-cl
|
||||
set CXX=%LLVM_DIR%\bin\clang-cl
|
||||
if "%BUILD_VS_YEAR%" == "2019" (
|
||||
rem build and tested against 2019 16.2
|
||||
set CFLAGS=-m64 -fmsc-version=1922
|
||||
set CXXFLAGS=-m64 -fmsc-version=1922
|
||||
) else (
|
||||
rem build and tested against 2017 15.7
|
||||
set CFLAGS=-m64 -fmsc-version=1914
|
||||
set CXXFLAGS=-m64 -fmsc-version=1914
|
||||
)
|
||||
rem build and tested against 2019 16.2
|
||||
set CFLAGS=-m64 -fmsc-version=1922
|
||||
set CXXFLAGS=-m64 -fmsc-version=1922
|
||||
)
|
||||
|
||||
if "%WITH_ASAN%"=="1" (
|
||||
|
@@ -1,3 +0,0 @@
|
||||
set BUILD_VS_VER=15
|
||||
set BUILD_VS_YEAR=2017
|
||||
call "%~dp0\detect_msvc_vswhere.cmd"
|
@@ -50,14 +50,6 @@ if NOT "%1" == "" (
|
||||
goto ERR
|
||||
) else if "%1" == "x64" (
|
||||
set BUILD_ARCH=x64
|
||||
) else if "%1" == "2017" (
|
||||
set BUILD_VS_YEAR=2017
|
||||
) else if "%1" == "2017pre" (
|
||||
set BUILD_VS_YEAR=2017
|
||||
set VSWHERE_ARGS=-prerelease
|
||||
) else if "%1" == "2017b" (
|
||||
set BUILD_VS_YEAR=2017
|
||||
set VSWHERE_ARGS=-products Microsoft.VisualStudio.Product.BuildTools
|
||||
) else if "%1" == "2019" (
|
||||
set BUILD_VS_YEAR=2019
|
||||
) else if "%1" == "2019pre" (
|
||||
|
@@ -24,12 +24,12 @@ echo - nobuildinfo ^(disable buildinfo^)
|
||||
echo - debug ^(Build an unoptimized debuggable build^)
|
||||
echo - packagename [newname] ^(override default cpack package name^)
|
||||
echo - builddir [newdir] ^(override default build folder^)
|
||||
echo - 2017 ^(build with visual studio 2017^)
|
||||
echo - 2017pre ^(build with visual studio 2017 pre-release^)
|
||||
echo - 2017b ^(build with visual studio 2017 Build Tools^)
|
||||
echo - 2019 ^(build with visual studio 2019^)
|
||||
echo - 2019pre ^(build with visual studio 2019 pre-release^)
|
||||
echo - 2019b ^(build with visual studio 2019 Build Tools^)
|
||||
echo - 2022 ^(build with visual studio 2022^)
|
||||
echo - 2022pre ^(build with visual studio 2022 pre-release^)
|
||||
echo - 2022b ^(build with visual studio 2022 Build Tools^)
|
||||
|
||||
echo.
|
||||
echo Documentation Targets ^(Not associated with building^)
|
||||
|
@@ -1,4 +1,3 @@
|
||||
if "%BUILD_VS_YEAR%"=="2017" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2019" set BUILD_VS_LIBDIRPOST=vc15
|
||||
if "%BUILD_VS_YEAR%"=="2022" set BUILD_VS_LIBDIRPOST=vc15
|
||||
|
||||
|
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = V3.1
|
||||
PROJECT_NUMBER = V3.2
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
2
extern/CMakeLists.txt
vendored
2
extern/CMakeLists.txt
vendored
@@ -113,6 +113,6 @@ if(WITH_MOD_FLUID)
|
||||
add_subdirectory(mantaflow)
|
||||
endif()
|
||||
|
||||
if (WITH_COMPOSITOR)
|
||||
if(WITH_COMPOSITOR)
|
||||
add_subdirectory(smaa_areatex)
|
||||
endif()
|
||||
|
@@ -61,6 +61,26 @@ static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS,
|
||||
|
||||
# define IS_HAIR(x) (x & 1)
|
||||
|
||||
/* This gets called by Embree at every valid ray/object intersection.
|
||||
* Things like recording subsurface or shadow hits for later evaluation
|
||||
* as well as filtering for volume objects happen here.
|
||||
* Cycles' own BVH does that directly inside the traversal calls.
|
||||
*/
|
||||
static void rtc_filter_intersection_func(const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
||||
const KernelGlobalsCPU *kg = ctx->kg;
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
if (kernel_embree_is_self_intersection(kg, hit, cray)) {
|
||||
*args->valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* This gets called by Embree at every valid ray/object intersection.
|
||||
* Things like recording subsurface or shadow hits for later evaluation
|
||||
* as well as filtering for volume objects happen here.
|
||||
@@ -75,12 +95,16 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
||||
const KernelGlobalsCPU *kg = ctx->kg;
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
switch (ctx->type) {
|
||||
case CCLIntersectContext::RAY_SHADOW_ALL: {
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(kg, ray, hit, ¤t_isect);
|
||||
|
||||
if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
/* If no transparent shadows or max number of hits exceeded, all light is blocked. */
|
||||
const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
|
||||
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
|
||||
@@ -160,6 +184,10 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* No intersection information requested, just return a hit. */
|
||||
if (ctx->max_hits == 0) {
|
||||
@@ -225,6 +253,11 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||
if (ctx->num_hits < ctx->max_hits) {
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(kg, ray, hit, ¤t_isect);
|
||||
if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Intersection *isect = &ctx->isect_s[ctx->num_hits];
|
||||
++ctx->num_hits;
|
||||
*isect = current_isect;
|
||||
@@ -236,12 +269,15 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
|
||||
}
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CCLIntersectContext::RAY_REGULAR:
|
||||
default:
|
||||
/* Nothing to do here. */
|
||||
if (kernel_embree_is_self_intersection(kg, hit, cray)) {
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -257,6 +293,14 @@ static void rtc_filter_func_backface_cull(const RTCFilterFunctionNArguments *arg
|
||||
*args->valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
|
||||
const KernelGlobalsCPU *kg = ctx->kg;
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
if (kernel_embree_is_self_intersection(kg, hit, cray)) {
|
||||
*args->valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtc_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
|
||||
@@ -505,6 +549,7 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
|
||||
|
||||
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_func);
|
||||
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
|
||||
|
||||
rtcCommitGeometry(geom_id);
|
||||
@@ -767,6 +812,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
|
||||
|
||||
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
||||
if (hair->curve_shape == CURVE_RIBBON) {
|
||||
rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_func);
|
||||
rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func);
|
||||
}
|
||||
else {
|
||||
|
@@ -559,10 +559,10 @@ if(WITH_CYCLES_DEVICE_METAL)
|
||||
find_library(METAL_LIBRARY Metal)
|
||||
|
||||
# This file was added in the 12.0 SDK, use it as a way to detect the version.
|
||||
if (METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
|
||||
if(METAL_LIBRARY AND NOT EXISTS "${METAL_LIBRARY}/Headers/MTLFunctionStitching.h")
|
||||
message(STATUS "Metal version too old, must be SDK 12.0 or newer, disabling WITH_CYCLES_DEVICE_METAL")
|
||||
set(WITH_CYCLES_DEVICE_METAL OFF)
|
||||
elseif (NOT METAL_LIBRARY)
|
||||
elseif(NOT METAL_LIBRARY)
|
||||
message(STATUS "Metal not found, disabling WITH_CYCLES_DEVICE_METAL")
|
||||
set(WITH_CYCLES_DEVICE_METAL OFF)
|
||||
else()
|
||||
|
@@ -905,8 +905,8 @@ void HIPDevice::tex_alloc(device_texture &mem)
|
||||
address_mode = hipAddressModeClamp;
|
||||
break;
|
||||
case EXTENSION_CLIP:
|
||||
// TODO : (Arya) setting this to Mode Clamp instead of Mode Border because it's unsupported
|
||||
// in hip
|
||||
/* TODO(@arya): setting this to Mode Clamp instead of Mode Border
|
||||
* because it's unsupported in HIP. */
|
||||
address_mode = hipAddressModeClamp;
|
||||
break;
|
||||
default:
|
||||
|
@@ -226,7 +226,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
|
||||
pipeline_options.usesMotionBlur = false;
|
||||
pipeline_options.traversableGraphFlags =
|
||||
OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING;
|
||||
pipeline_options.numPayloadValues = 6;
|
||||
pipeline_options.numPayloadValues = 8;
|
||||
pipeline_options.numAttributeValues = 2; /* u, v */
|
||||
pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE;
|
||||
pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */
|
||||
|
@@ -125,20 +125,41 @@ static Device *find_best_device(Device *device, DenoiserType type)
|
||||
return best_device;
|
||||
}
|
||||
|
||||
static DeviceInfo find_best_denoiser_device_info(const vector<DeviceInfo> &device_infos,
|
||||
DenoiserType denoiser_type)
|
||||
{
|
||||
for (const DeviceInfo &device_info : device_infos) {
|
||||
if ((device_info.denoisers & denoiser_type) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO(sergey): Use one of the already configured devices, so that OptiX denoising can happen
|
||||
* on a physical CUDA device which is already used for rendering. */
|
||||
|
||||
/* TODO(sergey): Choose fastest device for denoising. */
|
||||
|
||||
return device_info;
|
||||
}
|
||||
|
||||
DeviceInfo none_device;
|
||||
none_device.type = DEVICE_NONE;
|
||||
return none_device;
|
||||
}
|
||||
|
||||
static unique_ptr<Device> create_denoiser_device(Device *path_trace_device,
|
||||
const uint device_type_mask)
|
||||
const uint device_type_mask,
|
||||
DenoiserType denoiser_type)
|
||||
{
|
||||
const vector<DeviceInfo> device_infos = Device::available_devices(device_type_mask);
|
||||
if (device_infos.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* TODO(sergey): Use one of the already configured devices, so that OptiX denoising can happen on
|
||||
* a physical CUDA device which is already used for rendering. */
|
||||
|
||||
/* TODO(sergey): Choose fastest device for denoising. */
|
||||
|
||||
const DeviceInfo denoiser_device_info = device_infos.front();
|
||||
const DeviceInfo denoiser_device_info = find_best_denoiser_device_info(device_infos,
|
||||
denoiser_type);
|
||||
if (denoiser_device_info.type == DEVICE_NONE) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unique_ptr<Device> denoiser_device(
|
||||
Device::create(denoiser_device_info, path_trace_device->stats, path_trace_device->profiler));
|
||||
@@ -186,7 +207,8 @@ Device *Denoiser::ensure_denoiser_device(Progress *progress)
|
||||
device_creation_attempted_ = true;
|
||||
|
||||
const uint device_type_mask = get_device_type_mask();
|
||||
local_denoiser_device_ = create_denoiser_device(path_trace_device_, device_type_mask);
|
||||
local_denoiser_device_ = create_denoiser_device(
|
||||
path_trace_device_, device_type_mask, params_.type);
|
||||
denoiser_device_ = local_denoiser_device_.get();
|
||||
|
||||
return denoiser_device_;
|
||||
|
@@ -37,8 +37,6 @@ OIDNDenoiser::OIDNDenoiser(Device *path_trace_device, const DenoiseParams ¶m
|
||||
: Denoiser(path_trace_device, params)
|
||||
{
|
||||
DCHECK_EQ(params.type, DENOISER_OPENIMAGEDENOISE);
|
||||
|
||||
DCHECK(openimagedenoise_supported()) << "OpenImageDenoiser is not supported on this platform.";
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
@@ -585,6 +583,9 @@ bool OIDNDenoiser::denoise_buffer(const BufferParams &buffer_params,
|
||||
const int num_samples,
|
||||
bool allow_inplace_modification)
|
||||
{
|
||||
DCHECK(openimagedenoise_supported())
|
||||
<< "OpenImageDenoiser is not supported on this platform or build.";
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
thread_scoped_lock lock(mutex_);
|
||||
|
||||
@@ -635,4 +636,20 @@ uint OIDNDenoiser::get_device_type_mask() const
|
||||
return DEVICE_MASK_CPU;
|
||||
}
|
||||
|
||||
Device *OIDNDenoiser::ensure_denoiser_device(Progress *progress)
|
||||
{
|
||||
#ifndef WITH_OPENIMAGEDENOISE
|
||||
path_trace_device_->set_error("Build without OpenImageDenoiser");
|
||||
return nullptr;
|
||||
#else
|
||||
if (!openimagedenoise_supported()) {
|
||||
path_trace_device_->set_error(
|
||||
"OpenImageDenoiser is not supported on this CPU: missing SSE 4.1 support");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Denoiser::ensure_denoiser_device(progress);
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -38,6 +38,7 @@ class OIDNDenoiser : public Denoiser {
|
||||
|
||||
protected:
|
||||
virtual uint get_device_type_mask() const override;
|
||||
virtual Device *ensure_denoiser_device(Progress *progress) override;
|
||||
|
||||
/* We only perform one denoising at a time, since OpenImageDenoise itself is multithreaded.
|
||||
* Use this mutex whenever images are passed to the OIDN and needs to be denoised. */
|
||||
|
@@ -157,7 +157,7 @@ bool ShaderEval::eval_gpu(Device *device,
|
||||
queue->init_execution();
|
||||
|
||||
/* Execute work on GPU in chunk, so we can cancel.
|
||||
* TODO : query appropriate size from device.*/
|
||||
* TODO: query appropriate size from device. */
|
||||
const int32_t chunk_size = 65536;
|
||||
|
||||
device_ptr d_input = input.device_pointer;
|
||||
|
@@ -173,15 +173,16 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
uint p3 = 0;
|
||||
uint p4 = visibility;
|
||||
uint p5 = PRIMITIVE_NONE;
|
||||
uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
|
||||
uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
uint ray_flags = OPTIX_RAY_FLAG_NONE;
|
||||
uint ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
ray_mask = 0xFF;
|
||||
ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT;
|
||||
}
|
||||
else if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
||||
ray_flags = OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
|
||||
ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
|
||||
}
|
||||
|
||||
optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
|
||||
@@ -200,7 +201,9 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5);
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
isect->t = __uint_as_float(p0);
|
||||
isect->u = __uint_as_float(p1);
|
||||
@@ -242,6 +245,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
}
|
||||
|
||||
MetalRTIntersectionPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.u = 0.0f;
|
||||
payload.v = 0.0f;
|
||||
payload.visibility = visibility;
|
||||
@@ -309,6 +313,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
||||
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
|
||||
IntersectContext rtc_ctx(&ctx);
|
||||
RTCRayHit ray_hit;
|
||||
ctx.ray = ray;
|
||||
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
|
||||
rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit);
|
||||
if (ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID &&
|
||||
@@ -356,6 +361,9 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
uint p2 = pointer_pack_to_uint_0(local_isect);
|
||||
uint p3 = pointer_pack_to_uint_1(local_isect);
|
||||
uint p4 = local_object;
|
||||
uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
|
||||
uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
|
||||
|
||||
/* Is set to zero on miss or if ray is aborted, so can be used as return value. */
|
||||
uint p5 = max_hits;
|
||||
|
||||
@@ -379,7 +387,9 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5);
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
return p5;
|
||||
# elif defined(__METALRT__)
|
||||
@@ -417,6 +427,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
}
|
||||
|
||||
MetalRTIntersectionLocalPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.local_object = local_object;
|
||||
payload.max_hits = max_hits;
|
||||
payload.local_isect.num_hits = 0;
|
||||
@@ -460,6 +471,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
||||
kg, has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
|
||||
ctx.lcg_state = lcg_state;
|
||||
ctx.max_hits = max_hits;
|
||||
ctx.ray = ray;
|
||||
ctx.local_isect = local_isect;
|
||||
if (local_isect) {
|
||||
local_isect->num_hits = 0;
|
||||
@@ -532,6 +544,8 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
||||
uint p3 = max_hits;
|
||||
uint p4 = visibility;
|
||||
uint p5 = false;
|
||||
uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
|
||||
uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
@@ -555,7 +569,9 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5);
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
*num_recorded_hits = uint16_unpack_from_uint_0(p2);
|
||||
*throughput = __uint_as_float(p1);
|
||||
@@ -588,6 +604,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
||||
}
|
||||
|
||||
MetalRTIntersectionShadowPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.visibility = visibility;
|
||||
payload.max_hits = max_hits;
|
||||
payload.num_hits = 0;
|
||||
@@ -634,6 +651,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
||||
Intersection *isect_array = (Intersection *)state->shadow_isect;
|
||||
ctx.isect_s = isect_array;
|
||||
ctx.max_hits = max_hits;
|
||||
ctx.ray = ray;
|
||||
IntersectContext rtc_ctx(&ctx);
|
||||
RTCRay rtc_ray;
|
||||
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
|
||||
@@ -685,6 +703,8 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
uint p3 = 0;
|
||||
uint p4 = visibility;
|
||||
uint p5 = PRIMITIVE_NONE;
|
||||
uint p6 = ((uint64_t)ray) & 0xFFFFFFFF;
|
||||
uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF;
|
||||
|
||||
uint ray_mask = visibility & 0xFF;
|
||||
if (0 == ray_mask && (visibility & ~0xFF) != 0) {
|
||||
@@ -708,7 +728,9 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
p2,
|
||||
p3,
|
||||
p4,
|
||||
p5);
|
||||
p5,
|
||||
p6,
|
||||
p7);
|
||||
|
||||
isect->t = __uint_as_float(p0);
|
||||
isect->u = __uint_as_float(p1);
|
||||
@@ -744,6 +766,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
||||
}
|
||||
|
||||
MetalRTIntersectionPayload payload;
|
||||
payload.self = ray->self;
|
||||
payload.visibility = visibility;
|
||||
|
||||
typename metalrt_intersector_type::result_type intersection;
|
||||
@@ -820,6 +843,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg,
|
||||
ctx.isect_s = isect;
|
||||
ctx.max_hits = max_hits;
|
||||
ctx.num_hits = 0;
|
||||
ctx.ray = ray;
|
||||
IntersectContext rtc_ctx(&ctx);
|
||||
RTCRay rtc_ray;
|
||||
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "kernel/device/cpu/compat.h"
|
||||
#include "kernel/device/cpu/globals.h"
|
||||
|
||||
#include "kernel/bvh/util.h"
|
||||
|
||||
#include "util/vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
@@ -38,6 +40,9 @@ struct CCLIntersectContext {
|
||||
KernelGlobals kg;
|
||||
RayType type;
|
||||
|
||||
/* For avoiding self intersections */
|
||||
const Ray *ray;
|
||||
|
||||
/* for shadow rays */
|
||||
Intersection *isect_s;
|
||||
uint max_hits;
|
||||
@@ -56,6 +61,7 @@ struct CCLIntersectContext {
|
||||
{
|
||||
kg = kg_;
|
||||
type = type_;
|
||||
ray = NULL;
|
||||
max_hits = 1;
|
||||
num_hits = 0;
|
||||
num_recorded_hits = 0;
|
||||
@@ -102,7 +108,34 @@ ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray,
|
||||
{
|
||||
kernel_embree_setup_ray(ray, rayhit.ray, visibility);
|
||||
rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
|
||||
rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID;
|
||||
rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
|
||||
}
|
||||
|
||||
ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg,
|
||||
const RTCHit *hit,
|
||||
const Ray *ray)
|
||||
{
|
||||
bool status = false;
|
||||
if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
|
||||
const int oID = hit->instID[0] / 2;
|
||||
if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
|
||||
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
|
||||
rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
|
||||
const int pID = hit->primID +
|
||||
(intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
|
||||
status = intersection_skip_self_shadow(ray->self, oID, pID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const int oID = hit->geomID / 2;
|
||||
if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
|
||||
const int pID = hit->primID + (intptr_t)rtcGetGeometryUserData(
|
||||
rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
|
||||
status = intersection_skip_self_shadow(ray->self, oID, pID);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
|
||||
|
@@ -157,7 +157,11 @@ ccl_device_inline
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip self intersection. */
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (triangle_intersect_local(kg,
|
||||
local_isect,
|
||||
@@ -188,7 +192,11 @@ ccl_device_inline
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip self intersection. */
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (motion_triangle_intersect_local(kg,
|
||||
local_isect,
|
||||
|
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
struct MetalRTIntersectionPayload {
|
||||
RaySelfPrimitives self;
|
||||
uint visibility;
|
||||
float u, v;
|
||||
int prim;
|
||||
@@ -25,6 +26,7 @@ struct MetalRTIntersectionPayload {
|
||||
};
|
||||
|
||||
struct MetalRTIntersectionLocalPayload {
|
||||
RaySelfPrimitives self;
|
||||
uint local_object;
|
||||
uint lcg_state;
|
||||
short max_hits;
|
||||
@@ -34,6 +36,7 @@ struct MetalRTIntersectionLocalPayload {
|
||||
};
|
||||
|
||||
struct MetalRTIntersectionShadowPayload {
|
||||
RaySelfPrimitives self;
|
||||
uint visibility;
|
||||
#if defined(__METALRT_MOTION__)
|
||||
float time;
|
||||
|
@@ -160,6 +160,9 @@ ccl_device_inline
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
|
@@ -133,35 +133,29 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
--stack_ptr;
|
||||
|
||||
/* primitive intersection */
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type & PRIMITIVE_ALL) {
|
||||
case PRIMITIVE_TRIANGLE: {
|
||||
if (triangle_intersect(
|
||||
kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr)) {
|
||||
/* shadow ray early termination */
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if BVH_FEATURE(BVH_MOTION)
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
|
||||
case PRIMITIVE_MOTION_TRIANGLE: {
|
||||
if (motion_triangle_intersect(kg,
|
||||
isect,
|
||||
P,
|
||||
@@ -176,28 +170,21 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_MOTION) */
|
||||
#if BVH_FEATURE(BVH_HAIR)
|
||||
case PRIMITIVE_CURVE_THICK:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK:
|
||||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
case PRIMITIVE_CURVE_THICK:
|
||||
case PRIMITIVE_MOTION_CURVE_THICK:
|
||||
case PRIMITIVE_CURVE_RIBBON:
|
||||
case PRIMITIVE_MOTION_CURVE_RIBBON: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
|
||||
const int curve_type = kernel_tex_fetch(__prim_type, prim_addr);
|
||||
const bool hit = curve_intersect(
|
||||
kg, isect, P, dir, isect->t, prim_object, prim, ray->time, curve_type);
|
||||
@@ -206,26 +193,19 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_HAIR) */
|
||||
#if BVH_FEATURE(BVH_POINTCLOUD)
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
for (; prim_addr < prim_addr2; prim_addr++) {
|
||||
case PRIMITIVE_POINT:
|
||||
case PRIMITIVE_MOTION_POINT: {
|
||||
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
|
||||
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
|
||||
if (ray->time < prim_time.x || ray->time > prim_time.y) {
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const int prim_object = (object == OBJECT_NONE) ?
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
|
||||
const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
|
||||
const bool hit = point_intersect(
|
||||
kg, isect, P, dir, isect->t, prim_object, prim, ray->time, point_type);
|
||||
@@ -234,10 +214,10 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@@ -21,54 +21,22 @@ CCL_NAMESPACE_BEGIN
|
||||
/* Ray offset to avoid self intersection.
|
||||
*
|
||||
* This function should be used to compute a modified ray start position for
|
||||
* rays leaving from a surface. */
|
||||
|
||||
* rays leaving from a surface. This is from "A Fast and Robust Method for Avoiding
|
||||
* Self-Intersection" see https://research.nvidia.com/publication/2019-03_A-Fast-and
|
||||
*/
|
||||
ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
const float epsilon_f = 1e-5f;
|
||||
/* ideally this should match epsilon_f, but instancing and motion blur
|
||||
* precision makes it problematic */
|
||||
const float epsilon_test = 1.0f;
|
||||
const int epsilon_i = 32;
|
||||
const float int_scale = 256.0f;
|
||||
int3 of_i = make_int3((int)(int_scale * Ng.x), (int)(int_scale * Ng.y), (int)(int_scale * Ng.z));
|
||||
|
||||
float3 res;
|
||||
|
||||
/* x component */
|
||||
if (fabsf(P.x) < epsilon_test) {
|
||||
res.x = P.x + Ng.x * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint ix = __float_as_uint(P.x);
|
||||
ix += ((ix ^ __float_as_uint(Ng.x)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.x = __uint_as_float(ix);
|
||||
}
|
||||
|
||||
/* y component */
|
||||
if (fabsf(P.y) < epsilon_test) {
|
||||
res.y = P.y + Ng.y * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iy = __float_as_uint(P.y);
|
||||
iy += ((iy ^ __float_as_uint(Ng.y)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.y = __uint_as_float(iy);
|
||||
}
|
||||
|
||||
/* z component */
|
||||
if (fabsf(P.z) < epsilon_test) {
|
||||
res.z = P.z + Ng.z * epsilon_f;
|
||||
}
|
||||
else {
|
||||
uint iz = __float_as_uint(P.z);
|
||||
iz += ((iz ^ __float_as_uint(Ng.z)) >> 31) ? -epsilon_i : epsilon_i;
|
||||
res.z = __uint_as_float(iz);
|
||||
}
|
||||
|
||||
return res;
|
||||
#else
|
||||
const float epsilon_f = 1e-4f;
|
||||
return P + epsilon_f * Ng;
|
||||
#endif
|
||||
float3 p_i = make_float3(__int_as_float(__float_as_int(P.x) + ((P.x < 0) ? -of_i.x : of_i.x)),
|
||||
__int_as_float(__float_as_int(P.y) + ((P.y < 0) ? -of_i.y : of_i.y)),
|
||||
__int_as_float(__float_as_int(P.z) + ((P.z < 0) ? -of_i.z : of_i.z)));
|
||||
const float origin = 1.0f / 32.0f;
|
||||
const float float_scale = 1.0f / 65536.0f;
|
||||
return make_float3(fabsf(P.x) < origin ? P.x + float_scale * Ng.x : p_i.x,
|
||||
fabsf(P.y) < origin ? P.y + float_scale * Ng.y : p_i.y,
|
||||
fabsf(P.z) < origin ? P.z + float_scale * Ng.z : p_i.z);
|
||||
}
|
||||
|
||||
#if defined(__KERNEL_CPU__)
|
||||
@@ -227,4 +195,25 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg,
|
||||
return (1.0f - u) * f0 + u * f1;
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self(ccl_private const RaySelfPrimitives &self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim) && (self.object == object);
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_shadow(ccl_private const RaySelfPrimitives &self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return ((self.prim == prim) && (self.object == object)) ||
|
||||
((self.light_prim == prim) && (self.light_object == object));
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_local(ccl_private const RaySelfPrimitives &self,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -144,6 +144,9 @@ ccl_device_inline
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int object_flag = kernel_tex_fetch(__object_flag, prim_object);
|
||||
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
@@ -164,6 +167,9 @@ ccl_device_inline
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
int object_flag = kernel_tex_fetch(__object_flag, prim_object);
|
||||
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
continue;
|
||||
|
@@ -147,6 +147,9 @@ ccl_device_inline
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
int object_flag = kernel_tex_fetch(__object_flag, prim_object);
|
||||
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
continue;
|
||||
@@ -188,6 +191,9 @@ ccl_device_inline
|
||||
kernel_tex_fetch(__prim_object, prim_addr) :
|
||||
object;
|
||||
const int prim = kernel_tex_fetch(__prim_index, prim_addr);
|
||||
if (intersection_skip_self(ray->self, prim_object, prim)) {
|
||||
continue;
|
||||
}
|
||||
int object_flag = kernel_tex_fetch(__object_flag, prim_object);
|
||||
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
continue;
|
||||
|
@@ -40,6 +40,27 @@ struct TriangleIntersectionResult
|
||||
|
||||
enum { METALRT_HIT_TRIANGLE, METALRT_HIT_BOUNDING_BOX };
|
||||
|
||||
ccl_device_inline bool intersection_skip_self(ray_data const RaySelfPrimitives& self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim) && (self.object == object);
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_shadow(ray_data const RaySelfPrimitives& self,
|
||||
const int object,
|
||||
const int prim)
|
||||
{
|
||||
return ((self.prim == prim) && (self.object == object)) ||
|
||||
((self.light_prim == prim) && (self.light_object == object));
|
||||
}
|
||||
|
||||
ccl_device_inline bool intersection_skip_self_local(ray_data const RaySelfPrimitives& self,
|
||||
const int prim)
|
||||
{
|
||||
return (self.prim == prim);
|
||||
}
|
||||
|
||||
template<typename TReturn, uint intersection_type>
|
||||
TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
|
||||
ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload,
|
||||
@@ -53,8 +74,8 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
|
||||
#ifdef __BVH_LOCAL__
|
||||
uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
|
||||
|
||||
if (object != payload.local_object) {
|
||||
/* Only intersect with matching object */
|
||||
if ((object != payload.local_object) || intersection_skip_self_local(payload.self, prim)) {
|
||||
/* Only intersect with matching object and skip self-intersecton. */
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
@@ -166,6 +187,11 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
|
||||
}
|
||||
# endif
|
||||
|
||||
if (intersection_skip_self_shadow(payload.self, object, prim)) {
|
||||
/* continue search */
|
||||
return true;
|
||||
}
|
||||
|
||||
float u = 0.0f, v = 0.0f;
|
||||
int type = 0;
|
||||
if (intersection_type == METALRT_HIT_TRIANGLE) {
|
||||
@@ -322,21 +348,35 @@ inline TReturnType metalrt_visibility_test(constant KernelParamsMetal &launch_pa
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
uint visibility = payload.visibility;
|
||||
# ifdef __VISIBILITY_FLAG__
|
||||
if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Shadow ray early termination. */
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
||||
result.accept = true;
|
||||
result.continue_search = false;
|
||||
return result;
|
||||
if (intersection_skip_self_shadow(payload.self, object, prim)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
result.accept = true;
|
||||
result.continue_search = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (intersection_skip_self(payload.self, object, prim)) {
|
||||
result.accept = false;
|
||||
result.continue_search = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
result.accept = true;
|
||||
result.continue_search = true;
|
||||
|
@@ -45,6 +45,11 @@ template<typename T> ccl_device_forceinline T *get_payload_ptr_2()
|
||||
return pointer_unpack_from_uint<T>(optixGetPayload_2(), optixGetPayload_3());
|
||||
}
|
||||
|
||||
template<typename T> ccl_device_forceinline T *get_payload_ptr_6()
|
||||
{
|
||||
return (T *)(((uint64_t)optixGetPayload_7() << 32) | optixGetPayload_6());
|
||||
}
|
||||
|
||||
ccl_device_forceinline int get_object_id()
|
||||
{
|
||||
#ifdef __OBJECT_MOTION__
|
||||
@@ -111,6 +116,12 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
if (intersection_skip_self_local(ray->self, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
const uint max_hits = optixGetPayload_5();
|
||||
if (max_hits == 0) {
|
||||
/* Special case for when no hit information is requested, just report that something was hit */
|
||||
@@ -149,8 +160,6 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
|
||||
local_isect->num_hits = 1;
|
||||
}
|
||||
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
|
||||
Intersection *isect = &local_isect->hits[hit];
|
||||
isect->t = optixGetRayTmax();
|
||||
isect->prim = prim;
|
||||
@@ -185,6 +194,11 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
|
||||
}
|
||||
# endif
|
||||
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
if (intersection_skip_self_shadow(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
float u = 0.0f, v = 0.0f;
|
||||
int type = 0;
|
||||
if (optixIsTriangleHit()) {
|
||||
@@ -314,6 +328,12 @@ extern "C" __global__ void __anyhit__kernel_optix_volume_test()
|
||||
if ((kernel_tex_fetch(__object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
if (intersection_skip_self(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
|
||||
@@ -330,18 +350,31 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
const uint object = get_object_id();
|
||||
const uint visibility = optixGetPayload_4();
|
||||
#ifdef __VISIBILITY_FLAG__
|
||||
if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
|
||||
/* Shadow ray early termination. */
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
||||
return optixTerminateRay();
|
||||
}
|
||||
#endif
|
||||
|
||||
const int prim = optixGetPrimitiveIndex();
|
||||
ccl_private Ray *const ray = get_payload_ptr_6<Ray>();
|
||||
|
||||
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
||||
if (intersection_skip_self_shadow(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
else {
|
||||
/* Shadow ray early termination. */
|
||||
return optixTerminateRay();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (intersection_skip_self(ray->self, object, prim)) {
|
||||
return optixIgnoreIntersection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __global__ void __closesthit__kernel_optix_hit()
|
||||
|
@@ -29,46 +29,19 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Refine triangle intersection to more precise hit point. For rays that travel
|
||||
* far the precision is often not so good, this reintersects the primitive from
|
||||
* a closer distance.
|
||||
/**
|
||||
* Use the barycentric coordinates to get the intersection location
|
||||
*/
|
||||
|
||||
ccl_device_inline float3 motion_triangle_refine(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
float3 P,
|
||||
float3 D,
|
||||
float t,
|
||||
const int isect_object,
|
||||
const int isect_prim,
|
||||
float3 verts[3])
|
||||
ccl_device_inline float3 motion_triangle_point_from_uv(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const int isect_object,
|
||||
const int isect_prim,
|
||||
const float u,
|
||||
const float v,
|
||||
float3 verts[3])
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
if (UNLIKELY(t == 0.0f)) {
|
||||
return P;
|
||||
}
|
||||
const Transform tfm = object_get_inverse_transform(kg, sd);
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
D = transform_direction(&tfm, D * t);
|
||||
D = normalize_len(D, &t);
|
||||
}
|
||||
|
||||
P = P + D * t;
|
||||
|
||||
/* Compute refined intersection distance. */
|
||||
const float3 e1 = verts[0] - verts[2];
|
||||
const float3 e2 = verts[1] - verts[2];
|
||||
const float3 s1 = cross(D, e2);
|
||||
|
||||
const float invdivisor = 1.0f / dot(s1, e1);
|
||||
const float3 d = P - verts[2];
|
||||
const float3 s2 = cross(d, e1);
|
||||
float rt = dot(e2, s2) * invdivisor;
|
||||
|
||||
/* Compute refined position. */
|
||||
P = P + D * rt;
|
||||
float w = 1.0f - u - v;
|
||||
float3 P = u * verts[0] + v * verts[1] + w * verts[2];
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_transform(kg, sd);
|
||||
@@ -76,71 +49,8 @@ ccl_device_inline float3 motion_triangle_refine(KernelGlobals kg,
|
||||
}
|
||||
|
||||
return P;
|
||||
#else
|
||||
return P + D * t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Same as above, except that t is assumed to be in object space
|
||||
* for instancing.
|
||||
*/
|
||||
|
||||
#ifdef __BVH_LOCAL__
|
||||
# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
|
||||
ccl_device_noinline
|
||||
# else
|
||||
ccl_device_inline
|
||||
# endif
|
||||
float3
|
||||
motion_triangle_refine_local(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
float3 P,
|
||||
float3 D,
|
||||
float t,
|
||||
const int isect_object,
|
||||
const int isect_prim,
|
||||
float3 verts[3])
|
||||
{
|
||||
# if defined(__KERNEL_GPU_RAYTRACING__)
|
||||
/* t is always in world space with OptiX and MetalRT. */
|
||||
return motion_triangle_refine(kg, sd, P, D, t, isect_object, isect_prim, verts);
|
||||
# else
|
||||
# ifdef __INTERSECTION_REFINE__
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_inverse_transform(kg, sd);
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
D = transform_direction(&tfm, D);
|
||||
D = normalize(D);
|
||||
}
|
||||
|
||||
P = P + D * t;
|
||||
|
||||
/* compute refined intersection distance */
|
||||
const float3 e1 = verts[0] - verts[2];
|
||||
const float3 e2 = verts[1] - verts[2];
|
||||
const float3 s1 = cross(D, e2);
|
||||
|
||||
const float invdivisor = 1.0f / dot(s1, e1);
|
||||
const float3 d = P - verts[2];
|
||||
const float3 s2 = cross(d, e1);
|
||||
float rt = dot(e2, s2) * invdivisor;
|
||||
|
||||
P = P + D * rt;
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_transform(kg, sd);
|
||||
P = transform_point(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
# else /* __INTERSECTION_REFINE__ */
|
||||
return P + D * t;
|
||||
# endif /* __INTERSECTION_REFINE__ */
|
||||
# endif
|
||||
}
|
||||
#endif /* __BVH_LOCAL__ */
|
||||
|
||||
/* Ray intersection. We simply compute the vertex positions at the given ray
|
||||
* time and do a ray intersection with the resulting triangle.
|
||||
*/
|
||||
|
@@ -68,15 +68,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
|
||||
verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
|
||||
verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
|
||||
/* Compute refined position. */
|
||||
#ifdef __BVH_LOCAL__
|
||||
if (is_local) {
|
||||
sd->P = motion_triangle_refine_local(kg, sd, P, D, ray_t, isect_object, isect_prim, verts);
|
||||
}
|
||||
else
|
||||
#endif /* __BVH_LOCAL__*/
|
||||
{
|
||||
sd->P = motion_triangle_refine(kg, sd, P, D, ray_t, isect_object, isect_prim, verts);
|
||||
}
|
||||
sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
|
||||
/* Compute face normal. */
|
||||
float3 Ng;
|
||||
if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
|
||||
|
@@ -89,7 +89,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
|
||||
sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
|
||||
|
||||
/* vectors */
|
||||
sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
|
||||
sd->P = triangle_point_from_uv(kg, sd, isect->object, isect->prim, isect->u, isect->v);
|
||||
sd->Ng = Ng;
|
||||
sd->N = Ng;
|
||||
|
||||
@@ -190,40 +190,46 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
||||
#ifdef __OBJECT_MOTION__
|
||||
shader_setup_object_transforms(kg, sd, time);
|
||||
#endif
|
||||
}
|
||||
else if (lamp != LAMP_NONE) {
|
||||
sd->lamp = lamp;
|
||||
}
|
||||
|
||||
/* transform into world space */
|
||||
if (object_space) {
|
||||
object_position_transform_auto(kg, sd, &sd->P);
|
||||
object_normal_transform_auto(kg, sd, &sd->Ng);
|
||||
sd->N = sd->Ng;
|
||||
object_dir_transform_auto(kg, sd, &sd->I);
|
||||
}
|
||||
/* transform into world space */
|
||||
if (object_space) {
|
||||
object_position_transform_auto(kg, sd, &sd->P);
|
||||
object_normal_transform_auto(kg, sd, &sd->Ng);
|
||||
sd->N = sd->Ng;
|
||||
object_dir_transform_auto(kg, sd, &sd->I);
|
||||
}
|
||||
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
/* smooth normal */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
/* smooth normal */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_normal_transform_auto(kg, sd, &sd->N);
|
||||
}
|
||||
}
|
||||
|
||||
/* dPdu/dPdv */
|
||||
#ifdef __DPDU__
|
||||
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_normal_transform_auto(kg, sd, &sd->N);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
}
|
||||
}
|
||||
|
||||
/* dPdu/dPdv */
|
||||
#ifdef __DPDU__
|
||||
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = zero_float3();
|
||||
sd->dPdv = zero_float3();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lamp != LAMP_NONE) {
|
||||
sd->lamp = lamp;
|
||||
}
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = zero_float3();
|
||||
sd->dPdv = zero_float3();
|
||||
|
@@ -142,58 +142,23 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
|
||||
}
|
||||
#endif /* __BVH_LOCAL__ */
|
||||
|
||||
/* Refine triangle intersection to more precise hit point. For rays that travel
|
||||
* far the precision is often not so good, this reintersects the primitive from
|
||||
* a closer distance. */
|
||||
|
||||
/* Reintersections uses the paper:
|
||||
*
|
||||
* Tomas Moeller
|
||||
* Fast, minimum storage ray/triangle intersection
|
||||
* http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
|
||||
/**
|
||||
* Use the barycentric coordinates to get the intersection location
|
||||
*/
|
||||
|
||||
ccl_device_inline float3 triangle_refine(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
float3 P,
|
||||
float3 D,
|
||||
float t,
|
||||
const int isect_object,
|
||||
const int isect_prim)
|
||||
ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
const int isect_object,
|
||||
const int isect_prim,
|
||||
const float u,
|
||||
const float v)
|
||||
{
|
||||
#ifdef __INTERSECTION_REFINE__
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
if (UNLIKELY(t == 0.0f)) {
|
||||
return P;
|
||||
}
|
||||
const Transform tfm = object_get_inverse_transform(kg, sd);
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
D = transform_direction(&tfm, D * t);
|
||||
D = normalize_len(D, &t);
|
||||
}
|
||||
|
||||
P = P + D * t;
|
||||
|
||||
const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
|
||||
const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
|
||||
tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
|
||||
tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 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);
|
||||
float3 qvec = cross(tvec, edge1);
|
||||
float3 pvec = cross(D, edge2);
|
||||
float det = dot(edge1, pvec);
|
||||
if (det != 0.0f) {
|
||||
/* If determinant is zero it means ray lies in the plane of
|
||||
* the triangle. It is possible in theory due to watertight
|
||||
* nature of triangle intersection. For such cases we simply
|
||||
* don't refine intersection hoping it'll go all fine.
|
||||
*/
|
||||
float rt = dot(edge2, qvec) / det;
|
||||
P = P + D * rt;
|
||||
}
|
||||
float w = 1.0f - u - v;
|
||||
|
||||
float3 P = u * tri_a + v * tri_b + w * tri_c;
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_transform(kg, sd);
|
||||
@@ -201,65 +166,6 @@ ccl_device_inline float3 triangle_refine(KernelGlobals kg,
|
||||
}
|
||||
|
||||
return P;
|
||||
#else
|
||||
return P + D * t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Same as above, except that t is assumed to be in object space for
|
||||
* instancing.
|
||||
*/
|
||||
ccl_device_inline float3 triangle_refine_local(KernelGlobals kg,
|
||||
ccl_private ShaderData *sd,
|
||||
float3 P,
|
||||
float3 D,
|
||||
float t,
|
||||
const int isect_object,
|
||||
const int isect_prim)
|
||||
{
|
||||
#if defined(__KERNEL_GPU_RAYTRACING__)
|
||||
/* t is always in world space with OptiX and MetalRT. */
|
||||
return triangle_refine(kg, sd, P, D, t, isect_object, isect_prim);
|
||||
#else
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_inverse_transform(kg, sd);
|
||||
|
||||
P = transform_point(&tfm, P);
|
||||
D = transform_direction(&tfm, D);
|
||||
D = normalize(D);
|
||||
}
|
||||
|
||||
P = P + D * t;
|
||||
|
||||
# ifdef __INTERSECTION_REFINE__
|
||||
const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
|
||||
const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
|
||||
tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
|
||||
tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 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);
|
||||
float3 qvec = cross(tvec, edge1);
|
||||
float3 pvec = cross(D, edge2);
|
||||
float det = dot(edge1, pvec);
|
||||
if (det != 0.0f) {
|
||||
/* If determinant is zero it means ray lies in the plane of
|
||||
* the triangle. It is possible in theory due to watertight
|
||||
* nature of triangle intersection. For such cases we simply
|
||||
* don't refine intersection hoping it'll go all fine.
|
||||
*/
|
||||
float rt = dot(edge2, qvec) / det;
|
||||
P = P + D * rt;
|
||||
}
|
||||
# endif /* __INTERSECTION_REFINE__ */
|
||||
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
const Transform tfm = object_get_transform(kg, sd);
|
||||
P = transform_point(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -328,6 +328,12 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
|
||||
|
||||
/* Scene Intersection. */
|
||||
Intersection isect ccl_optional_struct_init;
|
||||
isect.object = OBJECT_NONE;
|
||||
isect.prim = PRIM_NONE;
|
||||
ray.self.object = last_isect_object;
|
||||
ray.self.prim = last_isect_prim;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
bool hit = scene_intersect(kg, &ray, visibility, &isect);
|
||||
|
||||
/* TODO: remove this and do it in the various intersection functions instead. */
|
||||
|
@@ -156,7 +156,10 @@ ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowSt
|
||||
/* Read ray from integrator state into local memory. */
|
||||
Ray ray ccl_optional_struct_init;
|
||||
integrator_state_read_shadow_ray(kg, state, &ray);
|
||||
|
||||
ray.self.object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, object);
|
||||
ray.self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim);
|
||||
ray.self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object);
|
||||
ray.self.light_prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, prim);
|
||||
/* Compute visibility. */
|
||||
const uint visibility = integrate_intersect_shadow_visibility(kg, state);
|
||||
|
||||
|
@@ -38,7 +38,10 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
|
||||
Ray volume_ray ccl_optional_struct_init;
|
||||
volume_ray.P = from_P;
|
||||
volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t);
|
||||
|
||||
volume_ray.self.object = INTEGRATOR_STATE(state, isect, object);
|
||||
volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim);
|
||||
volume_ray.self.light_object = OBJECT_NONE;
|
||||
volume_ray.self.light_prim = PRIM_NONE;
|
||||
/* Store to avoid global fetches on every intersection step. */
|
||||
const uint volume_stack_size = kernel_data.volume_stack_size;
|
||||
|
||||
@@ -68,7 +71,7 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
|
||||
volume_stack_enter_exit(kg, state, stack_sd);
|
||||
|
||||
/* Move ray forward. */
|
||||
volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
|
||||
volume_ray.P = stack_sd->P;
|
||||
if (volume_ray.t != FLT_MAX) {
|
||||
volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t);
|
||||
}
|
||||
@@ -91,6 +94,10 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s
|
||||
* fewest hits. */
|
||||
volume_ray.D = make_float3(0.0f, 0.0f, 1.0f);
|
||||
volume_ray.t = FLT_MAX;
|
||||
volume_ray.self.object = OBJECT_NONE;
|
||||
volume_ray.self.prim = PRIM_NONE;
|
||||
volume_ray.self.light_object = OBJECT_NONE;
|
||||
volume_ray.self.light_prim = PRIM_NONE;
|
||||
|
||||
int stack_index = 0, enclosed_index = 0;
|
||||
|
||||
@@ -203,7 +210,7 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s
|
||||
}
|
||||
|
||||
/* Move ray forward. */
|
||||
volume_ray.P = ray_offset(stack_sd->P, -stack_sd->Ng);
|
||||
volume_ray.P = stack_sd->P;
|
||||
++step;
|
||||
}
|
||||
#endif
|
||||
|
@@ -37,8 +37,9 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
|
||||
|
||||
/* Advance ray beyond light. */
|
||||
/* TODO: can we make this more numerically robust to avoid reintersecting the
|
||||
* same light in some cases? */
|
||||
const float3 new_ray_P = ray_offset(ray_P + ray_D * isect.t, ray_D);
|
||||
* same light in some cases? Ray should not intersect surface anymore as the
|
||||
* object and prim ids will prevent self intersection. */
|
||||
const float3 new_ray_P = ray_P + ray_D * isect.t;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = new_ray_P;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, t) -= isect.t;
|
||||
|
||||
@@ -46,7 +47,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
|
||||
const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
|
||||
ray_P -= ray_D * mis_ray_t;
|
||||
isect.t += mis_ray_t;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = mis_ray_t + isect.t;
|
||||
INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = isect.t;
|
||||
|
||||
LightSample ls ccl_optional_struct_init;
|
||||
const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray_P, ray_D, &ls);
|
||||
|
@@ -83,7 +83,10 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg,
|
||||
/* Setup shader data. */
|
||||
Ray ray ccl_optional_struct_init;
|
||||
integrator_state_read_shadow_ray(kg, state, &ray);
|
||||
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
/* Modify ray position and length to match current segment. */
|
||||
const float start_t = (hit == 0) ? 0.0f :
|
||||
INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t);
|
||||
@@ -149,7 +152,7 @@ ccl_device_inline bool integrate_transparent_shadow(KernelGlobals kg,
|
||||
const float last_hit_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, num_recorded_hits - 1, t);
|
||||
const float3 ray_P = INTEGRATOR_STATE(state, shadow_ray, P);
|
||||
const float3 ray_D = INTEGRATOR_STATE(state, shadow_ray, D);
|
||||
INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray_offset(ray_P + last_hit_t * ray_D, ray_D);
|
||||
INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray_P + last_hit_t * ray_D;
|
||||
INTEGRATOR_STATE_WRITE(state, shadow_ray, t) -= last_hit_t;
|
||||
}
|
||||
|
||||
|
@@ -182,6 +182,11 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
|
||||
|
||||
/* Write shadow ray and associated state to global memory. */
|
||||
integrator_state_write_shadow_ray(kg, shadow_state, &ray);
|
||||
// Save memory by storing the light and object indices in the shadow_isect
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
|
||||
|
||||
/* Copy state from main path to shadow path. */
|
||||
const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||
@@ -266,13 +271,11 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
|
||||
}
|
||||
|
||||
/* Setup ray. Note that clipping works through transparent bounces. */
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P,
|
||||
(label & LABEL_TRANSMIT) ? -sd->Ng : sd->Ng);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(bsdf_omega_in);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, t) = (label & LABEL_TRANSPARENT) ?
|
||||
INTEGRATOR_STATE(state, ray, t) - sd->ray_length :
|
||||
FLT_MAX;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(bsdf_domega_in);
|
||||
@@ -316,7 +319,7 @@ ccl_device_forceinline bool integrate_surface_volume_only_bounce(IntegratorState
|
||||
}
|
||||
|
||||
/* Setup ray position, direction stays unchanged. */
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = ray_offset(sd->P, -sd->Ng);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
|
||||
|
||||
/* Clipping works through transparent. */
|
||||
INTEGRATOR_STATE_WRITE(state, ray, t) -= sd->ray_length;
|
||||
@@ -360,10 +363,14 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
|
||||
}
|
||||
|
||||
Ray ray ccl_optional_struct_init;
|
||||
ray.P = ray_offset(sd->P, sd->Ng);
|
||||
ray.P = sd->P;
|
||||
ray.D = ao_D;
|
||||
ray.t = kernel_data.integrator.ao_bounces_distance;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = sd->object;
|
||||
ray.self.prim = sd->prim;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
|
||||
@@ -375,6 +382,10 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
|
||||
|
||||
/* Write shadow ray and associated state to global memory. */
|
||||
integrator_state_write_shadow_ray(kg, shadow_state, &ray);
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
|
||||
|
||||
/* Copy state from main path to shadow path. */
|
||||
const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||
|
@@ -791,6 +791,10 @@ ccl_device_forceinline void integrate_volume_direct_light(
|
||||
|
||||
/* Write shadow ray and associated state to global memory. */
|
||||
integrator_state_write_shadow_ray(kg, shadow_state, &ray);
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object;
|
||||
INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim;
|
||||
|
||||
/* Copy state from main path to shadow path. */
|
||||
const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce);
|
||||
@@ -873,11 +877,13 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
|
||||
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
|
||||
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_omega_in);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
|
||||
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
|
||||
INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(phase_domega_in);
|
||||
# endif
|
||||
// Save memory by storing last hit prim and object in isect
|
||||
INTEGRATOR_STATE_WRITE(state, isect, prim) = sd->prim;
|
||||
INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
|
||||
|
||||
/* Update throughput. */
|
||||
const float3 throughput = INTEGRATOR_STATE(state, path, throughput);
|
||||
|
@@ -61,6 +61,7 @@ KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_MEMBER(shadow_ray, int, object, KERNEL_FEATURE_PATH_TRACING)
|
||||
KERNEL_STRUCT_END(shadow_ray)
|
||||
|
||||
/*********************** Shadow Intersection result **************************/
|
||||
|
@@ -57,7 +57,6 @@ ccl_device int subsurface_bounce(KernelGlobals kg,
|
||||
|
||||
/* Pass along object info, reusing isect to save memory. */
|
||||
INTEGRATOR_STATE_WRITE(state, subsurface, Ng) = sd->Ng;
|
||||
INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object;
|
||||
|
||||
uint32_t path_flag = (INTEGRATOR_STATE(state, path, flag) & ~PATH_RAY_CAMERA) |
|
||||
((sc->type == CLOSURE_BSSRDF_BURLEY_ID) ? PATH_RAY_SUBSURFACE_DISK :
|
||||
@@ -165,10 +164,8 @@ ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState stat
|
||||
|
||||
if (object_flag & SD_OBJECT_INTERSECTS_VOLUME) {
|
||||
float3 P = INTEGRATOR_STATE(state, ray, P);
|
||||
const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
|
||||
const float3 offset_P = ray_offset(P, -Ng);
|
||||
|
||||
integrator_volume_stack_update_for_subsurface(kg, state, offset_P, ray.P);
|
||||
integrator_volume_stack_update_for_subsurface(kg, state, P, ray.P);
|
||||
}
|
||||
}
|
||||
# endif /* __VOLUME__ */
|
||||
|
@@ -99,6 +99,10 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
|
||||
ray.dP = ray_dP;
|
||||
ray.dD = differential_zero_compact();
|
||||
ray.time = time;
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = OBJECT_NONE;
|
||||
|
||||
/* Intersect with the same object. if multiple intersections are found it
|
||||
* will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */
|
||||
|
@@ -195,6 +195,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
|
||||
const float time = INTEGRATOR_STATE(state, ray, time);
|
||||
const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng);
|
||||
const int object = INTEGRATOR_STATE(state, isect, object);
|
||||
const int prim = INTEGRATOR_STATE(state, isect, prim);
|
||||
|
||||
/* Sample diffuse surface scatter into the object. */
|
||||
float3 D;
|
||||
@@ -205,12 +206,16 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
|
||||
}
|
||||
|
||||
/* Setup ray. */
|
||||
ray.P = ray_offset(P, -Ng);
|
||||
ray.P = P;
|
||||
ray.D = D;
|
||||
ray.t = FLT_MAX;
|
||||
ray.time = time;
|
||||
ray.dP = ray_dP;
|
||||
ray.dD = differential_zero_compact();
|
||||
ray.self.object = object;
|
||||
ray.self.prim = prim;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
|
||||
#ifndef __KERNEL_GPU_RAYTRACING__
|
||||
/* Compute or fetch object transforms. */
|
||||
@@ -377,7 +382,15 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
|
||||
* If yes, we will later use backwards guided sampling in order to have a decent
|
||||
* chance of connecting to it.
|
||||
* TODO: Maybe use less than 10 times the mean free path? */
|
||||
ray.t = (bounce == 0) ? max(t, 10.0f / (min3(sigma_t))) : t;
|
||||
if (bounce == 0) {
|
||||
ray.t = max(t, 10.0f / (min3(sigma_t)));
|
||||
}
|
||||
else {
|
||||
ray.t = t;
|
||||
/* After the first bounce the object can intersect the same surface again */
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
}
|
||||
scene_intersect_local(kg, &ray, &ss_isect, object, NULL, 1);
|
||||
hit = (ss_isect.num_hits > 0);
|
||||
|
||||
@@ -408,13 +421,6 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
|
||||
if (hit) {
|
||||
t = ray.t;
|
||||
}
|
||||
else if (bounce == 0) {
|
||||
/* Restore original position if nothing was hit after the first bounce,
|
||||
* without the ray_offset() that was added to avoid self-intersection.
|
||||
* Otherwise if that offset is relatively large compared to the scattering
|
||||
* radius, we never go back up high enough to exit the surface. */
|
||||
ray.P = P;
|
||||
}
|
||||
|
||||
/* Advance to new scatter location. */
|
||||
ray.P += t * ray.D;
|
||||
|
@@ -418,8 +418,8 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
|
||||
LightType type = (LightType)klight->type;
|
||||
ls->type = type;
|
||||
ls->shader = klight->shader_id;
|
||||
ls->object = PRIM_NONE;
|
||||
ls->prim = PRIM_NONE;
|
||||
ls->object = isect->object;
|
||||
ls->prim = isect->prim;
|
||||
ls->lamp = lamp;
|
||||
/* todo: missing texture coordinates */
|
||||
ls->t = isect->t;
|
||||
|
@@ -198,7 +198,7 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
|
||||
float NL = dot(sd->N, L);
|
||||
bool transmit = (NL < 0.0f);
|
||||
float3 Ng = (transmit ? -sd->Ng : sd->Ng);
|
||||
float3 P = ray_offset(sd->P, Ng);
|
||||
float3 P = sd->P;
|
||||
|
||||
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
|
||||
const float offset_cutoff =
|
||||
@@ -243,7 +243,7 @@ ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restri
|
||||
}
|
||||
else {
|
||||
/* other lights, avoid self-intersection */
|
||||
ray->D = ray_offset(ls->P, ls->Ng) - P;
|
||||
ray->D = ls->P - P;
|
||||
ray->D = normalize_len(ray->D, &ray->t);
|
||||
}
|
||||
}
|
||||
@@ -257,6 +257,12 @@ ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restri
|
||||
ray->dP = differential_make_compact(sd->dP);
|
||||
ray->dD = differential_zero_compact();
|
||||
ray->time = sd->time;
|
||||
|
||||
/* Fill in intersection surface and light details. */
|
||||
ray->self.prim = sd->prim;
|
||||
ray->self.object = sd->object;
|
||||
ray->self.light_prim = ls->prim;
|
||||
ray->self.light_object = ls->object;
|
||||
}
|
||||
|
||||
/* Create shadow ray towards light sample. */
|
||||
|
@@ -70,10 +70,14 @@ ccl_device float svm_ao(
|
||||
|
||||
/* Create ray. */
|
||||
Ray ray;
|
||||
ray.P = ray_offset(sd->P, N);
|
||||
ray.P = sd->P;
|
||||
ray.D = D.x * T + D.y * B + D.z * N;
|
||||
ray.t = max_dist;
|
||||
ray.time = sd->time;
|
||||
ray.self.object = sd->object;
|
||||
ray.self.prim = sd->prim;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
|
||||
|
@@ -196,6 +196,10 @@ ccl_device float3 svm_bevel(
|
||||
ray.dP = differential_zero_compact();
|
||||
ray.dD = differential_zero_compact();
|
||||
ray.time = sd->time;
|
||||
ray.self.object = OBJECT_NONE;
|
||||
ray.self.prim = PRIM_NONE;
|
||||
ray.self.light_object = OBJECT_NONE;
|
||||
ray.self.light_prim = PRIM_NONE;
|
||||
|
||||
/* Intersect with the same object. if multiple intersections are found it
|
||||
* will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */
|
||||
@@ -207,15 +211,24 @@ ccl_device float3 svm_bevel(
|
||||
/* Quickly retrieve P and Ng without setting up ShaderData. */
|
||||
float3 hit_P;
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
hit_P = triangle_refine_local(
|
||||
kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim);
|
||||
hit_P = triangle_point_from_uv(kg,
|
||||
sd,
|
||||
isect.hits[hit].object,
|
||||
isect.hits[hit].prim,
|
||||
isect.hits[hit].u,
|
||||
isect.hits[hit].v);
|
||||
}
|
||||
# ifdef __OBJECT_MOTION__
|
||||
else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
|
||||
float3 verts[3];
|
||||
motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
|
||||
hit_P = motion_triangle_refine_local(
|
||||
kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim, verts);
|
||||
hit_P = motion_triangle_point_from_uv(kg,
|
||||
sd,
|
||||
isect.hits[hit].object,
|
||||
isect.hits[hit].prim,
|
||||
isect.hits[hit].u,
|
||||
isect.hits[hit].v,
|
||||
verts);
|
||||
}
|
||||
# endif /* __OBJECT_MOTION__ */
|
||||
|
||||
|
@@ -512,12 +512,21 @@ typedef struct differential {
|
||||
|
||||
/* Ray */
|
||||
|
||||
typedef struct RaySelfPrimitives {
|
||||
int prim; /* Primitive the ray is starting from */
|
||||
int object; /* Instance prim is a part of */
|
||||
int light_prim; /* Light primitive */
|
||||
int light_object; /* Light object */
|
||||
} RaySelfPrimitives;
|
||||
|
||||
typedef struct Ray {
|
||||
float3 P; /* origin */
|
||||
float3 D; /* direction */
|
||||
float t; /* length of the ray */
|
||||
float time; /* time (for motion blur) */
|
||||
|
||||
RaySelfPrimitives self;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
float dP;
|
||||
float dD;
|
||||
|
@@ -291,7 +291,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
|
||||
include(CheckSymbolExists)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
|
||||
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
|
||||
if (HAVE_MEMFD_CREATE)
|
||||
if(HAVE_MEMFD_CREATE)
|
||||
add_definitions(-DHAVE_MEMFD_CREATE)
|
||||
endif()
|
||||
|
||||
@@ -307,7 +307,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
|
||||
pkg_get_variable(WAYLAND_SCANNER wayland-scanner wayland_scanner)
|
||||
|
||||
pkg_check_modules(wayland-protocols wayland-protocols>=1.15)
|
||||
if (${wayland-protocols_FOUND})
|
||||
if(${wayland-protocols_FOUND})
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
else()
|
||||
find_path(WAYLAND_PROTOCOLS_DIR
|
||||
@@ -316,7 +316,7 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT EXISTS ${WAYLAND_PROTOCOLS_DIR})
|
||||
if(NOT EXISTS ${WAYLAND_PROTOCOLS_DIR})
|
||||
message(FATAL_ERROR "path to wayland-protocols not found")
|
||||
endif()
|
||||
|
||||
@@ -518,11 +518,11 @@ if(WITH_XR_OPENXR)
|
||||
)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
list(APPEND XR_PLATFORM_DEFINES -DXR_OS_LINUX)
|
||||
if (WITH_GHOST_WAYLAND)
|
||||
if(WITH_GHOST_WAYLAND)
|
||||
list(APPEND XR_PLATFORM_DEFINES -DXR_USE_PLATFORM_WAYLAND)
|
||||
endif()
|
||||
if (WITH_GHOST_X11)
|
||||
if (WITH_GL_EGL)
|
||||
if(WITH_GHOST_X11)
|
||||
if(WITH_GL_EGL)
|
||||
list(APPEND XR_PLATFORM_DEFINES -DXR_USE_PLATFORM_EGL)
|
||||
else()
|
||||
list(APPEND XR_PLATFORM_DEFINES -DXR_USE_PLATFORM_XLIB)
|
||||
|
@@ -96,7 +96,7 @@ bool GHOST_ImeWin32::IsEnglishMode()
|
||||
!(conversion_modes_ & (IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE));
|
||||
}
|
||||
|
||||
bool GHOST_ImeWin32::IsImeKeyEvent(char ascii)
|
||||
bool GHOST_ImeWin32::IsImeKeyEvent(char ascii, GHOST_TKey key)
|
||||
{
|
||||
if (!(IsEnglishMode())) {
|
||||
/* In Chinese, Japanese, Korean, all alpha keys are processed by IME. */
|
||||
@@ -106,7 +106,8 @@ bool GHOST_ImeWin32::IsImeKeyEvent(char ascii)
|
||||
if (IsLanguage(IMELANG_JAPANESE) && (ascii >= ' ' && ascii <= '~')) {
|
||||
return true;
|
||||
}
|
||||
else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`/", ascii)) {
|
||||
else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`/", ascii) &&
|
||||
!(key == GHOST_kKeyNumpadPeriod)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -161,7 +161,7 @@ class GHOST_ImeWin32 {
|
||||
bool IsEnglishMode();
|
||||
|
||||
/* Checks a key whether IME has to do handling. */
|
||||
bool IsImeKeyEvent(char ascii);
|
||||
bool IsImeKeyEvent(char ascii, GHOST_TKey key);
|
||||
|
||||
/**
|
||||
* Create the IME windows, and allocate required resources for them.
|
||||
|
@@ -890,7 +890,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
|
||||
bool anyProcessed = false;
|
||||
NSEvent *event;
|
||||
|
||||
// TODO : implement timer ??
|
||||
/* TODO: implement timer? */
|
||||
#if 0
|
||||
do {
|
||||
GHOST_TimerManager* timerMgr = getTimerManager();
|
||||
|
@@ -1220,7 +1220,7 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
if (window->getImeInput()->IsImeKeyEvent(ascii)) {
|
||||
if (window->getImeInput()->IsImeKeyEvent(ascii, key)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif /* WITH_INPUT_IME */
|
||||
|
@@ -71,6 +71,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
m_mousePresent(false),
|
||||
m_inLiveResize(false),
|
||||
m_system(system),
|
||||
m_dropTarget(NULL),
|
||||
m_hWnd(0),
|
||||
m_hDC(0),
|
||||
m_isDialog(dialog),
|
||||
m_hasMouseCaptured(false),
|
||||
@@ -78,6 +80,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
m_nPressedButtons(0),
|
||||
m_customCursor(0),
|
||||
m_wantAlphaBackground(alphaBackground),
|
||||
m_Bar(NULL),
|
||||
m_wintab(NULL),
|
||||
m_lastPointerTabletData(GHOST_TABLET_DATA_NONE),
|
||||
m_normal_state(GHOST_kWindowStateNormal),
|
||||
@@ -129,8 +132,24 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
||||
m_hDC = ::GetDC(m_hWnd);
|
||||
|
||||
if (!setDrawingContextType(type)) {
|
||||
const char *title = "Blender - Unsupported Graphics Card Configuration";
|
||||
const char *text =
|
||||
"A graphics card and driver with support for OpenGL 3.3 or higher is "
|
||||
"required.\n\nInstalling the latest driver for your graphics card might resolve the "
|
||||
"issue.";
|
||||
if (GetSystemMetrics(SM_CMONITORS) > 1) {
|
||||
text =
|
||||
"A graphics card and driver with support for OpenGL 3.3 or higher is "
|
||||
"required.\n\nPlugging all monitors into your primary graphics card might resolve "
|
||||
"this issue. Installing the latest driver for your graphics card could also help.";
|
||||
}
|
||||
MessageBox(m_hWnd, text, title, MB_OK | MB_ICONERROR);
|
||||
::ReleaseDC(m_hWnd, m_hDC);
|
||||
::DestroyWindow(m_hWnd);
|
||||
m_hWnd = NULL;
|
||||
if (!parentwindow) {
|
||||
exit(0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -564,20 +583,13 @@ GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType ty
|
||||
(m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
|
||||
GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
|
||||
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
}
|
||||
else {
|
||||
MessageBox(m_hWnd,
|
||||
"A graphics card and driver with support for OpenGL 3.3 or higher is required.\n"
|
||||
"Installing the latest driver for your graphics card may resolve the issue.\n\n"
|
||||
"The program will now close.",
|
||||
"Blender - Unsupported Graphics Card or Driver",
|
||||
MB_OK | MB_ICONERROR);
|
||||
if (context && !context->initializeDrawingContext()) {
|
||||
delete context;
|
||||
exit(0);
|
||||
context = nullptr;
|
||||
}
|
||||
|
||||
return context;
|
||||
|
||||
#elif defined(WITH_GL_PROFILE_COMPAT)
|
||||
// ask for 2.1 context, driver gives any GL version >= 2.1
|
||||
// (hopefully the latest compatibility profile)
|
||||
|
@@ -86,6 +86,7 @@ void GHOST_XrContext::initialize(const GHOST_XrContextCreateInfo *create_info)
|
||||
initApiLayers();
|
||||
initExtensions();
|
||||
if (isDebugMode()) {
|
||||
printSDKVersion();
|
||||
printAvailableAPILayersAndExtensionsInfo();
|
||||
}
|
||||
|
||||
@@ -156,6 +157,16 @@ void GHOST_XrContext::storeInstanceProperties()
|
||||
/** \name Debug Printing
|
||||
* \{ */
|
||||
|
||||
void GHOST_XrContext::printSDKVersion()
|
||||
{
|
||||
const XrVersion sdk_version = XR_CURRENT_API_VERSION;
|
||||
|
||||
printf("OpenXR SDK Version: %u.%u.%u\n",
|
||||
XR_VERSION_MAJOR(sdk_version),
|
||||
XR_VERSION_MINOR(sdk_version),
|
||||
XR_VERSION_PATCH(sdk_version));
|
||||
}
|
||||
|
||||
void GHOST_XrContext::printInstanceInfo()
|
||||
{
|
||||
assert(m_oxr->instance != XR_NULL_HANDLE);
|
||||
|
@@ -126,6 +126,7 @@ class GHOST_XrContext : public GHOST_IXrContext {
|
||||
void storeInstanceProperties();
|
||||
void initDebugMessenger();
|
||||
|
||||
void printSDKVersion();
|
||||
void printInstanceInfo();
|
||||
void printAvailableAPILayersAndExtensionsInfo();
|
||||
void printExtensionsAndAPILayersToEnable();
|
||||
|
@@ -292,7 +292,7 @@ target_link_libraries(multitest_c
|
||||
guardedalloc_lib
|
||||
wcwidth_lib
|
||||
${OPENGL_gl_LIBRARY}
|
||||
${FREETYPE_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${CMAKE_DL_LIBS}
|
||||
${PLATFORM_LINKLIBS}
|
||||
|
@@ -39,8 +39,8 @@
|
||||
* second intern/ module with MEM_ prefix, for use in c++.
|
||||
*
|
||||
* \subsection memdependencies Dependencies
|
||||
* - stdlib
|
||||
* - stdio
|
||||
* - `stdlib`
|
||||
* - `stdio`
|
||||
*
|
||||
* \subsection memdocs API Documentation
|
||||
* See \ref MEM_guardedalloc.h
|
||||
|
@@ -56,7 +56,6 @@ if(WITH_INTERNATIONAL)
|
||||
list(APPEND LIB
|
||||
${BOOST_LIBRARIES}
|
||||
)
|
||||
add_definitions(-DWITH_INTERNATIONAL)
|
||||
add_definitions(${BOOST_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
|
@@ -298,7 +298,7 @@ def xml2rna(
|
||||
del value_xml_split
|
||||
tp_name = 'ARRAY'
|
||||
|
||||
# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
|
||||
# print(" %s.%s (%s) --- %s" % (type(value).__name__, attr, tp_name, subvalue_type))
|
||||
try:
|
||||
setattr(value, attr, value_xml_coerce)
|
||||
except ValueError:
|
||||
@@ -340,7 +340,6 @@ def xml2rna(
|
||||
|
||||
else:
|
||||
# print(elems)
|
||||
|
||||
if len(elems) == 1:
|
||||
# sub node named by its type
|
||||
child_xml_real, = elems
|
||||
@@ -376,7 +375,6 @@ def _get_context_val(context, path):
|
||||
|
||||
|
||||
def xml_file_run(context, filepath, rna_map):
|
||||
|
||||
import xml.dom.minidom
|
||||
|
||||
xml_nodes = xml.dom.minidom.parse(filepath)
|
||||
@@ -391,27 +389,25 @@ def xml_file_run(context, filepath, rna_map):
|
||||
value = _get_context_val(context, rna_path)
|
||||
|
||||
if value is not Ellipsis and value is not None:
|
||||
print(" loading XML: %r -> %r" % (filepath, rna_path))
|
||||
# print(" loading XML: %r -> %r" % (filepath, rna_path))
|
||||
xml2rna(xml_node, root_rna=value)
|
||||
|
||||
|
||||
def xml_file_write(context, filepath, rna_map, *, skip_typemap=None):
|
||||
with open(filepath, "w", encoding="utf-8") as file:
|
||||
fw = file.write
|
||||
fw("<bpy>\n")
|
||||
|
||||
file = open(filepath, "w", encoding="utf-8")
|
||||
fw = file.write
|
||||
|
||||
fw("<bpy>\n")
|
||||
|
||||
for rna_path, _xml_tag in rna_map:
|
||||
# xml_tag is ignored, we get this from the rna
|
||||
value = _get_context_val(context, rna_path)
|
||||
rna2xml(fw,
|
||||
for rna_path, _xml_tag in rna_map:
|
||||
# xml_tag is ignored, we get this from the rna
|
||||
value = _get_context_val(context, rna_path)
|
||||
rna2xml(
|
||||
fw=fw,
|
||||
root_rna=value,
|
||||
method='ATTR',
|
||||
root_ident=" ",
|
||||
ident_val=" ",
|
||||
skip_typemap=skip_typemap,
|
||||
)
|
||||
)
|
||||
|
||||
fw("</bpy>\n")
|
||||
file.close()
|
||||
fw("</bpy>\n")
|
||||
|
@@ -2961,93 +2961,75 @@ class WM_MT_splash_quick_setup(Menu):
|
||||
bl_label = "Quick Setup"
|
||||
|
||||
def draw(self, context):
|
||||
wm = context.window_manager
|
||||
# prefs = context.preferences
|
||||
|
||||
layout = self.layout
|
||||
|
||||
layout.operator_context = 'EXEC_DEFAULT'
|
||||
|
||||
layout.label(text="Quick Setup")
|
||||
|
||||
split = layout.split(factor=0.25)
|
||||
split = layout.split(factor=0.14) # Left margin.
|
||||
split.label()
|
||||
split = split.split(factor=2.0 / 3.0)
|
||||
split = split.split(factor=0.73) # Content width.
|
||||
|
||||
col = split.column()
|
||||
|
||||
col.use_property_split = True
|
||||
col.use_property_decorate = False
|
||||
|
||||
# Languages.
|
||||
if bpy.app.build_options.international:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Language")
|
||||
prefs = context.preferences
|
||||
sub.prop(prefs.view, "language", text="")
|
||||
col.prop(prefs.view, "language")
|
||||
col.separator()
|
||||
|
||||
col.separator()
|
||||
# Shortcuts.
|
||||
wm = context.window_manager
|
||||
kc = wm.keyconfigs.active
|
||||
kc_prefs = kc.preferences
|
||||
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Shortcuts")
|
||||
text = bpy.path.display_name(wm.keyconfigs.active.name)
|
||||
sub = col.column(heading="Shortcuts")
|
||||
text = bpy.path.display_name(kc.name)
|
||||
if not text:
|
||||
text = "Blender"
|
||||
sub.menu("USERPREF_MT_keyconfigs", text=text)
|
||||
|
||||
kc = wm.keyconfigs.active
|
||||
kc_prefs = kc.preferences
|
||||
has_select_mouse = hasattr(kc_prefs, "select_mouse")
|
||||
if has_select_mouse:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Select With")
|
||||
sub.row().prop(kc_prefs, "select_mouse", expand=True)
|
||||
has_select_mouse = True
|
||||
col.row().prop(kc_prefs, "select_mouse", text="Select With", expand=True)
|
||||
|
||||
has_spacebar_action = hasattr(kc_prefs, "spacebar_action")
|
||||
if has_spacebar_action:
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Spacebar")
|
||||
sub.row().prop(kc_prefs, "spacebar_action", expand=True)
|
||||
has_select_mouse = True
|
||||
col.row().prop(kc_prefs, "spacebar_action", text="Spacebar")
|
||||
|
||||
col.separator()
|
||||
|
||||
sub = col.split(factor=0.35)
|
||||
row = sub.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text="Theme")
|
||||
# Themes.
|
||||
sub = col.column(heading="Theme")
|
||||
label = bpy.types.USERPREF_MT_interface_theme_presets.bl_label
|
||||
if label == "Presets":
|
||||
label = "Blender Dark"
|
||||
sub.menu("USERPREF_MT_interface_theme_presets", text=label)
|
||||
|
||||
# Keep height constant
|
||||
# Keep height constant.
|
||||
if not has_select_mouse:
|
||||
col.label()
|
||||
if not has_spacebar_action:
|
||||
col.label()
|
||||
|
||||
layout.label()
|
||||
layout.separator(factor=2.0)
|
||||
|
||||
row = layout.row()
|
||||
# Save settings buttons.
|
||||
sub = layout.row()
|
||||
|
||||
sub = row.row()
|
||||
old_version = bpy.types.PREFERENCES_OT_copy_prev.previous_version()
|
||||
if bpy.types.PREFERENCES_OT_copy_prev.poll(context) and old_version:
|
||||
sub.operator("preferences.copy_prev", text=iface_("Load %d.%d Settings", "Operator") % old_version)
|
||||
sub.operator("preferences.copy_prev", text="Load %d.%d Settings" % old_version)
|
||||
sub.operator("wm.save_userpref", text="Save New Settings")
|
||||
else:
|
||||
sub.label()
|
||||
sub.label()
|
||||
sub.operator("wm.save_userpref", text="Next")
|
||||
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
layout.separator(factor=2.4)
|
||||
|
||||
|
||||
class WM_MT_splash(Menu):
|
||||
|
@@ -761,6 +761,15 @@ class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel):
|
||||
col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="")
|
||||
col.separator()
|
||||
col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="")
|
||||
col.menu("ASSETBROWSER_MT_metadata_preview_menu", icon='DOWNARROW_HLT', text="")
|
||||
|
||||
|
||||
class ASSETBROWSER_MT_metadata_preview_menu(bpy.types.Menu):
|
||||
bl_label = "Preview"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator("ed.lib_id_generate_preview_from_object", text="Render Active Object")
|
||||
|
||||
|
||||
class ASSETBROWSER_PT_metadata_tags(asset_utils.AssetMetaDataPanel, Panel):
|
||||
@@ -840,6 +849,7 @@ classes = (
|
||||
ASSETBROWSER_MT_view,
|
||||
ASSETBROWSER_MT_select,
|
||||
ASSETBROWSER_MT_edit,
|
||||
ASSETBROWSER_MT_metadata_preview_menu,
|
||||
ASSETBROWSER_PT_metadata,
|
||||
ASSETBROWSER_PT_metadata_preview,
|
||||
ASSETBROWSER_PT_metadata_tags,
|
||||
|
@@ -2316,7 +2316,6 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
|
||||
context, (
|
||||
({"property": "use_undo_legacy"}, "T60695"),
|
||||
({"property": "override_auto_resync"}, "T83811"),
|
||||
({"property": "proxy_to_override_auto_conversion"}, "T91671"),
|
||||
({"property": "use_cycles_debug"}, None),
|
||||
({"property": "use_geometry_nodes_legacy"}, "T91274"),
|
||||
({"property": "show_asset_debug_info"}, None),
|
||||
|
@@ -547,6 +547,8 @@ compositor_node_categories = [
|
||||
NodeItem("CompositorNodeCombYUVA"),
|
||||
NodeItem("CompositorNodeSepYCCA"),
|
||||
NodeItem("CompositorNodeCombYCCA"),
|
||||
NodeItem("CompositorNodeSeparateXYZ"),
|
||||
NodeItem("CompositorNodeCombineXYZ"),
|
||||
NodeItem("CompositorNodeSwitchView"),
|
||||
NodeItem("CompositorNodeConvertColorSpace"),
|
||||
]),
|
||||
|
@@ -27,7 +27,7 @@ if(WITH_CLANG_TIDY AND NOT MSVC)
|
||||
message(WARNING "Currently Clang-Tidy might fail with GCC toolchain, switch to Clang toolchain if that happens")
|
||||
if(COMMAND target_precompile_headers)
|
||||
message(STATUS "Clang-Tidy and GCC precompiled headers are incompatible, disabling precompiled headers")
|
||||
set(CMAKE_DISABLE_PRECOMPILE_HEADERS On)
|
||||
set(CMAKE_DISABLE_PRECOMPILE_HEADERS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@@ -54,7 +54,7 @@ set(LIB
|
||||
bf_gpu
|
||||
bf_intern_guardedalloc
|
||||
|
||||
${FREETYPE_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
@@ -63,10 +63,6 @@ if(WIN32)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_INTERNATIONAL)
|
||||
add_definitions(-DWITH_INTERNATIONAL)
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
add_definitions(-DWITH_PYTHON)
|
||||
list(APPEND INC
|
||||
|
@@ -104,14 +104,6 @@ typedef enum DerivedMeshType {
|
||||
DM_TYPE_CCGDM,
|
||||
} DerivedMeshType;
|
||||
|
||||
typedef enum DMDirtyFlag {
|
||||
/* dm has valid tessellated faces, but tessellated CDDATA need to be updated. */
|
||||
DM_DIRTY_TESS_CDLAYERS = 1 << 0,
|
||||
|
||||
/* check this with modifier dependsOnNormals callback to see if normals need recalculation */
|
||||
DM_DIRTY_NORMALS = 1 << 1,
|
||||
} DMDirtyFlag;
|
||||
|
||||
typedef struct DerivedMesh DerivedMesh;
|
||||
struct DerivedMesh {
|
||||
/** Private DerivedMesh data, only for internal DerivedMesh use */
|
||||
@@ -120,7 +112,6 @@ struct DerivedMesh {
|
||||
int needsFree; /* checked on ->release, is set to 0 for cached results */
|
||||
int deformedOnly; /* set by modifier stack if only deformed from original */
|
||||
DerivedMeshType type;
|
||||
DMDirtyFlag dirty;
|
||||
|
||||
/**
|
||||
* \warning Typical access is done via #getLoopTriArray, #getNumLoopTri.
|
||||
@@ -139,9 +130,6 @@ struct DerivedMesh {
|
||||
|
||||
short tangent_mask; /* which tangent layers are calculated */
|
||||
|
||||
/** Calculate vert and face normals */
|
||||
void (*calcNormals)(DerivedMesh *dm);
|
||||
|
||||
/** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */
|
||||
void (*recalcLoopTri)(DerivedMesh *dm);
|
||||
/** accessor functions */
|
||||
@@ -164,7 +152,6 @@ struct DerivedMesh {
|
||||
*/
|
||||
struct MVert *(*getVertArray)(DerivedMesh *dm);
|
||||
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
|
||||
struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
|
||||
struct MLoop *(*getLoopArray)(DerivedMesh *dm);
|
||||
struct MPoly *(*getPolyArray)(DerivedMesh *dm);
|
||||
|
||||
@@ -173,7 +160,6 @@ struct DerivedMesh {
|
||||
*/
|
||||
void (*copyVertArray)(DerivedMesh *dm, struct MVert *r_vert);
|
||||
void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *r_edge);
|
||||
void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *r_face);
|
||||
void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *r_loop);
|
||||
void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *r_poly);
|
||||
|
||||
@@ -182,37 +168,18 @@ struct DerivedMesh {
|
||||
*/
|
||||
struct MVert *(*dupVertArray)(DerivedMesh *dm);
|
||||
struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
|
||||
struct MFace *(*dupTessFaceArray)(DerivedMesh *dm);
|
||||
struct MLoop *(*dupLoopArray)(DerivedMesh *dm);
|
||||
struct MPoly *(*dupPolyArray)(DerivedMesh *dm);
|
||||
|
||||
/** Return a pointer to a single element of vert/edge/face custom data
|
||||
* from the derived mesh (this gives a pointer to the actual data, not
|
||||
* a copy)
|
||||
*/
|
||||
void *(*getVertData)(DerivedMesh *dm, int index, int type);
|
||||
void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
|
||||
void *(*getTessFaceData)(DerivedMesh *dm, int index, int type);
|
||||
void *(*getPolyData)(DerivedMesh *dm, int index, int type);
|
||||
|
||||
/** Return a pointer to the entire array of vert/edge/face custom data
|
||||
* from the derived mesh (this gives a pointer to the actual data, not
|
||||
* a copy)
|
||||
*/
|
||||
void *(*getVertDataArray)(DerivedMesh *dm, int type);
|
||||
void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
|
||||
void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
|
||||
void *(*getLoopDataArray)(DerivedMesh *dm, int type);
|
||||
void *(*getPolyDataArray)(DerivedMesh *dm, int type);
|
||||
|
||||
/** Retrieves the base CustomData structures for
|
||||
* verts/edges/tessfaces/loops/faces. */
|
||||
CustomData *(*getVertDataLayout)(DerivedMesh *dm);
|
||||
CustomData *(*getEdgeDataLayout)(DerivedMesh *dm);
|
||||
CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm);
|
||||
CustomData *(*getLoopDataLayout)(DerivedMesh *dm);
|
||||
CustomData *(*getPolyDataLayout)(DerivedMesh *dm);
|
||||
|
||||
/** Optional grid access for subsurf */
|
||||
int (*getNumGrids)(DerivedMesh *dm);
|
||||
int (*getGridSize)(DerivedMesh *dm);
|
||||
@@ -231,11 +198,6 @@ struct DerivedMesh {
|
||||
|
||||
/** Get smooth vertex normal, undefined if index is not valid */
|
||||
void (*getVertNo)(DerivedMesh *dm, int index, float r_no[3]);
|
||||
void (*getPolyNo)(DerivedMesh *dm, int index, float r_no[3]);
|
||||
|
||||
/** Get a map of vertices to faces
|
||||
*/
|
||||
const struct MeshElemMap *(*getPolyMap)(struct Object *ob, DerivedMesh *dm);
|
||||
|
||||
/** Release reference to the DerivedMesh. This function decides internally
|
||||
* if the DerivedMesh will be freed, or cached for later use. */
|
||||
@@ -265,15 +227,6 @@ void DM_init(DerivedMesh *dm,
|
||||
* Utility function to initialize a DerivedMesh for the desired number
|
||||
* of vertices, edges and faces, with a layer setup copied from source
|
||||
*/
|
||||
void DM_from_template_ex(DerivedMesh *dm,
|
||||
DerivedMesh *source,
|
||||
DerivedMeshType type,
|
||||
int numVerts,
|
||||
int numEdges,
|
||||
int numTessFaces,
|
||||
int numLoops,
|
||||
int numPolys,
|
||||
const struct CustomData_MeshMasks *mask);
|
||||
void DM_from_template(DerivedMesh *dm,
|
||||
DerivedMesh *source,
|
||||
DerivedMeshType type,
|
||||
@@ -303,25 +256,8 @@ void DM_set_only_copy(DerivedMesh *dm, const struct CustomData_MeshMasks *mask);
|
||||
|
||||
void DM_add_vert_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
|
||||
void DM_add_edge_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
|
||||
void DM_add_tessface_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
|
||||
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
|
||||
void DM_add_poly_layer(struct DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer);
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Custom Data Access Functions
|
||||
*
|
||||
* \return pointer to data from first layer which matches type
|
||||
* if they return NULL for valid indices, data doesn't exist.
|
||||
* \note these return pointers - any change modifies the internals of the mesh.
|
||||
* \{ */
|
||||
|
||||
void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
|
||||
void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
|
||||
void *DM_get_tessface_data(struct DerivedMesh *dm, int index, int type);
|
||||
void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type);
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Custom Data Layer Access Functions
|
||||
*
|
||||
@@ -332,7 +268,6 @@ void *DM_get_poly_data(struct DerivedMesh *dm, int index, int type);
|
||||
|
||||
void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
|
||||
void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
|
||||
void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
|
||||
void *DM_get_poly_data_layer(struct DerivedMesh *dm, int type);
|
||||
void *DM_get_loop_data_layer(struct DerivedMesh *dm, int type);
|
||||
|
||||
@@ -354,8 +289,6 @@ void DM_copy_vert_data(struct DerivedMesh *source,
|
||||
*/
|
||||
void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
|
||||
|
||||
void DM_ensure_normals(DerivedMesh *dm);
|
||||
|
||||
/**
|
||||
* Ensure the array is large enough.
|
||||
*
|
||||
|
@@ -31,7 +31,7 @@ extern "C" {
|
||||
*/
|
||||
|
||||
/* Blender major and minor version. */
|
||||
#define BLENDER_VERSION 301
|
||||
#define BLENDER_VERSION 302
|
||||
/* Blender patch version for bugfix releases. */
|
||||
#define BLENDER_VERSION_PATCH 0
|
||||
/** Blender release cycle stage: alpha/beta/rc/release. */
|
||||
@@ -39,7 +39,7 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 5
|
||||
#define BLENDER_FILE_SUBVERSION 1
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
@@ -46,7 +46,7 @@ void *BKE_camera_add(struct Main *bmain, const char *name);
|
||||
/**
|
||||
* Get the camera's DOF value, takes the DOF object into account.
|
||||
*/
|
||||
float BKE_camera_object_dof_distance(struct Object *ob);
|
||||
float BKE_camera_object_dof_distance(const struct Object *ob);
|
||||
|
||||
int BKE_camera_sensor_fit(int sensor_fit, float sizex, float sizey);
|
||||
float BKE_camera_sensor_size(int sensor_fit, float sensor_x, float sensor_y);
|
||||
|
@@ -436,6 +436,12 @@ int CustomData_get_render_layer(const struct CustomData *data, int type);
|
||||
int CustomData_get_clone_layer(const struct CustomData *data, int type);
|
||||
int CustomData_get_stencil_layer(const struct CustomData *data, int type);
|
||||
|
||||
/**
|
||||
* Returns name of the active layer of the given type or NULL
|
||||
* if no such active layer is defined.
|
||||
*/
|
||||
const char *CustomData_get_active_layer_name(const struct CustomData *data, int type);
|
||||
|
||||
/**
|
||||
* Copies the data from source to the data element at index in the first layer of type
|
||||
* no effect if there is no layer of type.
|
||||
|
@@ -24,6 +24,8 @@
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -561,19 +563,27 @@ struct GPUTexture *BKE_image_get_gpu_tilemap(struct Image *image,
|
||||
* Is the alpha of the `GPUTexture` for a given image/ibuf premultiplied.
|
||||
*/
|
||||
bool BKE_image_has_gpu_texture_premultiplied_alpha(struct Image *image, struct ImBuf *ibuf);
|
||||
|
||||
/**
|
||||
* Partial update of texture for texture painting.
|
||||
* This is often much quicker than fully updating the texture for high resolution images.
|
||||
*/
|
||||
void BKE_image_update_gputexture(
|
||||
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
|
||||
|
||||
/**
|
||||
* Mark areas on the #GPUTexture that needs to be updated. The areas are marked in chunks.
|
||||
* The next time the #GPUTexture is used these tiles will be refreshes. This saves time
|
||||
* when writing to the same place multiple times This happens for during foreground rendering.
|
||||
*/
|
||||
void BKE_image_update_gputexture_delayed(
|
||||
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h);
|
||||
void BKE_image_update_gputexture_delayed(struct Image *ima,
|
||||
struct ImageTile *image_tile,
|
||||
struct ImBuf *ibuf,
|
||||
int x,
|
||||
int y,
|
||||
int w,
|
||||
int h);
|
||||
|
||||
/**
|
||||
* Called on entering and exiting texture paint mode,
|
||||
* temporary disabling/enabling mipmapping on all images for quick texture
|
||||
@@ -591,6 +601,32 @@ bool BKE_image_remove_renderslot(struct Image *ima, struct ImageUser *iuser, int
|
||||
struct RenderSlot *BKE_image_get_renderslot(struct Image *ima, int index);
|
||||
bool BKE_image_clear_renderslot(struct Image *ima, struct ImageUser *iuser, int slot);
|
||||
|
||||
/* --- image_partial_update.cc --- */
|
||||
/** Image partial updates. */
|
||||
struct PartialUpdateUser;
|
||||
|
||||
/**
|
||||
* \brief Create a new PartialUpdateUser. An Object that contains data to use partial updates.
|
||||
*/
|
||||
struct PartialUpdateUser *BKE_image_partial_update_create(const struct Image *image);
|
||||
|
||||
/**
|
||||
* \brief free a partial update user.
|
||||
*/
|
||||
void BKE_image_partial_update_free(struct PartialUpdateUser *user);
|
||||
|
||||
/* --- partial updater (image side) --- */
|
||||
struct PartialUpdateRegister;
|
||||
|
||||
void BKE_image_partial_update_register_free(struct Image *image);
|
||||
/** \brief Mark a region of the image to update. */
|
||||
void BKE_image_partial_update_mark_region(struct Image *image,
|
||||
const struct ImageTile *image_tile,
|
||||
const struct ImBuf *image_buffer,
|
||||
const rcti *updated_region);
|
||||
/** \brief Mark the whole image to be updated. */
|
||||
void BKE_image_partial_update_mark_full_update(struct Image *image);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
298
source/blender/blenkernel/BKE_image_partial_update.hh
Normal file
298
source/blender/blenkernel/BKE_image_partial_update.hh
Normal file
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Copyright 2021, Blender Foundation.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* To reduce the overhead of image processing this file contains a mechanism to detect areas of the
|
||||
* image that are changed. These areas are organized in chunks. Changes that happen over time are
|
||||
* organized in changesets.
|
||||
*
|
||||
* A common use case is to update #GPUTexture for drawing where only that part is uploaded that
|
||||
* only changed.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_rect.h"
|
||||
|
||||
#include "DNA_image_types.h"
|
||||
|
||||
extern "C" {
|
||||
struct PartialUpdateUser;
|
||||
struct PartialUpdateRegister;
|
||||
}
|
||||
|
||||
namespace blender::bke::image {
|
||||
|
||||
using TileNumber = int;
|
||||
|
||||
namespace partial_update {
|
||||
|
||||
/* --- image_partial_update.cc --- */
|
||||
/** Image partial updates. */
|
||||
|
||||
/**
|
||||
* \brief Result codes of #BKE_image_partial_update_collect_changes.
|
||||
*/
|
||||
enum class ePartialUpdateCollectResult {
|
||||
/** \brief Unable to construct partial updates. Caller should perform a full update. */
|
||||
FullUpdateNeeded,
|
||||
|
||||
/** \brief No changes detected since the last time requested. */
|
||||
NoChangesDetected,
|
||||
|
||||
/** \brief Changes detected since the last time requested. */
|
||||
PartialChangesDetected,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A region to update.
|
||||
*
|
||||
* Data is organized in tiles. These tiles are in texel space (1 unit is a single texel). When
|
||||
* tiles are requested they are merged with neighboring tiles.
|
||||
*/
|
||||
struct PartialUpdateRegion {
|
||||
/** \brief region of the image that has been updated. Region can be bigger than actual changes.
|
||||
*/
|
||||
struct rcti region;
|
||||
|
||||
/**
|
||||
* \brief Tile number (UDIM) that this region belongs to.
|
||||
*/
|
||||
TileNumber tile_number;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return codes of #BKE_image_partial_update_get_next_change.
|
||||
*/
|
||||
enum class ePartialUpdateIterResult {
|
||||
/** \brief no tiles left when iterating over tiles. */
|
||||
Finished = 0,
|
||||
|
||||
/** \brief a chunk was available and has been loaded. */
|
||||
ChangeAvailable = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief collect the partial update since the last request.
|
||||
*
|
||||
* Invoke #BKE_image_partial_update_get_next_change to iterate over the collected tiles.
|
||||
*
|
||||
* \returns ePartialUpdateCollectResult::FullUpdateNeeded: called should not use partial updates
|
||||
* but recalculate the full image. This result can be expected when called for the first time for a
|
||||
* user and when it isn't possible to reconstruct the changes as the internal state doesn't have
|
||||
* enough data stored. ePartialUpdateCollectResult::NoChangesDetected: The have been no changes
|
||||
* detected since last invoke for the same user.
|
||||
* ePartialUpdateCollectResult::PartialChangesDetected: Parts of the image has been updated since
|
||||
* last invoke for the same user. The changes can be read by using
|
||||
* #BKE_image_partial_update_get_next_change.
|
||||
*/
|
||||
ePartialUpdateCollectResult BKE_image_partial_update_collect_changes(
|
||||
struct Image *image, struct PartialUpdateUser *user);
|
||||
|
||||
ePartialUpdateIterResult BKE_image_partial_update_get_next_change(
|
||||
struct PartialUpdateUser *user, struct PartialUpdateRegion *r_region);
|
||||
|
||||
/** \brief Abstract class to load tile data when using the PartialUpdateChecker. */
|
||||
class AbstractTileData {
|
||||
protected:
|
||||
virtual ~AbstractTileData() = default;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Load the data for the given tile_number.
|
||||
*
|
||||
* Invoked when changes are on a different tile compared to the previous tile..
|
||||
*/
|
||||
virtual void init_data(TileNumber tile_number) = 0;
|
||||
/**
|
||||
* \brief Unload the data that has been loaded.
|
||||
*
|
||||
* Invoked when changes are on a different tile compared to the previous tile or when finished
|
||||
* iterating over the changes.
|
||||
*/
|
||||
virtual void free_data() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Class to not load any tile specific data when iterating over changes.
|
||||
*/
|
||||
class NoTileData : AbstractTileData {
|
||||
public:
|
||||
NoTileData(Image *UNUSED(image), ImageUser *UNUSED(image_user))
|
||||
{
|
||||
}
|
||||
|
||||
void init_data(TileNumber UNUSED(new_tile_number)) override
|
||||
{
|
||||
}
|
||||
|
||||
void free_data() override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Load the ImageTile and ImBuf associated with the partial change.
|
||||
*/
|
||||
class ImageTileData : AbstractTileData {
|
||||
public:
|
||||
/**
|
||||
* \brief Not owned Image that is being iterated over.
|
||||
*/
|
||||
Image *image;
|
||||
|
||||
/**
|
||||
* \brief Local copy of the image user.
|
||||
*
|
||||
* The local copy is required so we don't change the image user of the caller.
|
||||
* We need to change it in order to request data for a specific tile.
|
||||
*/
|
||||
ImageUser image_user = {0};
|
||||
|
||||
/**
|
||||
* \brief ImageTile associated with the loaded tile.
|
||||
* Data is not owned by this instance but by the `image`.
|
||||
*/
|
||||
ImageTile *tile = nullptr;
|
||||
|
||||
/**
|
||||
* \brief ImBuf of the loaded tile.
|
||||
*
|
||||
* Can be nullptr when the file doesn't exist or when the tile hasn't been initialized.
|
||||
*/
|
||||
ImBuf *tile_buffer = nullptr;
|
||||
|
||||
ImageTileData(Image *image, ImageUser *image_user) : image(image)
|
||||
{
|
||||
if (image_user != nullptr) {
|
||||
this->image_user = *image_user;
|
||||
}
|
||||
}
|
||||
|
||||
void init_data(TileNumber new_tile_number) override
|
||||
{
|
||||
image_user.tile = new_tile_number;
|
||||
tile = BKE_image_get_tile(image, new_tile_number);
|
||||
tile_buffer = BKE_image_acquire_ibuf(image, &image_user, NULL);
|
||||
}
|
||||
|
||||
void free_data() override
|
||||
{
|
||||
BKE_image_release_ibuf(image, tile_buffer, nullptr);
|
||||
tile = nullptr;
|
||||
tile_buffer = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TileData = NoTileData> struct PartialUpdateChecker {
|
||||
|
||||
/**
|
||||
* \brief Not owned Image that is being iterated over.
|
||||
*/
|
||||
Image *image;
|
||||
ImageUser *image_user;
|
||||
|
||||
/**
|
||||
* \brief the collected changes are stored inside the PartialUpdateUser.
|
||||
*/
|
||||
PartialUpdateUser *user;
|
||||
|
||||
struct CollectResult {
|
||||
PartialUpdateChecker<TileData> *checker;
|
||||
|
||||
/**
|
||||
* \brief Tile specific data.
|
||||
*/
|
||||
TileData tile_data;
|
||||
PartialUpdateRegion changed_region;
|
||||
ePartialUpdateCollectResult result_code;
|
||||
|
||||
private:
|
||||
TileNumber last_tile_number;
|
||||
|
||||
public:
|
||||
CollectResult(PartialUpdateChecker<TileData> *checker, ePartialUpdateCollectResult result_code)
|
||||
: checker(checker),
|
||||
tile_data(checker->image, checker->image_user),
|
||||
result_code(result_code)
|
||||
{
|
||||
}
|
||||
|
||||
const ePartialUpdateCollectResult get_result_code() const
|
||||
{
|
||||
return result_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load the next changed region.
|
||||
*
|
||||
* This member function can only be called when partial changes are detected.
|
||||
* (`get_result_code()` returns `ePartialUpdateCollectResult::PartialChangesDetected`).
|
||||
*
|
||||
* When changes for another tile than the previous tile is loaded the #tile_data will be
|
||||
* updated.
|
||||
*/
|
||||
ePartialUpdateIterResult get_next_change()
|
||||
{
|
||||
BLI_assert(result_code == ePartialUpdateCollectResult::PartialChangesDetected);
|
||||
ePartialUpdateIterResult result = BKE_image_partial_update_get_next_change(checker->user,
|
||||
&changed_region);
|
||||
switch (result) {
|
||||
case ePartialUpdateIterResult::Finished:
|
||||
tile_data.free_data();
|
||||
return result;
|
||||
|
||||
case ePartialUpdateIterResult::ChangeAvailable:
|
||||
if (last_tile_number == changed_region.tile_number) {
|
||||
return result;
|
||||
}
|
||||
tile_data.free_data();
|
||||
tile_data.init_data(changed_region.tile_number);
|
||||
last_tile_number = changed_region.tile_number;
|
||||
return result;
|
||||
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
PartialUpdateChecker(Image *image, ImageUser *image_user, PartialUpdateUser *user)
|
||||
: image(image), image_user(image_user), user(user)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check for new changes since the last time this method was invoked for this #user.
|
||||
*/
|
||||
CollectResult collect_changes()
|
||||
{
|
||||
ePartialUpdateCollectResult collect_result = BKE_image_partial_update_collect_changes(image,
|
||||
user);
|
||||
return CollectResult(this, collect_result);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace partial_update
|
||||
} // namespace blender::bke::image
|
@@ -100,6 +100,9 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
|
||||
* main. You can add more local IDs to be remapped to use new overriding ones by setting their
|
||||
* LIB_TAG_DOIT tag.
|
||||
*
|
||||
* \param owner_library: the library in which the overrides should be created. Besides versioning
|
||||
* and resync code path, this should always be NULL (i.e. the local .blend file).
|
||||
*
|
||||
* \param reference_library: the library from which the linked data being overridden come from
|
||||
* (i.e. the library of the linked reference ID).
|
||||
*
|
||||
@@ -109,6 +112,7 @@ struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain,
|
||||
* \return \a true on success, \a false otherwise.
|
||||
*/
|
||||
bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
|
||||
struct Library *owner_library,
|
||||
const struct Library *reference_library,
|
||||
bool do_no_main);
|
||||
/**
|
||||
@@ -122,16 +126,24 @@ bool BKE_lib_override_library_create_from_tag(struct Main *bmain,
|
||||
*
|
||||
* \param view_layer: the active view layer to search instantiated collections in, can be NULL (in
|
||||
* which case \a scene's master collection children hierarchy is used instead).
|
||||
*
|
||||
* \param owner_library: the library in which the overrides should be created. Besides versioning
|
||||
* and resync code path, this should always be NULL (i.e. the local .blend file).
|
||||
*
|
||||
* \param id_root: The root ID to create an override from.
|
||||
*
|
||||
* \param id_reference: Some reference ID used to do some post-processing after overrides have been
|
||||
* created, may be NULL. Typically, the Empty object instantiating the linked collection we
|
||||
* override, currently.
|
||||
*
|
||||
* \param r_id_root_override: if not NULL, the override generated for the given \a id_root.
|
||||
*
|
||||
* \return true if override was successfully created.
|
||||
*/
|
||||
bool BKE_lib_override_library_create(struct Main *bmain,
|
||||
struct Scene *scene,
|
||||
struct ViewLayer *view_layer,
|
||||
struct Library *owner_library,
|
||||
struct ID *id_root,
|
||||
struct ID *id_reference,
|
||||
struct ID **r_id_root_override);
|
||||
|
@@ -38,6 +38,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ID;
|
||||
struct IDRemapper;
|
||||
|
||||
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
|
||||
|
||||
/* Also IDRemap->flag. */
|
||||
@@ -97,6 +100,19 @@ enum {
|
||||
ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9,
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all references in given Main using the given \a mappings
|
||||
*
|
||||
* \note Is preferred over BKE_libblock_remap_locked due to performance.
|
||||
*/
|
||||
void BKE_libblock_remap_multiple_locked(struct Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags);
|
||||
|
||||
void BKE_libblock_remap_multiple(struct Main *bmain,
|
||||
const struct IDRemapper *mappings,
|
||||
const short remap_flags);
|
||||
|
||||
/**
|
||||
* Replace all references in given Main to \a old_id by \a new_id
|
||||
* (if \a new_id is NULL, it unlinks \a old_id).
|
||||
@@ -146,12 +162,61 @@ void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, int remap_f
|
||||
ATTR_NONNULL();
|
||||
|
||||
typedef void (*BKE_library_free_notifier_reference_cb)(const void *);
|
||||
typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *);
|
||||
typedef void (*BKE_library_remap_editor_id_reference_cb)(const struct IDRemapper *mappings);
|
||||
|
||||
void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func);
|
||||
void BKE_library_callback_remap_editor_id_reference_set(
|
||||
BKE_library_remap_editor_id_reference_cb func);
|
||||
|
||||
/* IDRemapper */
|
||||
struct IDRemapper;
|
||||
typedef enum IDRemapperApplyResult {
|
||||
/** No remapping rules available for the source. */
|
||||
ID_REMAP_RESULT_SOURCE_UNAVAILABLE,
|
||||
/** Source isn't mappable (e.g. NULL). */
|
||||
ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE,
|
||||
/** Source has been remapped to a new pointer. */
|
||||
ID_REMAP_RESULT_SOURCE_REMAPPED,
|
||||
/** Source has been set to NULL. */
|
||||
ID_REMAP_RESULT_SOURCE_UNASSIGNED,
|
||||
} IDRemapperApplyResult;
|
||||
|
||||
typedef enum IDRemapperApplyOptions {
|
||||
ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
|
||||
ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
|
||||
|
||||
ID_REMAP_APPLY_DEFAULT = 0,
|
||||
} IDRemapperApplyOptions;
|
||||
|
||||
typedef void (*IDRemapperIterFunction)(struct ID *old_id, struct ID *new_id, void *user_data);
|
||||
|
||||
/**
|
||||
* Create a new ID Remapper.
|
||||
*
|
||||
* An ID remapper stores multiple remapping rules.
|
||||
*/
|
||||
struct IDRemapper *BKE_id_remapper_create(void);
|
||||
|
||||
void BKE_id_remapper_clear(struct IDRemapper *id_remapper);
|
||||
bool BKE_id_remapper_is_empty(const struct IDRemapper *id_remapper);
|
||||
/** Free the given ID Remapper. */
|
||||
void BKE_id_remapper_free(struct IDRemapper *id_remapper);
|
||||
/** Add a new remapping. */
|
||||
void BKE_id_remapper_add(struct IDRemapper *id_remapper, struct ID *old_id, struct ID *new_id);
|
||||
|
||||
/**
|
||||
* Apply a remapping.
|
||||
*
|
||||
* Update the id pointer stored in the given r_id_ptr if a remapping rule exists.
|
||||
*/
|
||||
IDRemapperApplyResult BKE_id_remapper_apply(const struct IDRemapper *id_remapper,
|
||||
struct ID **r_id_ptr,
|
||||
IDRemapperApplyOptions options);
|
||||
bool BKE_id_remapper_has_mapping_for(const struct IDRemapper *id_remapper, uint64_t type_filter);
|
||||
void BKE_id_remapper_iter(const struct IDRemapper *id_remapper,
|
||||
IDRemapperIterFunction func,
|
||||
void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -245,10 +245,6 @@ typedef struct ModifierTypeInfo {
|
||||
const struct ModifierEvalContext *ctx,
|
||||
struct Mesh *mesh);
|
||||
|
||||
struct Hair *(*modifyHair)(struct ModifierData *md,
|
||||
const struct ModifierEvalContext *ctx,
|
||||
struct Hair *hair);
|
||||
|
||||
/**
|
||||
* The modifier has to change the geometry set in-place. The geometry set can contain zero or
|
||||
* more geometry components. This callback can be used by modifiers that don't work on any
|
||||
|
@@ -1291,6 +1291,8 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define CMP_NODE_POSTERIZE 327
|
||||
#define CMP_NODE_CONVERT_COLOR_SPACE 328
|
||||
#define CMP_NODE_SCENE_TIME 329
|
||||
#define CMP_NODE_SEPARATE_XYZ 330
|
||||
#define CMP_NODE_COMBINE_XYZ 331
|
||||
|
||||
/* channel toggles */
|
||||
#define CMP_CHAN_RGB 1
|
||||
|
@@ -499,7 +499,6 @@ typedef struct SculptSession {
|
||||
|
||||
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
|
||||
struct MVert *mvert;
|
||||
const float (*vert_normals)[3];
|
||||
struct MPoly *mpoly;
|
||||
struct MLoop *mloop;
|
||||
|
||||
|
@@ -38,6 +38,7 @@ struct BlendLibReader;
|
||||
struct BlendWriter;
|
||||
struct Header;
|
||||
struct ID;
|
||||
struct IDRemapper;
|
||||
struct LibraryForeachIDData;
|
||||
struct ListBase;
|
||||
struct Menu;
|
||||
@@ -117,10 +118,7 @@ typedef struct SpaceType {
|
||||
bContextDataCallback context;
|
||||
|
||||
/* Used when we want to replace an ID by another (or NULL). */
|
||||
void (*id_remap)(struct ScrArea *area,
|
||||
struct SpaceLink *sl,
|
||||
struct ID *old_id,
|
||||
struct ID *new_id);
|
||||
void (*id_remap)(struct ScrArea *area, struct SpaceLink *sl, const struct IDRemapper *mappings);
|
||||
|
||||
int (*space_subtype_get)(struct ScrArea *area);
|
||||
void (*space_subtype_set)(struct ScrArea *area, int value);
|
||||
|
@@ -165,6 +165,7 @@ set(SRC
|
||||
intern/idprop_utils.c
|
||||
intern/idtype.c
|
||||
intern/image.c
|
||||
intern/image_partial_update.cc
|
||||
intern/image_gen.c
|
||||
intern/image_gpu.cc
|
||||
intern/image_save.c
|
||||
@@ -179,6 +180,7 @@ set(SRC
|
||||
intern/lib_id.c
|
||||
intern/lib_id_delete.c
|
||||
intern/lib_id_eval.c
|
||||
intern/lib_id_remapper.cc
|
||||
intern/lib_override.c
|
||||
intern/lib_query.c
|
||||
intern/lib_remap.c
|
||||
@@ -522,7 +524,7 @@ set(LIB
|
||||
bf_simulation
|
||||
|
||||
# For `vfontdata_freetype.c`.
|
||||
${FREETYPE_LIBRARIES}
|
||||
${FREETYPE_LIBRARIES} ${BROTLI_LIBRARIES}
|
||||
)
|
||||
|
||||
if(WITH_BINRELOC)
|
||||
@@ -717,10 +719,6 @@ if(WITH_FFTW3)
|
||||
add_definitions(-DFFTW3=1)
|
||||
endif()
|
||||
|
||||
if(WITH_INTERNATIONAL)
|
||||
add_definitions(-DWITH_INTERNATIONAL)
|
||||
endif()
|
||||
|
||||
if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
@@ -821,8 +819,10 @@ if(WITH_GTESTS)
|
||||
intern/cryptomatte_test.cc
|
||||
intern/fcurve_test.cc
|
||||
intern/idprop_serialize_test.cc
|
||||
intern/image_partial_update_test.cc
|
||||
intern/lattice_deform_test.cc
|
||||
intern/layer_test.cc
|
||||
intern/lib_id_remapper_test.cc
|
||||
intern/lib_id_test.cc
|
||||
intern/lib_remap_test.cc
|
||||
intern/tracking_test.cc
|
||||
|
@@ -127,30 +127,6 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm)
|
||||
return medge;
|
||||
}
|
||||
|
||||
static MFace *dm_getTessFaceArray(DerivedMesh *dm)
|
||||
{
|
||||
MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
|
||||
|
||||
if (!mface) {
|
||||
int numTessFaces = dm->getNumTessFaces(dm);
|
||||
|
||||
if (!numTessFaces) {
|
||||
/* Do not add layer if there's no elements in it, this leads to issues later when
|
||||
* this layer is needed with non-zero size, but currently CD stuff does not check
|
||||
* for requested layer size on creation and just returns layer which was previously
|
||||
* added (sergey) */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mface = (MFace *)CustomData_add_layer(
|
||||
&dm->faceData, CD_MFACE, CD_CALLOC, nullptr, numTessFaces);
|
||||
CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
|
||||
dm->copyTessFaceArray(dm, mface);
|
||||
}
|
||||
|
||||
return mface;
|
||||
}
|
||||
|
||||
static MLoop *dm_getLoopArray(DerivedMesh *dm)
|
||||
{
|
||||
MLoop *mloop = (MLoop *)CustomData_get_layer(&dm->loopData, CD_MLOOP);
|
||||
@@ -203,18 +179,6 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static MFace *dm_dupFaceArray(DerivedMesh *dm)
|
||||
{
|
||||
MFace *tmp = (MFace *)MEM_malloc_arrayN(
|
||||
dm->getNumTessFaces(dm), sizeof(*tmp), "dm_dupFaceArray tmp");
|
||||
|
||||
if (tmp) {
|
||||
dm->copyTessFaceArray(dm, tmp);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static MLoop *dm_dupLoopArray(DerivedMesh *dm)
|
||||
{
|
||||
MLoop *tmp = (MLoop *)MEM_malloc_arrayN(
|
||||
@@ -270,42 +234,15 @@ static const MLoopTri *dm_getLoopTriArray(DerivedMesh *dm)
|
||||
return looptri;
|
||||
}
|
||||
|
||||
static CustomData *dm_getVertCData(DerivedMesh *dm)
|
||||
{
|
||||
return &dm->vertData;
|
||||
}
|
||||
|
||||
static CustomData *dm_getEdgeCData(DerivedMesh *dm)
|
||||
{
|
||||
return &dm->edgeData;
|
||||
}
|
||||
|
||||
static CustomData *dm_getTessFaceCData(DerivedMesh *dm)
|
||||
{
|
||||
return &dm->faceData;
|
||||
}
|
||||
|
||||
static CustomData *dm_getLoopCData(DerivedMesh *dm)
|
||||
{
|
||||
return &dm->loopData;
|
||||
}
|
||||
|
||||
static CustomData *dm_getPolyCData(DerivedMesh *dm)
|
||||
{
|
||||
return &dm->polyData;
|
||||
}
|
||||
|
||||
void DM_init_funcs(DerivedMesh *dm)
|
||||
{
|
||||
/* default function implementations */
|
||||
dm->getVertArray = dm_getVertArray;
|
||||
dm->getEdgeArray = dm_getEdgeArray;
|
||||
dm->getTessFaceArray = dm_getTessFaceArray;
|
||||
dm->getLoopArray = dm_getLoopArray;
|
||||
dm->getPolyArray = dm_getPolyArray;
|
||||
dm->dupVertArray = dm_dupVertArray;
|
||||
dm->dupEdgeArray = dm_dupEdgeArray;
|
||||
dm->dupTessFaceArray = dm_dupFaceArray;
|
||||
dm->dupLoopArray = dm_dupLoopArray;
|
||||
dm->dupPolyArray = dm_dupPolyArray;
|
||||
|
||||
@@ -314,19 +251,8 @@ void DM_init_funcs(DerivedMesh *dm)
|
||||
/* subtypes handle getting actual data */
|
||||
dm->getNumLoopTri = dm_getNumLoopTri;
|
||||
|
||||
dm->getVertDataLayout = dm_getVertCData;
|
||||
dm->getEdgeDataLayout = dm_getEdgeCData;
|
||||
dm->getTessFaceDataLayout = dm_getTessFaceCData;
|
||||
dm->getLoopDataLayout = dm_getLoopCData;
|
||||
dm->getPolyDataLayout = dm_getPolyCData;
|
||||
|
||||
dm->getVertData = DM_get_vert_data;
|
||||
dm->getEdgeData = DM_get_edge_data;
|
||||
dm->getTessFaceData = DM_get_tessface_data;
|
||||
dm->getPolyData = DM_get_poly_data;
|
||||
dm->getVertDataArray = DM_get_vert_data_layer;
|
||||
dm->getEdgeDataArray = DM_get_edge_data_layer;
|
||||
dm->getTessFaceDataArray = DM_get_tessface_data_layer;
|
||||
dm->getPolyDataArray = DM_get_poly_data_layer;
|
||||
dm->getLoopDataArray = DM_get_loop_data_layer;
|
||||
}
|
||||
@@ -349,7 +275,6 @@ void DM_init(DerivedMesh *dm,
|
||||
DM_init_funcs(dm);
|
||||
|
||||
dm->needsFree = 1;
|
||||
dm->dirty = (DMDirtyFlag)0;
|
||||
|
||||
/* Don't use #CustomData_reset because we don't want to touch custom-data. */
|
||||
copy_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
|
||||
@@ -359,16 +284,16 @@ void DM_init(DerivedMesh *dm,
|
||||
copy_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
|
||||
}
|
||||
|
||||
void DM_from_template_ex(DerivedMesh *dm,
|
||||
DerivedMesh *source,
|
||||
DerivedMeshType type,
|
||||
int numVerts,
|
||||
int numEdges,
|
||||
int numTessFaces,
|
||||
int numLoops,
|
||||
int numPolys,
|
||||
const CustomData_MeshMasks *mask)
|
||||
void DM_from_template(DerivedMesh *dm,
|
||||
DerivedMesh *source,
|
||||
DerivedMeshType type,
|
||||
int numVerts,
|
||||
int numEdges,
|
||||
int numTessFaces,
|
||||
int numLoops,
|
||||
int numPolys)
|
||||
{
|
||||
const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH;
|
||||
CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts);
|
||||
CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges);
|
||||
CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces);
|
||||
@@ -387,26 +312,6 @@ void DM_from_template_ex(DerivedMesh *dm,
|
||||
DM_init_funcs(dm);
|
||||
|
||||
dm->needsFree = 1;
|
||||
dm->dirty = (DMDirtyFlag)0;
|
||||
}
|
||||
void DM_from_template(DerivedMesh *dm,
|
||||
DerivedMesh *source,
|
||||
DerivedMeshType type,
|
||||
int numVerts,
|
||||
int numEdges,
|
||||
int numTessFaces,
|
||||
int numLoops,
|
||||
int numPolys)
|
||||
{
|
||||
DM_from_template_ex(dm,
|
||||
source,
|
||||
type,
|
||||
numVerts,
|
||||
numEdges,
|
||||
numTessFaces,
|
||||
numLoops,
|
||||
numPolys,
|
||||
&CD_MASK_DERIVEDMESH);
|
||||
}
|
||||
|
||||
bool DM_release(DerivedMesh *dm)
|
||||
@@ -464,14 +369,6 @@ void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
|
||||
}
|
||||
}
|
||||
|
||||
void DM_ensure_normals(DerivedMesh *dm)
|
||||
{
|
||||
if (dm->dirty & DM_DIRTY_NORMALS) {
|
||||
dm->calcNormals(dm);
|
||||
}
|
||||
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
|
||||
}
|
||||
|
||||
void DM_ensure_looptri_data(DerivedMesh *dm)
|
||||
{
|
||||
const unsigned int totpoly = dm->numPolyData;
|
||||
@@ -524,7 +421,7 @@ void DM_set_only_copy(DerivedMesh *dm, const CustomData_MeshMasks *mask)
|
||||
* see replies to r50969, Campbell */
|
||||
#if 0
|
||||
CustomData_set_only_copy(&dm->loopData, mask->lmask);
|
||||
CustomData_set_only_copy(&dm->polyData, mask->pmask);
|
||||
Custom(&dm->polyData, mask->pmask);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -552,45 +449,11 @@ void DM_add_edge_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *
|
||||
CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
|
||||
}
|
||||
|
||||
void DM_add_tessface_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
|
||||
{
|
||||
CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numTessFaceData);
|
||||
}
|
||||
|
||||
void DM_add_loop_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
|
||||
{
|
||||
CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
|
||||
}
|
||||
|
||||
void DM_add_poly_layer(DerivedMesh *dm, int type, eCDAllocType alloctype, void *layer)
|
||||
{
|
||||
CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
|
||||
}
|
||||
|
||||
void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < dm->getNumVerts(dm));
|
||||
return CustomData_get(&dm->vertData, index, type);
|
||||
}
|
||||
|
||||
void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < dm->getNumEdges(dm));
|
||||
return CustomData_get(&dm->edgeData, index, type);
|
||||
}
|
||||
|
||||
void *DM_get_tessface_data(DerivedMesh *dm, int index, int type)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < dm->getNumTessFaces(dm));
|
||||
return CustomData_get(&dm->faceData, index, type);
|
||||
}
|
||||
|
||||
void *DM_get_poly_data(DerivedMesh *dm, int index, int type)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < dm->getNumPolys(dm));
|
||||
return CustomData_get(&dm->polyData, index, type);
|
||||
}
|
||||
|
||||
void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
|
||||
{
|
||||
if (type == CD_MVERT) {
|
||||
@@ -609,15 +472,6 @@ void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
|
||||
return CustomData_get_layer(&dm->edgeData, type);
|
||||
}
|
||||
|
||||
void *DM_get_tessface_data_layer(DerivedMesh *dm, int type)
|
||||
{
|
||||
if (type == CD_MFACE) {
|
||||
return dm->getTessFaceArray(dm);
|
||||
}
|
||||
|
||||
return CustomData_get_layer(&dm->faceData, type);
|
||||
}
|
||||
|
||||
void *DM_get_poly_data_layer(DerivedMesh *dm, int type)
|
||||
{
|
||||
return CustomData_get_layer(&dm->polyData, type);
|
||||
|
@@ -78,6 +78,23 @@
|
||||
/** \name High Level `.blend` file read/write.
|
||||
* \{ */
|
||||
|
||||
static bool blendfile_or_libraries_versions_atleast(Main *bmain,
|
||||
const short versionfile,
|
||||
const short subversionfile)
|
||||
{
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, versionfile, subversionfile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (Library *, library, &bmain->libraries) {
|
||||
if (!MAIN_VERSION_ATLEAST(library, versionfile, subversionfile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool foreach_path_clean_cb(BPathForeachPathData *UNUSED(bpath_data),
|
||||
char *path_dst,
|
||||
const char *path_src)
|
||||
@@ -349,10 +366,11 @@ static void setup_app_data(bContext *C,
|
||||
do_versions_ipos_to_animato(bmain);
|
||||
}
|
||||
|
||||
/* FIXME: Same as above, readfile's `do_version` do not allow to create new IDs. */
|
||||
/* TODO: Once this is definitively validated for 3.0 and option to not do it is removed, add a
|
||||
* version bump and check here. */
|
||||
if (mode != LOAD_UNDO && !USER_EXPERIMENTAL_TEST(&U, no_proxy_to_override_conversion)) {
|
||||
/* NOTE: readfile's `do_version` does not allow to create new IDs, and only operates on a single
|
||||
* library at a time. This code needs to operate on the whole Main at once. */
|
||||
/* NOTE: Check bmain version (i.e. current blend file version), AND the versions of all the
|
||||
* linked libraries. */
|
||||
if (mode != LOAD_UNDO && !blendfile_or_libraries_versions_atleast(bmain, 302, 1)) {
|
||||
BKE_lib_override_library_main_proxy_convert(bmain, reports);
|
||||
}
|
||||
|
||||
|
@@ -993,6 +993,27 @@ static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_d
|
||||
/** \name Library link/append code.
|
||||
* \{ */
|
||||
|
||||
static void blendfile_link_append_proxies_convert(Main *bmain, ReportList *reports)
|
||||
{
|
||||
/* NOTE: Do not bother checking file versions here, if there are no proxies to convert this code
|
||||
* is quite fast anyway. */
|
||||
|
||||
BlendFileReadReport bf_reports = {.reports = reports};
|
||||
BKE_lib_override_library_main_proxy_convert(bmain, &bf_reports);
|
||||
|
||||
if (bf_reports.count.proxies_to_lib_overrides_success != 0 ||
|
||||
bf_reports.count.proxies_to_lib_overrides_failures != 0) {
|
||||
BKE_reportf(
|
||||
bf_reports.reports,
|
||||
RPT_WARNING,
|
||||
"Proxies have been removed from Blender (%d proxies were automatically converted "
|
||||
"to library overrides, %d proxies could not be converted and were cleared). "
|
||||
"Please consider re-saving any library .blend file with the newest Blender version.",
|
||||
bf_reports.count.proxies_to_lib_overrides_success,
|
||||
bf_reports.count.proxies_to_lib_overrides_failures);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
|
||||
{
|
||||
if (lapp_context->num_items == 0) {
|
||||
@@ -1259,6 +1280,8 @@ void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *
|
||||
}
|
||||
|
||||
BKE_main_id_newptr_and_tag_clear(bmain);
|
||||
|
||||
blendfile_link_append_proxies_convert(bmain, reports);
|
||||
}
|
||||
|
||||
void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports)
|
||||
@@ -1361,6 +1384,10 @@ void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *re
|
||||
.active_collection = NULL};
|
||||
loose_data_instantiate(&instantiate_context);
|
||||
}
|
||||
|
||||
if ((lapp_context->params->flag & FILE_LINK) != 0) {
|
||||
blendfile_link_append_proxies_convert(lapp_context->params->bmain, reports);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -218,7 +218,7 @@ void *BKE_camera_add(Main *bmain, const char *name)
|
||||
return cam;
|
||||
}
|
||||
|
||||
float BKE_camera_object_dof_distance(Object *ob)
|
||||
float BKE_camera_object_dof_distance(const Object *ob)
|
||||
{
|
||||
Camera *cam = (Camera *)ob->data;
|
||||
if (ob->type != OB_CAMERA) {
|
||||
|
@@ -116,12 +116,6 @@ static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *r_edge)
|
||||
memcpy(r_edge, cddm->medge, sizeof(*r_edge) * dm->numEdgeData);
|
||||
}
|
||||
|
||||
static void cdDM_copyTessFaceArray(DerivedMesh *dm, MFace *r_face)
|
||||
{
|
||||
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
|
||||
memcpy(r_face, cddm->mface, sizeof(*r_face) * dm->numTessFaceData);
|
||||
}
|
||||
|
||||
static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *r_loop)
|
||||
{
|
||||
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
|
||||
@@ -147,20 +141,6 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
|
||||
copy_v3_v3(r_no, cddm->vert_normals[index]);
|
||||
}
|
||||
|
||||
static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
|
||||
{
|
||||
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
|
||||
|
||||
if (!cddm->pmap && ob->type == OB_MESH) {
|
||||
Mesh *me = ob->data;
|
||||
|
||||
BKE_mesh_vert_poly_map_create(
|
||||
&cddm->pmap, &cddm->pmap_mem, me->mpoly, me->mloop, me->totvert, me->totpoly, me->totloop);
|
||||
}
|
||||
|
||||
return cddm->pmap;
|
||||
}
|
||||
|
||||
static void cdDM_recalc_looptri(DerivedMesh *dm)
|
||||
{
|
||||
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
|
||||
@@ -216,24 +196,17 @@ static CDDerivedMesh *cdDM_create(const char *desc)
|
||||
|
||||
dm->copyVertArray = cdDM_copyVertArray;
|
||||
dm->copyEdgeArray = cdDM_copyEdgeArray;
|
||||
dm->copyTessFaceArray = cdDM_copyTessFaceArray;
|
||||
dm->copyLoopArray = cdDM_copyLoopArray;
|
||||
dm->copyPolyArray = cdDM_copyPolyArray;
|
||||
|
||||
dm->getVertData = DM_get_vert_data;
|
||||
dm->getEdgeData = DM_get_edge_data;
|
||||
dm->getTessFaceData = DM_get_tessface_data;
|
||||
dm->getVertDataArray = DM_get_vert_data_layer;
|
||||
dm->getEdgeDataArray = DM_get_edge_data_layer;
|
||||
dm->getTessFaceDataArray = DM_get_tessface_data_layer;
|
||||
|
||||
dm->recalcLoopTri = cdDM_recalc_looptri;
|
||||
|
||||
dm->getVertCo = cdDM_getVertCo;
|
||||
dm->getVertNo = cdDM_getVertNo;
|
||||
|
||||
dm->getPolyMap = cdDM_getPolyMap;
|
||||
|
||||
dm->release = cdDM_release;
|
||||
|
||||
return cddm;
|
||||
@@ -265,12 +238,6 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
|
||||
dm->deformedOnly = 1;
|
||||
dm->cd_flag = mesh->cd_flag;
|
||||
|
||||
if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
|
||||
dm->dirty |= DM_DIRTY_NORMALS;
|
||||
}
|
||||
/* TODO: DM_DIRTY_TESS_CDLAYERS ? Maybe not though,
|
||||
* since we probably want to switch to looptris? */
|
||||
|
||||
CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert);
|
||||
CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge);
|
||||
CustomData_merge(&mesh->fdata,
|
||||
@@ -282,7 +249,9 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
|
||||
CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
|
||||
|
||||
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
|
||||
cddm->vert_normals = CustomData_get_layer(&dm->vertData, CD_NORMAL);
|
||||
/* Though this may be an unnecessary calculation, simply retrieving the layer may return nothing
|
||||
* or dirty normals. */
|
||||
cddm->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
|
||||
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
|
||||
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
|
||||
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
|
||||
@@ -327,12 +296,6 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
|
||||
DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
|
||||
dm->deformedOnly = source->deformedOnly;
|
||||
dm->cd_flag = source->cd_flag;
|
||||
dm->dirty = source->dirty;
|
||||
|
||||
/* Tessellation data is never copied, so tag it here.
|
||||
* Only tag dirty layers if we really ignored tessellation faces.
|
||||
*/
|
||||
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
|
||||
|
||||
CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
|
||||
CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
|
||||
|
@@ -194,13 +194,10 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
|
||||
float (*mappedcos)[3],
|
||||
float (*quats)[4])
|
||||
{
|
||||
MVert *mvert = me->mvert;
|
||||
for (int i = 0; i < me->totvert; i++, mvert++) {
|
||||
mvert->flag &= ~ME_VERT_TMP_TAG;
|
||||
}
|
||||
BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
|
||||
|
||||
/* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
|
||||
mvert = me->mvert;
|
||||
MVert *mvert = me->mvert;
|
||||
MPoly *mp = me->mpoly;
|
||||
MLoop *mloop = me->mloop;
|
||||
|
||||
@@ -210,7 +207,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
|
||||
MLoop *ml_prev = &ml_next[mp->totloop - 2];
|
||||
|
||||
for (int j = 0; j < mp->totloop; j++) {
|
||||
if ((mvert[ml_curr->v].flag & ME_VERT_TMP_TAG) == 0) {
|
||||
if (!BLI_BITMAP_TEST(vert_tag, ml_curr->v)) {
|
||||
const float *co_prev, *co_curr, *co_next; /* orig */
|
||||
const float *vd_prev, *vd_curr, *vd_next; /* deform */
|
||||
|
||||
@@ -233,7 +230,7 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
|
||||
set_crazy_vertex_quat(
|
||||
quats[ml_curr->v], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev);
|
||||
|
||||
mvert[ml_curr->v].flag |= ME_VERT_TMP_TAG;
|
||||
BLI_BITMAP_ENABLE(vert_tag, ml_curr->v);
|
||||
}
|
||||
|
||||
ml_prev = ml_curr;
|
||||
@@ -241,6 +238,8 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
|
||||
ml_next++;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_freeN(vert_tag);
|
||||
}
|
||||
|
||||
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph,
|
||||
|
@@ -66,8 +66,8 @@ static void vert_extrude_to_mesh_data(const Spline &spline,
|
||||
|
||||
if (spline.is_cyclic() && spline.evaluated_edges_size() > 1) {
|
||||
MEdge &edge = r_edges[edge_offset + spline.evaluated_edges_size() - 1];
|
||||
edge.v1 = vert_offset;
|
||||
edge.v2 = vert_offset + eval_size - 1;
|
||||
edge.v1 = vert_offset + eval_size - 1;
|
||||
edge.v2 = vert_offset;
|
||||
edge.flag = ME_LOOSEEDGE;
|
||||
}
|
||||
|
||||
|
@@ -2427,6 +2427,13 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
|
||||
return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
|
||||
}
|
||||
|
||||
const char *CustomData_get_active_layer_name(const struct CustomData *data, const int type)
|
||||
{
|
||||
/* Get the layer index of the active layer of this type. */
|
||||
const int layer_index = CustomData_get_active_layer_index(data, type);
|
||||
return layer_index < 0 ? NULL : data->layers[layer_index].name;
|
||||
}
|
||||
|
||||
void CustomData_set_layer_active(CustomData *data, int type, int n)
|
||||
{
|
||||
for (int i = 0; i < data->totlayer; i++) {
|
||||
|
@@ -1518,7 +1518,7 @@ static void dynamic_paint_set_init_color_tex_to_vcol_cb(
|
||||
multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
|
||||
|
||||
if (texres.tin > pPoint[vert].color[3]) {
|
||||
copy_v3_v3(pPoint[vert].color, &texres.tr);
|
||||
copy_v3_v3(pPoint[vert].color, texres.trgba);
|
||||
pPoint[vert].color[3] = texres.tin;
|
||||
}
|
||||
}
|
||||
@@ -1559,7 +1559,7 @@ static void dynamic_paint_set_init_color_tex_to_imseq_cb(
|
||||
multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
|
||||
|
||||
/* apply color */
|
||||
copy_v3_v3(pPoint[i].color, &texres.tr);
|
||||
copy_v3_v3(pPoint[i].color, texres.trgba);
|
||||
pPoint[i].color[3] = texres.tin;
|
||||
}
|
||||
|
||||
@@ -1985,9 +1985,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
|
||||
}
|
||||
|
||||
MEM_freeN(fcolor);
|
||||
|
||||
/* Mark tessellated CD layers as dirty. */
|
||||
// result->dirty |= DM_DIRTY_TESS_CDLAYERS;
|
||||
}
|
||||
/* vertex group paint */
|
||||
else if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
|
||||
|
@@ -908,9 +908,9 @@ static void do_texture_effector(EffectorCache *eff,
|
||||
eff->pd->tex, tex_co, NULL, NULL, 0, result, 0, NULL, scene_color_manage, false);
|
||||
|
||||
if (hasrgb && mode == PFIELD_TEX_RGB) {
|
||||
force[0] = (0.5f - result->tr) * strength;
|
||||
force[1] = (0.5f - result->tg) * strength;
|
||||
force[2] = (0.5f - result->tb) * strength;
|
||||
force[0] = (0.5f - result->trgba[0]) * strength;
|
||||
force[1] = (0.5f - result->trgba[1]) * strength;
|
||||
force[2] = (0.5f - result->trgba[2]) * strength;
|
||||
}
|
||||
else if (nabla != 0) {
|
||||
strength /= nabla;
|
||||
@@ -933,7 +933,8 @@ static void do_texture_effector(EffectorCache *eff,
|
||||
/* generate intensity if texture only has rgb value */
|
||||
if (hasrgb & TEX_RGB) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
result[i].tin = (1.0f / 3.0f) * (result[i].tr + result[i].tg + result[i].tb);
|
||||
result[i].tin = (1.0f / 3.0f) *
|
||||
(result[i].trgba[0] + result[i].trgba[1] + result[i].trgba[2]);
|
||||
}
|
||||
}
|
||||
force[0] = (result[0].tin - result[1].tin) * strength;
|
||||
@@ -943,12 +944,12 @@ static void do_texture_effector(EffectorCache *eff,
|
||||
else { /*PFIELD_TEX_CURL*/
|
||||
float dbdy, dgdz, drdz, dbdx, dgdx, drdy;
|
||||
|
||||
dbdy = result[2].tb - result[0].tb;
|
||||
dgdz = result[3].tg - result[0].tg;
|
||||
drdz = result[3].tr - result[0].tr;
|
||||
dbdx = result[1].tb - result[0].tb;
|
||||
dgdx = result[1].tg - result[0].tg;
|
||||
drdy = result[2].tr - result[0].tr;
|
||||
dbdy = result[2].trgba[2] - result[0].trgba[2];
|
||||
dgdz = result[3].trgba[1] - result[0].trgba[1];
|
||||
drdz = result[3].trgba[0] - result[0].trgba[0];
|
||||
dbdx = result[1].trgba[2] - result[0].trgba[2];
|
||||
dgdx = result[1].trgba[1] - result[0].trgba[1];
|
||||
drdy = result[2].trgba[0] - result[0].trgba[0];
|
||||
|
||||
force[0] = (dbdy - dgdz) * strength;
|
||||
force[1] = (drdz - dbdx) * strength;
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vec_types.hh"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_rand.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "BLO_read_write.h"
|
||||
|
||||
using blender::float3;
|
||||
using blender::RandomNumberGenerator;
|
||||
|
||||
static const char *HAIR_ATTR_POSITION = "position";
|
||||
static const char *HAIR_ATTR_RADIUS = "radius";
|
||||
@@ -220,38 +221,32 @@ static void hair_random(Hair *hair)
|
||||
CustomData_realloc(&hair->cdata, hair->totcurve);
|
||||
BKE_hair_update_customdata_pointers(hair);
|
||||
|
||||
RNG *rng = BLI_rng_new(0);
|
||||
RandomNumberGenerator rng;
|
||||
|
||||
for (int i = 0; i < hair->totcurve; i++) {
|
||||
HairCurve *curve = &hair->curves[i];
|
||||
curve->firstpoint = i * numpoints;
|
||||
curve->numpoints = numpoints;
|
||||
|
||||
float theta = 2.0f * M_PI * BLI_rng_get_float(rng);
|
||||
float phi = saacosf(2.0f * BLI_rng_get_float(rng) - 1.0f);
|
||||
const float theta = 2.0f * M_PI * rng.get_float();
|
||||
const float phi = saacosf(2.0f * rng.get_float() - 1.0f);
|
||||
|
||||
float no[3] = {sinf(theta) * sinf(phi), cosf(theta) * sinf(phi), cosf(phi)};
|
||||
normalize_v3(no);
|
||||
float3 no = {std::sin(theta) * std::sin(phi), std::cos(theta) * std::sin(phi), std::cos(phi)};
|
||||
blender::math::normalize(no);
|
||||
|
||||
float co[3];
|
||||
copy_v3_v3(co, no);
|
||||
|
||||
float(*curve_co)[3] = hair->co + curve->firstpoint;
|
||||
float *curve_radius = hair->radius + curve->firstpoint;
|
||||
float(*curve_positions)[3] = hair->co + curve->firstpoint;
|
||||
float *curve_radii = hair->radius + curve->firstpoint;
|
||||
float3 co = no;
|
||||
for (int key = 0; key < numpoints; key++) {
|
||||
float t = key / (float)(numpoints - 1);
|
||||
copy_v3_v3(curve_co[key], co);
|
||||
curve_radius[key] = 0.02f * (1.0f - t);
|
||||
copy_v3_v3(curve_positions[key], co);
|
||||
curve_radii[key] = 0.02f * (1.0f - t);
|
||||
|
||||
float offset[3] = {2.0f * BLI_rng_get_float(rng) - 1.0f,
|
||||
2.0f * BLI_rng_get_float(rng) - 1.0f,
|
||||
2.0f * BLI_rng_get_float(rng) - 1.0f};
|
||||
add_v3_v3(offset, no);
|
||||
madd_v3_v3fl(co, offset, 1.0f / numpoints);
|
||||
float3 offset = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
|
||||
|
||||
co += (offset + no) / numpoints;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_rng_free(rng);
|
||||
}
|
||||
|
||||
void *BKE_hair_add(Main *bmain, const char *name)
|
||||
@@ -380,22 +375,6 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
|
||||
/* Created deformed coordinates array on demand. */
|
||||
mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
|
||||
}
|
||||
else if (mti->modifyHair) {
|
||||
/* Ensure we are not modifying the input. */
|
||||
if (hair == hair_input) {
|
||||
hair = BKE_hair_copy_for_eval(hair, true);
|
||||
}
|
||||
|
||||
Hair *hair_next = mti->modifyHair(md, &mectx, hair);
|
||||
|
||||
if (hair_next && hair_next != hair) {
|
||||
/* If the modifier returned a new hair, release the old one. */
|
||||
if (hair != hair_input) {
|
||||
BKE_id_free(nullptr, hair);
|
||||
}
|
||||
hair = hair_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hair;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user