Compare commits
329 Commits
temp-ui-cp
...
grease-pen
Author | SHA1 | Date | |
---|---|---|---|
99e17c236e | |||
5355c40dd1 | |||
3fd807c088 | |||
![]() |
0082017833 | ||
a109b289dc | |||
![]() |
24f1b91259 | ||
58b1887934 | |||
bef2fd9218 | |||
808e153179 | |||
856c30675a | |||
ddfa59d164 | |||
5e8ba041c6 | |||
07efe1119e | |||
9febb30b40 | |||
ccf39d5aa0 | |||
369292de61 | |||
b182c0dd30 | |||
c21d63ff3e | |||
e22e1a486d | |||
c710815881 | |||
a1f9ca9135 | |||
96e628d6f7 | |||
![]() |
10b6cada7f | ||
883f9cdd1b | |||
1dc6bd1060 | |||
354e75f160 | |||
a0e3fdfc47 | |||
9f6f24edec | |||
8de596cdad | |||
ba2300904f | |||
c6ebbf2b8c | |||
1cfe61bf18 | |||
351201ef18 | |||
208514114d | |||
67f4191277 | |||
12a1a280af | |||
f313329862 | |||
085eef1d15 | |||
2aabbd9fb6 | |||
ea51099303 | |||
65936b9217 | |||
1c57069a0f | |||
5c335e9b89 | |||
749ee40690 | |||
![]() |
c0f4975ecb | ||
107083a6a9 | |||
9adc5c5e19 | |||
195e80e94c | |||
db3ea8cfc4 | |||
c0b9e97675 | |||
175aea121c | |||
b209d7c553 | |||
![]() |
3c411830da | ||
e266147495 | |||
![]() |
ed70a2a4fc | ||
![]() |
9e1a1eafaa | ||
6067f0e62b | |||
![]() |
a1f6562c5d | ||
![]() |
ea7c408d7e | ||
df23ee1bc2 | |||
c060112a12 | |||
584f378a09 | |||
95badd1e2c | |||
17565a6249 | |||
4be3f122e1 | |||
952754bd6a | |||
23bea89248 | |||
bd5cc1d4c8 | |||
6d7cc47be5 | |||
099dd3eb2b | |||
e090dcff21 | |||
5679ebc255 | |||
f73cfb49e6 | |||
a5a504e8f6 | |||
d1d3bc711e | |||
5f392593ce | |||
7512aa553a | |||
00c7713047 | |||
f75005d34c | |||
cca3c0061e | |||
6ab0e48333 | |||
8e1b5a28fc | |||
033491d7a6 | |||
93686646e3 | |||
a1d6a21915 | |||
bf03f3e8aa | |||
4f488ca6a3 | |||
3606cd41e7 | |||
743558f000 | |||
![]() |
cfaa3cf25e | ||
![]() |
991d39f1e0 | ||
![]() |
e640f2a7c6 | ||
![]() |
52af4ec289 | ||
![]() |
b1640a2ee2 | ||
![]() |
fcb0a2ef42 | ||
![]() |
76bfe05ff6 | ||
![]() |
7340a1ea3e | ||
![]() |
00d45628f8 | ||
![]() |
58b0216510 | ||
93d7efa3a2 | |||
![]() |
093c524a65 | ||
ae9f4872af | |||
40e60e718b | |||
![]() |
13f9c856d4 | ||
![]() |
3445c728e3 | ||
![]() |
a46a0a1686 | ||
![]() |
ec9115cab9 | ||
![]() |
b2186f8b9a | ||
![]() |
3ac871100d | ||
a68aab494d | |||
0b87985661 | |||
603962bb86 | |||
faad153ad9 | |||
2e37142e19 | |||
a786a1c0f4 | |||
4db2748b58 | |||
11eda64b59 | |||
f0be1d9312 | |||
40d8ac24ea | |||
8d971635b9 | |||
e3a239b99f | |||
d1bac1bdc3 | |||
d6dcf63961 | |||
cea7c27cec | |||
78c5e17ac8 | |||
86a6bbae7c | |||
a5915f6fc6 | |||
8a64b75d86 | |||
2bb9435a88 | |||
0adb60af03 | |||
1a7ba05969 | |||
3e6859f838 | |||
56d65b5564 | |||
dba4f58383 | |||
75d2892a2b | |||
880af3de17 | |||
3facf573ba | |||
08d91813cd | |||
4844e4cfd5 | |||
be054a9c20 | |||
b4755f900a | |||
050800c168 | |||
f276e5c23c | |||
c1e2c164e0 | |||
8001ccd90a | |||
bb349ccf7a | |||
6ded42943e | |||
e721659845 | |||
b74123edec | |||
0b7c331de8 | |||
361b9cd8d7 | |||
eb5210bcc4 | |||
4bde6672fa | |||
18ecea939a | |||
69e56bb96e | |||
040d562485 | |||
bdaa221b5b | |||
f3931e8ff5 | |||
adaf74e8d4 | |||
83b0ef02e6 | |||
6a10ae7c5f | |||
b8a8b9a049 | |||
5d72e40db9 | |||
85b5ebf321 | |||
799eedcd89 | |||
e7cb47c5b7 | |||
51e4d291a0 | |||
75bda9aefc | |||
9f379b7c2b | |||
a308fa78c2 | |||
cbc60576f7 | |||
a53520ebfd | |||
1bbda801cf | |||
49cc48a7d9 | |||
374c3e73c3 | |||
178aaef081 | |||
ad88ffbebd | |||
241c7b9f87 | |||
304f0d97d5 | |||
6c2856e4d0 | |||
1435825efc | |||
ab2db63e28 | |||
0277e3c140 | |||
8a443f005e | |||
7b9c3faad5 | |||
81205e9fc8 | |||
96c786bc82 | |||
81c9ffbfd2 | |||
8ed6712cc7 | |||
922a55ac40 | |||
9db699177f | |||
c9d4c2781e | |||
0655496eab | |||
c5862517b7 | |||
2cb474cba8 | |||
513cca249e | |||
dcd64c2b8c | |||
4b9241b613 | |||
3cbcc3153d | |||
af09470d48 | |||
09ca2d9cc8 | |||
285324e39a | |||
81d2c9455d | |||
086629d33c | |||
fd8e94bc66 | |||
c0095b7a74 | |||
b6bd62b75c | |||
442de0c64a | |||
212e2f30c1 | |||
4210691885 | |||
b7af14448a | |||
1d18126d9d | |||
81bc5f71aa | |||
495f8f6084 | |||
26d1976d19 | |||
d3e149f360 | |||
f93a8d60b7 | |||
de5648f9db | |||
9ed9028e0b | |||
7768aa76bd | |||
a92cd80bc1 | |||
1f2449a252 | |||
2e95634897 | |||
1aeb069146 | |||
e1ae7b2d93 | |||
16d1355d5d | |||
b1d054cb0c | |||
eb4d211ae2 | |||
6a94ddfdec | |||
7ce5ab3942 | |||
55dce81ae7 | |||
625ac94c3a | |||
f3904ac307 | |||
6f4964529e | |||
d635362078 | |||
2a8cd6cf4e | |||
2f4313b1e6 | |||
c1a95c839c | |||
92afda6375 | |||
b36e144fd8 | |||
fdddabc2a7 | |||
662ed5a125 | |||
43c4b57a14 | |||
cd808e2ddb | |||
781bcd8050 | |||
9d8b092084 | |||
0019350af8 | |||
5dc6d10a81 | |||
da17bffcdb | |||
15f0eda528 | |||
29cb000aea | |||
9891ea0239 | |||
51f0632a17 | |||
5849f7a117 | |||
1c9bc8910a | |||
85e96d1716 | |||
b756f84e41 | |||
2bb9db6155 | |||
be7b8a5b3e | |||
8ecb55f550 | |||
b7e7fe09d5 | |||
e7d9f18fe7 | |||
409de3b263 | |||
6937d59860 | |||
9d9b7a5c89 | |||
39cb55efca | |||
4bfad73897 | |||
e3d544fe79 | |||
20b2db0398 | |||
9ad6dc1605 | |||
3f4fac464d | |||
17c89b4896 | |||
791130a187 | |||
d163b566a2 | |||
b61016779b | |||
aa2a8891f5 | |||
dad591b1c6 | |||
da036fa5a3 | |||
4df7c734fd | |||
6d1d3cafe9 | |||
d0086da2e5 | |||
d53b9ea13b | |||
2f6a369d8d | |||
6ccb0770d0 | |||
fbbc10165b | |||
c8273fda20 | |||
fd4448bddc | |||
b1a7fc2ae9 | |||
02d535107d | |||
f004714ec2 | |||
7cbc0138c0 | |||
286f152988 | |||
21e30b40f2 | |||
6f87e59468 | |||
09c335a82a | |||
e4a4a7f8ac | |||
f46132a1d4 | |||
74ee5907a1 | |||
2c4abb3c69 | |||
bcc3434d51 | |||
a02c2a1390 | |||
a98d2bcafa | |||
cb1ef606c7 | |||
fdc4b63982 | |||
3cf309b420 | |||
2a0d92797c | |||
1077a0e7ae | |||
a4a2cd7450 | |||
31fc56b8f6 | |||
e7fe7e6fa4 | |||
c97caa15c3 | |||
b111706dff | |||
1207efaadc | |||
e4aa70ee9a | |||
fb0182e0fa | |||
476afefd0e | |||
43c88b4465 | |||
3d56b9edc8 | |||
bf3dc5e092 | |||
65d0110235 | |||
b228e027f4 | |||
2f1d55d9ce | |||
421d7a21af | |||
4421c27b78 | |||
35802276f6 | |||
740e29a76a | |||
fcfc6c6dbf | |||
e7f240568f | |||
50eeb6a5cb |
@@ -323,6 +323,10 @@ option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)
|
||||
option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" ${_init_CODEC_FFMPEG})
|
||||
option(WITH_CODEC_SNDFILE "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
|
||||
|
||||
# Alembic support
|
||||
option(WITH_ALEMBIC "Enable Alembic Support" OFF)
|
||||
option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF)
|
||||
|
||||
if(APPLE)
|
||||
option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON)
|
||||
endif()
|
||||
@@ -393,6 +397,7 @@ option(WITH_CYCLES "Enable Cycles Render Engine" ON)
|
||||
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
|
||||
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
|
||||
option(WITH_CYCLES_OSL "Build Cycles with OSL support" ${_init_CYCLES_OSL})
|
||||
option(WITH_CYCLES_OPENSUBDIV "Build Cycles with OpenSubdiv support" ON)
|
||||
option(WITH_CYCLES_CUDA_BINARIES "Build Cycles CUDA binaries" OFF)
|
||||
set(CYCLES_CUDA_BINARIES_ARCH sm_20 sm_21 sm_30 sm_35 sm_37 sm_50 sm_52 CACHE STRING "CUDA architectures to build binaries for")
|
||||
mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
|
||||
@@ -720,6 +725,11 @@ if(WITH_OPENIMAGEIO)
|
||||
set(WITH_IMAGE_TIFF ON)
|
||||
endif()
|
||||
|
||||
# auto enable alembic linking dependencies
|
||||
if(WITH_ALEMBIC)
|
||||
set(WITH_IMAGE_OPENEXR ON)
|
||||
endif()
|
||||
|
||||
# don't store paths to libs for portable distribution
|
||||
if(WITH_INSTALL_PORTABLE)
|
||||
set(CMAKE_SKIP_BUILD_RPATH TRUE)
|
||||
@@ -1091,6 +1101,21 @@ if(UNIX AND NOT APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package_wrapper(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package_wrapper(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_BOOST)
|
||||
# uses in build instructions to override include and library variables
|
||||
if(NOT BOOST_CUSTOM)
|
||||
@@ -1326,10 +1351,8 @@ elseif(WIN32)
|
||||
# MSVC11 needs _ALLOW_KEYWORD_MACROS to build
|
||||
add_definitions(-D_ALLOW_KEYWORD_MACROS)
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
# We want to support Vista level ABI for x64
|
||||
add_definitions(-D_WIN32_WINNT=0x600)
|
||||
endif()
|
||||
# We want to support Vista level ABI
|
||||
add_definitions(-D_WIN32_WINNT=0x600)
|
||||
|
||||
# Make cmake find the msvc redistributables
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
@@ -1660,6 +1683,21 @@ elseif(WIN32)
|
||||
set(OPENVDB_LIBPATH ${LIBDIR}/openvdb/lib)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_MOD_CLOTH_ELTOPO)
|
||||
set(LAPACK ${LIBDIR}/lapack)
|
||||
# set(LAPACK_INCLUDE_DIR ${LAPACK}/include)
|
||||
@@ -1959,6 +1997,21 @@ elseif(WIN32)
|
||||
set(OPENVDB_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package_wrapper(Alembic)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package_wrapper(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(PLATFORM_LINKFLAGS "-Xlinker --stack=2097152")
|
||||
|
||||
## DISABLE - causes linking errors
|
||||
@@ -2043,6 +2096,20 @@ elseif(APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
set(ALEMBIC_ROOT_DIR ${LIBDIR}/alembic)
|
||||
find_package(Alembic)
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
set(HDF5_ROOT_DIR ${LIBDIR}/hdf5)
|
||||
find_package(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT ALEMBIC_FOUND OR (WITH_ALEMBIC_HDF5 AND NOT HDF5_FOUND))
|
||||
set(WITH_ALEMBIC OFF)
|
||||
set(WITH_ALEMBIC_HDF5 OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENSUBDIV)
|
||||
set(OPENSUBDIV ${LIBDIR}/opensubdiv)
|
||||
set(OPENSUBDIV_LIBPATH ${OPENSUBDIV}/lib)
|
||||
@@ -2452,6 +2519,11 @@ if(WITH_CYCLES)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_OPENSUBDIV AND NOT WITH_OPENSUBDIV)
|
||||
message(STATUS "WITH_CYCLES_OPENSUBDIV requires WITH_OPENSUBDIV to be ON, turning OFF")
|
||||
set(WITH_CYCLES_OPENSUBDIV OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_INTERNATIONAL)
|
||||
@@ -3215,6 +3287,7 @@ if(FIRST_RUN)
|
||||
info_cfg_option(WITH_FREESTYLE)
|
||||
info_cfg_option(WITH_OPENCOLORIO)
|
||||
info_cfg_option(WITH_OPENVDB)
|
||||
info_cfg_option(WITH_ALEMBIC)
|
||||
|
||||
info_cfg_text("Compiler Options:")
|
||||
info_cfg_option(WITH_BUILDINFO)
|
||||
|
@@ -29,13 +29,13 @@ getopt \
|
||||
ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,\
|
||||
force-all,force-python,force-numpy,force-boost,\
|
||||
force-ocio,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
|
||||
force-ffmpeg,force-opencollada,\
|
||||
force-ffmpeg,force-opencollada,force-alembic,\
|
||||
build-all,build-python,build-numpy,build-boost,\
|
||||
build-ocio,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
|
||||
build-ffmpeg,build-opencollada,\
|
||||
build-ffmpeg,build-opencollada,build-alembic,\
|
||||
skip-python,skip-numpy,skip-boost,\
|
||||
skip-ocio,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
|
||||
skip-ffmpeg,skip-opencollada \
|
||||
skip-ffmpeg,skip-opencollada,skip-alembic \
|
||||
-- "$@" \
|
||||
)
|
||||
|
||||
@@ -167,6 +167,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--build-openvdb
|
||||
Force the build of OpenVDB.
|
||||
|
||||
--build-alembic
|
||||
Force the build of Alembic.
|
||||
|
||||
--build-opencollada
|
||||
Force the build of OpenCOLLADA.
|
||||
|
||||
@@ -216,6 +219,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--force-openvdb
|
||||
Force the rebuild of OpenVDB.
|
||||
|
||||
--force-alembic
|
||||
Force the rebuild of Alembic.
|
||||
|
||||
--force-opencollada
|
||||
Force the rebuild of OpenCOLLADA.
|
||||
|
||||
@@ -258,6 +264,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
|
||||
--skip-openvdb
|
||||
Unconditionally skip OpenVDB installation/building.
|
||||
|
||||
--skip-alembic
|
||||
Unconditionally skip Alembic installation/building.
|
||||
|
||||
--skip-opencollada
|
||||
Unconditionally skip OpenCOLLADA installation/building.
|
||||
|
||||
@@ -343,6 +352,13 @@ OPENVDB_FORCE_BUILD=false
|
||||
OPENVDB_FORCE_REBUILD=false
|
||||
OPENVDB_SKIP=false
|
||||
|
||||
# Alembic needs to be compiled for now
|
||||
ALEMBIC_VERSION="1.6.0"
|
||||
ALEMBIC_VERSION_MIN=$ALEMBIC_VERSION
|
||||
ALEMBIC_FORCE_BUILD=false
|
||||
ALEMBIC_FORCE_REBUILD=false
|
||||
ALEMBIC_SKIP=false
|
||||
|
||||
# Version??
|
||||
OPENCOLLADA_VERSION="1.3"
|
||||
OPENCOLLADA_FORCE_BUILD=false
|
||||
@@ -525,6 +541,7 @@ while true; do
|
||||
OPENVDB_FORCE_BUILD=true
|
||||
OPENCOLLADA_FORCE_BUILD=true
|
||||
FFMPEG_FORCE_BUILD=true
|
||||
ALEMBIC_FORCE_BUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--build-python)
|
||||
@@ -567,6 +584,9 @@ while true; do
|
||||
--build-ffmpeg)
|
||||
FFMPEG_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--build-alembic)
|
||||
ALEMBIC_FORCE_BUILD=true; shift; continue
|
||||
;;
|
||||
--force-all)
|
||||
PYTHON_FORCE_REBUILD=true
|
||||
NUMPY_FORCE_REBUILD=true
|
||||
@@ -580,6 +600,7 @@ while true; do
|
||||
OPENVDB_FORCE_REBUILD=true
|
||||
OPENCOLLADA_FORCE_REBUILD=true
|
||||
FFMPEG_FORCE_REBUILD=true
|
||||
ALEMBIC_FORCE_REBUILD=true
|
||||
shift; continue
|
||||
;;
|
||||
--force-python)
|
||||
@@ -620,6 +641,9 @@ while true; do
|
||||
--force-ffmpeg)
|
||||
FFMPEG_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--force-alembic)
|
||||
ALEMBIC_FORCE_REBUILD=true; shift; continue
|
||||
;;
|
||||
--skip-python)
|
||||
PYTHON_SKIP=true; shift; continue
|
||||
;;
|
||||
@@ -656,6 +680,9 @@ while true; do
|
||||
--skip-ffmpeg)
|
||||
FFMPEG_SKIP=true; shift; continue
|
||||
;;
|
||||
--skip-alembic)
|
||||
ALEMBIC_SKIP=true; shift; continue
|
||||
;;
|
||||
--)
|
||||
# no more arguments to parse
|
||||
break
|
||||
@@ -683,7 +710,7 @@ NUMPY_SOURCE=( "http://sourceforge.net/projects/numpy/files/NumPy/$NUMPY_VERSION
|
||||
|
||||
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
|
||||
BOOST_SOURCE=( "http://sourceforge.net/projects/boost/files/boost/$BOOST_VERSION/boost_$_boost_version_nodots.tar.bz2/download" )
|
||||
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams"
|
||||
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams --with-python --with-program_options"
|
||||
|
||||
OCIO_SOURCE=( "https://github.com/imageworks/OpenColorIO/tarball/v$OCIO_VERSION" )
|
||||
|
||||
@@ -727,6 +754,12 @@ OPENVDB_SOURCE=( "https://github.com/dreamworksanimation/openvdb/archive/v${OPEN
|
||||
#~ OPENVDB_SOURCE_REPO_UID="404659fffa659da075d1c9416e4fc939139a84ee"
|
||||
#~ OPENVDB_SOURCE_REPO_BRANCH="dev"
|
||||
|
||||
ALEMBIC_USE_REPO=false
|
||||
ALEMBIC_SOURCE=( "https://github.com/alembic/alembic/archive/${ALEMBIC_VERSION}.tar.gz" )
|
||||
# ALEMBIC_SOURCE_REPO=( "https://github.com/alembic/alembic.git" )
|
||||
# ALEMBIC_SOURCE_REPO_UID="e6c90d4faa32c4550adeaaf3f556dad4b73a92bb"
|
||||
# ALEMBIC_SOURCE_REPO_BRANCH="master"
|
||||
|
||||
OPENCOLLADA_SOURCE=( "https://github.com/KhronosGroup/OpenCOLLADA.git" )
|
||||
OPENCOLLADA_REPO_UID="3335ac164e68b2512a40914b14c74db260e6ff7d"
|
||||
OPENCOLLADA_REPO_BRANCH="master"
|
||||
@@ -767,7 +800,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
|
||||
* [OpenShadingLanguage $OSL_VERSION_MIN] (from $OSL_SOURCE_REPO, branch $OSL_SOURCE_REPO_BRANCH, commit $OSL_SOURCE_REPO_UID).
|
||||
* [OpenSubDiv $OSD_VERSION_MIN] (from $OSD_SOURCE_REPO, branch $OSD_SOURCE_REPO_BRANCH, commit $OSD_SOURCE_REPO_UID).
|
||||
* [OpenVDB $OPENVDB_VERSION_MIN] (from $OPENVDB_SOURCE), [Blosc $OPENVDB_BLOSC_VERSION] (from $OPENVDB_BLOSC_SOURCE).
|
||||
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).\""
|
||||
* [OpenCollada] (from $OPENCOLLADA_SOURCE, branch $OPENCOLLADA_REPO_BRANCH, commit $OPENCOLLADA_REPO_UID).
|
||||
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).\""
|
||||
|
||||
if [ "$DO_SHOW_DEPS" = true ]; then
|
||||
PRINT ""
|
||||
@@ -1118,7 +1152,7 @@ compile_Boost() {
|
||||
fi
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
boost_magic=10
|
||||
boost_magic=11
|
||||
|
||||
_init_boost
|
||||
|
||||
@@ -2138,6 +2172,102 @@ compile_OPENVDB() {
|
||||
run_ldconfig "openvdb"
|
||||
}
|
||||
|
||||
#### Build Alembic ####
|
||||
_init_alembic() {
|
||||
_src=$SRC/alembic-$ALEMBIC_VERSION
|
||||
_git=false
|
||||
_inst=$INST/alembic-$ALEMBIC_VERSION
|
||||
_inst_shortcut=$INST/alembic
|
||||
}
|
||||
|
||||
clean_ALEMBIC() {
|
||||
_init_alembic
|
||||
_clean
|
||||
}
|
||||
|
||||
compile_ALEMBIC() {
|
||||
if [ "$NO_BUILD" = true ]; then
|
||||
WARNING "--no-build enabled, Alembic will not be compiled!"
|
||||
return
|
||||
fi
|
||||
|
||||
compile_HDF5
|
||||
PRINT ""
|
||||
|
||||
# To be changed each time we make edits that would modify the compiled result!
|
||||
alembic_magic=2
|
||||
_init_alembic
|
||||
|
||||
# Clean install if needed!
|
||||
magic_compile_check alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
if [ $? -eq 1 -o "$ALEMBIC_FORCE_REBUILD" = true ]; then
|
||||
clean_ALEMBIC
|
||||
fi
|
||||
|
||||
if [ ! -d $_inst ]; then
|
||||
INFO "Building Alembic-$ALEMBIC_VERSION"
|
||||
|
||||
prepare_opt
|
||||
|
||||
if [ ! -d $_src -o true ]; then
|
||||
mkdir -p $SRC
|
||||
download ALEMBIC_SOURCE[@] "$_src.tar.gz"
|
||||
|
||||
INFO "Unpacking Alembic-$ALEMBIC_VERSION"
|
||||
tar -C $SRC -xf $_src.tar.gz
|
||||
fi
|
||||
|
||||
cd $_src
|
||||
|
||||
cmake_d="-D CMAKE_INSTALL_PREFIX=$_inst"
|
||||
|
||||
if [ -d $INST/boost ]; then
|
||||
cmake_d="$cmake_d -D BOOST_ROOT=$INST/boost"
|
||||
cmake_d="$cmake_d -D USE_STATIC_BOOST=ON"
|
||||
else
|
||||
cmake_d="$cmake_d -D USE_STATIC_BOOST=OFF"
|
||||
fi
|
||||
|
||||
if [ "$_with_built_openexr" = true ]; then
|
||||
cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
|
||||
cmake_d="$cmake_d -D USE_ARNOLD=OFF"
|
||||
cmake_d="$cmake_d -D USE_BINARIES=OFF"
|
||||
cmake_d="$cmake_d -D USE_EXAMPLES=OFF"
|
||||
cmake_d="$cmake_d -D USE_HDF5=OFF"
|
||||
cmake_d="$cmake_d -D USE_MAYA=OFF"
|
||||
cmake_d="$cmake_d -D USE_PRMAN=OFF"
|
||||
cmake_d="$cmake_d -D USE_PYALEMBIC=OFF"
|
||||
cmake_d="$cmake_d -D USE_STATIC_HDF5=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_ILMBASE_LINK_STATIC=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_SHARED_LIBS=OFF"
|
||||
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_BOOST=ON"
|
||||
cmake_d="$cmake_d -D ALEMBIC_LIB_USES_TR1=OFF"
|
||||
INFO "ILMBASE_ROOT=$INST/openexr"
|
||||
fi
|
||||
|
||||
cmake $cmake_d ./
|
||||
make -j$THREADS install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
magic_compile_set alembic-$ALEMBIC_VERSION $alembic_magic
|
||||
|
||||
cd $CWD
|
||||
INFO "Done compiling Alembic-$ALEMBIC_VERSION!"
|
||||
else
|
||||
INFO "Own Alembic-$ALEMBIC_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
|
||||
fi
|
||||
|
||||
run_ldconfig "alembic"
|
||||
}
|
||||
|
||||
#### Build OpenCOLLADA ####
|
||||
_init_opencollada() {
|
||||
_src=$SRC/OpenCOLLADA-$OPENCOLLADA_VERSION
|
||||
@@ -2746,6 +2876,17 @@ install_DEB() {
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
# No package currently, only HDF5!
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
_do_compile_collada=false
|
||||
@@ -3283,6 +3424,17 @@ install_RPM() {
|
||||
compile_OPENVDB
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
# No package currently!
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
PRINT ""
|
||||
@@ -3693,6 +3845,16 @@ install_ARCH() {
|
||||
fi
|
||||
fi
|
||||
|
||||
PRINT ""
|
||||
if [ "$ALEMBIC_SKIP" = true ]; then
|
||||
WARNING "Skipping Alembic installation, as requested..."
|
||||
elif [ "$ALEMBIC_FORCE_BUILD" = true ]; then
|
||||
INFO "Forced Alembic building, as requested..."
|
||||
compile_ALEMBIC
|
||||
else
|
||||
compile_ALEMBIC
|
||||
fi
|
||||
|
||||
|
||||
if [ "$WITH_OPENCOLLADA" = true ]; then
|
||||
PRINT ""
|
||||
@@ -4000,7 +4162,7 @@ print_info() {
|
||||
|
||||
_buildargs="-U *SNDFILE* -U *PYTHON* -U *BOOST* -U *Boost*"
|
||||
_buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
|
||||
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG*"
|
||||
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC*"
|
||||
|
||||
_1="-D WITH_CODEC_SNDFILE=ON"
|
||||
PRINT " $_1"
|
||||
@@ -4106,6 +4268,17 @@ print_info() {
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
|
||||
if [ "$ALEMBIC_SKIP" = false ]; then
|
||||
_1="-D WITH_ALEMBIC=ON"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
if [ -d $INST/alembic ]; then
|
||||
_1="-D ALEMBIC_ROOT_DIR=$INST/alembic"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SYSTEM_GLEW" = true ]; then
|
||||
_1="-D WITH_SYSTEM_GLEW=OFF"
|
||||
PRINT " $_1"
|
||||
|
70
build_files/cmake/Modules/FindAlembic.cmake
Normal file
70
build_files/cmake/Modules/FindAlembic.cmake
Normal file
@@ -0,0 +1,70 @@
|
||||
# - Find Alembic library
|
||||
# Find the native Alembic includes and libraries
|
||||
# This module defines
|
||||
# ALEMBIC_INCLUDE_DIRS, where to find Alembic headers, Set when
|
||||
# ALEMBIC_INCLUDE_DIR is found.
|
||||
# ALEMBIC_LIBRARIES, libraries to link against to use Alembic.
|
||||
# ALEMBIC_ROOT_DIR, The base directory to search for Alembic.
|
||||
# This can also be an environment variable.
|
||||
# ALEMBIC_FOUND, If false, do not try to use Alembic.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2016 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If ALEMBIC_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT ALEMBIC_ROOT_DIR AND NOT $ENV{ALEMBIC_ROOT_DIR} STREQUAL "")
|
||||
SET(ALEMBIC_ROOT_DIR $ENV{ALEMBIC_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_alembic_SEARCH_DIRS
|
||||
${ALEMBIC_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/alembic
|
||||
)
|
||||
|
||||
FIND_PATH(ALEMBIC_INCLUDE_DIR
|
||||
NAMES
|
||||
Alembic/Abc/All.h
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ALEMBIC_LIBRARY
|
||||
NAMES
|
||||
Alembic
|
||||
HINTS
|
||||
${_alembic_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib lib/static
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ALEMBIC_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ALEMBIC DEFAULT_MSG ALEMBIC_LIBRARY ALEMBIC_INCLUDE_DIR)
|
||||
|
||||
IF(ALEMBIC_FOUND)
|
||||
SET(ALEMBIC_LIBRARIES ${ALEMBIC_LIBRARY})
|
||||
SET(ALEMBIC_INCLUDE_DIRS ${ALEMBIC_INCLUDE_DIR})
|
||||
ENDIF(ALEMBIC_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ALEMBIC_INCLUDE_DIR
|
||||
ALEMBIC_LIBRARY
|
||||
)
|
||||
|
||||
UNSET(_alembic_SEARCH_DIRS)
|
69
build_files/cmake/Modules/FindHDF5.cmake
Normal file
69
build_files/cmake/Modules/FindHDF5.cmake
Normal file
@@ -0,0 +1,69 @@
|
||||
# - Find HDF5 library
|
||||
# Find the native HDF5 includes and libraries
|
||||
# This module defines
|
||||
# HDF5_INCLUDE_DIRS, where to find hdf5.h, Set when HDF5_INCLUDE_DIR is found.
|
||||
# HDF5_LIBRARIES, libraries to link against to use HDF5.
|
||||
# HDF5_ROOT_DIR, The base directory to search for HDF5.
|
||||
# This can also be an environment variable.
|
||||
# HDF5_FOUND, If false, do not try to use HDF5.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2016 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If HDF5_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT HDF5_ROOT_DIR AND NOT $ENV{HDF5_ROOT_DIR} STREQUAL "")
|
||||
SET(HDF5_ROOT_DIR $ENV{HDF5_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_hdf5_SEARCH_DIRS
|
||||
${HDF5_ROOT_DIR}
|
||||
/usr/local
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt/lib/hdf5
|
||||
)
|
||||
|
||||
FIND_LIBRARY(HDF5_LIBRARY
|
||||
NAMES
|
||||
hdf5
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
)
|
||||
|
||||
FIND_PATH(HDF5_INCLUDE_DIR
|
||||
NAMES
|
||||
hdf5.h
|
||||
HINTS
|
||||
${_hdf5_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set HDF5_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(HDF5 DEFAULT_MSG HDF5_LIBRARY HDF5_INCLUDE_DIR)
|
||||
|
||||
IF(HDF5_FOUND)
|
||||
SET(HDF5_LIBRARIES ${HDF5_LIBRARY})
|
||||
SET(HDF5_INCLUDE_DIRS ${HDF5_INCLUDE_DIR})
|
||||
ENDIF(HDF5_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
HDF5_INCLUDE_DIR
|
||||
HDF5_LIBRARY
|
||||
)
|
||||
|
||||
UNSET(_hdf5_SEARCH_DIRS)
|
@@ -4,6 +4,7 @@
|
||||
# cmake -C../blender/build_files/cmake/config/blender_full.cmake ../blender
|
||||
#
|
||||
|
||||
set(WITH_ALEMBIC ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO ON CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET ON CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI ON CACHE BOOL "" FORCE)
|
||||
|
@@ -8,6 +8,7 @@
|
||||
set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE)
|
||||
set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE)
|
||||
|
||||
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
|
||||
|
@@ -32,3 +32,4 @@ set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_BULLET OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_OPENVDB OFF CACHE BOOL "" FORCE)
|
||||
set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE)
|
||||
|
@@ -333,6 +333,11 @@ function(SETUP_LIBDIRS)
|
||||
link_directories(${LLVM_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
link_directories(${ALEMBIC_LIBPATH})
|
||||
link_directories(${HDF5_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
link_directories(${PTHREADS_LIBPATH})
|
||||
endif()
|
||||
@@ -434,6 +439,9 @@ function(setup_liblinks
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${target} ${JPEG_LIBRARIES})
|
||||
if(WITH_ALEMBIC)
|
||||
target_link_libraries(${target} ${ALEMBIC_LIBRARIES} ${HDF5_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_IMAGE_OPENEXR)
|
||||
target_link_libraries(${target} ${OPENEXR_LIBRARIES})
|
||||
endif()
|
||||
@@ -607,6 +615,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
||||
bf_imbuf_openimageio
|
||||
bf_imbuf_dds
|
||||
bf_collada
|
||||
bf_alembic
|
||||
bf_intern_elbeem
|
||||
bf_intern_memutil
|
||||
bf_intern_guardedalloc
|
||||
|
5
extern/curve_fit_nd/README.blender
vendored
Normal file
5
extern/curve_fit_nd/README.blender
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
Project: Curve-Fit-nD
|
||||
URL: https://github.com/ideasman42/curve-fit-nd
|
||||
License: BSD 3-Clause
|
||||
Upstream version: Unknown (Last Release)
|
||||
Local modifications: None
|
12
extern/curve_fit_nd/intern/curve_fit_cubic.c
vendored
12
extern/curve_fit_nd/intern/curve_fit_cubic.c
vendored
@@ -614,7 +614,7 @@ static void cubic_from_points_offset_fallback(
|
||||
|
||||
double dists[2] = {0, 0};
|
||||
|
||||
const double *pt = points_offset;
|
||||
const double *pt = &points_offset[dims];
|
||||
for (uint i = 1; i < points_offset_len - 1; i++, pt += dims) {
|
||||
for (uint k = 0; k < 2; k++) {
|
||||
sub_vn_vnvn(tmp, p0, pt, dims);
|
||||
@@ -623,13 +623,13 @@ static void cubic_from_points_offset_fallback(
|
||||
}
|
||||
}
|
||||
|
||||
float alpha_l = (dists[0] / 0.75) / dot_vnvn(tan_l, a[0], dims);
|
||||
float alpha_r = (dists[1] / 0.75) / -dot_vnvn(tan_r, a[1], dims);
|
||||
double alpha_l = (dists[0] / 0.75) / dot_vnvn(tan_l, a[0], dims);
|
||||
double alpha_r = (dists[1] / 0.75) / -dot_vnvn(tan_r, a[1], dims);
|
||||
|
||||
if (!(alpha_l > 0.0f)) {
|
||||
if (!(alpha_l > 0.0)) {
|
||||
alpha_l = dir_dist / 3.0;
|
||||
}
|
||||
if (!(alpha_r > 0.0f)) {
|
||||
if (!(alpha_r > 0.0)) {
|
||||
alpha_r = dir_dist / 3.0;
|
||||
}
|
||||
|
||||
@@ -896,7 +896,7 @@ static double points_calc_coord_length(
|
||||
}
|
||||
assert(!is_almost_zero(r_u[points_offset_len - 1]));
|
||||
const double w = r_u[points_offset_len - 1];
|
||||
for (uint i = 0; i < points_offset_len; i++) {
|
||||
for (uint i = 1; i < points_offset_len; i++) {
|
||||
r_u[i] /= w;
|
||||
}
|
||||
return w;
|
||||
|
@@ -146,6 +146,14 @@ if(WITH_CYCLES_OSL)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_CYCLES_OPENSUBDIV)
|
||||
add_definitions(-DWITH_OPENSUBDIV)
|
||||
include_directories(
|
||||
SYSTEM
|
||||
${OPENSUBDIV_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(WITH_CYCLES_DEVICE_OPENCL TRUE)
|
||||
set(WITH_CYCLES_DEVICE_CUDA TRUE)
|
||||
set(WITH_CYCLES_DEVICE_MULTI TRUE)
|
||||
|
@@ -41,6 +41,8 @@ def update_script_node(node, report):
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
oso_file_remove = False
|
||||
|
||||
if node.mode == 'EXTERNAL':
|
||||
# compile external script file
|
||||
script_path = bpy.path.abspath(node.filepath, library=node.id_data.library)
|
||||
@@ -49,7 +51,6 @@ def update_script_node(node, report):
|
||||
if script_ext == ".oso":
|
||||
# it's a .oso file, no need to compile
|
||||
ok, oso_path = True, script_path
|
||||
oso_file_remove = False
|
||||
elif script_ext == ".osl":
|
||||
# compile .osl file
|
||||
ok, oso_path = osl_compile(script_path, report)
|
||||
@@ -65,7 +66,6 @@ def update_script_node(node, report):
|
||||
elif os.path.dirname(node.filepath) == "":
|
||||
# module in search path
|
||||
oso_path = node.filepath
|
||||
oso_file_remove = False
|
||||
ok = True
|
||||
else:
|
||||
# unknown
|
||||
@@ -88,12 +88,10 @@ def update_script_node(node, report):
|
||||
osl_file.close()
|
||||
|
||||
ok, oso_path = osl_compile(osl_file.name, report)
|
||||
oso_file_remove = False
|
||||
os.remove(osl_file.name)
|
||||
else:
|
||||
# compile text datablock from disk directly
|
||||
ok, oso_path = osl_compile(osl_path, report)
|
||||
oso_file_remove = False
|
||||
|
||||
if ok:
|
||||
# read bytecode
|
||||
|
@@ -775,6 +775,13 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
|
||||
default='LINEAR',
|
||||
)
|
||||
|
||||
cls.displacement_method = EnumProperty(
|
||||
name="Displacement Method",
|
||||
description="Method to use for the displacement",
|
||||
items=enum_displacement_methods,
|
||||
default='BUMP',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Material.cycles
|
||||
@@ -952,13 +959,6 @@ class CyclesMeshSettings(bpy.types.PropertyGroup):
|
||||
type=cls,
|
||||
)
|
||||
|
||||
cls.displacement_method = EnumProperty(
|
||||
name="Displacement Method",
|
||||
description="Method to use for the displacement",
|
||||
items=enum_displacement_methods,
|
||||
default='BUMP',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Mesh.cycles
|
||||
|
@@ -674,40 +674,6 @@ class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
|
||||
split.separator()
|
||||
|
||||
|
||||
class Cycles_PT_mesh_displacement(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Displacement"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if CyclesButtonsPanel.poll(context):
|
||||
if context.mesh or context.curve or context.meta_ball:
|
||||
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mesh = context.mesh
|
||||
curve = context.curve
|
||||
mball = context.meta_ball
|
||||
|
||||
if mesh:
|
||||
cdata = mesh.cycles
|
||||
elif curve:
|
||||
cdata = curve.cycles
|
||||
elif mball:
|
||||
cdata = mball.cycles
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.label(text="Displacement:")
|
||||
sub.prop(cdata, "displacement_method", text="")
|
||||
|
||||
class CyclesObject_PT_motion_blur(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Motion Blur"
|
||||
bl_context = "object"
|
||||
@@ -1219,6 +1185,11 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
|
||||
col.prop(cmat, "sample_as_light", text="Multiple Importance")
|
||||
col.prop(cmat, "use_transparent_shadow")
|
||||
|
||||
if context.scene.cycles.feature_set == 'EXPERIMENTAL':
|
||||
col.separator()
|
||||
col.label(text="Displacement:")
|
||||
col.prop(cmat, "displacement_method", text="")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Volume:")
|
||||
sub = col.column()
|
||||
|
@@ -409,7 +409,8 @@ static void attr_create_uv_map(Scene *scene,
|
||||
BL::Mesh& b_mesh,
|
||||
const vector<int>& nverts,
|
||||
const vector<int>& face_flags,
|
||||
bool subdivision)
|
||||
bool subdivision,
|
||||
bool subdivide_uvs)
|
||||
{
|
||||
if(subdivision) {
|
||||
BL::Mesh::uv_layers_iterator l;
|
||||
@@ -429,6 +430,10 @@ static void attr_create_uv_map(Scene *scene,
|
||||
else
|
||||
attr = mesh->subd_attributes.add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CORNER);
|
||||
|
||||
if(subdivide_uvs) {
|
||||
attr->flags |= ATTR_SUBDIVIDED;
|
||||
}
|
||||
|
||||
BL::Mesh::polygons_iterator p;
|
||||
float3 *fdata = attr->data_float3();
|
||||
|
||||
@@ -592,7 +597,8 @@ static void create_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh& b_mesh,
|
||||
const vector<Shader*>& used_shaders,
|
||||
bool subdivision=false)
|
||||
bool subdivision=false,
|
||||
bool subdivide_uvs=true)
|
||||
{
|
||||
/* count vertices and faces */
|
||||
int numverts = b_mesh.vertices.length();
|
||||
@@ -638,6 +644,7 @@ static void create_mesh(Scene *scene,
|
||||
/* create generated coordinates from undeformed coordinates */
|
||||
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
|
||||
Attribute *attr = attributes.add(ATTR_STD_GENERATED);
|
||||
attr->flags |= ATTR_SUBDIVIDED;
|
||||
|
||||
float3 loc, size;
|
||||
mesh_texture_space(b_mesh, loc, size);
|
||||
@@ -746,7 +753,7 @@ static void create_mesh(Scene *scene,
|
||||
* The calculate functions will check whether they're needed or not.
|
||||
*/
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, nverts, face_flags, subdivision);
|
||||
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision);
|
||||
attr_create_uv_map(scene, mesh, b_mesh, nverts, face_flags, subdivision, subdivide_uvs);
|
||||
|
||||
/* for volume objects, create a matrix to transform from object space to
|
||||
* mesh texture space. this does not work with deformations but that can
|
||||
@@ -770,8 +777,35 @@ static void create_subd_mesh(Scene *scene,
|
||||
float dicing_rate,
|
||||
int max_subdivisions)
|
||||
{
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, true);
|
||||
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length()-1]);
|
||||
bool subdivide_uvs = subsurf_mod.use_subsurf_uv();
|
||||
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
|
||||
|
||||
/* export creases */
|
||||
size_t num_creases = 0;
|
||||
BL::Mesh::edges_iterator e;
|
||||
|
||||
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
||||
if(e->crease() != 0.0f) {
|
||||
num_creases++;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->subd_creases.resize(num_creases);
|
||||
|
||||
Mesh::SubdEdgeCrease* crease = mesh->subd_creases.data();
|
||||
for(b_mesh.edges.begin(e); e != b_mesh.edges.end(); ++e) {
|
||||
if(e->crease() != 0.0f) {
|
||||
crease->v[0] = e->vertices()[0];
|
||||
crease->v[1] = e->vertices()[1];
|
||||
crease->crease = e->crease();
|
||||
|
||||
crease++;
|
||||
}
|
||||
}
|
||||
|
||||
/* set subd params */
|
||||
SubdParams sdparams(mesh);
|
||||
|
||||
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
@@ -903,8 +937,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
|
||||
mesh_synced.insert(mesh);
|
||||
|
||||
/* create derived mesh */
|
||||
PointerRNA cmesh = RNA_pointer_get(&b_ob_data.ptr, "cycles");
|
||||
|
||||
array<int> oldtriangle = mesh->triangles;
|
||||
|
||||
/* compares curve_keys rather than strands in order to handle quick hair
|
||||
@@ -974,21 +1006,6 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob,
|
||||
}
|
||||
mesh->geometry_flags = requested_geometry_flags;
|
||||
|
||||
/* displacement method */
|
||||
if(cmesh.data) {
|
||||
const int method = get_enum(cmesh,
|
||||
"displacement_method",
|
||||
Mesh::DISPLACE_NUM_METHODS,
|
||||
Mesh::DISPLACE_BUMP);
|
||||
|
||||
if(method == 0 || !experimental)
|
||||
mesh->displacement_method = Mesh::DISPLACE_BUMP;
|
||||
else if(method == 1)
|
||||
mesh->displacement_method = Mesh::DISPLACE_TRUE;
|
||||
else
|
||||
mesh->displacement_method = Mesh::DISPLACE_BOTH;
|
||||
}
|
||||
|
||||
/* fluid motion */
|
||||
sync_mesh_fluid_motion(b_ob, scene, mesh);
|
||||
|
||||
|
@@ -329,16 +329,18 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
|
||||
/* object transformation */
|
||||
if(tfm != object->tfm) {
|
||||
VLOG(1) << "Object " << b_ob.name() << " motion detected.";
|
||||
if(motion_time == -1.0f) {
|
||||
object->motion.pre = tfm;
|
||||
object->use_motion = true;
|
||||
}
|
||||
else if(motion_time == 1.0f) {
|
||||
object->motion.post = tfm;
|
||||
if(motion_time == -1.0f || motion_time == 1.0f) {
|
||||
object->use_motion = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(motion_time == -1.0f) {
|
||||
object->motion.pre = tfm;
|
||||
}
|
||||
else if(motion_time == 1.0f) {
|
||||
object->motion.post = tfm;
|
||||
}
|
||||
|
||||
/* mesh deformation */
|
||||
if(object->mesh)
|
||||
sync_mesh_motion(b_ob, object, motion_time);
|
||||
@@ -395,8 +397,8 @@ Object *BlenderSync::sync_object(BL::Object& b_parent,
|
||||
object->name = b_ob.name().c_str();
|
||||
object->pass_id = b_ob.pass_index();
|
||||
object->tfm = tfm;
|
||||
object->motion.pre = tfm;
|
||||
object->motion.post = tfm;
|
||||
object->motion.pre = transform_empty();
|
||||
object->motion.post = transform_empty();
|
||||
object->use_motion = false;
|
||||
|
||||
/* motion blur */
|
||||
|
@@ -64,6 +64,14 @@ static VolumeInterpolation get_volume_interpolation(PointerRNA& ptr)
|
||||
VOLUME_INTERPOLATION_LINEAR);
|
||||
}
|
||||
|
||||
static DisplacementMethod get_displacement_method(PointerRNA& ptr)
|
||||
{
|
||||
return (DisplacementMethod)get_enum(ptr,
|
||||
"displacement_method",
|
||||
DISPLACE_NUM_METHODS,
|
||||
DISPLACE_BUMP);
|
||||
}
|
||||
|
||||
static int validate_enum_value(int value, int num_values, int default_value)
|
||||
{
|
||||
if(value >= num_values) {
|
||||
@@ -837,8 +845,10 @@ static ShaderNode *add_node(Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
if(node)
|
||||
if(node) {
|
||||
node->name = b_node.name();
|
||||
graph->add(node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -1180,6 +1190,7 @@ void BlenderSync::sync_materials(bool update_all)
|
||||
shader->heterogeneous_volume = !get_boolean(cmat, "homogeneous_volume");
|
||||
shader->volume_sampling_method = get_volume_sampling(cmat);
|
||||
shader->volume_interpolation_method = get_volume_interpolation(cmat);
|
||||
shader->displacement_method = (experimental) ? get_displacement_method(cmat) : DISPLACE_BUMP;
|
||||
|
||||
shader->set_graph(graph);
|
||||
shader->tag_update(scene);
|
||||
|
@@ -875,6 +875,7 @@ public:
|
||||
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
opencl_error("OpenCL build failed: errors in console");
|
||||
fprintf(stderr, "Build error: %s\n", clewErrorString(ciErr));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -162,6 +162,7 @@ set(SRC_GEOM_HEADERS
|
||||
geom/geom_motion_curve.h
|
||||
geom/geom_motion_triangle.h
|
||||
geom/geom_object.h
|
||||
geom/geom_patch.h
|
||||
geom/geom_primitive.h
|
||||
geom/geom_subd_triangle.h
|
||||
geom/geom_triangle.h
|
||||
|
@@ -144,7 +144,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
return label;
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_CUDS__
|
||||
#ifndef __KERNEL_CUDA__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
|
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "geom_attribute.h"
|
||||
#include "geom_object.h"
|
||||
#include "geom_patch.h"
|
||||
#include "geom_triangle.h"
|
||||
#include "geom_subd_triangle.h"
|
||||
#include "geom_triangle_intersect.h"
|
||||
|
@@ -43,12 +43,19 @@ ccl_device_inline uint attribute_primitive_type(KernelGlobals *kg, const ShaderD
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline AttributeDescriptor attribute_not_found()
|
||||
{
|
||||
const AttributeDescriptor desc = {ATTR_ELEMENT_NONE, (NodeAttributeType)0, 0, ATTR_STD_NOT_FOUND};
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* Find attribute based on ID */
|
||||
|
||||
ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
|
||||
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
|
||||
{
|
||||
if(ccl_fetch(sd, object) == PRIM_NONE)
|
||||
return (int)ATTR_STD_NOT_FOUND;
|
||||
if(ccl_fetch(sd, object) == PRIM_NONE) {
|
||||
return attribute_not_found();
|
||||
}
|
||||
|
||||
/* for SVM, find attribute by unique id */
|
||||
uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
|
||||
@@ -57,31 +64,37 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui
|
||||
|
||||
while(attr_map.x != id) {
|
||||
if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
|
||||
return ATTR_STD_NOT_FOUND;
|
||||
return attribute_not_found();
|
||||
}
|
||||
attr_offset += ATTR_PRIM_TYPES;
|
||||
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
|
||||
}
|
||||
|
||||
*elem = (AttributeElement)attr_map.y;
|
||||
AttributeDescriptor desc;
|
||||
desc.element = (AttributeElement)attr_map.y;
|
||||
|
||||
if(ccl_fetch(sd, prim) == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH)
|
||||
return ATTR_STD_NOT_FOUND;
|
||||
if(ccl_fetch(sd, prim) == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH) {
|
||||
return attribute_not_found();
|
||||
}
|
||||
|
||||
/* return result */
|
||||
return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
|
||||
desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
|
||||
desc.type = (NodeAttributeType)(attr_map.w & 0xff);
|
||||
desc.flags = (AttributeFlag)(attr_map.w >> 8);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* Transform matrix attribute on meshes */
|
||||
|
||||
ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, int offset)
|
||||
ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc)
|
||||
{
|
||||
Transform tfm;
|
||||
|
||||
tfm.x = kernel_tex_fetch(__attributes_float3, offset + 0);
|
||||
tfm.y = kernel_tex_fetch(__attributes_float3, offset + 1);
|
||||
tfm.z = kernel_tex_fetch(__attributes_float3, offset + 2);
|
||||
tfm.w = kernel_tex_fetch(__attributes_float3, offset + 3);
|
||||
tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0);
|
||||
tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1);
|
||||
tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2);
|
||||
tfm.w = kernel_tex_fetch(__attributes_float3, desc.offset + 3);
|
||||
|
||||
return tfm;
|
||||
}
|
||||
|
@@ -24,23 +24,23 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Reading attributes on various curve elements */
|
||||
|
||||
ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
|
||||
ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_CURVE) {
|
||||
if(desc.element == ATTR_ELEMENT_CURVE) {
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
#endif
|
||||
|
||||
return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
|
||||
return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
|
||||
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
|
||||
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
|
||||
int k1 = k0 + 1;
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
|
||||
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
|
||||
@@ -59,9 +59,9 @@ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd,
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
|
||||
ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_CURVE) {
|
||||
if(desc.element == ATTR_ELEMENT_CURVE) {
|
||||
/* idea: we can't derive any useful differentials here, but for tiled
|
||||
* mipmap image caching it would be useful to avoid reading the highest
|
||||
* detail level always. maybe a derivative based on the hair density
|
||||
@@ -71,15 +71,15 @@ ccl_device float3 curve_attribute_float3(KernelGlobals *kg, const ShaderData *sd
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CURVE_KEY || elem == ATTR_ELEMENT_CURVE_KEY_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_CURVE_KEY || desc.element == ATTR_ELEMENT_CURVE_KEY_MOTION) {
|
||||
float4 curvedata = kernel_tex_fetch(__curves, ccl_fetch(sd, prim));
|
||||
int k0 = __float_as_int(curvedata.x) + PRIMITIVE_UNPACK_SEGMENT(ccl_fetch(sd, type));
|
||||
int k1 = k0 + 1;
|
||||
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k0));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + k1));
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k0));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k1));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*(f1 - f0);
|
||||
|
@@ -292,6 +292,18 @@ ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *nu
|
||||
*numverts = __float_as_int(f.w);
|
||||
}
|
||||
|
||||
/* Offset to an objects patch map */
|
||||
|
||||
ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
|
||||
{
|
||||
if(object == OBJECT_NONE)
|
||||
return 0;
|
||||
|
||||
int offset = object*OBJECT_SIZE + 11;
|
||||
float4 f = kernel_tex_fetch(__objects, offset);
|
||||
return __float_as_uint(f.x);
|
||||
}
|
||||
|
||||
/* Pass ID for shader */
|
||||
|
||||
ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
|
||||
|
343
intern/cycles/kernel/geom/geom_patch.h
Normal file
343
intern/cycles/kernel/geom/geom_patch.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Based on code from OpenSubdiv released under this license:
|
||||
*
|
||||
* Copyright 2013 Pixar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
* with the following modification; you may not use this file except in
|
||||
* compliance with the Apache License and the following modification to it:
|
||||
* Section 6. Trademarks. is deleted and replaced with:
|
||||
*
|
||||
* 6. Trademarks. This License does not grant permission to use the trade
|
||||
* names, trademarks, service marks, or product names of the Licensor
|
||||
* and its affiliates, except as required to comply with Section 4(c) of
|
||||
* the License and to reproduce the content of the NOTICE file.
|
||||
*
|
||||
* You may obtain a copy of the Apache License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the Apache License with the above modification is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the Apache License for the specific
|
||||
* language governing permissions and limitations under the Apache License.
|
||||
*
|
||||
*/
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
typedef struct PatchHandle {
|
||||
int array_index, patch_index, vert_index;
|
||||
} PatchHandle;
|
||||
|
||||
ccl_device_inline int patch_map_resolve_quadrant(float median, float *u, float *v)
|
||||
{
|
||||
int quadrant = -1;
|
||||
|
||||
if(*u < median) {
|
||||
if(*v < median) {
|
||||
quadrant = 0;
|
||||
}
|
||||
else {
|
||||
quadrant = 1;
|
||||
*v -= median;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(*v < median) {
|
||||
quadrant = 3;
|
||||
}
|
||||
else {
|
||||
quadrant = 2;
|
||||
*v -= median;
|
||||
}
|
||||
*u -= median;
|
||||
}
|
||||
|
||||
return quadrant;
|
||||
}
|
||||
|
||||
/* retrieve PatchHandle from patch coords */
|
||||
|
||||
ccl_device_inline PatchHandle patch_map_find_patch(KernelGlobals *kg, int object, int patch, float u, float v)
|
||||
{
|
||||
PatchHandle handle;
|
||||
|
||||
kernel_assert((u >= 0.0f) && (u <= 1.0f) && (v >= 0.0f) && (v <= 1.0f));
|
||||
|
||||
int node = (object_patch_map_offset(kg, object) + patch)/2;
|
||||
float median = 0.5f;
|
||||
|
||||
for(int depth = 0; depth < 0xff; depth++) {
|
||||
float delta = median * 0.5f;
|
||||
|
||||
int quadrant = patch_map_resolve_quadrant(median, &u, &v);
|
||||
kernel_assert(quadrant >= 0);
|
||||
|
||||
uint child = kernel_tex_fetch(__patches, node + quadrant);
|
||||
|
||||
/* is the quadrant a hole? */
|
||||
if(!(child & PATCH_MAP_NODE_IS_SET)) {
|
||||
handle.array_index = -1;
|
||||
return handle;
|
||||
}
|
||||
|
||||
uint index = child & PATCH_MAP_NODE_INDEX_MASK;
|
||||
|
||||
if(child & PATCH_MAP_NODE_IS_LEAF) {
|
||||
handle.array_index = kernel_tex_fetch(__patches, index + 0);
|
||||
handle.patch_index = kernel_tex_fetch(__patches, index + 1);
|
||||
handle.vert_index = kernel_tex_fetch(__patches, index + 2);
|
||||
|
||||
return handle;
|
||||
} else {
|
||||
node = index;
|
||||
}
|
||||
|
||||
median = delta;
|
||||
}
|
||||
|
||||
/* no leaf found */
|
||||
kernel_assert(0);
|
||||
|
||||
handle.array_index = -1;
|
||||
return handle;
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_bspline_weights(float t, float *point, float *deriv)
|
||||
{
|
||||
/* The four uniform cubic B-Spline basis functions evaluated at t */
|
||||
float inv_6 = 1.0f / 6.0f;
|
||||
|
||||
float t2 = t * t;
|
||||
float t3 = t * t2;
|
||||
|
||||
point[0] = inv_6 * (1.0f - 3.0f*(t - t2) - t3);
|
||||
point[1] = inv_6 * (4.0f - 6.0f*t2 + 3.0f*t3);
|
||||
point[2] = inv_6 * (1.0f + 3.0f*(t + t2 - t3));
|
||||
point[3] = inv_6 * t3;
|
||||
|
||||
/* Derivatives of the above four basis functions at t */
|
||||
deriv[0] = -0.5f*t2 + t - 0.5f;
|
||||
deriv[1] = 1.5f*t2 - 2.0f*t;
|
||||
deriv[2] = -1.5f*t2 + t + 0.5f;
|
||||
deriv[3] = 0.5f*t2;
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_adjust_boundary_weights(uint bits, float *s, float *t)
|
||||
{
|
||||
int boundary = ((bits >> 8) & 0xf);
|
||||
|
||||
if(boundary & 1) {
|
||||
t[2] -= t[0];
|
||||
t[1] += 2*t[0];
|
||||
t[0] = 0;
|
||||
}
|
||||
|
||||
if(boundary & 2) {
|
||||
s[1] -= s[3];
|
||||
s[2] += 2*s[3];
|
||||
s[3] = 0;
|
||||
}
|
||||
|
||||
if(boundary & 4) {
|
||||
t[1] -= t[3];
|
||||
t[2] += 2*t[3];
|
||||
t[3] = 0;
|
||||
}
|
||||
|
||||
if(boundary & 8) {
|
||||
s[2] -= s[0];
|
||||
s[1] += 2*s[0];
|
||||
s[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline int patch_eval_depth(uint patch_bits)
|
||||
{
|
||||
return (patch_bits & 0xf);
|
||||
}
|
||||
|
||||
ccl_device_inline float patch_eval_param_fraction(uint patch_bits)
|
||||
{
|
||||
bool non_quad_root = (patch_bits >> 4) & 0x1;
|
||||
int depth = patch_eval_depth(patch_bits);
|
||||
|
||||
if(non_quad_root) {
|
||||
return 1.0f / (float)(1 << (depth-1));
|
||||
}
|
||||
else {
|
||||
return 1.0f / (float)(1 << depth);
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device_inline void patch_eval_normalize_coords(uint patch_bits, float *u, float *v)
|
||||
{
|
||||
float frac = patch_eval_param_fraction(patch_bits);
|
||||
|
||||
int iu = (patch_bits >> 22) & 0x3ff;
|
||||
int iv = (patch_bits >> 12) & 0x3ff;
|
||||
|
||||
/* top left corner */
|
||||
float pu = (float)iu*frac;
|
||||
float pv = (float)iv*frac;
|
||||
|
||||
/* normalize uv coordinates */
|
||||
*u = (*u - pu) / frac;
|
||||
*v = (*v - pv) / frac;
|
||||
}
|
||||
|
||||
/* retrieve patch control indices */
|
||||
|
||||
ccl_device_inline int patch_eval_indices(KernelGlobals *kg, const PatchHandle *handle, int channel,
|
||||
int indices[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
|
||||
|
||||
/* XXX: regular patches only */
|
||||
for(int i = 0; i < 16; i++) {
|
||||
indices[i] = kernel_tex_fetch(__patches, index_base + i);
|
||||
}
|
||||
|
||||
return 16;
|
||||
}
|
||||
|
||||
/* evaluate patch basis functions */
|
||||
|
||||
ccl_device_inline void patch_eval_basis(KernelGlobals *kg, const PatchHandle *handle, float u, float v,
|
||||
float weights[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
|
||||
float d_scale = 1 << patch_eval_depth(patch_bits);
|
||||
|
||||
bool non_quad_root = (patch_bits >> 4) & 0x1;
|
||||
if(non_quad_root) {
|
||||
d_scale *= 0.5f;
|
||||
}
|
||||
|
||||
patch_eval_normalize_coords(patch_bits, &u, &v);
|
||||
|
||||
/* XXX: regular patches only for now. */
|
||||
|
||||
float s[4], t[4], ds[4], dt[4];
|
||||
|
||||
patch_eval_bspline_weights(u, s, ds);
|
||||
patch_eval_bspline_weights(v, t, dt);
|
||||
|
||||
patch_eval_adjust_boundary_weights(patch_bits, s, t);
|
||||
patch_eval_adjust_boundary_weights(patch_bits, ds, dt);
|
||||
|
||||
for(int k = 0; k < 4; k++) {
|
||||
for(int l = 0; l < 4; l++) {
|
||||
weights[4*k+l] = s[l] * t[k];
|
||||
weights_du[4*k+l] = ds[l] * t[k] * d_scale;
|
||||
weights_dv[4*k+l] = s[l] * dt[k] * d_scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generic function for evaluating indices and weights from patch coords */
|
||||
|
||||
ccl_device_inline int patch_eval_control_verts(KernelGlobals *kg, int object, int patch, float u, float v, int channel,
|
||||
int indices[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS],
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS])
|
||||
{
|
||||
PatchHandle handle = patch_map_find_patch(kg, object, patch, u, v);
|
||||
kernel_assert(handle.array_index >= 0);
|
||||
|
||||
int num_control = patch_eval_indices(kg, &handle, channel, indices);
|
||||
patch_eval_basis(kg, &handle, u, v, weights, weights_du, weights_dv);
|
||||
|
||||
return num_control;
|
||||
}
|
||||
|
||||
/* functions for evaluating attributes on patches */
|
||||
|
||||
ccl_device float patch_eval_float(KernelGlobals *kg, const ShaderData *sd, int offset,
|
||||
int patch, float u, float v, int channel,
|
||||
float *du, float* dv)
|
||||
{
|
||||
int indices[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
||||
|
||||
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
|
||||
indices, weights, weights_du, weights_dv);
|
||||
|
||||
float val = 0.0f;
|
||||
if(du) *du = 0.0f;
|
||||
if(dv) *dv = 0.0f;
|
||||
|
||||
for(int i = 0; i < num_control; i++) {
|
||||
float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
|
||||
|
||||
val += v * weights[i];
|
||||
if(du) *du += v * weights_du[i];
|
||||
if(dv) *dv += v * weights_dv[i];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
ccl_device float3 patch_eval_float3(KernelGlobals *kg, const ShaderData *sd, int offset,
|
||||
int patch, float u, float v, int channel,
|
||||
float3 *du, float3 *dv)
|
||||
{
|
||||
int indices[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
||||
|
||||
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
|
||||
indices, weights, weights_du, weights_dv);
|
||||
|
||||
float3 val = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i < num_control; i++) {
|
||||
float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i]));
|
||||
|
||||
val += v * weights[i];
|
||||
if(du) *du += v * weights_du[i];
|
||||
if(dv) *dv += v * weights_dv[i];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
ccl_device float3 patch_eval_uchar4(KernelGlobals *kg, const ShaderData *sd, int offset,
|
||||
int patch, float u, float v, int channel,
|
||||
float3 *du, float3 *dv)
|
||||
{
|
||||
int indices[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_du[PATCH_MAX_CONTROL_VERTS];
|
||||
float weights_dv[PATCH_MAX_CONTROL_VERTS];
|
||||
|
||||
int num_control = patch_eval_control_verts(kg, ccl_fetch(sd, object), patch, u, v, channel,
|
||||
indices, weights, weights_du, weights_dv);
|
||||
|
||||
float3 val = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(du) *du = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dv) *dv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i < num_control; i++) {
|
||||
float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
|
||||
|
||||
val += v * weights[i];
|
||||
if(du) *du += v * weights_du[i];
|
||||
if(dv) *dv += v * weights_dv[i];
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -25,24 +25,23 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
|
||||
const ShaderData *sd,
|
||||
AttributeElement elem,
|
||||
int offset,
|
||||
const AttributeDescriptor desc,
|
||||
float *dx, float *dy)
|
||||
{
|
||||
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if(subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
|
||||
return triangle_attribute_float(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float(kg, sd, elem, offset, dx, dy);
|
||||
return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
|
||||
return curve_attribute_float(kg, sd, elem, offset, dx, dy);
|
||||
return curve_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __VOLUME__
|
||||
else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
|
||||
return volume_attribute_float(kg, sd, elem, offset, dx, dy);
|
||||
else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
|
||||
return volume_attribute_float(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
@@ -54,25 +53,23 @@ ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
|
||||
|
||||
ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
|
||||
const ShaderData *sd,
|
||||
AttributeElement elem,
|
||||
int offset,
|
||||
float3 *dx,
|
||||
float3 *dy)
|
||||
const AttributeDescriptor desc,
|
||||
float3 *dx, float3 *dy)
|
||||
{
|
||||
if(ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE) {
|
||||
if(subd_triangle_patch(kg, sd) == ~0)
|
||||
return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
|
||||
return triangle_attribute_float3(kg, sd, desc, dx, dy);
|
||||
else
|
||||
return subd_triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
|
||||
return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#ifdef __HAIR__
|
||||
else if(ccl_fetch(sd, type) & PRIMITIVE_ALL_CURVE) {
|
||||
return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
|
||||
return curve_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
#ifdef __VOLUME__
|
||||
else if(ccl_fetch(sd, object) != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) {
|
||||
return volume_attribute_float3(kg, sd, elem, offset, dx, dy);
|
||||
else if(ccl_fetch(sd, object) != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
|
||||
return volume_attribute_float3(kg, sd, desc, dx, dy);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
@@ -86,13 +83,12 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
|
||||
|
||||
ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
|
||||
{
|
||||
AttributeElement elem_uv;
|
||||
int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
|
||||
|
||||
if(offset_uv == ATTR_STD_NOT_FOUND)
|
||||
if(desc.offset == ATTR_STD_NOT_FOUND)
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
|
||||
float3 uv = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
uv.z = 1.0f;
|
||||
return uv;
|
||||
}
|
||||
@@ -102,15 +98,14 @@ ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
|
||||
ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id)
|
||||
{
|
||||
/* storing ptex data as attributes is not memory efficient but simple for tests */
|
||||
AttributeElement elem_face_id, elem_uv;
|
||||
int offset_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID, &elem_face_id);
|
||||
int offset_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV, &elem_uv);
|
||||
const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
|
||||
const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
|
||||
|
||||
if(offset_face_id == ATTR_STD_NOT_FOUND || offset_uv == ATTR_STD_NOT_FOUND)
|
||||
if(desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
|
||||
return false;
|
||||
|
||||
float3 uv3 = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
|
||||
float face_id_f = primitive_attribute_float(kg, sd, elem_face_id, offset_face_id, NULL, NULL);
|
||||
float3 uv3 = primitive_attribute_float3(kg, sd, desc_uv, NULL, NULL);
|
||||
float face_id_f = primitive_attribute_float(kg, sd, desc_face_id, NULL, NULL);
|
||||
|
||||
*uv = make_float2(uv3.x, uv3.y);
|
||||
*face_id = (int)face_id_f;
|
||||
@@ -132,11 +127,10 @@ ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
|
||||
#endif
|
||||
|
||||
/* try to create spherical tangent from generated coordinates */
|
||||
AttributeElement attr_elem;
|
||||
int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
|
||||
|
||||
if(attr_offset != ATTR_STD_NOT_FOUND) {
|
||||
float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
|
||||
if(desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
float3 data = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
|
||||
object_normal_transform(kg, sd, &data);
|
||||
return cross(ccl_fetch(sd, N), normalize(cross(data, ccl_fetch(sd, N))));
|
||||
@@ -173,19 +167,18 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *
|
||||
float3 motion_pre = center, motion_post = center;
|
||||
|
||||
/* deformation motion */
|
||||
AttributeElement elem;
|
||||
int offset = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION, &elem);
|
||||
AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if(offset != ATTR_STD_NOT_FOUND) {
|
||||
if(desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
/* get motion info */
|
||||
int numverts, numkeys;
|
||||
object_motion_info(kg, ccl_fetch(sd, object), NULL, &numverts, &numkeys);
|
||||
|
||||
/* lookup attributes */
|
||||
int offset_next = (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? offset + numverts: offset + numkeys;
|
||||
motion_pre = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
|
||||
motion_pre = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
motion_post = primitive_attribute_float3(kg, sd, elem, offset_next, NULL, NULL);
|
||||
desc.offset += (ccl_fetch(sd, type) & PRIMITIVE_ALL_TRIANGLE)? numverts: numkeys;
|
||||
motion_post = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
|
||||
#ifdef __HAIR__
|
||||
if(is_curve_primitive && (ccl_fetch(sd, flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
|
||||
|
@@ -97,36 +97,78 @@ ccl_device_inline void subd_triangle_patch_corners(KernelGlobals *kg, int patch,
|
||||
|
||||
/* Reading attributes on various subdivision triangle elements */
|
||||
|
||||
ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
|
||||
ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
|
||||
{
|
||||
int patch = subd_triangle_patch(kg, sd);
|
||||
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(desc.flags & ATTR_SUBDIVIDED) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
float2 dpdu = uv[0] - uv[2];
|
||||
float2 dpdv = uv[1] - uv[2];
|
||||
|
||||
/* p is [s, t] */
|
||||
float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
|
||||
|
||||
float a, dads, dadt;
|
||||
a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx || dy) {
|
||||
float dsdu = dpdu.x;
|
||||
float dtdu = dpdu.y;
|
||||
float dsdv = dpdv.x;
|
||||
float dtdv = dpdv.y;
|
||||
|
||||
if(dx) {
|
||||
float dudx = ccl_fetch(sd, du).dx;
|
||||
float dvdx = ccl_fetch(sd, dv).dx;
|
||||
|
||||
float dsdx = dsdu*dudx + dsdv*dvdx;
|
||||
float dtdx = dtdu*dudx + dtdv*dvdx;
|
||||
|
||||
*dx = dads*dsdx + dadt*dtdx;
|
||||
}
|
||||
if(dy) {
|
||||
float dudy = ccl_fetch(sd, du).dy;
|
||||
float dvdy = ccl_fetch(sd, dv).dy;
|
||||
|
||||
float dsdy = dsdu*dudy + dsdv*dvdy;
|
||||
float dtdy = dtdu*dudy + dtdv*dvdy;
|
||||
|
||||
*dy = dads*dsdy + dadt*dtdy;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return a;
|
||||
}
|
||||
else if(desc.element == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return kernel_tex_fetch(__attributes_float, offset + subd_triangle_patch_face(kg, patch));
|
||||
return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
uint4 v = subd_triangle_patch_indices(kg, patch);
|
||||
|
||||
float a, b, c;
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + v.x);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + v.y);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, offset + v.z);
|
||||
float f3 = kernel_tex_fetch(__attributes_float, offset + v.w);
|
||||
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
|
||||
float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
|
||||
|
||||
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
f1 = (f1+f0)*0.5f;
|
||||
f3 = (f3+f0)*0.5f;
|
||||
}
|
||||
|
||||
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
|
||||
@@ -135,28 +177,26 @@ ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderDa
|
||||
|
||||
return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int corners[4];
|
||||
subd_triangle_patch_corners(kg, patch, corners);
|
||||
|
||||
else if(desc.element == ATTR_ELEMENT_CORNER) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
float a, b, c;
|
||||
int corners[4];
|
||||
subd_triangle_patch_corners(kg, patch, corners);
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, corners[0] + offset);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, corners[1] + offset);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, corners[2] + offset);
|
||||
float f3 = kernel_tex_fetch(__attributes_float, corners[3] + offset);
|
||||
float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
|
||||
float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
|
||||
|
||||
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
f1 = (f1+f0)*0.5f;
|
||||
f3 = (f3+f0)*0.5f;
|
||||
}
|
||||
|
||||
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
|
||||
@@ -173,36 +213,84 @@ ccl_device float subd_triangle_attribute_float(KernelGlobals *kg, const ShaderDa
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
|
||||
ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
|
||||
{
|
||||
int patch = subd_triangle_patch(kg, sd);
|
||||
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(desc.flags & ATTR_SUBDIVIDED) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
float2 dpdu = uv[0] - uv[2];
|
||||
float2 dpdv = uv[1] - uv[2];
|
||||
|
||||
/* p is [s, t] */
|
||||
float2 p = dpdu * ccl_fetch(sd, u) + dpdv * ccl_fetch(sd, v) + uv[2];
|
||||
|
||||
float3 a, dads, dadt;
|
||||
|
||||
if(desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
||||
}
|
||||
else {
|
||||
a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx || dy) {
|
||||
float dsdu = dpdu.x;
|
||||
float dtdu = dpdu.y;
|
||||
float dsdv = dpdv.x;
|
||||
float dtdv = dpdv.y;
|
||||
|
||||
if(dx) {
|
||||
float dudx = ccl_fetch(sd, du).dx;
|
||||
float dvdx = ccl_fetch(sd, dv).dx;
|
||||
|
||||
float dsdx = dsdu*dudx + dsdv*dvdx;
|
||||
float dtdx = dtdu*dudx + dtdv*dvdx;
|
||||
|
||||
*dx = dads*dsdx + dadt*dtdx;
|
||||
}
|
||||
if(dy) {
|
||||
float dudy = ccl_fetch(sd, du).dy;
|
||||
float dvdy = ccl_fetch(sd, dv).dy;
|
||||
|
||||
float dsdy = dsdu*dudy + dsdv*dvdy;
|
||||
float dtdy = dtdu*dudy + dtdv*dvdy;
|
||||
|
||||
*dy = dads*dsdy + dadt*dtdy;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return a;
|
||||
}
|
||||
else if(desc.element == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + subd_triangle_patch_face(kg, patch)));
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch)));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
uint4 v = subd_triangle_patch_indices(kg, patch);
|
||||
|
||||
float3 a, b, c;
|
||||
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.x));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.y));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.z));
|
||||
float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + v.w));
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.x));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.y));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.z));
|
||||
float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.w));
|
||||
|
||||
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
f1 = (f1+f0)*0.5f;
|
||||
f3 = (f3+f0)*0.5f;
|
||||
}
|
||||
|
||||
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
|
||||
@@ -211,27 +299,26 @@ ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const Shader
|
||||
|
||||
return ccl_fetch(sd, u)*a + ccl_fetch(sd, v)*b + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*c;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
int corners[4];
|
||||
subd_triangle_patch_corners(kg, patch, corners);
|
||||
|
||||
else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
float2 uv[3];
|
||||
subd_triangle_patch_uv(kg, sd, uv);
|
||||
|
||||
float3 a, b, c;
|
||||
int corners[4];
|
||||
subd_triangle_patch_corners(kg, patch, corners);
|
||||
|
||||
float3 f0, f1, f2, f3;
|
||||
|
||||
if(elem == ATTR_ELEMENT_CORNER) {
|
||||
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + offset));
|
||||
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + offset));
|
||||
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + offset));
|
||||
f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + offset));
|
||||
if(desc.element == ATTR_ELEMENT_CORNER) {
|
||||
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
|
||||
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
|
||||
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
|
||||
f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
|
||||
}
|
||||
else {
|
||||
f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + offset));
|
||||
f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + offset));
|
||||
f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + offset));
|
||||
f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + offset));
|
||||
f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
|
||||
f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
|
||||
f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
|
||||
f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
|
||||
}
|
||||
|
||||
if(subd_triangle_patch_num_corners(kg, patch) != 4) {
|
||||
@@ -239,9 +326,9 @@ ccl_device float3 subd_triangle_attribute_float3(KernelGlobals *kg, const Shader
|
||||
f3 = (f3+f0)*0.5f;
|
||||
}
|
||||
|
||||
a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
||||
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
||||
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*a + ccl_fetch(sd, dv).dx*b - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*c;
|
||||
|
@@ -105,20 +105,20 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_spa
|
||||
|
||||
/* Reading attributes on various triangle elements */
|
||||
|
||||
ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
|
||||
ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(desc.element == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = 0.0f;
|
||||
if(dy) *dy = 0.0f;
|
||||
|
||||
return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim));
|
||||
return kernel_tex_fetch(__attributes_float, desc.offset + ccl_fetch(sd, prim));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
|
||||
|
||||
float f0 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.x);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.y);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.z);
|
||||
float f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
|
||||
@@ -127,8 +127,8 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
|
||||
|
||||
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER) {
|
||||
int tri = offset + ccl_fetch(sd, prim)*3;
|
||||
else if(desc.element == ATTR_ELEMENT_CORNER) {
|
||||
int tri = desc.offset + ccl_fetch(sd, prim)*3;
|
||||
float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
|
||||
float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
|
||||
float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
|
||||
@@ -148,20 +148,20 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s
|
||||
}
|
||||
}
|
||||
|
||||
ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
|
||||
ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
|
||||
{
|
||||
if(elem == ATTR_ELEMENT_FACE) {
|
||||
if(desc.element == ATTR_ELEMENT_FACE) {
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim)));
|
||||
return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + ccl_fetch(sd, prim)));
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
else if(desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
||||
uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim));
|
||||
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z));
|
||||
float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x));
|
||||
float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y));
|
||||
float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z));
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2;
|
||||
@@ -170,11 +170,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData
|
||||
|
||||
return ccl_fetch(sd, u)*f0 + ccl_fetch(sd, v)*f1 + (1.0f - ccl_fetch(sd, u) - ccl_fetch(sd, v))*f2;
|
||||
}
|
||||
else if(elem == ATTR_ELEMENT_CORNER || elem == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
int tri = offset + ccl_fetch(sd, prim)*3;
|
||||
else if(desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
int tri = desc.offset + ccl_fetch(sd, prim)*3;
|
||||
float3 f0, f1, f2;
|
||||
|
||||
if(elem == ATTR_ELEMENT_CORNER) {
|
||||
if(desc.element == ATTR_ELEMENT_CORNER) {
|
||||
f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
|
||||
f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
|
||||
f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
|
||||
|
@@ -50,36 +50,35 @@ ccl_device_inline float3 volume_normalized_position(KernelGlobals *kg,
|
||||
{
|
||||
/* todo: optimize this so it's just a single matrix multiplication when
|
||||
* possible (not motion blur), or perhaps even just translation + scale */
|
||||
AttributeElement attr_elem;
|
||||
int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem);
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM);
|
||||
|
||||
object_inverse_position_transform(kg, sd, &P);
|
||||
|
||||
if(attr_offset != ATTR_STD_NOT_FOUND) {
|
||||
Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset);
|
||||
if(desc.offset != ATTR_STD_NOT_FOUND) {
|
||||
Transform tfm = primitive_attribute_matrix(kg, sd, desc);
|
||||
P = transform_point(&tfm, P);
|
||||
}
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float *dx, float *dy)
|
||||
ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
|
||||
{
|
||||
float3 P = volume_normalized_position(kg, sd, sd->P);
|
||||
#ifdef __KERNEL_GPU__
|
||||
# if __CUDA_ARCH__ >= 300
|
||||
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
|
||||
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
|
||||
float f = kernel_tex_image_interp_3d_float(tex, P.x, P.y, P.z);
|
||||
float4 r = make_float4(f, f, f, 1.0);
|
||||
# else
|
||||
float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
|
||||
float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
|
||||
# endif
|
||||
#else
|
||||
float4 r;
|
||||
if(sd->flag & SD_VOLUME_CUBIC)
|
||||
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
else
|
||||
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
|
||||
r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
|
||||
#endif
|
||||
|
||||
if(dx) *dx = 0.0f;
|
||||
@@ -88,22 +87,22 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
|
||||
return average(float4_to_float3(r));
|
||||
}
|
||||
|
||||
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy)
|
||||
ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
|
||||
{
|
||||
float3 P = volume_normalized_position(kg, sd, sd->P);
|
||||
#ifdef __KERNEL_GPU__
|
||||
# if __CUDA_ARCH__ >= 300
|
||||
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id);
|
||||
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
|
||||
float4 r = kernel_tex_image_interp_3d_float4(tex, P.x, P.y, P.z);
|
||||
# else
|
||||
float4 r = volume_image_texture_3d(id, P.x, P.y, P.z);
|
||||
float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
|
||||
# endif
|
||||
#else
|
||||
float4 r;
|
||||
if(sd->flag & SD_VOLUME_CUBIC)
|
||||
r = kernel_tex_image_interp_3d_ex(id, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
r = kernel_tex_image_interp_3d_ex(desc.offset, P.x, P.y, P.z, INTERPOLATION_CUBIC);
|
||||
else
|
||||
r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z);
|
||||
r = kernel_tex_image_interp_3d(desc.offset, P.x, P.y, P.z);
|
||||
#endif
|
||||
|
||||
if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
@@ -149,7 +149,7 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
|
||||
/* ShaderData setup from BSSRDF scatter */
|
||||
|
||||
#ifdef __SUBSURFACE__
|
||||
# ifndef __KERNEL_CUDS__
|
||||
# ifndef __KERNEL_CUDA__
|
||||
ccl_device
|
||||
# else
|
||||
ccl_device_inline
|
||||
@@ -539,7 +539,7 @@ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg,
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __KERNEL_CUDS__
|
||||
#ifndef __KERNEL_CUDA__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_inline
|
||||
|
@@ -86,7 +86,7 @@ ccl_device ShaderClosure *subsurface_scatter_pick_closure(KernelGlobals *kg, Sha
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_GPU__
|
||||
ccl_device
|
||||
ccl_device_noinline
|
||||
#else
|
||||
ccl_device_inline
|
||||
#endif
|
||||
|
@@ -34,7 +34,7 @@
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* constants */
|
||||
#define OBJECT_SIZE 11
|
||||
#define OBJECT_SIZE 12
|
||||
#define OBJECT_VECTOR_SIZE 6
|
||||
#define LIGHT_SIZE 5
|
||||
#define FILTER_TABLE_SIZE 1024
|
||||
@@ -624,6 +624,18 @@ typedef enum AttributeStandard {
|
||||
ATTR_STD_NOT_FOUND = ~0
|
||||
} AttributeStandard;
|
||||
|
||||
typedef enum AttributeFlag {
|
||||
ATTR_FINAL_SIZE = (1 << 0),
|
||||
ATTR_SUBDIVIDED = (1 << 1),
|
||||
} AttributeFlag;
|
||||
|
||||
typedef struct AttributeDescriptor {
|
||||
AttributeElement element;
|
||||
NodeAttributeType type;
|
||||
uint flags; /* see enum AttributeFlag */
|
||||
int offset;
|
||||
} AttributeDescriptor;
|
||||
|
||||
/* Closure data */
|
||||
|
||||
#ifdef __MULTI_CLOSURE__
|
||||
@@ -1239,6 +1251,16 @@ enum RayState {
|
||||
#define REMOVE_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] & (~flag)))
|
||||
#define IS_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] & flag)
|
||||
|
||||
/* Patches */
|
||||
|
||||
#define PATCH_MAX_CONTROL_VERTS 16
|
||||
|
||||
/* Patch map node flags */
|
||||
|
||||
#define PATCH_MAP_NODE_IS_SET (1 << 30)
|
||||
#define PATCH_MAP_NODE_IS_LEAF (1 << 31)
|
||||
#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __KERNEL_TYPES_H__ */
|
||||
|
@@ -59,8 +59,7 @@ struct OSLGlobals {
|
||||
/* attributes */
|
||||
struct Attribute {
|
||||
TypeDesc type;
|
||||
AttributeElement elem;
|
||||
int offset;
|
||||
AttributeDescriptor desc;
|
||||
ParamValue value;
|
||||
};
|
||||
|
||||
|
@@ -554,13 +554,13 @@ static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd,
|
||||
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
|
||||
{
|
||||
float3 fval[3];
|
||||
fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
|
||||
fval[0] = primitive_attribute_float3(kg, sd, attr.desc,
|
||||
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
|
||||
return set_attribute_float3(fval, type, derivatives, val);
|
||||
}
|
||||
else if(attr.type == TypeDesc::TypeFloat) {
|
||||
float fval[3];
|
||||
fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
|
||||
fval[0] = primitive_attribute_float(kg, sd, attr.desc,
|
||||
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
|
||||
return set_attribute_float(fval, type, derivatives, val);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
|
||||
const TypeDesc& type, bool derivatives, void *val)
|
||||
{
|
||||
if(attr.type == TypeDesc::TypeMatrix) {
|
||||
Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
|
||||
Transform tfm = primitive_attribute_matrix(kg, sd, attr.desc);
|
||||
return set_attribute_matrix(tfm, type, val);
|
||||
}
|
||||
else {
|
||||
@@ -815,7 +815,7 @@ bool OSLRenderServices::get_attribute(ShaderData *sd, bool derivatives, ustring
|
||||
if(it != attribute_map.end()) {
|
||||
const OSLGlobals::Attribute& attr = it->second;
|
||||
|
||||
if(attr.elem != ATTR_ELEMENT_OBJECT) {
|
||||
if(attr.desc.element != ATTR_ELEMENT_OBJECT) {
|
||||
/* triangle and vertex attributes */
|
||||
if(get_mesh_element_attribute(kg, sd, attr, type, derivatives, val))
|
||||
return true;
|
||||
|
@@ -334,7 +334,7 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderConte
|
||||
|
||||
/* Attributes */
|
||||
|
||||
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem)
|
||||
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc)
|
||||
{
|
||||
/* for OSL, a hash map is used to lookup the attribute by name. */
|
||||
int object = sd->object*ATTR_PRIM_TYPES;
|
||||
@@ -348,16 +348,23 @@ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id,
|
||||
|
||||
if(it != attr_map.end()) {
|
||||
const OSLGlobals::Attribute &osl_attr = it->second;
|
||||
*elem = osl_attr.elem;
|
||||
*desc = osl_attr.desc;
|
||||
|
||||
if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.elem != ATTR_ELEMENT_MESH)
|
||||
if(sd->prim == PRIM_NONE && (AttributeElement)osl_attr.desc.element != ATTR_ELEMENT_MESH) {
|
||||
desc->offset = ATTR_STD_NOT_FOUND;
|
||||
return ATTR_STD_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* return result */
|
||||
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
|
||||
if(osl_attr.desc.element == ATTR_ELEMENT_NONE) {
|
||||
desc->offset = ATTR_STD_NOT_FOUND;
|
||||
}
|
||||
return desc->offset;
|
||||
}
|
||||
else
|
||||
else {
|
||||
desc->offset = ATTR_STD_NOT_FOUND;
|
||||
return (int)ATTR_STD_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -59,7 +59,7 @@ public:
|
||||
static void eval_displacement(KernelGlobals *kg, ShaderData *sd, ShaderContext ctx);
|
||||
|
||||
/* attributes */
|
||||
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeElement *elem);
|
||||
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id, AttributeDescriptor *desc);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -18,117 +18,101 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Attribute Node */
|
||||
|
||||
ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
|
||||
ccl_device AttributeDescriptor svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
|
||||
uint4 node, NodeAttributeType *type,
|
||||
NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset)
|
||||
uint *out_offset)
|
||||
{
|
||||
*out_offset = node.z;
|
||||
*type = (NodeAttributeType)node.w;
|
||||
if(ccl_fetch(sd, object) != OBJECT_NONE) {
|
||||
/* find attribute by unique id */
|
||||
uint id = node.y;
|
||||
uint attr_offset = ccl_fetch(sd, object)*kernel_data.bvh.attributes_map_stride;
|
||||
attr_offset += attribute_primitive_type(kg, sd);
|
||||
uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
|
||||
|
||||
while(attr_map.x != id) {
|
||||
if(UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
|
||||
*elem = ATTR_ELEMENT_NONE;
|
||||
*offset = 0;
|
||||
*mesh_type = (NodeAttributeType)node.w;
|
||||
return;
|
||||
}
|
||||
attr_offset += ATTR_PRIM_TYPES;
|
||||
attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
|
||||
}
|
||||
|
||||
/* return result */
|
||||
*elem = (AttributeElement)attr_map.y;
|
||||
*offset = as_int(attr_map.z);
|
||||
*mesh_type = (NodeAttributeType)attr_map.w;
|
||||
AttributeDescriptor desc;
|
||||
|
||||
if(ccl_fetch(sd, object) != OBJECT_NONE) {
|
||||
desc = find_attribute(kg, sd, node.y);
|
||||
if(desc.offset == ATTR_STD_NOT_FOUND) {
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
desc.type = (NodeAttributeType)node.w;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* background */
|
||||
*elem = ATTR_ELEMENT_NONE;
|
||||
*offset = 0;
|
||||
*mesh_type = (NodeAttributeType)node.w;
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
desc.type = (NodeAttributeType)node.w;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||
{
|
||||
NodeAttributeType type, mesh_type;
|
||||
AttributeElement elem;
|
||||
NodeAttributeType type;
|
||||
uint out_offset;
|
||||
int offset;
|
||||
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
if(desc.type == NODE_ATTR_FLOAT) {
|
||||
float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, NULL);
|
||||
if(desc.type == NODE_ATTR_FLOAT3) {
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, NULL);
|
||||
float f = primitive_attribute_float(kg, sd, desc, NULL, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f, f, f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_CUDS__
|
||||
#ifndef __KERNEL_CUDA__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_noinline
|
||||
#endif
|
||||
void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||
{
|
||||
NodeAttributeType type, mesh_type;
|
||||
AttributeElement elem;
|
||||
NodeAttributeType type;
|
||||
uint out_offset;
|
||||
int offset;
|
||||
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
if(desc.type == NODE_ATTR_FLOAT) {
|
||||
float dx;
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, f+dx);
|
||||
}
|
||||
else {
|
||||
float3 dx;
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
|
||||
stack_store_float(stack, out_offset, average(f+dx));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
if(desc.type == NODE_ATTR_FLOAT3) {
|
||||
float3 dx;
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, &dx, NULL);
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, f+dx);
|
||||
}
|
||||
else {
|
||||
float dx;
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, &dx, NULL);
|
||||
float f = primitive_attribute_float(kg, sd, desc, &dx, NULL);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __KERNEL_CUDS__
|
||||
#ifndef __KERNEL_CUDA__
|
||||
ccl_device
|
||||
#else
|
||||
ccl_device_noinline
|
||||
@@ -138,35 +122,32 @@ void svm_node_attr_bump_dy(KernelGlobals *kg,
|
||||
float *stack,
|
||||
uint4 node)
|
||||
{
|
||||
NodeAttributeType type, mesh_type;
|
||||
AttributeElement elem;
|
||||
NodeAttributeType type;
|
||||
uint out_offset;
|
||||
int offset;
|
||||
|
||||
svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
|
||||
AttributeDescriptor desc = svm_node_attr_init(kg, sd, node, &type, &out_offset);
|
||||
|
||||
/* fetch and store attribute */
|
||||
if(type == NODE_ATTR_FLOAT) {
|
||||
if(mesh_type == NODE_ATTR_FLOAT) {
|
||||
if(desc.type == NODE_ATTR_FLOAT) {
|
||||
float dy;
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, f+dy);
|
||||
}
|
||||
else {
|
||||
float3 dy;
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
|
||||
stack_store_float(stack, out_offset, average(f+dy));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mesh_type == NODE_ATTR_FLOAT3) {
|
||||
if(desc.type == NODE_ATTR_FLOAT3) {
|
||||
float3 dy;
|
||||
float3 f = primitive_attribute_float3(kg, sd, elem, offset, NULL, &dy);
|
||||
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, f+dy);
|
||||
}
|
||||
else {
|
||||
float dy;
|
||||
float f = primitive_attribute_float(kg, sd, elem, offset, NULL, &dy);
|
||||
float f = primitive_attribute_float(kg, sd, desc, NULL, &dy);
|
||||
stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
|
||||
}
|
||||
}
|
||||
|
@@ -287,23 +287,22 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
}
|
||||
|
||||
/* first try to get tangent attribute */
|
||||
AttributeElement attr_elem, attr_sign_elem, attr_normal_elem;
|
||||
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
|
||||
int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
|
||||
int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
|
||||
const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
|
||||
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
|
||||
const AttributeDescriptor attr_normal = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL);
|
||||
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
|
||||
if(attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND || attr_normal.offset == ATTR_STD_NOT_FOUND) {
|
||||
stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
/* get _unnormalized_ interpolated normal and tangent */
|
||||
float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
|
||||
float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
|
||||
float3 tangent = primitive_attribute_float3(kg, sd, attr, NULL, NULL);
|
||||
float sign = primitive_attribute_float(kg, sd, attr_sign, NULL, NULL);
|
||||
float3 normal;
|
||||
|
||||
if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) {
|
||||
normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
|
||||
normal = primitive_attribute_float3(kg, sd, attr_normal, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
normal = ccl_fetch(sd, Ng);
|
||||
@@ -356,24 +355,22 @@ ccl_device void svm_node_tangent(KernelGlobals *kg, ShaderData *sd, float *stack
|
||||
|
||||
if(direction_type == NODE_TANGENT_UVMAP) {
|
||||
/* UV map */
|
||||
AttributeElement attr_elem;
|
||||
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
|
||||
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND)
|
||||
if(desc.offset == ATTR_STD_NOT_FOUND)
|
||||
tangent = make_float3(0.0f, 0.0f, 0.0f);
|
||||
else
|
||||
tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
|
||||
tangent = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
}
|
||||
else {
|
||||
/* radial */
|
||||
AttributeElement attr_elem;
|
||||
int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
|
||||
const AttributeDescriptor desc = find_attribute(kg, sd, node.z);
|
||||
float3 generated;
|
||||
|
||||
if(attr_offset == ATTR_STD_NOT_FOUND)
|
||||
if(desc.offset == ATTR_STD_NOT_FOUND)
|
||||
generated = ccl_fetch(sd, P);
|
||||
else
|
||||
generated = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
|
||||
generated = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
|
||||
|
||||
if(axis == NODE_TANGENT_AXIS_X)
|
||||
tangent = make_float3(0.0f, -(generated.z - 0.5f), (generated.y - 0.5f));
|
||||
|
@@ -44,6 +44,7 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
|
||||
type = type_;
|
||||
element = element_;
|
||||
std = ATTR_STD_NONE;
|
||||
flags = 0;
|
||||
|
||||
/* string and matrix not supported! */
|
||||
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
|
||||
@@ -61,6 +62,11 @@ void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
|
||||
}
|
||||
}
|
||||
|
||||
void Attribute::resize(size_t num_elements)
|
||||
{
|
||||
buffer.resize(num_elements * data_sizeof(), 0);
|
||||
}
|
||||
|
||||
void Attribute::add(const float& f)
|
||||
{
|
||||
char *data = (char*)&f;
|
||||
@@ -130,6 +136,10 @@ size_t Attribute::data_sizeof() const
|
||||
|
||||
size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const
|
||||
{
|
||||
if(flags & ATTR_FINAL_SIZE) {
|
||||
return buffer.size() / data_sizeof();
|
||||
}
|
||||
|
||||
size_t size;
|
||||
|
||||
switch(element) {
|
||||
@@ -517,16 +527,19 @@ AttributeRequest::AttributeRequest(ustring name_)
|
||||
std = ATTR_STD_NONE;
|
||||
|
||||
triangle_type = TypeDesc::TypeFloat;
|
||||
triangle_element = ATTR_ELEMENT_NONE;
|
||||
triangle_offset = 0;
|
||||
triangle_desc.element = ATTR_ELEMENT_NONE;
|
||||
triangle_desc.offset = 0;
|
||||
triangle_desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
curve_type = TypeDesc::TypeFloat;
|
||||
curve_element = ATTR_ELEMENT_NONE;
|
||||
curve_offset = 0;
|
||||
curve_desc.element = ATTR_ELEMENT_NONE;
|
||||
curve_desc.offset = 0;
|
||||
curve_desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
subd_type = TypeDesc::TypeFloat;
|
||||
subd_element = ATTR_ELEMENT_NONE;
|
||||
subd_offset = 0;
|
||||
subd_desc.element = ATTR_ELEMENT_NONE;
|
||||
subd_desc.offset = 0;
|
||||
subd_desc.type = NODE_ATTR_FLOAT;
|
||||
}
|
||||
|
||||
AttributeRequest::AttributeRequest(AttributeStandard std_)
|
||||
@@ -535,16 +548,19 @@ AttributeRequest::AttributeRequest(AttributeStandard std_)
|
||||
std = std_;
|
||||
|
||||
triangle_type = TypeDesc::TypeFloat;
|
||||
triangle_element = ATTR_ELEMENT_NONE;
|
||||
triangle_offset = 0;
|
||||
triangle_desc.element = ATTR_ELEMENT_NONE;
|
||||
triangle_desc.offset = 0;
|
||||
triangle_desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
curve_type = TypeDesc::TypeFloat;
|
||||
curve_element = ATTR_ELEMENT_NONE;
|
||||
curve_offset = 0;
|
||||
curve_desc.element = ATTR_ELEMENT_NONE;
|
||||
curve_desc.offset = 0;
|
||||
curve_desc.type = NODE_ATTR_FLOAT;
|
||||
|
||||
subd_type = TypeDesc::TypeFloat;
|
||||
subd_element = ATTR_ELEMENT_NONE;
|
||||
subd_offset = 0;
|
||||
subd_desc.element = ATTR_ELEMENT_NONE;
|
||||
subd_desc.offset = 0;
|
||||
subd_desc.type = NODE_ATTR_FLOAT;
|
||||
}
|
||||
|
||||
/* AttributeRequestSet */
|
||||
|
@@ -54,11 +54,13 @@ public:
|
||||
TypeDesc type;
|
||||
vector<char> buffer;
|
||||
AttributeElement element;
|
||||
uint flags; /* enum AttributeFlag */
|
||||
|
||||
Attribute() {}
|
||||
~Attribute();
|
||||
void set(ustring name, TypeDesc type, AttributeElement element);
|
||||
void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only);
|
||||
void resize(size_t num_elements);
|
||||
|
||||
size_t data_sizeof() const;
|
||||
size_t element_size(Mesh *mesh, AttributePrimitive prim) const;
|
||||
@@ -135,8 +137,7 @@ public:
|
||||
|
||||
/* temporary variables used by MeshManager */
|
||||
TypeDesc triangle_type, curve_type, subd_type;
|
||||
AttributeElement triangle_element, curve_element, subd_element;
|
||||
int triangle_offset, curve_offset, subd_offset;
|
||||
AttributeDescriptor triangle_desc, curve_desc, subd_desc;
|
||||
|
||||
explicit AttributeRequest(ustring name_);
|
||||
explicit AttributeRequest(AttributeStandard std);
|
||||
|
@@ -30,6 +30,8 @@
|
||||
|
||||
#include "osl_globals.h"
|
||||
|
||||
#include "subd_patch_table.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
#include "util_logging.h"
|
||||
#include "util_progress.h"
|
||||
@@ -112,19 +114,12 @@ float3 Mesh::SubdFace::normal(const Mesh *mesh) const
|
||||
return safe_normalize(cross(v1 - v0, v2 - v0));
|
||||
}
|
||||
|
||||
|
||||
/* Mesh */
|
||||
|
||||
NODE_DEFINE(Mesh)
|
||||
{
|
||||
NodeType* type = NodeType::add("mesh", create);
|
||||
|
||||
static NodeEnum displacement_method_enum;
|
||||
displacement_method_enum.insert("bump", DISPLACE_BUMP);
|
||||
displacement_method_enum.insert("true", DISPLACE_TRUE);
|
||||
displacement_method_enum.insert("both", DISPLACE_BOTH);
|
||||
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
|
||||
|
||||
SOCKET_UINT(motion_steps, "Motion Steps", 3);
|
||||
SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false);
|
||||
|
||||
@@ -177,11 +172,14 @@ Mesh::Mesh()
|
||||
num_ngons = 0;
|
||||
|
||||
subdivision_type = SUBDIVISION_NONE;
|
||||
|
||||
patch_table = NULL;
|
||||
}
|
||||
|
||||
Mesh::~Mesh()
|
||||
{
|
||||
delete bvh;
|
||||
delete patch_table;
|
||||
}
|
||||
|
||||
void Mesh::resize_mesh(int numverts, int numtris)
|
||||
@@ -274,6 +272,8 @@ void Mesh::clear()
|
||||
|
||||
num_subd_verts = 0;
|
||||
|
||||
subd_creases.clear();
|
||||
|
||||
attributes.clear();
|
||||
curve_attributes.clear();
|
||||
subd_attributes.clear();
|
||||
@@ -283,6 +283,9 @@ void Mesh::clear()
|
||||
transform_negative_scaled = false;
|
||||
transform_normal = transform_identity();
|
||||
geometry_flags = GEOMETRY_NONE;
|
||||
|
||||
delete patch_table;
|
||||
patch_table = NULL;
|
||||
}
|
||||
|
||||
int Mesh::split_vertex(int vertex)
|
||||
@@ -705,7 +708,6 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mesh::compute_bvh(DeviceScene *dscene,
|
||||
SceneParams *params,
|
||||
Progress *progress,
|
||||
@@ -779,6 +781,17 @@ bool Mesh::has_motion_blur() const
|
||||
curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)));
|
||||
}
|
||||
|
||||
bool Mesh::has_true_displacement() const
|
||||
{
|
||||
foreach(Shader *shader, used_shaders) {
|
||||
if(shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mesh::need_build_bvh() const
|
||||
{
|
||||
return !transform_applied || has_surface_bssrdf;
|
||||
@@ -831,9 +844,10 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
|
||||
OSLGlobals::Attribute osl_attr;
|
||||
|
||||
osl_attr.type = attr.type();
|
||||
osl_attr.elem = ATTR_ELEMENT_OBJECT;
|
||||
osl_attr.desc.element = ATTR_ELEMENT_OBJECT;
|
||||
osl_attr.value = attr;
|
||||
osl_attr.offset = 0;
|
||||
osl_attr.desc.offset = 0;
|
||||
osl_attr.desc.flags = 0;
|
||||
|
||||
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr;
|
||||
og->attribute_map[i*ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr;
|
||||
@@ -853,9 +867,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
|
||||
foreach(AttributeRequest& req, attributes.requests) {
|
||||
OSLGlobals::Attribute osl_attr;
|
||||
|
||||
if(req.triangle_element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.elem = req.triangle_element;
|
||||
osl_attr.offset = req.triangle_offset;
|
||||
if(req.triangle_desc.element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.desc = req.triangle_desc;
|
||||
|
||||
if(req.triangle_type == TypeDesc::TypeFloat)
|
||||
osl_attr.type = TypeDesc::TypeFloat;
|
||||
@@ -875,9 +888,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
|
||||
}
|
||||
}
|
||||
|
||||
if(req.curve_element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.elem = req.curve_element;
|
||||
osl_attr.offset = req.curve_offset;
|
||||
if(req.curve_desc.element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.desc = req.curve_desc;
|
||||
|
||||
if(req.curve_type == TypeDesc::TypeFloat)
|
||||
osl_attr.type = TypeDesc::TypeFloat;
|
||||
@@ -897,9 +909,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
|
||||
}
|
||||
}
|
||||
|
||||
if(req.subd_element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.elem = req.subd_element;
|
||||
osl_attr.offset = req.subd_offset;
|
||||
if(req.subd_desc.element != ATTR_ELEMENT_NONE) {
|
||||
osl_attr.desc = req.subd_desc;
|
||||
|
||||
if(req.subd_type == TypeDesc::TypeFloat)
|
||||
osl_attr.type = TypeDesc::TypeFloat;
|
||||
@@ -971,8 +982,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
|
||||
|
||||
if(mesh->num_triangles()) {
|
||||
attr_map[index].x = id;
|
||||
attr_map[index].y = req.triangle_element;
|
||||
attr_map[index].z = as_uint(req.triangle_offset);
|
||||
attr_map[index].y = req.triangle_desc.element;
|
||||
attr_map[index].z = as_uint(req.triangle_desc.offset);
|
||||
|
||||
if(req.triangle_type == TypeDesc::TypeFloat)
|
||||
attr_map[index].w = NODE_ATTR_FLOAT;
|
||||
@@ -980,14 +991,16 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
|
||||
attr_map[index].w = NODE_ATTR_MATRIX;
|
||||
else
|
||||
attr_map[index].w = NODE_ATTR_FLOAT3;
|
||||
|
||||
attr_map[index].w |= req.triangle_desc.flags << 8;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
if(mesh->num_curves()) {
|
||||
attr_map[index].x = id;
|
||||
attr_map[index].y = req.curve_element;
|
||||
attr_map[index].z = as_uint(req.curve_offset);
|
||||
attr_map[index].y = req.curve_desc.element;
|
||||
attr_map[index].z = as_uint(req.curve_desc.offset);
|
||||
|
||||
if(req.curve_type == TypeDesc::TypeFloat)
|
||||
attr_map[index].w = NODE_ATTR_FLOAT;
|
||||
@@ -995,14 +1008,16 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
|
||||
attr_map[index].w = NODE_ATTR_MATRIX;
|
||||
else
|
||||
attr_map[index].w = NODE_ATTR_FLOAT3;
|
||||
|
||||
attr_map[index].w |= req.curve_desc.flags << 8;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
if(mesh->subd_faces.size()) {
|
||||
attr_map[index].x = id;
|
||||
attr_map[index].y = req.subd_element;
|
||||
attr_map[index].z = as_uint(req.subd_offset);
|
||||
attr_map[index].y = req.subd_desc.element;
|
||||
attr_map[index].z = as_uint(req.subd_desc.offset);
|
||||
|
||||
if(req.subd_type == TypeDesc::TypeFloat)
|
||||
attr_map[index].w = NODE_ATTR_FLOAT;
|
||||
@@ -1010,6 +1025,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
|
||||
attr_map[index].w = NODE_ATTR_MATRIX;
|
||||
else
|
||||
attr_map[index].w = NODE_ATTR_FLOAT3;
|
||||
|
||||
attr_map[index].w |= req.subd_desc.flags << 8;
|
||||
}
|
||||
|
||||
index++;
|
||||
@@ -1069,17 +1086,20 @@ static void update_attribute_element_offset(Mesh *mesh,
|
||||
Attribute *mattr,
|
||||
AttributePrimitive prim,
|
||||
TypeDesc& type,
|
||||
int& offset,
|
||||
AttributeElement& element)
|
||||
AttributeDescriptor& desc)
|
||||
{
|
||||
if(mattr) {
|
||||
/* store element and type */
|
||||
element = mattr->element;
|
||||
desc.element = mattr->element;
|
||||
desc.flags = mattr->flags;
|
||||
type = mattr->type;
|
||||
|
||||
/* store attribute data in arrays */
|
||||
size_t size = mattr->element_size(mesh, prim);
|
||||
|
||||
AttributeElement& element = desc.element;
|
||||
int& offset = desc.offset;
|
||||
|
||||
if(mattr->element == ATTR_ELEMENT_VOXEL) {
|
||||
/* store slot in offset value */
|
||||
VoxelAttribute *voxel_data = mattr->data_voxel();
|
||||
@@ -1128,7 +1148,11 @@ static void update_attribute_element_offset(Mesh *mesh,
|
||||
|
||||
/* mesh vertex/curve index is global, not per object, so we sneak
|
||||
* a correction for that in here */
|
||||
if(element == ATTR_ELEMENT_VERTEX)
|
||||
if(mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && desc.flags & ATTR_SUBDIVIDED) {
|
||||
/* indices for subdivided attributes are retrieved
|
||||
* from patch table so no need for correction here*/
|
||||
}
|
||||
else if(element == ATTR_ELEMENT_VERTEX)
|
||||
offset -= mesh->vert_offset;
|
||||
else if(element == ATTR_ELEMENT_VERTEX_MOTION)
|
||||
offset -= mesh->vert_offset;
|
||||
@@ -1153,8 +1177,8 @@ static void update_attribute_element_offset(Mesh *mesh,
|
||||
}
|
||||
else {
|
||||
/* attribute not found */
|
||||
element = ATTR_ELEMENT_NONE;
|
||||
offset = 0;
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,8 +1267,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
|
||||
triangle_mattr,
|
||||
ATTR_PRIM_TRIANGLE,
|
||||
req.triangle_type,
|
||||
req.triangle_offset,
|
||||
req.triangle_element);
|
||||
req.triangle_desc);
|
||||
|
||||
update_attribute_element_offset(mesh,
|
||||
attr_float, attr_float_offset,
|
||||
@@ -1253,8 +1276,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
|
||||
curve_mattr,
|
||||
ATTR_PRIM_CURVE,
|
||||
req.curve_type,
|
||||
req.curve_offset,
|
||||
req.curve_element);
|
||||
req.curve_desc);
|
||||
|
||||
update_attribute_element_offset(mesh,
|
||||
attr_float, attr_float_offset,
|
||||
@@ -1263,8 +1285,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
|
||||
subd_mattr,
|
||||
ATTR_PRIM_SUBD,
|
||||
req.subd_type,
|
||||
req.subd_offset,
|
||||
req.subd_element);
|
||||
req.subd_desc);
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
}
|
||||
@@ -1327,6 +1348,12 @@ void MeshManager::mesh_calc_offset(Scene *scene)
|
||||
if(mesh->subd_faces.size()) {
|
||||
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
|
||||
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
|
||||
|
||||
/* patch tables are stored in same array so include them in patch_size */
|
||||
if(mesh->patch_table) {
|
||||
mesh->patch_table_offset = patch_size;
|
||||
patch_size += mesh->patch_table->total_size();
|
||||
}
|
||||
}
|
||||
face_size += mesh->subd_faces.size();
|
||||
corner_size += mesh->subd_face_corners.size();
|
||||
@@ -1358,6 +1385,12 @@ void MeshManager::device_update_mesh(Device *device,
|
||||
if(mesh->subd_faces.size()) {
|
||||
Mesh::SubdFace& last = mesh->subd_faces[mesh->subd_faces.size()-1];
|
||||
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
|
||||
|
||||
/* patch tables are stored in same array so include them in patch_size */
|
||||
if(mesh->patch_table) {
|
||||
mesh->patch_table_offset = patch_size;
|
||||
patch_size += mesh->patch_table->total_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,6 +1473,11 @@ void MeshManager::device_update_mesh(Device *device,
|
||||
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
mesh->pack_patches(&patch_data[mesh->patch_offset], mesh->vert_offset, mesh->face_offset, mesh->corner_offset);
|
||||
|
||||
if(mesh->patch_table) {
|
||||
mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], mesh->patch_table_offset);
|
||||
}
|
||||
|
||||
if(progress.get_cancel()) return;
|
||||
}
|
||||
|
||||
@@ -1626,7 +1664,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
|
||||
bool old_need_object_flags_update = false;
|
||||
foreach(Mesh *mesh, scene->meshes) {
|
||||
if(mesh->need_update &&
|
||||
mesh->displacement_method != Mesh::DISPLACE_BUMP)
|
||||
mesh->has_true_displacement())
|
||||
{
|
||||
true_displacement_used = true;
|
||||
break;
|
||||
@@ -1652,6 +1690,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
|
||||
}
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
/* after mesh data has been copied to device memory we need to update
|
||||
* offsets for patch tables as this can't be known before hand */
|
||||
scene->object_manager->device_update_patch_map_offsets(device, dscene, scene);
|
||||
|
||||
device_update_attributes(device, dscene, scene, progress);
|
||||
if(progress.get_cancel()) return;
|
||||
|
||||
|
@@ -40,6 +40,7 @@ class Scene;
|
||||
class SceneParams;
|
||||
class AttributeRequest;
|
||||
class DiagSplit;
|
||||
struct PackedPatchTable;
|
||||
|
||||
/* Mesh */
|
||||
|
||||
@@ -110,13 +111,9 @@ public:
|
||||
int num_ptex_faces() const { return num_corners == 4 ? 1 : num_corners; }
|
||||
};
|
||||
|
||||
/* Displacement */
|
||||
enum DisplacementMethod {
|
||||
DISPLACE_BUMP = 0,
|
||||
DISPLACE_TRUE = 1,
|
||||
DISPLACE_BOTH = 2,
|
||||
|
||||
DISPLACE_NUM_METHODS,
|
||||
struct SubdEdgeCrease {
|
||||
int v[2];
|
||||
float crease;
|
||||
};
|
||||
|
||||
enum SubdivisionType {
|
||||
@@ -157,6 +154,8 @@ public:
|
||||
array<int> subd_face_corners;
|
||||
int num_ngons;
|
||||
|
||||
array<SubdEdgeCrease> subd_creases;
|
||||
|
||||
vector<Shader*> used_shaders;
|
||||
AttributeSet attributes;
|
||||
AttributeSet curve_attributes;
|
||||
@@ -166,7 +165,8 @@ public:
|
||||
bool transform_applied;
|
||||
bool transform_negative_scaled;
|
||||
Transform transform_normal;
|
||||
DisplacementMethod displacement_method;
|
||||
|
||||
PackedPatchTable *patch_table;
|
||||
|
||||
uint motion_steps;
|
||||
bool use_motion_blur;
|
||||
@@ -184,6 +184,7 @@ public:
|
||||
size_t curvekey_offset;
|
||||
|
||||
size_t patch_offset;
|
||||
size_t patch_table_offset;
|
||||
size_t face_offset;
|
||||
size_t corner_offset;
|
||||
|
||||
@@ -234,6 +235,7 @@ public:
|
||||
void tag_update(Scene *scene, bool rebuild);
|
||||
|
||||
bool has_motion_blur() const;
|
||||
bool has_true_displacement() const;
|
||||
|
||||
/* Check whether the mesh should have own BVH built separately. Briefly,
|
||||
* own BVH is needed for mesh, if:
|
||||
|
@@ -26,19 +26,27 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static float3 compute_face_normal(const Mesh::Triangle& t, float3 *verts)
|
||||
{
|
||||
float3 v0 = verts[t.v[0]];
|
||||
float3 v1 = verts[t.v[1]];
|
||||
float3 v2 = verts[t.v[2]];
|
||||
|
||||
float3 norm = cross(v1 - v0, v2 - v0);
|
||||
float normlen = len(norm);
|
||||
|
||||
if(normlen == 0.0f)
|
||||
return make_float3(1.0f, 0.0f, 0.0f);
|
||||
|
||||
return norm / normlen;
|
||||
}
|
||||
|
||||
bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress& progress)
|
||||
{
|
||||
/* verify if we have a displacement shader */
|
||||
bool has_displacement = false;
|
||||
|
||||
if(mesh->displacement_method != Mesh::DISPLACE_BUMP) {
|
||||
foreach(Shader *shader, mesh->used_shaders)
|
||||
if(shader->has_displacement)
|
||||
has_displacement = true;
|
||||
}
|
||||
|
||||
if(!has_displacement)
|
||||
if(!mesh->has_true_displacement()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string msg = string_printf("Computing Displacement %s", mesh->name.c_str());
|
||||
progress.set_status("Updating Mesh", msg);
|
||||
@@ -67,8 +75,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
|
||||
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
|
||||
mesh->used_shaders[shader_index] : scene->default_surface;
|
||||
|
||||
if(!shader->has_displacement)
|
||||
if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < 3; j++) {
|
||||
if(done[t.v[j]])
|
||||
@@ -153,8 +162,9 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
|
||||
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
|
||||
mesh->used_shaders[shader_index] : scene->default_surface;
|
||||
|
||||
if(!shader->has_displacement)
|
||||
if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int j = 0; j < 3; j++) {
|
||||
if(!done[t.v[j]]) {
|
||||
@@ -178,9 +188,131 @@ bool MeshManager::displace(Device *device, DeviceScene *dscene, Scene *scene, Me
|
||||
mesh->attributes.remove(ATTR_STD_FACE_NORMAL);
|
||||
mesh->add_face_normals();
|
||||
|
||||
if(mesh->displacement_method == Mesh::DISPLACE_TRUE) {
|
||||
mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL);
|
||||
mesh->add_vertex_normals();
|
||||
bool need_recompute_vertex_normals = false;
|
||||
|
||||
foreach(Shader *shader, mesh->used_shaders) {
|
||||
if(shader->has_displacement && shader->displacement_method == DISPLACE_TRUE) {
|
||||
need_recompute_vertex_normals = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_recompute_vertex_normals) {
|
||||
bool flip = mesh->transform_negative_scaled;
|
||||
vector<bool> tri_has_true_disp(num_triangles, false);
|
||||
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
int shader_index = mesh->shader[i];
|
||||
Shader *shader = (shader_index < mesh->used_shaders.size()) ?
|
||||
mesh->used_shaders[shader_index] : scene->default_surface;
|
||||
|
||||
tri_has_true_disp[i] = shader->has_displacement && shader->displacement_method == DISPLACE_TRUE;
|
||||
}
|
||||
|
||||
/* static vertex normals */
|
||||
|
||||
/* get attributes */
|
||||
Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
|
||||
Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
|
||||
|
||||
float3 *fN = attr_fN->data_float3();
|
||||
float3 *vN = attr_vN->data_float3();
|
||||
|
||||
/* compute vertex normals */
|
||||
|
||||
/* zero vertex normals on triangles with true displacement */
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
vN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add face normals to vertex normals */
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
vN[mesh->get_triangle(i).v[j]] += fN[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize vertex normals */
|
||||
done.clear();
|
||||
done.resize(num_verts, false);
|
||||
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
int vert = mesh->get_triangle(i).v[j];
|
||||
|
||||
if(done[vert]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vN[vert] = normalize(vN[vert]);
|
||||
if(flip)
|
||||
vN[vert] = -vN[vert];
|
||||
|
||||
done[vert] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* motion vertex normals */
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL);
|
||||
|
||||
if(mesh->has_motion_blur() && attr_mP && attr_mN) {
|
||||
for(int step = 0; step < mesh->motion_steps - 1; step++) {
|
||||
float3 *mP = attr_mP->data_float3() + step*mesh->verts.size();
|
||||
float3 *mN = attr_mN->data_float3() + step*mesh->verts.size();
|
||||
|
||||
/* compute */
|
||||
|
||||
/* zero vertex normals on triangles with true displacement */
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
mN[mesh->get_triangle(i).v[j]] = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add face normals to vertex normals */
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
float3 fN = compute_face_normal(mesh->get_triangle(i), mP);
|
||||
mN[mesh->get_triangle(i).v[j]] += fN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize vertex normals */
|
||||
done.clear();
|
||||
done.resize(num_verts, false);
|
||||
|
||||
for(size_t i = 0; i < num_triangles; i++) {
|
||||
if(tri_has_true_disp[i]) {
|
||||
for(size_t j = 0; j < 3; j++) {
|
||||
int vert = mesh->get_triangle(i).v[j];
|
||||
|
||||
if(done[vert]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mN[vert] = normalize(mN[vert]);
|
||||
if(flip)
|
||||
mN[vert] = -mN[vert];
|
||||
|
||||
done[vert] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -19,13 +19,302 @@
|
||||
|
||||
#include "subd_split.h"
|
||||
#include "subd_patch.h"
|
||||
#include "subd_patch_table.h"
|
||||
|
||||
#include "util_foreach.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#include <opensubdiv/far/topologyRefinerFactory.h>
|
||||
#include <opensubdiv/far/primvarRefiner.h>
|
||||
#include <opensubdiv/far/patchTableFactory.h>
|
||||
#include <opensubdiv/far/patchMap.h>
|
||||
|
||||
/* specializations of TopologyRefinerFactory for ccl::Mesh */
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
namespace Far {
|
||||
template<>
|
||||
bool TopologyRefinerFactory<ccl::Mesh>::resizeComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
|
||||
{
|
||||
setNumBaseVertices(refiner, mesh.verts.size());
|
||||
setNumBaseFaces(refiner, mesh.subd_faces.size());
|
||||
|
||||
ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
|
||||
|
||||
for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
|
||||
setNumBaseFaceVertices(refiner, i, face->num_corners);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTopology(TopologyRefiner& refiner, ccl::Mesh const& mesh)
|
||||
{
|
||||
ccl::Mesh::SubdFace* face = &mesh.subd_faces[0];
|
||||
|
||||
for(int i = 0; i < mesh.subd_faces.size(); i++, face++) {
|
||||
IndexArray face_verts = getBaseFaceVertices(refiner, i);
|
||||
|
||||
int* corner = &mesh.subd_face_corners[face->start_corner];
|
||||
|
||||
for(int j = 0; j < face->num_corners; j++, corner++) {
|
||||
face_verts[j] = *corner;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool TopologyRefinerFactory<ccl::Mesh>::assignComponentTags(TopologyRefiner& refiner, ccl::Mesh const& mesh)
|
||||
{
|
||||
const ccl::Mesh::SubdEdgeCrease* crease = mesh.subd_creases.data();
|
||||
|
||||
for(int i = 0; i < mesh.subd_creases.size(); i++, crease++) {
|
||||
Index edge = findBaseEdge(refiner, crease->v[0], crease->v[1]);
|
||||
|
||||
if(edge != INDEX_INVALID) {
|
||||
setBaseEdgeSharpness(refiner, edge, crease->crease * 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < mesh.verts.size(); i++) {
|
||||
ConstIndexArray vert_edges = getBaseVertexEdges(refiner, i);
|
||||
|
||||
if(vert_edges.size() == 2) {
|
||||
float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]);
|
||||
sharpness = std::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1]));
|
||||
|
||||
setBaseVertexSharpness(refiner, i, sharpness);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool TopologyRefinerFactory<ccl::Mesh>::assignFaceVaryingTopology(TopologyRefiner& /*refiner*/, ccl::Mesh const& /*mesh*/)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
void TopologyRefinerFactory<ccl::Mesh>::reportInvalidTopology(TopologyError /*err_code*/,
|
||||
char const */*msg*/, ccl::Mesh const& /*mesh*/)
|
||||
{
|
||||
}
|
||||
} /* namespace Far */
|
||||
} /* namespace OPENSUBDIV_VERSION */
|
||||
} /* namespace OpenSubdiv */
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
/* struct that implements OpenSubdiv's vertex interface */
|
||||
|
||||
template<typename T>
|
||||
struct OsdValue {
|
||||
T value;
|
||||
|
||||
OsdValue() {}
|
||||
|
||||
void Clear(void* = 0) {
|
||||
memset(&value, 0, sizeof(T));
|
||||
}
|
||||
|
||||
void AddWithWeight(OsdValue<T> const& src, float weight) {
|
||||
value += src.value * weight;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void OsdValue<uchar4>::AddWithWeight(OsdValue<uchar4> const& src, float weight)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
value[i] += (uchar)(src.value[i] * weight);
|
||||
}
|
||||
}
|
||||
|
||||
/* class for holding OpenSubdiv data used during tessellation */
|
||||
|
||||
class OsdData {
|
||||
Mesh* mesh;
|
||||
vector<OsdValue<float3> > verts;
|
||||
Far::TopologyRefiner* refiner;
|
||||
Far::PatchTable* patch_table;
|
||||
Far::PatchMap* patch_map;
|
||||
|
||||
public:
|
||||
OsdData() : mesh(NULL), refiner(NULL), patch_table(NULL), patch_map(NULL) {}
|
||||
|
||||
~OsdData()
|
||||
{
|
||||
delete refiner;
|
||||
delete patch_table;
|
||||
delete patch_map;
|
||||
}
|
||||
|
||||
void build_from_mesh(Mesh* mesh_)
|
||||
{
|
||||
mesh = mesh_;
|
||||
|
||||
/* type and options */
|
||||
Sdc::SchemeType type = Sdc::SCHEME_CATMARK;
|
||||
|
||||
Sdc::Options options;
|
||||
options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
|
||||
|
||||
/* create refiner */
|
||||
refiner = Far::TopologyRefinerFactory<Mesh>::Create(*mesh,
|
||||
Far::TopologyRefinerFactory<Mesh>::Options(type, options));
|
||||
|
||||
/* adaptive refinement */
|
||||
int max_isolation = 10;
|
||||
refiner->RefineAdaptive(Far::TopologyRefiner::AdaptiveOptions(max_isolation));
|
||||
|
||||
/* create patch table */
|
||||
Far::PatchTableFactory::Options patch_options;
|
||||
patch_options.endCapType = Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS;
|
||||
|
||||
patch_table = Far::PatchTableFactory::Create(*refiner, patch_options);
|
||||
|
||||
/* interpolate verts */
|
||||
int num_refiner_verts = refiner->GetNumVerticesTotal();
|
||||
int num_local_points = patch_table->GetNumLocalPoints();
|
||||
|
||||
verts.resize(num_refiner_verts + num_local_points);
|
||||
for(int i = 0; i < mesh->verts.size(); i++) {
|
||||
verts[i].value = mesh->verts[i];
|
||||
}
|
||||
|
||||
OsdValue<float3>* src = &verts[0];
|
||||
for(int i = 0; i < refiner->GetMaxLevel(); i++) {
|
||||
OsdValue<float3>* dest = src + refiner->GetLevel(i).GetNumVertices();
|
||||
Far::PrimvarRefiner(*refiner).Interpolate(i+1, src, dest);
|
||||
src = dest;
|
||||
}
|
||||
|
||||
patch_table->ComputeLocalPointValues(&verts[0], &verts[num_refiner_verts]);
|
||||
|
||||
/* create patch map */
|
||||
patch_map = new Far::PatchMap(*patch_table);
|
||||
}
|
||||
|
||||
void subdivide_attribute(Attribute& attr)
|
||||
{
|
||||
Far::PrimvarRefiner primvar_refiner(*refiner);
|
||||
|
||||
if(attr.element == ATTR_ELEMENT_VERTEX) {
|
||||
int num_refiner_verts = refiner->GetNumVerticesTotal();
|
||||
int num_local_points = patch_table->GetNumLocalPoints();
|
||||
|
||||
attr.resize(num_refiner_verts + num_local_points);
|
||||
attr.flags |= ATTR_FINAL_SIZE;
|
||||
|
||||
char* src = &attr.buffer[0];
|
||||
|
||||
for(int i = 0; i < refiner->GetMaxLevel(); i++) {
|
||||
char* dest = src + refiner->GetLevel(i).GetNumVertices() * attr.data_sizeof();
|
||||
|
||||
if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
|
||||
primvar_refiner.Interpolate(i+1, (OsdValue<float>*)src, (OsdValue<float>*&)dest);
|
||||
}
|
||||
else {
|
||||
primvar_refiner.Interpolate(i+1, (OsdValue<float4>*)src, (OsdValue<float4>*&)dest);
|
||||
}
|
||||
|
||||
src = dest;
|
||||
}
|
||||
|
||||
if(attr.same_storage(attr.type, TypeDesc::TypeFloat)) {
|
||||
patch_table->ComputeLocalPointValues((OsdValue<float>*)&attr.buffer[0],
|
||||
(OsdValue<float>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
}
|
||||
else {
|
||||
patch_table->ComputeLocalPointValues((OsdValue<float4>*)&attr.buffer[0],
|
||||
(OsdValue<float4>*)&attr.buffer[num_refiner_verts * attr.data_sizeof()]);
|
||||
}
|
||||
}
|
||||
else if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
// TODO(mai): fvar interpolation
|
||||
}
|
||||
}
|
||||
|
||||
friend struct OsdPatch;
|
||||
friend class Mesh;
|
||||
};
|
||||
|
||||
/* ccl::Patch implementation that uses OpenSubdiv for eval */
|
||||
|
||||
struct OsdPatch : Patch {
|
||||
OsdData* osd_data;
|
||||
|
||||
OsdPatch(OsdData* data) : osd_data(data) {}
|
||||
|
||||
void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v)
|
||||
{
|
||||
const Far::PatchTable::PatchHandle* handle = osd_data->patch_map->FindPatch(patch_index, u, v);
|
||||
assert(handle);
|
||||
|
||||
float p_weights[20], du_weights[20], dv_weights[20];
|
||||
osd_data->patch_table->EvaluateBasis(*handle, u, v, p_weights, du_weights, dv_weights);
|
||||
|
||||
Far::ConstIndexArray cv = osd_data->patch_table->GetPatchVertices(*handle);
|
||||
|
||||
float3 du, dv;
|
||||
if(P) *P = make_float3(0.0f, 0.0f, 0.0f);
|
||||
du = make_float3(0.0f, 0.0f, 0.0f);
|
||||
dv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for(int i = 0; i < cv.size(); i++) {
|
||||
float3 p = osd_data->verts[cv[i]].value;
|
||||
|
||||
if(P) *P += p * p_weights[i];
|
||||
du += p * du_weights[i];
|
||||
dv += p * dv_weights[i];
|
||||
}
|
||||
|
||||
if(dPdu) *dPdu = du;
|
||||
if(dPdv) *dPdv = dv;
|
||||
if(N) *N = normalize(cross(du, dv));
|
||||
}
|
||||
|
||||
BoundBox bound() { return BoundBox::empty; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
void Mesh::tessellate(DiagSplit *split)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
OsdData osd_data;
|
||||
bool need_packed_patch_table = false;
|
||||
|
||||
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
|
||||
osd_data.build_from_mesh(this);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* force linear subdivision if OpenSubdiv is unavailable to avoid
|
||||
* falling into catmull-clark code paths by accident
|
||||
*/
|
||||
subdivision_type = SUBDIVISION_LINEAR;
|
||||
|
||||
/* force disable attribute subdivision for same reason as above */
|
||||
foreach(Attribute& attr, subd_attributes.attributes) {
|
||||
attr.flags &= ~ATTR_SUBDIVIDED;
|
||||
}
|
||||
}
|
||||
|
||||
int num_faces = subd_faces.size();
|
||||
|
||||
Attribute *attr_vN = subd_attributes.find(ATTR_STD_VERTEX_NORMAL);
|
||||
@@ -36,98 +325,33 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
|
||||
if(face.is_quad()) {
|
||||
/* quad */
|
||||
LinearQuadPatch patch;
|
||||
float3 *hull = patch.hull;
|
||||
float3 *normals = patch.normals;
|
||||
|
||||
patch.patch_index = face.ptex_offset;
|
||||
patch.shader = face.shader;
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
hull[i] = verts[subd_face_corners[face.start_corner+i]];
|
||||
}
|
||||
|
||||
if(face.smooth) {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
normals[i] = vN[subd_face_corners[face.start_corner+i]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
float3 N = face.normal(this);
|
||||
for(int i = 0; i < 4; i++) {
|
||||
normals[i] = N;
|
||||
}
|
||||
}
|
||||
|
||||
swap(hull[2], hull[3]);
|
||||
swap(normals[2], normals[3]);
|
||||
|
||||
/* Quad faces need to be split at least once to line up with split ngons, we do this
|
||||
* here in this manner because if we do it later edge factors may end up slightly off.
|
||||
*/
|
||||
QuadDice::SubPatch subpatch;
|
||||
subpatch.patch = &patch;
|
||||
|
||||
subpatch.P00 = make_float2(0.0f, 0.0f);
|
||||
subpatch.P10 = make_float2(0.5f, 0.0f);
|
||||
subpatch.P01 = make_float2(0.0f, 0.5f);
|
||||
subpatch.P11 = make_float2(0.5f, 0.5f);
|
||||
split->split_quad(&patch, &subpatch);
|
||||
LinearQuadPatch quad_patch;
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
OsdPatch osd_patch(&osd_data);
|
||||
|
||||
subpatch.P00 = make_float2(0.5f, 0.0f);
|
||||
subpatch.P10 = make_float2(1.0f, 0.0f);
|
||||
subpatch.P01 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P11 = make_float2(1.0f, 0.5f);
|
||||
split->split_quad(&patch, &subpatch);
|
||||
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
|
||||
osd_patch.patch_index = face.ptex_offset;
|
||||
|
||||
subpatch.P00 = make_float2(0.0f, 0.5f);
|
||||
subpatch.P10 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P01 = make_float2(0.0f, 1.0f);
|
||||
subpatch.P11 = make_float2(0.5f, 1.0f);
|
||||
split->split_quad(&patch, &subpatch);
|
||||
|
||||
subpatch.P00 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P10 = make_float2(1.0f, 0.5f);
|
||||
subpatch.P01 = make_float2(0.5f, 1.0f);
|
||||
subpatch.P11 = make_float2(1.0f, 1.0f);
|
||||
split->split_quad(&patch, &subpatch);
|
||||
}
|
||||
else {
|
||||
/* ngon */
|
||||
float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float inv_num_corners = 1.0f/float(face.num_corners);
|
||||
for(int corner = 0; corner < face.num_corners; corner++) {
|
||||
center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
subpatch.patch = &osd_patch;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
float3 *hull = quad_patch.hull;
|
||||
float3 *normals = quad_patch.normals;
|
||||
|
||||
for(int corner = 0; corner < face.num_corners; corner++) {
|
||||
LinearQuadPatch patch;
|
||||
float3 *hull = patch.hull;
|
||||
float3 *normals = patch.normals;
|
||||
quad_patch.patch_index = face.ptex_offset;
|
||||
|
||||
patch.patch_index = face.ptex_offset + corner;
|
||||
|
||||
patch.shader = face.shader;
|
||||
|
||||
hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
|
||||
hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
|
||||
hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
|
||||
hull[3] = center_vert;
|
||||
|
||||
hull[1] = (hull[1] + hull[0]) * 0.5;
|
||||
hull[2] = (hull[2] + hull[0]) * 0.5;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
hull[i] = verts[subd_face_corners[face.start_corner+i]];
|
||||
}
|
||||
|
||||
if(face.smooth) {
|
||||
normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
|
||||
normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
|
||||
normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
|
||||
normals[3] = center_normal;
|
||||
|
||||
normals[1] = (normals[1] + normals[0]) * 0.5;
|
||||
normals[2] = (normals[2] + normals[0]) * 0.5;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
normals[i] = vN[subd_face_corners[face.start_corner+i]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
float3 N = face.normal(this);
|
||||
@@ -136,13 +360,123 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
}
|
||||
}
|
||||
|
||||
split->split_quad(&patch);
|
||||
swap(hull[2], hull[3]);
|
||||
swap(normals[2], normals[3]);
|
||||
|
||||
subpatch.patch = &quad_patch;
|
||||
}
|
||||
|
||||
subpatch.patch->shader = face.shader;
|
||||
|
||||
/* Quad faces need to be split at least once to line up with split ngons, we do this
|
||||
* here in this manner because if we do it later edge factors may end up slightly off.
|
||||
*/
|
||||
subpatch.P00 = make_float2(0.0f, 0.0f);
|
||||
subpatch.P10 = make_float2(0.5f, 0.0f);
|
||||
subpatch.P01 = make_float2(0.0f, 0.5f);
|
||||
subpatch.P11 = make_float2(0.5f, 0.5f);
|
||||
split->split_quad(subpatch.patch, &subpatch);
|
||||
|
||||
subpatch.P00 = make_float2(0.5f, 0.0f);
|
||||
subpatch.P10 = make_float2(1.0f, 0.0f);
|
||||
subpatch.P01 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P11 = make_float2(1.0f, 0.5f);
|
||||
split->split_quad(subpatch.patch, &subpatch);
|
||||
|
||||
subpatch.P00 = make_float2(0.0f, 0.5f);
|
||||
subpatch.P10 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P01 = make_float2(0.0f, 1.0f);
|
||||
subpatch.P11 = make_float2(0.5f, 1.0f);
|
||||
split->split_quad(subpatch.patch, &subpatch);
|
||||
|
||||
subpatch.P00 = make_float2(0.5f, 0.5f);
|
||||
subpatch.P10 = make_float2(1.0f, 0.5f);
|
||||
subpatch.P01 = make_float2(0.5f, 1.0f);
|
||||
subpatch.P11 = make_float2(1.0f, 1.0f);
|
||||
split->split_quad(subpatch.patch, &subpatch);
|
||||
}
|
||||
else {
|
||||
/* ngon */
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
if(subdivision_type == SUBDIVISION_CATMULL_CLARK) {
|
||||
OsdPatch patch(&osd_data);
|
||||
|
||||
patch.shader = face.shader;
|
||||
|
||||
for(int corner = 0; corner < face.num_corners; corner++) {
|
||||
patch.patch_index = face.ptex_offset + corner;
|
||||
|
||||
split->split_quad(&patch);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
float3 center_vert = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float3 center_normal = make_float3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
float inv_num_corners = 1.0f/float(face.num_corners);
|
||||
for(int corner = 0; corner < face.num_corners; corner++) {
|
||||
center_vert += verts[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
center_normal += vN[subd_face_corners[face.start_corner + corner]] * inv_num_corners;
|
||||
}
|
||||
|
||||
for(int corner = 0; corner < face.num_corners; corner++) {
|
||||
LinearQuadPatch patch;
|
||||
float3 *hull = patch.hull;
|
||||
float3 *normals = patch.normals;
|
||||
|
||||
patch.patch_index = face.ptex_offset + corner;
|
||||
|
||||
patch.shader = face.shader;
|
||||
|
||||
hull[0] = verts[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
|
||||
hull[1] = verts[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
|
||||
hull[2] = verts[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
|
||||
hull[3] = center_vert;
|
||||
|
||||
hull[1] = (hull[1] + hull[0]) * 0.5;
|
||||
hull[2] = (hull[2] + hull[0]) * 0.5;
|
||||
|
||||
if(face.smooth) {
|
||||
normals[0] = vN[subd_face_corners[face.start_corner + mod(corner + 0, face.num_corners)]];
|
||||
normals[1] = vN[subd_face_corners[face.start_corner + mod(corner + 1, face.num_corners)]];
|
||||
normals[2] = vN[subd_face_corners[face.start_corner + mod(corner - 1, face.num_corners)]];
|
||||
normals[3] = center_normal;
|
||||
|
||||
normals[1] = (normals[1] + normals[0]) * 0.5;
|
||||
normals[2] = (normals[2] + normals[0]) * 0.5;
|
||||
}
|
||||
else {
|
||||
float3 N = face.normal(this);
|
||||
for(int i = 0; i < 4; i++) {
|
||||
normals[i] = N;
|
||||
}
|
||||
}
|
||||
|
||||
split->split_quad(&patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* interpolate center points for attributes */
|
||||
foreach(Attribute& attr, subd_attributes.attributes) {
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
if(subdivision_type == SUBDIVISION_CATMULL_CLARK && attr.flags & ATTR_SUBDIVIDED) {
|
||||
if(attr.element == ATTR_ELEMENT_CORNER || attr.element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
/* keep subdivision for corner attributes disabled for now */
|
||||
attr.flags &= ~ATTR_SUBDIVIDED;
|
||||
}
|
||||
else {
|
||||
osd_data.subdivide_attribute(attr);
|
||||
|
||||
need_packed_patch_table = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
char* data = attr.data();
|
||||
size_t stride = attr.data_sizeof();
|
||||
int ngons = 0;
|
||||
@@ -218,6 +552,15 @@ void Mesh::tessellate(DiagSplit *split)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* pack patch tables */
|
||||
if(need_packed_patch_table) {
|
||||
delete patch_table;
|
||||
patch_table = new PackedPatchTable;
|
||||
patch_table->pack(osd_data.patch_table);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include "util_progress.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
#include "subd_patch_table.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Object */
|
||||
@@ -55,9 +57,9 @@ Object::Object()
|
||||
particle_system = NULL;
|
||||
particle_index = 0;
|
||||
bounds = BoundBox::empty;
|
||||
motion.pre = transform_identity();
|
||||
motion.mid = transform_identity();
|
||||
motion.post = transform_identity();
|
||||
motion.pre = transform_empty();
|
||||
motion.mid = transform_empty();
|
||||
motion.post = transform_empty();
|
||||
use_motion = false;
|
||||
}
|
||||
|
||||
@@ -70,19 +72,28 @@ void Object::compute_bounds(bool motion_blur)
|
||||
BoundBox mbounds = mesh->bounds;
|
||||
|
||||
if(motion_blur && use_motion) {
|
||||
DecompMotionTransform decomp;
|
||||
transform_motion_decompose(&decomp, &motion, &tfm);
|
||||
if(motion.pre == transform_empty() ||
|
||||
motion.post == transform_empty()) {
|
||||
/* Hide objects that have no valid previous or next transform, for
|
||||
* example particle that stop existing. TODO: add support for this
|
||||
* case in the kernel so we don't get render artifacts. */
|
||||
bounds = BoundBox::empty;
|
||||
}
|
||||
else {
|
||||
DecompMotionTransform decomp;
|
||||
transform_motion_decompose(&decomp, &motion, &tfm);
|
||||
|
||||
bounds = BoundBox::empty;
|
||||
bounds = BoundBox::empty;
|
||||
|
||||
/* todo: this is really terrible. according to pbrt there is a better
|
||||
* way to find this iteratively, but did not find implementation yet
|
||||
* or try to implement myself */
|
||||
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
|
||||
Transform ttfm;
|
||||
/* todo: this is really terrible. according to pbrt there is a better
|
||||
* way to find this iteratively, but did not find implementation yet
|
||||
* or try to implement myself */
|
||||
for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
|
||||
Transform ttfm;
|
||||
|
||||
transform_motion_interpolate(&ttfm, &decomp, t);
|
||||
bounds.grow(mbounds.transformed(&ttfm));
|
||||
transform_motion_interpolate(&ttfm, &decomp, t);
|
||||
bounds.grow(mbounds.transformed(&ttfm));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -228,7 +239,7 @@ vector<float> Object::motion_times()
|
||||
bool Object::is_traceable()
|
||||
{
|
||||
/* Mesh itself can be empty,can skip all such objects. */
|
||||
if (bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
|
||||
if (!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) {
|
||||
return false;
|
||||
}
|
||||
/* TODO(sergey): Check for mesh vertices/curves. visibility flags. */
|
||||
@@ -337,6 +348,15 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
|
||||
Transform mtfm_pre = ob->motion.pre;
|
||||
Transform mtfm_post = ob->motion.post;
|
||||
|
||||
/* In case of missing motion information for previous/next frame,
|
||||
* assume there is no motion. */
|
||||
if(!ob->use_motion || mtfm_pre == transform_empty()) {
|
||||
mtfm_pre = ob->tfm;
|
||||
}
|
||||
if(!ob->use_motion || mtfm_post == transform_empty()) {
|
||||
mtfm_post = ob->tfm;
|
||||
}
|
||||
|
||||
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
|
||||
mtfm_pre = mtfm_pre * itfm;
|
||||
mtfm_post = mtfm_post * itfm;
|
||||
@@ -589,6 +609,37 @@ void ObjectManager::device_update_flags(Device *device,
|
||||
device->tex_alloc("__object_flag", dscene->object_flag);
|
||||
}
|
||||
|
||||
void ObjectManager::device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
{
|
||||
uint4* objects = (uint4*)dscene->objects.get_data();
|
||||
|
||||
bool update = false;
|
||||
|
||||
int object_index = 0;
|
||||
foreach(Object *object, scene->objects) {
|
||||
int offset = object_index*OBJECT_SIZE + 11;
|
||||
|
||||
Mesh* mesh = object->mesh;
|
||||
|
||||
if(mesh->patch_table) {
|
||||
uint patch_map_offset = 2*(mesh->patch_table_offset + mesh->patch_table->total_size() -
|
||||
mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - mesh->patch_offset;
|
||||
|
||||
if(objects[offset].x != patch_map_offset) {
|
||||
objects[offset].x = patch_map_offset;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
object_index++;
|
||||
}
|
||||
|
||||
if(update) {
|
||||
device->tex_free(dscene->objects);
|
||||
device->tex_alloc("__objects", dscene->objects);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectManager::device_free(Device *device, DeviceScene *dscene)
|
||||
{
|
||||
device->tex_free(dscene->objects);
|
||||
@@ -638,7 +689,7 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u
|
||||
* Could be solved by moving reference counter to Mesh.
|
||||
*/
|
||||
if((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) &&
|
||||
object->mesh->displacement_method == Mesh::DISPLACE_BUMP)
|
||||
!object->mesh->has_true_displacement())
|
||||
{
|
||||
if(!(motion_blur && object->use_motion)) {
|
||||
if(!object->mesh->transform_applied) {
|
||||
|
@@ -97,6 +97,8 @@ public:
|
||||
Scene *scene,
|
||||
Progress& progress,
|
||||
bool bounds_valid = true);
|
||||
void device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene);
|
||||
|
||||
void device_free(Device *device, DeviceScene *dscene);
|
||||
|
||||
void tag_update(Scene *scene);
|
||||
|
@@ -549,7 +549,7 @@ string OSLCompiler::id(ShaderNode *node)
|
||||
{
|
||||
/* assign layer unique name based on pointer address + bump mode */
|
||||
stringstream stream;
|
||||
stream << "node_" << node->name << "_" << node;
|
||||
stream << "node_" << node->type->name << "_" << node;
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
@@ -150,6 +150,12 @@ NODE_DEFINE(Shader)
|
||||
volume_interpolation_method_enum.insert("cubic", VOLUME_INTERPOLATION_CUBIC);
|
||||
SOCKET_ENUM(volume_interpolation_method, "Volume Interpolation Method", volume_interpolation_method_enum, VOLUME_INTERPOLATION_LINEAR);
|
||||
|
||||
static NodeEnum displacement_method_enum;
|
||||
displacement_method_enum.insert("bump", DISPLACE_BUMP);
|
||||
displacement_method_enum.insert("true", DISPLACE_TRUE);
|
||||
displacement_method_enum.insert("both", DISPLACE_BOTH);
|
||||
SOCKET_ENUM(displacement_method, "Displacement Method", displacement_method_enum, DISPLACE_BUMP);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -173,6 +179,8 @@ Shader::Shader()
|
||||
has_object_dependency = false;
|
||||
has_integrator_dependency = false;
|
||||
|
||||
displacement_method = DISPLACE_BUMP;
|
||||
|
||||
id = -1;
|
||||
used = false;
|
||||
|
||||
@@ -310,7 +318,7 @@ int ShaderManager::get_shader_id(Shader *shader, Mesh *mesh, bool smooth)
|
||||
int id = shader->id*2;
|
||||
|
||||
/* index depends bump since this setting is not in the shader */
|
||||
if(mesh && mesh->displacement_method != Mesh::DISPLACE_TRUE)
|
||||
if(mesh && shader->displacement_method != DISPLACE_TRUE)
|
||||
id += 1;
|
||||
/* smooth flag */
|
||||
if(smooth)
|
||||
|
@@ -66,6 +66,14 @@ enum VolumeInterpolation {
|
||||
VOLUME_NUM_INTERPOLATION,
|
||||
};
|
||||
|
||||
enum DisplacementMethod {
|
||||
DISPLACE_BUMP = 0,
|
||||
DISPLACE_TRUE = 1,
|
||||
DISPLACE_BOTH = 2,
|
||||
|
||||
DISPLACE_NUM_METHODS,
|
||||
};
|
||||
|
||||
/* Shader describing the appearance of a Mesh, Light or Background.
|
||||
*
|
||||
* While there is only a single shader graph, it has three outputs: surface,
|
||||
@@ -110,6 +118,9 @@ public:
|
||||
bool has_object_dependency;
|
||||
bool has_integrator_dependency;
|
||||
|
||||
/* displacement */
|
||||
DisplacementMethod displacement_method;
|
||||
|
||||
/* requested mesh attributes */
|
||||
AttributeRequestSet attributes;
|
||||
|
||||
|
@@ -16,6 +16,7 @@ set(SRC
|
||||
subd_dice.cpp
|
||||
subd_patch.cpp
|
||||
subd_split.cpp
|
||||
subd_patch_table.cpp
|
||||
)
|
||||
|
||||
set(SRC_HEADERS
|
||||
@@ -24,10 +25,6 @@ set(SRC_HEADERS
|
||||
subd_split.h
|
||||
)
|
||||
|
||||
if(WITH_CYCLES_OPENSUBDIV)
|
||||
add_definitions(-DWITH_OPENSUBDIV)
|
||||
endif()
|
||||
|
||||
include_directories(${INC})
|
||||
include_directories(SYSTEM ${INC_SYS})
|
||||
|
||||
|
297
intern/cycles/subd/subd_patch_table.cpp
Normal file
297
intern/cycles/subd/subd_patch_table.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Based on code from OpenSubdiv released under this license:
|
||||
*
|
||||
* Copyright 2014 DreamWorks Animation LLC.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "Apache License")
|
||||
* with the following modification; you may not use this file except in
|
||||
* compliance with the Apache License and the following modification to it:
|
||||
* Section 6. Trademarks. is deleted and replaced with:
|
||||
*
|
||||
* 6. Trademarks. This License does not grant permission to use the trade
|
||||
* names, trademarks, service marks, or product names of the Licensor
|
||||
* and its affiliates, except as required to comply with Section 4(c) of
|
||||
* the License and to reproduce the content of the NOTICE file.
|
||||
*
|
||||
* You may obtain a copy of the Apache License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the Apache License with the above modification is
|
||||
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the Apache License for the specific
|
||||
* language governing permissions and limitations under the Apache License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "subd_patch_table.h"
|
||||
#include "kernel_types.h"
|
||||
|
||||
#include "util_math.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
#include <opensubdiv/far/patchTable.h>
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
|
||||
using namespace OpenSubdiv;
|
||||
|
||||
/* functions for building patch maps */
|
||||
|
||||
struct PatchMapQuadNode {
|
||||
/* sets all the children to point to the patch of index */
|
||||
void set_child(int index)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
|
||||
}
|
||||
}
|
||||
|
||||
/* sets the child in quadrant to point to the node or patch of the given index */
|
||||
void set_child(unsigned char quadrant, int index, bool is_leaf=true)
|
||||
{
|
||||
assert(quadrant < 4);
|
||||
children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
|
||||
}
|
||||
|
||||
uint children[4];
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static int resolve_quadrant(T& median, T& u, T& v)
|
||||
{
|
||||
int quadrant = -1;
|
||||
|
||||
if(u < median) {
|
||||
if(v < median) {
|
||||
quadrant = 0;
|
||||
}
|
||||
else {
|
||||
quadrant = 1;
|
||||
v -= median;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(v < median) {
|
||||
quadrant = 3;
|
||||
}
|
||||
else {
|
||||
quadrant = 2;
|
||||
v -= median;
|
||||
}
|
||||
u -= median;
|
||||
}
|
||||
|
||||
return quadrant;
|
||||
}
|
||||
|
||||
static void build_patch_map(PackedPatchTable& table, OpenSubdiv::Far::PatchTable* patch_table, int offset)
|
||||
{
|
||||
int num_faces = 0;
|
||||
|
||||
for(int array = 0; array < table.num_arrays; array++) {
|
||||
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
|
||||
|
||||
for(int j = 0; j < patch_table->GetNumPatches(array); j++) {
|
||||
num_faces = max(num_faces, (int)params[j].GetFaceId());
|
||||
}
|
||||
}
|
||||
num_faces++;
|
||||
|
||||
vector<PatchMapQuadNode> quadtree;
|
||||
quadtree.reserve(num_faces + table.num_patches);
|
||||
quadtree.resize(num_faces);
|
||||
|
||||
/* adjust offsets to make indices relative to the table */
|
||||
int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
|
||||
offset += table.total_size();
|
||||
|
||||
/* populate the quadtree from the FarPatchArrays sub-patches */
|
||||
for(int array = 0; array < table.num_arrays; array++) {
|
||||
Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
|
||||
|
||||
for(int i = 0; i < patch_table->GetNumPatches(array); i++, handle_index += PATCH_HANDLE_SIZE) {
|
||||
const Far::PatchParam& param = params[i];
|
||||
unsigned short depth = param.GetDepth();
|
||||
|
||||
PatchMapQuadNode* node = &quadtree[params[i].GetFaceId()];
|
||||
|
||||
if(depth == (param.NonQuadRoot() ? 1 : 0)) {
|
||||
/* special case : regular BSpline face w/ no sub-patches */
|
||||
node->set_child(handle_index + offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
int u = param.GetU();
|
||||
int v = param.GetV();
|
||||
int pdepth = param.NonQuadRoot() ? depth-2 : depth-1;
|
||||
int half = 1 << pdepth;
|
||||
|
||||
for(int j = 0; j < depth; j++) {
|
||||
int delta = half >> 1;
|
||||
|
||||
int quadrant = resolve_quadrant(half, u, v);
|
||||
assert(quadrant >= 0);
|
||||
|
||||
half = delta;
|
||||
|
||||
if(j == pdepth) {
|
||||
/* we have reached the depth of the sub-patch : add a leaf */
|
||||
assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
|
||||
node->set_child(quadrant, handle_index + offset, true);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* travel down the child node of the corresponding quadrant */
|
||||
if(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
|
||||
/* create a new branch in the quadrant */
|
||||
quadtree.push_back(PatchMapQuadNode());
|
||||
|
||||
int idx = (int)quadtree.size() - 1;
|
||||
node->set_child(quadrant, idx*4 + offset, false);
|
||||
|
||||
node = &quadtree[idx];
|
||||
}
|
||||
else {
|
||||
/* travel down an existing branch */
|
||||
uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
|
||||
node = &(quadtree[(idx - offset)/4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* copy into table */
|
||||
assert(table.table.size() == table.total_size());
|
||||
uint map_offset = table.total_size();
|
||||
|
||||
table.num_nodes = quadtree.size() * 4;
|
||||
table.table.resize(table.total_size());
|
||||
|
||||
uint* data = &table.table[map_offset];
|
||||
|
||||
for(int i = 0; i < quadtree.size(); i++) {
|
||||
for(int j = 0; j < 4; j++) {
|
||||
assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
|
||||
*(data++) = quadtree[i].children[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* packed patch table functions */
|
||||
|
||||
size_t PackedPatchTable::total_size()
|
||||
{
|
||||
return num_arrays * PATCH_ARRAY_SIZE +
|
||||
num_indices +
|
||||
num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) +
|
||||
num_nodes * PATCH_NODE_SIZE;
|
||||
}
|
||||
|
||||
void PackedPatchTable::pack(Far::PatchTable* patch_table, int offset)
|
||||
{
|
||||
num_arrays = 0;
|
||||
num_patches = 0;
|
||||
num_indices = 0;
|
||||
num_nodes = 0;
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
num_arrays = patch_table->GetNumPatchArrays();
|
||||
|
||||
for(int i = 0; i < num_arrays; i++) {
|
||||
int patches = patch_table->GetNumPatches(i);
|
||||
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
|
||||
|
||||
num_patches += patches;
|
||||
num_indices += patches * num_control;
|
||||
}
|
||||
|
||||
table.resize(total_size());
|
||||
uint* data = &table[0];
|
||||
|
||||
uint* array = data;
|
||||
uint* index = array + num_arrays * PATCH_ARRAY_SIZE;
|
||||
uint* param = index + num_indices;
|
||||
uint* handle = param + num_patches * PATCH_PARAM_SIZE;
|
||||
|
||||
uint current_param = 0;
|
||||
|
||||
for(int i = 0; i < num_arrays; i++) {
|
||||
*(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
|
||||
*(array++) = patch_table->GetNumPatches(i);
|
||||
*(array++) = (index - data) + offset;
|
||||
*(array++) = (param - data) + offset;
|
||||
|
||||
Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
|
||||
|
||||
for(int j = 0; j < indices.size(); j++) {
|
||||
*(index++) = indices[j];
|
||||
}
|
||||
|
||||
const Far::PatchParamTable& param_table = patch_table->GetPatchParamTable();
|
||||
|
||||
int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
|
||||
int patches = patch_table->GetNumPatches(i);
|
||||
|
||||
for(int j = 0; j < patches; j++, current_param++) {
|
||||
*(param++) = param_table[current_param].field0;
|
||||
*(param++) = param_table[current_param].field1;
|
||||
|
||||
*(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
|
||||
*(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
|
||||
*(handle++) = j * num_control;
|
||||
}
|
||||
}
|
||||
|
||||
build_patch_map(*this, patch_table, offset);
|
||||
#else
|
||||
(void)patch_table;
|
||||
(void)offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PackedPatchTable::copy_adjusting_offsets(uint* dest, int doffset)
|
||||
{
|
||||
uint* src = &table[0];
|
||||
|
||||
/* arrays */
|
||||
for(int i = 0; i < num_arrays; i++) {
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++) + doffset;
|
||||
}
|
||||
|
||||
/* indices */
|
||||
for(int i = 0; i < num_indices; i++) {
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* params */
|
||||
for(int i = 0; i < num_patches; i++) {
|
||||
*(dest++) = *(src++);
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* handles */
|
||||
for(int i = 0; i < num_patches; i++) {
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++) + doffset;
|
||||
*(dest++) = *(src++);
|
||||
}
|
||||
|
||||
/* nodes */
|
||||
for(int i = 0; i < num_nodes; i++) {
|
||||
*(dest++) = *(src++) + doffset;
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
63
intern/cycles/subd/subd_patch_table.h
Normal file
63
intern/cycles/subd/subd_patch_table.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2011-2016 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SUBD_PATCH_TABLE_H__
|
||||
#define __SUBD_PATCH_TABLE_H__
|
||||
|
||||
#include "util_types.h"
|
||||
#include "util_vector.h"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
#ifdef _MSC_VER
|
||||
# include "iso646.h"
|
||||
#endif
|
||||
|
||||
#include <opensubdiv/far/patchTable.h>
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
using namespace OpenSubdiv;
|
||||
#else
|
||||
/* forward declare for when OpenSubdiv is unavailable */
|
||||
namespace Far { struct PatchTable; }
|
||||
#endif
|
||||
|
||||
#define PATCH_ARRAY_SIZE 4
|
||||
#define PATCH_PARAM_SIZE 2
|
||||
#define PATCH_HANDLE_SIZE 3
|
||||
#define PATCH_NODE_SIZE 1
|
||||
|
||||
struct PackedPatchTable {
|
||||
vector<uint> table;
|
||||
|
||||
size_t num_arrays;
|
||||
size_t num_indices;
|
||||
size_t num_patches;
|
||||
size_t num_nodes;
|
||||
|
||||
/* calculated size from num_* members */
|
||||
size_t total_size();
|
||||
|
||||
void pack(Far::PatchTable* patch_table, int offset = 0);
|
||||
void copy_adjusting_offsets(uint* dest, int doffset);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __SUBD_PATCH_TABLE_H__ */
|
||||
|
@@ -323,6 +323,15 @@ ccl_device_inline Transform transform_clear_scale(const Transform& tfm)
|
||||
return ntfm;
|
||||
}
|
||||
|
||||
ccl_device_inline Transform transform_empty()
|
||||
{
|
||||
return make_transform(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Motion Transform */
|
||||
|
@@ -222,6 +222,11 @@ public:
|
||||
return datasize_;
|
||||
}
|
||||
|
||||
T* data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const T* data() const
|
||||
{
|
||||
return data_;
|
||||
|
@@ -914,14 +914,25 @@ class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D):
|
||||
return self.qi_start <= qi <= self.qi_end
|
||||
|
||||
|
||||
def getQualifiedObjectName(ob):
|
||||
if ob.library is not None:
|
||||
return ob.library.filepath + '/' + ob.name
|
||||
return ob.name
|
||||
|
||||
|
||||
class ObjectNamesUP1D(UnaryPredicate1D):
|
||||
def __init__(self, names, negative):
|
||||
UnaryPredicate1D.__init__(self)
|
||||
self.names = names
|
||||
self.negative = negative
|
||||
|
||||
def getViewShapeName(self, vs):
|
||||
if vs.library_path is not None:
|
||||
return vs.library_path + '/' + vs.name
|
||||
return vs.name
|
||||
|
||||
def __call__(self, viewEdge):
|
||||
found = viewEdge.viewshape.name in self.names
|
||||
found = self.getViewShapeName(viewEdge.viewshape) in self.names
|
||||
if self.negative:
|
||||
return not found
|
||||
return found
|
||||
@@ -1256,7 +1267,7 @@ def process(layer_name, lineset_name):
|
||||
# prepare selection criteria by group of objects
|
||||
if lineset.select_by_group:
|
||||
if lineset.group is not None:
|
||||
names = {ob.name: True for ob in lineset.group.objects}
|
||||
names = {getQualifiedObjectName(ob): True for ob in lineset.group.objects}
|
||||
upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE')
|
||||
selection_criteria.append(upred)
|
||||
# prepare selection criteria by image border
|
||||
|
@@ -158,6 +158,13 @@ def write_sysinfo(filepath):
|
||||
else:
|
||||
output.write("Blender was built without OpenVDB support\n")
|
||||
|
||||
alembic = bpy.app.alembic
|
||||
output.write("Alembic: ")
|
||||
if alembic.supported:
|
||||
output.write("%s\n" % alembic.version_string)
|
||||
else:
|
||||
output.write("Blender was built without Alembic support\n")
|
||||
|
||||
if not bpy.app.build_options.sdl:
|
||||
output.write("SDL: Blender was built without SDL support\n")
|
||||
|
||||
|
@@ -880,6 +880,19 @@ class ConstraintButtonsPanel:
|
||||
|
||||
layout.operator("clip.constraint_to_fcurve")
|
||||
|
||||
def TRANSFORM_CACHE(self, context, layout, con):
|
||||
layout.label(text="Cache File Properties:")
|
||||
box = layout.box()
|
||||
box.template_cache_file(con, "cache_file")
|
||||
|
||||
cache_file = con.cache_file
|
||||
|
||||
layout.label(text="Constraint Properties:")
|
||||
box = layout.box()
|
||||
|
||||
if cache_file is not None:
|
||||
box.prop_search(con, "object_path", cache_file, "object_paths")
|
||||
|
||||
def SCRIPT(self, context, layout, con):
|
||||
layout.label("Blender 2.6 doesn't support python constraints yet")
|
||||
|
||||
|
@@ -181,6 +181,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
layout.prop(md, "cache_format")
|
||||
layout.prop(md, "filepath")
|
||||
|
||||
if md.cache_format == 'ABC':
|
||||
layout.prop(md, "sub_object")
|
||||
|
||||
layout.label(text="Evaluation:")
|
||||
layout.prop(md, "factor", slider=True)
|
||||
layout.prop(md, "deform_mode")
|
||||
@@ -215,6 +218,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
|
||||
row = split.row()
|
||||
row.prop(md, "flip_axis")
|
||||
|
||||
def MESH_SEQUENCE_CACHE(self, layout, ob, md):
|
||||
layout.label(text="Cache File Properties:")
|
||||
box = layout.box()
|
||||
box.template_cache_file(md, "cache_file")
|
||||
|
||||
cache_file = md.cache_file
|
||||
|
||||
layout.label(text="Modifier Properties:")
|
||||
box = layout.box()
|
||||
|
||||
if cache_file is not None:
|
||||
box.prop_search(md, "object_path", cache_file, "object_paths")
|
||||
|
||||
if ob.type == 'MESH':
|
||||
box.row().prop(md, "read_data")
|
||||
|
||||
def CAST(self, layout, ob, md):
|
||||
split = layout.split(percentage=0.25)
|
||||
|
||||
|
@@ -80,6 +80,7 @@ class GreasePencilDrawingToolsPanel:
|
||||
sub = col.column(align=True)
|
||||
sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing")
|
||||
sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
|
||||
sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
|
||||
|
||||
col.separator()
|
||||
col.separator()
|
||||
@@ -190,11 +191,11 @@ class GreasePencilStrokeEditPanel:
|
||||
col = layout.column(align=True)
|
||||
col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
|
||||
col.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
|
||||
col.operator("gpencil.stroke_flip", text="Flip direction")
|
||||
col.operator("gpencil.stroke_flip", text="Flip Direction")
|
||||
|
||||
gpd = context.gpencil_data
|
||||
if gpd:
|
||||
col.prop(gpd, "show_stroke_direction", text="Show drawing direction")
|
||||
col.prop(gpd, "show_stroke_direction", text="Show Directions")
|
||||
|
||||
|
||||
class GreasePencilBrushPanel:
|
||||
@@ -326,7 +327,7 @@ class GreasePencilStrokeSculptPanel:
|
||||
class GreasePencilBrushCurvesPanel:
|
||||
# subclass must set
|
||||
# bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_label = "Grease Pencil Curves"
|
||||
bl_label = "Brush Curves"
|
||||
bl_category = "Grease Pencil"
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
@@ -821,33 +822,32 @@ class GreasePencilDataPanel:
|
||||
def draw_layer(self, context, layout, gpl):
|
||||
row = layout.row(align=True)
|
||||
row.prop(gpl, "opacity", text="Opacity", slider=True)
|
||||
# layer settings
|
||||
|
||||
# Layer options
|
||||
split = layout.split(percentage=0.5)
|
||||
split.active = not gpl.lock
|
||||
# Options
|
||||
split.prop(gpl, "show_x_ray")
|
||||
split.prop(gpl, "show_points")
|
||||
|
||||
# Offsets + Parenting (where available)
|
||||
split = layout.split(percentage=0.5)
|
||||
col = split.column(align=True)
|
||||
col.active = not gpl.lock
|
||||
col.prop(gpl, "show_x_ray")
|
||||
split.active = not gpl.lock
|
||||
|
||||
col.label("Tint")
|
||||
col.prop(gpl, "tint_color", text="")
|
||||
col.prop(gpl, "tint_factor", text="Factor", slider=True)
|
||||
# Offsets - Color Tint
|
||||
col = split.column()
|
||||
subcol = col.column(align=True)
|
||||
subcol.label("Tint")
|
||||
subcol.prop(gpl, "tint_color", text="")
|
||||
subcol.prop(gpl, "tint_factor", text="Factor", slider=True)
|
||||
|
||||
col = split.column(align=True)
|
||||
col.active = not gpl.lock
|
||||
col.prop(gpl, "show_points", text="Points")
|
||||
# Full-Row - Parent
|
||||
'''
|
||||
row = layout.row()
|
||||
if context.area.type == 'VIEW_3D' and not gpl.lock:
|
||||
row.enabled = True
|
||||
else:
|
||||
row.enabled = False
|
||||
'''
|
||||
# Offsets - Thickness
|
||||
row = col.row(align=True)
|
||||
row.prop(gpl, "line_change", text="Thickness Change", slider=True)
|
||||
row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
|
||||
|
||||
# col = row.column()
|
||||
# Parenting
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
col = split.column(align=True)
|
||||
col.label(text="Parent:")
|
||||
col.prop(gpl, "parent", text="")
|
||||
|
||||
@@ -857,11 +857,7 @@ class GreasePencilDataPanel:
|
||||
if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
|
||||
sub.prop_search(gpl, "parent_bone", parent.data, "bones", text="")
|
||||
|
||||
# Full-Row - Thickness
|
||||
row = layout.row(align=True)
|
||||
row.active = not gpl.lock
|
||||
row.prop(gpl, "line_change", text="Thickness change", slider=True)
|
||||
row.operator("gpencil.stroke_apply_thickness", icon='STYLUS_PRESSURE', text="")
|
||||
layout.separator()
|
||||
|
||||
# Full-Row - Frame Locking (and Delete Frame)
|
||||
row = layout.row(align=True)
|
||||
@@ -875,6 +871,8 @@ class GreasePencilDataPanel:
|
||||
row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
|
||||
row.operator("gpencil.active_frame_delete", text="", icon='X')
|
||||
|
||||
layout.separator()
|
||||
|
||||
# Onion skinning
|
||||
col = layout.column(align=True)
|
||||
col.active = not gpl.lock
|
||||
@@ -925,7 +923,7 @@ class GreasePencilPaletteColorPanel:
|
||||
row.operator_menu_enum("gpencil.palette_change", "palette", text="", icon='COLOR')
|
||||
row.prop(palette, "name", text="")
|
||||
row.operator("gpencil.palette_add", icon='ZOOMIN', text="")
|
||||
row.operator("gpencil.palette_remove", icon='ZOOMOUT', text="")
|
||||
row.operator("gpencil.palette_remove", icon='X', text="")
|
||||
|
||||
# Palette colors
|
||||
row = layout.row()
|
||||
|
@@ -716,6 +716,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
|
||||
col.prop(boids, "land_personal_space")
|
||||
col.prop(boids, "land_stick_force")
|
||||
|
||||
layout.prop(part, "collision_group")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column(align=True)
|
||||
|
@@ -158,6 +158,8 @@ class INFO_MT_file_import(Menu):
|
||||
def draw(self, context):
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
|
||||
if bpy.app.build_options.alembic:
|
||||
self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
|
||||
|
||||
|
||||
class INFO_MT_file_export(Menu):
|
||||
@@ -167,6 +169,8 @@ class INFO_MT_file_export(Menu):
|
||||
def draw(self, context):
|
||||
if bpy.app.build_options.collada:
|
||||
self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
|
||||
if bpy.app.build_options.alembic:
|
||||
self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
|
||||
|
||||
|
||||
class INFO_MT_file_external_data(Menu):
|
||||
|
@@ -31,6 +31,7 @@ set(SRC_DNA_INC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_armature_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_boid_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_brush_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cloth_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_color_types.h
|
||||
@@ -153,3 +154,6 @@ if(WITH_FREESTYLE)
|
||||
add_subdirectory(freestyle)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
add_subdirectory(alembic)
|
||||
endif()
|
||||
|
110
source/blender/alembic/ABC_alembic.h
Normal file
110
source/blender/alembic/ABC_alembic.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_ALEMBIC_H__
|
||||
#define __ABC_ALEMBIC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct bContext;
|
||||
struct DerivedMesh;
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
||||
typedef struct AbcArchiveHandle AbcArchiveHandle;
|
||||
|
||||
enum {
|
||||
ABC_ARCHIVE_OGAWA = 0,
|
||||
ABC_ARCHIVE_HDF5 = 1,
|
||||
};
|
||||
|
||||
int ABC_get_version(void);
|
||||
|
||||
struct AlembicExportParams {
|
||||
double frame_start;
|
||||
double frame_end;
|
||||
|
||||
double frame_step_xform;
|
||||
double frame_step_shape;
|
||||
|
||||
double shutter_open;
|
||||
double shutter_close;
|
||||
|
||||
/* bools */
|
||||
unsigned int selected_only : 1;
|
||||
unsigned int uvs : 1;
|
||||
unsigned int normals : 1;
|
||||
unsigned int vcolors : 1;
|
||||
unsigned int apply_subdiv : 1;
|
||||
unsigned int flatten_hierarchy : 1;
|
||||
unsigned int visible_layers_only : 1;
|
||||
unsigned int renderable_only : 1;
|
||||
unsigned int face_sets : 1;
|
||||
unsigned int use_subdiv_schema : 1;
|
||||
unsigned int packuv : 1;
|
||||
|
||||
unsigned int compression_type : 1;
|
||||
float global_scale;
|
||||
};
|
||||
|
||||
void ABC_export(
|
||||
struct Scene *scene,
|
||||
struct bContext *C,
|
||||
const char *filepath,
|
||||
const struct AlembicExportParams *params);
|
||||
|
||||
void ABC_import(struct bContext *C,
|
||||
const char *filepath,
|
||||
float scale,
|
||||
bool is_sequence,
|
||||
bool set_frame_range,
|
||||
int sequence_len,
|
||||
int offset,
|
||||
bool validate_meshes);
|
||||
|
||||
AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths);
|
||||
|
||||
void ABC_free_handle(AbcArchiveHandle *handle);
|
||||
|
||||
void ABC_get_transform(AbcArchiveHandle *handle,
|
||||
struct Object *ob,
|
||||
const char *object_path,
|
||||
float r_mat[4][4],
|
||||
float time,
|
||||
float scale);
|
||||
|
||||
struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
|
||||
struct Object *ob,
|
||||
struct DerivedMesh *dm,
|
||||
const char *object_path,
|
||||
const float time,
|
||||
const char **err_str,
|
||||
int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ABC_ALEMBIC_H__ */
|
81
source/blender/alembic/CMakeLists.txt
Normal file
81
source/blender/alembic/CMakeLists.txt
Normal file
@@ -0,0 +1,81 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# The Original Code is Copyright (C) 2006, Blender Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# The Original Code is: all of this file.
|
||||
#
|
||||
# Contributor(s): Kevin Dietrich.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(INC
|
||||
.
|
||||
../blenkernel
|
||||
../blenlib
|
||||
../blenloader
|
||||
../editors/include
|
||||
../makesdna
|
||||
../makesrna
|
||||
../windowmanager
|
||||
../../../intern/guardedalloc
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
${ALEMBIC_INCLUDE_DIRS}
|
||||
${HDF5_INCLUDE_DIRS}
|
||||
${OPENEXR_INCLUDE_DIRS}
|
||||
)
|
||||
if(APPLE)
|
||||
list(APPEND INC_SYS
|
||||
${BOOST_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SRC
|
||||
intern/abc_camera.cc
|
||||
intern/abc_customdata.cc
|
||||
intern/abc_curves.cc
|
||||
intern/abc_exporter.cc
|
||||
intern/abc_hair.cc
|
||||
intern/abc_mesh.cc
|
||||
intern/abc_nurbs.cc
|
||||
intern/abc_object.cc
|
||||
intern/abc_points.cc
|
||||
intern/abc_transform.cc
|
||||
intern/abc_util.cc
|
||||
intern/alembic_capi.cc
|
||||
|
||||
ABC_alembic.h
|
||||
intern/abc_camera.h
|
||||
intern/abc_customdata.h
|
||||
intern/abc_curves.h
|
||||
intern/abc_exporter.h
|
||||
intern/abc_hair.h
|
||||
intern/abc_mesh.h
|
||||
intern/abc_nurbs.h
|
||||
intern/abc_object.h
|
||||
intern/abc_points.h
|
||||
intern/abc_transform.h
|
||||
intern/abc_util.h
|
||||
)
|
||||
|
||||
if(WITH_ALEMBIC_HDF5)
|
||||
add_definitions(-DWITH_ALEMBIC_HDF5)
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_alembic "${SRC}" "${INC}" "${INC_SYS}")
|
162
source/blender/alembic/intern/abc_camera.cc
Normal file
162
source/blender/alembic/intern/abc_camera.cc
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_camera.h"
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::ICamera;
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::IFloatProperty;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OCamera;
|
||||
using Alembic::AbcGeom::OFloatProperty;
|
||||
|
||||
using Alembic::AbcGeom::CameraSample;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCameraWriter::AbcCameraWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
OCamera camera(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_camera_schema = camera.getSchema();
|
||||
|
||||
m_custom_data_container = m_camera_schema.getUserProperties();
|
||||
m_stereo_distance = OFloatProperty(m_custom_data_container, "stereoDistance", m_time_sampling);
|
||||
m_eye_separation = OFloatProperty(m_custom_data_container, "eyeSeparation", m_time_sampling);
|
||||
}
|
||||
|
||||
void AbcCameraWriter::do_write()
|
||||
{
|
||||
Camera *cam = static_cast<Camera *>(m_object->data);
|
||||
|
||||
m_stereo_distance.set(cam->stereo.convergence_distance);
|
||||
m_eye_separation.set(cam->stereo.interocular_distance);
|
||||
|
||||
const double apperture_x = cam->sensor_x / 10.0;
|
||||
const double apperture_y = cam->sensor_y / 10.0;
|
||||
const double film_aspect = apperture_x / apperture_y;
|
||||
|
||||
m_camera_sample.setFocalLength(cam->lens);
|
||||
m_camera_sample.setHorizontalAperture(apperture_x);
|
||||
m_camera_sample.setVerticalAperture(apperture_y);
|
||||
m_camera_sample.setHorizontalFilmOffset(apperture_x * cam->shiftx);
|
||||
m_camera_sample.setVerticalFilmOffset(apperture_y * cam->shifty * film_aspect);
|
||||
m_camera_sample.setNearClippingPlane(cam->clipsta);
|
||||
m_camera_sample.setFarClippingPlane(cam->clipend);
|
||||
|
||||
if (cam->dof_ob) {
|
||||
Imath::V3f v(m_object->loc[0] - cam->dof_ob->loc[0],
|
||||
m_object->loc[1] - cam->dof_ob->loc[1],
|
||||
m_object->loc[2] - cam->dof_ob->loc[2]);
|
||||
m_camera_sample.setFocusDistance(v.length());
|
||||
}
|
||||
else {
|
||||
m_camera_sample.setFocusDistance(cam->gpu_dof.focus_distance);
|
||||
}
|
||||
|
||||
/* Blender camera does not have an fstop param, so try to find a custom prop
|
||||
* instead. */
|
||||
m_camera_sample.setFStop(cam->gpu_dof.fstop);
|
||||
|
||||
m_camera_sample.setLensSqueezeRatio(1.0);
|
||||
m_camera_schema.set(m_camera_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCameraReader::AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
ICamera abc_cam(m_iobject, kWrapExisting);
|
||||
m_schema = abc_cam.getSchema();
|
||||
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcCameraReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcCameraReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Camera *bcam = static_cast<Camera *>(BKE_camera_add(bmain, "abc_camera"));
|
||||
|
||||
ISampleSelector sample_sel(time);
|
||||
CameraSample cam_sample;
|
||||
m_schema.get(cam_sample, sample_sel);
|
||||
|
||||
ICompoundProperty customDataContainer = m_schema.getUserProperties();
|
||||
|
||||
if (customDataContainer.valid() &&
|
||||
customDataContainer.getPropertyHeader("stereoDistance") &&
|
||||
customDataContainer.getPropertyHeader("eyeSeparation"))
|
||||
{
|
||||
IFloatProperty convergence_plane(customDataContainer, "stereoDistance");
|
||||
IFloatProperty eye_separation(customDataContainer, "eyeSeparation");
|
||||
|
||||
bcam->stereo.interocular_distance = eye_separation.getValue(sample_sel);
|
||||
bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel);
|
||||
}
|
||||
|
||||
const float lens = cam_sample.getFocalLength();
|
||||
const float apperture_x = cam_sample.getHorizontalAperture();
|
||||
const float apperture_y = cam_sample.getVerticalAperture();
|
||||
const float h_film_offset = cam_sample.getHorizontalFilmOffset();
|
||||
const float v_film_offset = cam_sample.getVerticalFilmOffset();
|
||||
const float film_aspect = apperture_x / apperture_y;
|
||||
|
||||
bcam->lens = lens;
|
||||
bcam->sensor_x = apperture_x * 10;
|
||||
bcam->sensor_y = apperture_y * 10;
|
||||
bcam->shiftx = h_film_offset / apperture_x;
|
||||
bcam->shifty = v_film_offset / apperture_y / film_aspect;
|
||||
bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane());
|
||||
bcam->clipend = cam_sample.getFarClippingPlane();
|
||||
bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance();
|
||||
bcam->gpu_dof.fstop = cam_sample.getFStop();
|
||||
|
||||
BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str());
|
||||
m_object->data = bcam;
|
||||
}
|
61
source/blender/alembic/intern/abc_camera.h
Normal file
61
source/blender/alembic/intern/abc_camera.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CAMERA_H__
|
||||
#define __ABC_CAMERA_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCameraWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OCameraSchema m_camera_schema;
|
||||
Alembic::AbcGeom::CameraSample m_camera_sample;
|
||||
Alembic::AbcGeom::OCompoundProperty m_custom_data_container;
|
||||
Alembic::AbcGeom::OFloatProperty m_stereo_distance;
|
||||
Alembic::AbcGeom::OFloatProperty m_eye_separation;
|
||||
|
||||
public:
|
||||
AbcCameraWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCameraReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ICameraSchema m_schema;
|
||||
|
||||
public:
|
||||
AbcCameraReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
#endif /* __ABC_CAMERA_H__ */
|
355
source/blender/alembic/intern/abc_curves.cc
Normal file
355
source/blender/alembic/intern/abc_curves.cc
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_curves.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "ED_curve.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::IInt32ArrayProperty;
|
||||
using Alembic::Abc::Int32ArraySamplePtr;
|
||||
using Alembic::Abc::FloatArraySamplePtr;
|
||||
using Alembic::Abc::P3fArraySamplePtr;
|
||||
using Alembic::Abc::UcharArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::ICurves;
|
||||
using Alembic::AbcGeom::ICurvesSchema;
|
||||
using Alembic::AbcGeom::IFloatGeomParam;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::CurvePeriodicity;
|
||||
|
||||
using Alembic::AbcGeom::OCurves;
|
||||
using Alembic::AbcGeom::OCurvesSchema;
|
||||
using Alembic::AbcGeom::ON3fGeomParam;
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCurveWriter::AbcCurveWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = curves.getSchema();
|
||||
}
|
||||
|
||||
void AbcCurveWriter::do_write()
|
||||
{
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
|
||||
std::vector<Imath::V3f> verts;
|
||||
std::vector<int32_t> vert_counts;
|
||||
std::vector<float> widths;
|
||||
std::vector<float> weights;
|
||||
std::vector<float> knots;
|
||||
std::vector<uint8_t> orders;
|
||||
Imath::V3f temp_vert;
|
||||
|
||||
Alembic::AbcGeom::BasisType curve_basis;
|
||||
Alembic::AbcGeom::CurveType curve_type;
|
||||
Alembic::AbcGeom::CurvePeriodicity periodicity;
|
||||
|
||||
Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
|
||||
for (; nurbs; nurbs = nurbs->next) {
|
||||
if (nurbs->bp) {
|
||||
curve_basis = Alembic::AbcGeom::kNoBasis;
|
||||
curve_type = Alembic::AbcGeom::kLinear;
|
||||
|
||||
const int totpoint = nurbs->pntsu * nurbs->pntsv;
|
||||
|
||||
const BPoint *point = nurbs->bp;
|
||||
|
||||
for (int i = 0; i < totpoint; ++i, ++point) {
|
||||
copy_zup_yup(temp_vert.getValue(), point->vec);
|
||||
verts.push_back(temp_vert);
|
||||
weights.push_back(point->vec[3]);
|
||||
widths.push_back(point->radius);
|
||||
}
|
||||
}
|
||||
else if (nurbs->bezt) {
|
||||
curve_basis = Alembic::AbcGeom::kBezierBasis;
|
||||
curve_type = Alembic::AbcGeom::kCubic;
|
||||
|
||||
const int totpoint = nurbs->pntsu;
|
||||
|
||||
const BezTriple *bezier = nurbs->bezt;
|
||||
|
||||
/* TODO(kevin): store info about handles, Alembic doesn't have this. */
|
||||
for (int i = 0; i < totpoint; ++i, ++bezier) {
|
||||
copy_zup_yup(temp_vert.getValue(), bezier->vec[1]);
|
||||
verts.push_back(temp_vert);
|
||||
widths.push_back(bezier->radius);
|
||||
}
|
||||
}
|
||||
|
||||
if ((nurbs->flagu & CU_NURB_ENDPOINT) != 0) {
|
||||
periodicity = Alembic::AbcGeom::kNonPeriodic;
|
||||
}
|
||||
else if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
periodicity = Alembic::AbcGeom::kPeriodic;
|
||||
|
||||
/* Duplicate the start points to indicate that the curve is actually
|
||||
* cyclic since other software need those.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < nurbs->orderu; ++i) {
|
||||
verts.push_back(verts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (nurbs->knotsu != NULL) {
|
||||
const size_t num_knots = KNOTSU(nurbs);
|
||||
|
||||
/* Add an extra knot at the beggining and end of the array since most apps
|
||||
* require/expect them. */
|
||||
knots.resize(num_knots + 2);
|
||||
|
||||
for (int i = 0; i < num_knots; ++i) {
|
||||
knots[i + 1] = nurbs->knotsu[i];
|
||||
}
|
||||
|
||||
if ((nurbs->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
knots[0] = nurbs->knotsu[0];
|
||||
knots[num_knots - 1] = nurbs->knotsu[num_knots - 1];
|
||||
}
|
||||
else {
|
||||
knots[0] = (2.0f * nurbs->knotsu[0] - nurbs->knotsu[1]);
|
||||
knots[num_knots - 1] = (2.0f * nurbs->knotsu[num_knots - 1] - nurbs->knotsu[num_knots - 2]);
|
||||
}
|
||||
}
|
||||
|
||||
orders.push_back(nurbs->orderu + 1);
|
||||
vert_counts.push_back(verts.size());
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::OFloatGeomParam::Sample width_sample;
|
||||
width_sample.setVals(widths);
|
||||
|
||||
m_sample = OCurvesSchema::Sample(verts,
|
||||
vert_counts,
|
||||
curve_type,
|
||||
periodicity,
|
||||
width_sample,
|
||||
OV2fGeomParam::Sample(), /* UVs */
|
||||
ON3fGeomParam::Sample(), /* normals */
|
||||
curve_basis,
|
||||
weights,
|
||||
orders,
|
||||
knots);
|
||||
|
||||
m_sample.setSelfBounds(bounds());
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
ICurves abc_curves(object, kWrapExisting);
|
||||
m_curves_schema = abc_curves.getSchema();
|
||||
|
||||
get_min_max_time(m_curves_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcCurveReader::valid() const
|
||||
{
|
||||
return m_curves_schema.valid();
|
||||
}
|
||||
|
||||
void AbcCurveReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Curve *cu = BKE_curve_add(bmain, m_data_name.c_str(), OB_CURVE);
|
||||
|
||||
cu->flag |= CU_DEFORM_FILL | CU_3D;
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str());
|
||||
m_object->data = cu;
|
||||
|
||||
read_curve_sample(cu, m_curves_schema, time);
|
||||
|
||||
if (has_animations(m_curves_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time)
|
||||
{
|
||||
const ISampleSelector sample_sel(time);
|
||||
ICurvesSchema::Sample smp = schema.getValue(sample_sel);
|
||||
const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices();
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
const FloatArraySamplePtr knots = smp.getKnots();
|
||||
const CurvePeriodicity periodicity = smp.getWrap();
|
||||
const UcharArraySamplePtr orders = smp.getOrders();
|
||||
|
||||
const IFloatGeomParam widths_param = schema.getWidthsParam();
|
||||
FloatArraySamplePtr radiuses;
|
||||
|
||||
if (widths_param.valid()) {
|
||||
IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
|
||||
radiuses = wsample.getVals();
|
||||
}
|
||||
|
||||
int knot_offset = 0;
|
||||
|
||||
size_t idx = 0;
|
||||
for (size_t i = 0; i < num_vertices->size(); ++i) {
|
||||
const int num_verts = (*num_vertices)[i];
|
||||
|
||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
||||
nu->resolu = cu->resolu;
|
||||
nu->resolv = cu->resolv;
|
||||
nu->pntsu = num_verts;
|
||||
nu->pntsv = 1;
|
||||
nu->flag |= CU_SMOOTH;
|
||||
|
||||
nu->orderu = num_verts;
|
||||
|
||||
if (smp.getType() == Alembic::AbcGeom::kCubic) {
|
||||
nu->orderu = 3;
|
||||
}
|
||||
else if (orders && orders->size() > i) {
|
||||
nu->orderu = static_cast<short>((*orders)[i] - 1);
|
||||
}
|
||||
|
||||
if (periodicity == Alembic::AbcGeom::kNonPeriodic) {
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
else if (periodicity == Alembic::AbcGeom::kPeriodic) {
|
||||
nu->flagu |= CU_NURB_CYCLIC;
|
||||
|
||||
/* Check the number of points which overlap, we don't have
|
||||
* overlapping points in Blender, but other software do use them to
|
||||
* indicate that a curve is actually cyclic. Usually the number of
|
||||
* overlapping points is equal to the order/degree of the curve.
|
||||
*/
|
||||
|
||||
const int start = idx;
|
||||
const int end = idx + num_verts;
|
||||
int overlap = 0;
|
||||
|
||||
for (int j = start, k = end - nu->orderu; j < nu->orderu; ++j, ++k) {
|
||||
const Imath::V3f &p1 = (*positions)[j];
|
||||
const Imath::V3f &p2 = (*positions)[k];
|
||||
|
||||
if (p1 != p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
++overlap;
|
||||
}
|
||||
|
||||
/* TODO: Special case, need to figure out how it coincides with knots. */
|
||||
if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
|
||||
overlap = 1;
|
||||
}
|
||||
|
||||
/* There is no real cycles. */
|
||||
if (overlap == 0) {
|
||||
nu->flagu &= ~CU_NURB_CYCLIC;
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
nu->pntsu -= overlap;
|
||||
}
|
||||
|
||||
const bool do_weights = (weights != NULL) && (weights->size() > 1);
|
||||
float weight = 1.0f;
|
||||
|
||||
const bool do_radius = (radiuses != NULL) && (radiuses->size() > 1);
|
||||
float radius = (radiuses && radiuses->size() == 1) ? (*radiuses)[0] : 1.0f;
|
||||
|
||||
nu->type = CU_NURBS;
|
||||
|
||||
nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, "abc_getnurb"));
|
||||
BPoint *bp = nu->bp;
|
||||
|
||||
for (int j = 0; j < nu->pntsu; ++j, ++bp, ++idx) {
|
||||
const Imath::V3f &pos = (*positions)[idx];
|
||||
|
||||
if (do_radius) {
|
||||
radius = (*radiuses)[idx];
|
||||
}
|
||||
|
||||
if (do_weights) {
|
||||
weight = (*weights)[idx];
|
||||
}
|
||||
|
||||
copy_yup_zup(bp->vec, pos.getValue());
|
||||
bp->vec[3] = weight;
|
||||
bp->f1 = SELECT;
|
||||
bp->radius = radius;
|
||||
bp->weight = 1.0f;
|
||||
}
|
||||
|
||||
if (knots && knots->size() != 0) {
|
||||
nu->knotsu = static_cast<float *>(MEM_callocN(KNOTSU(nu) * sizeof(float), "abc_setsplineknotsu"));
|
||||
|
||||
/* TODO: second check is temporary, for until the check for cycles is rock solid. */
|
||||
if (periodicity == Alembic::AbcGeom::kPeriodic && (KNOTSU(nu) == knots->size() - 2)) {
|
||||
/* Skip first and last knots. */
|
||||
for (size_t i = 1; i < knots->size() - 1; ++i) {
|
||||
nu->knotsu[i - 1] = (*knots)[knot_offset + i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TODO: figure out how to use the knots array from other
|
||||
* software in this case. */
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
knot_offset += knots->size();
|
||||
}
|
||||
else {
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
||||
}
|
||||
}
|
65
source/blender/alembic/intern/abc_curves.h
Normal file
65
source/blender/alembic/intern/abc_curves.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CURVES_H__
|
||||
#define __ABC_CURVES_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
struct Curve;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCurveWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OCurvesSchema m_schema;
|
||||
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcCurveWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcCurveReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ICurvesSchema m_curves_schema;
|
||||
|
||||
public:
|
||||
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time);
|
||||
|
||||
#endif /* __ABC_CURVES_H__ */
|
379
source/blender/alembic/intern/abc_customdata.cc
Normal file
379
source/blender/alembic/intern/abc_customdata.cc
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_customdata.h"
|
||||
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_customdata_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
}
|
||||
|
||||
/* NOTE: for now only UVs and Vertex Colors are supported for streaming.
|
||||
* Although Alembic only allows for a single UV layer per {I|O}Schema, and does
|
||||
* not have a vertex color concept, there is a convention between DCCs to write
|
||||
* such data in a way that lets other DCC know what they are for. See comments
|
||||
* in the write code for the conventions. */
|
||||
|
||||
using Alembic::AbcGeom::kVertexScope;
|
||||
using Alembic::AbcGeom::kFacevaryingScope;
|
||||
|
||||
using Alembic::Abc::C4fArraySample;
|
||||
using Alembic::Abc::UInt32ArraySample;
|
||||
using Alembic::Abc::V2fArraySample;
|
||||
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
using Alembic::AbcGeom::OC4fGeomParam;
|
||||
|
||||
static void get_uvs(const CDStreamConfig &config,
|
||||
std::vector<Imath::V2f> &uvs,
|
||||
std::vector<uint32_t> &uvidx,
|
||||
void *cd_data)
|
||||
{
|
||||
MLoopUV *mloopuv_array = static_cast<MLoopUV *>(cd_data);
|
||||
|
||||
if (!mloopuv_array) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int num_poly = config.totpoly;
|
||||
MPoly *polygons = config.mpoly;
|
||||
|
||||
if (!config.pack_uvs) {
|
||||
int cnt = 0;
|
||||
uvidx.resize(config.totloop);
|
||||
uvs.resize(config.totloop);
|
||||
|
||||
for (int i = 0; i < num_poly; ++i) {
|
||||
MPoly ¤t_poly = polygons[i];
|
||||
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
|
||||
|
||||
for (int j = 0; j < current_poly.totloop; ++j, ++cnt) {
|
||||
--loopuvpoly;
|
||||
|
||||
uvidx[cnt] = cnt;
|
||||
uvs[cnt][0] = loopuvpoly->uv[0];
|
||||
uvs[cnt][1] = loopuvpoly->uv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < num_poly; ++i) {
|
||||
MPoly ¤t_poly = polygons[i];
|
||||
MLoopUV *loopuvpoly = mloopuv_array + current_poly.loopstart + current_poly.totloop;
|
||||
|
||||
for (int j = 0; j < current_poly.totloop; ++j) {
|
||||
loopuvpoly--;
|
||||
Imath::V2f uv(loopuvpoly->uv[0], loopuvpoly->uv[1]);
|
||||
|
||||
std::vector<Imath::V2f>::iterator it = std::find(uvs.begin(), uvs.end(), uv);
|
||||
|
||||
if (it == uvs.end()) {
|
||||
uvidx.push_back(uvs.size());
|
||||
uvs.push_back(uv);
|
||||
}
|
||||
else {
|
||||
uvidx.push_back(std::distance(uvs.begin(), it));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data)
|
||||
{
|
||||
const int active_uvlayer = CustomData_get_active_layer(data, CD_MLOOPUV);
|
||||
|
||||
if (active_uvlayer < 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
void *cd_data = CustomData_get_layer_n(data, CD_MLOOPUV, active_uvlayer);
|
||||
|
||||
get_uvs(config, sample.uvs, sample.indices, cd_data);
|
||||
|
||||
return CustomData_get_layer_name(data, CD_MLOOPUV, active_uvlayer);
|
||||
}
|
||||
|
||||
/* Convention to write UVs:
|
||||
* - V2fGeomParam on the arbGeomParam
|
||||
* - set scope as face varying
|
||||
* - (optional due to its behaviour) tag as UV using Alembic::AbcGeom::SetIsUV
|
||||
*/
|
||||
static void write_uv(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
|
||||
{
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<Imath::V2f> uvs;
|
||||
|
||||
get_uvs(config, uvs, indices, data);
|
||||
|
||||
if (indices.empty() || uvs.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OV2fGeomParam param(prop, name, true, kFacevaryingScope, 1);
|
||||
|
||||
OV2fGeomParam::Sample sample(
|
||||
V2fArraySample(&uvs.front(), uvs.size()),
|
||||
UInt32ArraySample(&indices.front(), indices.size()),
|
||||
kFacevaryingScope);
|
||||
|
||||
param.set(sample);
|
||||
}
|
||||
|
||||
/* Convention to write Vertex Colors:
|
||||
* - C3fGeomParam/C4fGeomParam on the arbGeomParam
|
||||
* - set scope as vertex varying
|
||||
*/
|
||||
static void write_mcol(const OCompoundProperty &prop, const CDStreamConfig &config, void *data, const char *name)
|
||||
{
|
||||
const float cscale = 1.0f / 255.0f;
|
||||
MPoly *polys = config.mpoly;
|
||||
MLoop *mloops = config.mloop;
|
||||
MCol *cfaces = static_cast<MCol *>(data);
|
||||
|
||||
std::vector<Imath::C4f> buffer(config.totvert);
|
||||
|
||||
Imath::C4f col;
|
||||
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
|
||||
col[0] = cface->a * cscale;
|
||||
col[1] = cface->r * cscale;
|
||||
col[2] = cface->g * cscale;
|
||||
col[3] = cface->b * cscale;
|
||||
|
||||
buffer[mloop->v] = col;
|
||||
}
|
||||
}
|
||||
|
||||
OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1);
|
||||
|
||||
OC4fGeomParam::Sample sample(
|
||||
C4fArraySample(&buffer.front(), buffer.size()),
|
||||
kVertexScope);
|
||||
|
||||
param.set(sample);
|
||||
}
|
||||
|
||||
void write_custom_data(const OCompoundProperty &prop, const CDStreamConfig &config, CustomData *data, int data_type)
|
||||
{
|
||||
CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
|
||||
|
||||
if (!CustomData_has_layer(data, cd_data_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int active_layer = CustomData_get_active_layer(data, cd_data_type);
|
||||
const int tot_layers = CustomData_number_of_layers(data, cd_data_type);
|
||||
|
||||
for (int i = 0; i < tot_layers; ++i) {
|
||||
void *cd_data = CustomData_get_layer_n(data, cd_data_type, i);
|
||||
const char *name = CustomData_get_layer_name(data, cd_data_type, i);
|
||||
|
||||
if (cd_data_type == CD_MLOOPUV) {
|
||||
/* Already exported. */
|
||||
if (i == active_layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
write_uv(prop, config, cd_data, name);
|
||||
}
|
||||
else if (cd_data_type == CD_MLOOPCOL) {
|
||||
write_mcol(prop, config, cd_data, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
using Alembic::Abc::C3fArraySamplePtr;
|
||||
using Alembic::Abc::C4fArraySamplePtr;
|
||||
using Alembic::Abc::PropertyHeader;
|
||||
|
||||
using Alembic::AbcGeom::IC3fGeomParam;
|
||||
using Alembic::AbcGeom::IC4fGeomParam;
|
||||
using Alembic::AbcGeom::IV2fGeomParam;
|
||||
|
||||
static void read_mcols(const CDStreamConfig &config, void *data,
|
||||
const C3fArraySamplePtr &c3f_ptr, const C4fArraySamplePtr &c4f_ptr)
|
||||
{
|
||||
MCol *cfaces = static_cast<MCol *>(data);
|
||||
MPoly *polys = config.mpoly;
|
||||
MLoop *mloops = config.mloop;
|
||||
|
||||
if (c3f_ptr) {
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
const Imath::C3f &color = (*c3f_ptr)[mloop->v];
|
||||
cface->a = FTOCHAR(color[0]);
|
||||
cface->r = FTOCHAR(color[1]);
|
||||
cface->g = FTOCHAR(color[2]);
|
||||
cface->b = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c4f_ptr) {
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly *p = &polys[i];
|
||||
MCol *cface = &cfaces[p->loopstart + p->totloop];
|
||||
MLoop *mloop = &mloops[p->loopstart + p->totloop];
|
||||
|
||||
for (int j = 0; j < p->totloop; ++j) {
|
||||
cface--;
|
||||
mloop--;
|
||||
const Imath::C4f &color = (*c4f_ptr)[mloop->v];
|
||||
cface->a = FTOCHAR(color[0]);
|
||||
cface->r = FTOCHAR(color[1]);
|
||||
cface->g = FTOCHAR(color[2]);
|
||||
cface->b = FTOCHAR(color[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_uvs(const CDStreamConfig &config, void *data,
|
||||
const Alembic::AbcGeom::V2fArraySamplePtr &uvs,
|
||||
const Alembic::AbcGeom::UInt32ArraySamplePtr &indices)
|
||||
{
|
||||
MPoly *mpolys = config.mpoly;
|
||||
MLoopUV *mloopuvs = static_cast<MLoopUV *>(data);
|
||||
|
||||
unsigned int uv_index, loop_index;
|
||||
|
||||
for (int i = 0; i < config.totpoly; ++i) {
|
||||
MPoly &poly = mpolys[i];
|
||||
|
||||
for (int f = 0; f < poly.totloop; ++f) {
|
||||
loop_index = poly.loopstart + f;
|
||||
uv_index = (*indices)[loop_index];
|
||||
const Imath::V2f &uv = (*uvs)[uv_index];
|
||||
|
||||
MLoopUV &loopuv = mloopuvs[loop_index];
|
||||
loopuv.uv[0] = uv[0];
|
||||
loopuv.uv[1] = uv[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_custom_data_ex(const ICompoundProperty &prop,
|
||||
const PropertyHeader &prop_header,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss,
|
||||
int data_type)
|
||||
{
|
||||
if (data_type == CD_MLOOPCOL) {
|
||||
C3fArraySamplePtr c3f_ptr = C3fArraySamplePtr();
|
||||
C4fArraySamplePtr c4f_ptr = C4fArraySamplePtr();
|
||||
|
||||
if (IC3fGeomParam::matches(prop_header)) {
|
||||
IC3fGeomParam color_param(prop, prop_header.getName());
|
||||
IC3fGeomParam::Sample sample;
|
||||
color_param.getIndexed(sample, iss);
|
||||
|
||||
c3f_ptr = sample.getVals();
|
||||
}
|
||||
else if (IC4fGeomParam::matches(prop_header)) {
|
||||
IC4fGeomParam color_param(prop, prop_header.getName());
|
||||
IC4fGeomParam::Sample sample;
|
||||
color_param.getIndexed(sample, iss);
|
||||
|
||||
c4f_ptr = sample.getVals();
|
||||
}
|
||||
|
||||
void *cd_data = config.add_customdata_cb(config.user_data,
|
||||
prop_header.getName().c_str(),
|
||||
data_type);
|
||||
|
||||
read_mcols(config, cd_data, c3f_ptr, c4f_ptr);
|
||||
}
|
||||
else if (data_type == CD_MLOOPUV) {
|
||||
IV2fGeomParam uv_param(prop, prop_header.getName());
|
||||
IV2fGeomParam::Sample sample;
|
||||
uv_param.getIndexed(sample, iss);
|
||||
|
||||
if (uv_param.getScope() != kFacevaryingScope) {
|
||||
return;
|
||||
}
|
||||
|
||||
void *cd_data = config.add_customdata_cb(config.user_data,
|
||||
prop_header.getName().c_str(),
|
||||
data_type);
|
||||
|
||||
read_uvs(config, cd_data, sample.getVals(), sample.getIndices());
|
||||
}
|
||||
}
|
||||
|
||||
void read_custom_data(const ICompoundProperty &prop, const CDStreamConfig &config, const Alembic::Abc::ISampleSelector &iss)
|
||||
{
|
||||
if (!prop.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int num_uvs = 0;
|
||||
int num_colors = 0;
|
||||
|
||||
const size_t num_props = prop.getNumProperties();
|
||||
|
||||
for (size_t i = 0; i < num_props; ++i) {
|
||||
const Alembic::Abc::PropertyHeader &prop_header = prop.getPropertyHeader(i);
|
||||
|
||||
/* Read UVs according to convention. */
|
||||
if (IV2fGeomParam::matches(prop_header) && Alembic::AbcGeom::isUV(prop_header)) {
|
||||
if (++num_uvs > MAX_MTFACE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPUV);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read vertex colors according to convention. */
|
||||
if (IC3fGeomParam::matches(prop_header) || IC4fGeomParam::matches(prop_header)) {
|
||||
if (++num_colors > MAX_MCOL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_custom_data_ex(prop, prop_header, config, iss, CD_MLOOPCOL);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
93
source/blender/alembic/intern/abc_customdata.h
Normal file
93
source/blender/alembic/intern/abc_customdata.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_CUSTOMDATA_H__
|
||||
#define __ABC_CUSTOMDATA_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
|
||||
struct CustomData;
|
||||
struct MLoop;
|
||||
struct MLoopUV;
|
||||
struct MPoly;
|
||||
struct MVert;
|
||||
|
||||
using Alembic::Abc::ICompoundProperty;
|
||||
using Alembic::Abc::OCompoundProperty;
|
||||
|
||||
struct UVSample {
|
||||
std::vector<Imath::V2f> uvs;
|
||||
std::vector<uint32_t> indices;
|
||||
};
|
||||
|
||||
struct CDStreamConfig {
|
||||
MLoop *mloop;
|
||||
int totloop;
|
||||
|
||||
MPoly *mpoly;
|
||||
int totpoly;
|
||||
|
||||
MVert *mvert;
|
||||
int totvert;
|
||||
|
||||
MLoopUV *mloopuv;
|
||||
|
||||
CustomData *loopdata;
|
||||
|
||||
bool pack_uvs;
|
||||
|
||||
/* TODO(kevin): might need a better way to handle adding and/or updating
|
||||
* custom datas such that it updates the custom data holder and its pointers
|
||||
* properly. */
|
||||
void *user_data;
|
||||
void *(*add_customdata_cb)(void *user_data, const char *name, int data_type);
|
||||
|
||||
CDStreamConfig()
|
||||
: mloop(NULL)
|
||||
, totloop(0)
|
||||
, mpoly(NULL)
|
||||
, totpoly(0)
|
||||
, totvert(0)
|
||||
, pack_uvs(false)
|
||||
, user_data(NULL)
|
||||
, add_customdata_cb(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
/* Get the UVs for the main UV property on a OSchema.
|
||||
* Returns the name of the UV layer.
|
||||
*
|
||||
* For now the active layer is used, maybe needs a better way to choose this. */
|
||||
const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, CustomData *data);
|
||||
|
||||
void write_custom_data(const OCompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
CustomData *data,
|
||||
int data_type);
|
||||
|
||||
void read_custom_data(const ICompoundProperty &prop,
|
||||
const CDStreamConfig &config,
|
||||
const Alembic::Abc::ISampleSelector &iss);
|
||||
|
||||
#endif /* __ABC_CUSTOMDATA_H__ */
|
600
source/blender/alembic/intern/abc_exporter.cc
Normal file
600
source/blender/alembic/intern/abc_exporter.cc
Normal file
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_exporter.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifdef WITH_ALEMBIC_HDF5
|
||||
# include <Alembic/AbcCoreHDF5/All.h>
|
||||
#endif
|
||||
|
||||
#include <Alembic/AbcCoreOgawa/All.h>
|
||||
|
||||
#include "abc_camera.h"
|
||||
#include "abc_curves.h"
|
||||
#include "abc_hair.h"
|
||||
#include "abc_mesh.h"
|
||||
#include "abc_nurbs.h"
|
||||
#include "abc_points.h"
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_space_types.h" /* for FILE_MAX */
|
||||
|
||||
#include "BLI_string.h"
|
||||
|
||||
#ifdef WIN32
|
||||
/* needed for MSCV because of snprintf from BLI_string */
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
|
||||
#include "BKE_anim.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_scene.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::TimeSamplingPtr;
|
||||
using Alembic::Abc::OBox3dProperty;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
ExportSettings::ExportSettings()
|
||||
: scene(NULL)
|
||||
, selected_only(false)
|
||||
, visible_layers_only(false)
|
||||
, renderable_only(false)
|
||||
, frame_start(1)
|
||||
, frame_end(1)
|
||||
, frame_step_xform(1)
|
||||
, frame_step_shape(1)
|
||||
, shutter_open(0.0)
|
||||
, shutter_close(1.0)
|
||||
, global_scale(1.0f)
|
||||
, flatten_hierarchy(false)
|
||||
, export_normals(false)
|
||||
, export_uvs(false)
|
||||
, export_vcols(false)
|
||||
, export_face_sets(false)
|
||||
, export_vweigths(false)
|
||||
, apply_subdiv(false)
|
||||
, use_subdiv_schema(false)
|
||||
, export_child_hairs(true)
|
||||
, export_ogawa(true)
|
||||
, pack_uv(false)
|
||||
, do_convert_axis(false)
|
||||
{}
|
||||
|
||||
static bool object_is_smoke_sim(Object *ob)
|
||||
{
|
||||
ModifierData *md = modifiers_findByType(ob, eModifierType_Smoke);
|
||||
|
||||
if (md) {
|
||||
SmokeModifierData *smd = reinterpret_cast<SmokeModifierData *>(md);
|
||||
return (smd->type == MOD_SMOKE_TYPE_DOMAIN);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool object_is_shape(Object *ob)
|
||||
{
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
if (object_is_smoke_sim(ob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
case OB_CURVE:
|
||||
case OB_SURF:
|
||||
case OB_CAMERA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool export_object(const ExportSettings * const settings, Object *ob)
|
||||
{
|
||||
if (settings->selected_only && !parent_selected(ob)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings->visible_layers_only && !(settings->scene->lay & ob->lay)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (settings->renderable_only && (ob->restrictflag & OB_RESTRICT_RENDER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcExporter::AbcExporter(Scene *scene, const char *filename, ExportSettings &settings)
|
||||
: m_settings(settings)
|
||||
, m_filename(filename)
|
||||
, m_trans_sampling_index(0)
|
||||
, m_shape_sampling_index(0)
|
||||
, m_scene(scene)
|
||||
{}
|
||||
|
||||
AbcExporter::~AbcExporter()
|
||||
{
|
||||
std::map<std::string, AbcTransformWriter*>::iterator it, e;
|
||||
for (it = m_xforms.begin(), e = m_xforms.end(); it != e; ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
|
||||
delete m_shapes[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::getShutterSamples(double step, bool time_relative,
|
||||
std::vector<double> &samples)
|
||||
{
|
||||
samples.clear();
|
||||
|
||||
const double time_factor = time_relative ? m_scene->r.frs_sec : 1.0;
|
||||
const double shutter_open = m_settings.shutter_open;
|
||||
const double shutter_close = m_settings.shutter_close;
|
||||
|
||||
/* sample all frame */
|
||||
if (shutter_open == 0.0 && shutter_close == 1.0) {
|
||||
for (double t = 0; t < 1.0; t += step) {
|
||||
samples.push_back(t / time_factor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* sample between shutter open & close */
|
||||
const int nsamples = std::max((1.0 / step) - 1.0, 1.0);
|
||||
const double time_inc = (shutter_close - shutter_open) / nsamples;
|
||||
|
||||
for (double t = shutter_open; t <= shutter_close; t += time_inc) {
|
||||
samples.push_back(t / time_factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Alembic::Abc::TimeSamplingPtr AbcExporter::createTimeSampling(double step)
|
||||
{
|
||||
TimeSamplingPtr time_sampling;
|
||||
std::vector<double> samples;
|
||||
|
||||
if (m_settings.frame_start == m_settings.frame_end) {
|
||||
time_sampling.reset(new Alembic::Abc::TimeSampling());
|
||||
return time_sampling;
|
||||
}
|
||||
|
||||
getShutterSamples(step, true, samples);
|
||||
|
||||
Alembic::Abc::TimeSamplingType ts(static_cast<uint32_t>(samples.size()), 1.0 / m_scene->r.frs_sec);
|
||||
time_sampling.reset(new Alembic::Abc::TimeSampling(ts, samples));
|
||||
|
||||
return time_sampling;
|
||||
}
|
||||
|
||||
void AbcExporter::getFrameSet(double step, std::set<double> &frames)
|
||||
{
|
||||
frames.clear();
|
||||
|
||||
std::vector<double> shutter_samples;
|
||||
|
||||
getShutterSamples(step, false, shutter_samples);
|
||||
|
||||
for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) {
|
||||
for (int j = 0, e = shutter_samples.size(); j < e; ++j) {
|
||||
frames.insert(frame + shutter_samples[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
|
||||
{
|
||||
std::string scene_name;
|
||||
|
||||
if (bmain->name[0] != '\0') {
|
||||
char scene_file_name[FILE_MAX];
|
||||
BLI_strncpy(scene_file_name, bmain->name, FILE_MAX);
|
||||
scene_name = scene_file_name;
|
||||
}
|
||||
else {
|
||||
scene_name = "untitled";
|
||||
}
|
||||
|
||||
Scene *scene = m_scene;
|
||||
const int fps = FPS;
|
||||
char buf[16];
|
||||
snprintf(buf, 15, "%d", fps);
|
||||
const std::string str_fps = buf;
|
||||
|
||||
Alembic::AbcCoreAbstract::MetaData md;
|
||||
md.set("FramesPerTimeUnit", str_fps);
|
||||
|
||||
Alembic::Abc::Argument arg(md);
|
||||
|
||||
#ifdef WITH_ALEMBIC_HDF5
|
||||
if (!m_settings.export_ogawa) {
|
||||
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
|
||||
m_filename,
|
||||
"Blender",
|
||||
scene_name,
|
||||
Alembic::Abc::ErrorHandler::kThrowPolicy,
|
||||
arg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
|
||||
m_filename,
|
||||
"Blender",
|
||||
scene_name,
|
||||
Alembic::Abc::ErrorHandler::kThrowPolicy,
|
||||
arg);
|
||||
}
|
||||
|
||||
/* Create time samplings for transforms and shapes. */
|
||||
|
||||
TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
|
||||
|
||||
m_trans_sampling_index = m_archive.addTimeSampling(*trans_time);
|
||||
|
||||
TimeSamplingPtr shape_time;
|
||||
|
||||
if ((m_settings.frame_step_shape == m_settings.frame_step_xform) ||
|
||||
(m_settings.frame_start == m_settings.frame_end))
|
||||
{
|
||||
shape_time = trans_time;
|
||||
m_shape_sampling_index = m_trans_sampling_index;
|
||||
}
|
||||
else {
|
||||
shape_time = createTimeSampling(m_settings.frame_step_shape);
|
||||
m_shape_sampling_index = m_archive.addTimeSampling(*shape_time);
|
||||
}
|
||||
|
||||
OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_archive, m_trans_sampling_index);
|
||||
|
||||
if (m_settings.flatten_hierarchy) {
|
||||
createTransformWritersFlat();
|
||||
}
|
||||
else {
|
||||
createTransformWritersHierarchy(bmain->eval_ctx);
|
||||
}
|
||||
|
||||
createShapeWriters(bmain->eval_ctx);
|
||||
|
||||
/* Make a list of frames to export. */
|
||||
|
||||
std::set<double> xform_frames;
|
||||
getFrameSet(m_settings.frame_step_xform, xform_frames);
|
||||
|
||||
std::set<double> shape_frames;
|
||||
getFrameSet(m_settings.frame_step_shape, shape_frames);
|
||||
|
||||
/* Merge all frames needed. */
|
||||
|
||||
std::set<double> frames(xform_frames);
|
||||
frames.insert(shape_frames.begin(), shape_frames.end());
|
||||
|
||||
/* Export all frames. */
|
||||
|
||||
std::set<double>::const_iterator begin = frames.begin();
|
||||
std::set<double>::const_iterator end = frames.end();
|
||||
|
||||
const float size = static_cast<float>(frames.size());
|
||||
size_t i = 0;
|
||||
|
||||
for (; begin != end; ++begin) {
|
||||
progress = (++i / size);
|
||||
|
||||
if (G.is_break) {
|
||||
was_canceled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
double f = *begin;
|
||||
setCurrentFrame(bmain, f);
|
||||
|
||||
if (shape_frames.count(f) != 0) {
|
||||
for (int i = 0, e = m_shapes.size(); i != e; ++i) {
|
||||
m_shapes[i]->write();
|
||||
}
|
||||
}
|
||||
|
||||
if (xform_frames.count(f) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<std::string, AbcTransformWriter *>::iterator xit, xe;
|
||||
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
|
||||
xit->second->write();
|
||||
}
|
||||
|
||||
/* Save the archive 's bounding box. */
|
||||
Imath::Box3d bounds;
|
||||
|
||||
for (xit = m_xforms.begin(), xe = m_xforms.end(); xit != xe; ++xit) {
|
||||
Imath::Box3d box = xit->second->bounds();
|
||||
bounds.extendBy(box);
|
||||
}
|
||||
|
||||
archive_bounds_prop.set(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx)
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (export_object(&m_settings, ob)) {
|
||||
switch(ob->type) {
|
||||
case OB_LAMP:
|
||||
case OB_LATTICE:
|
||||
case OB_MBALL:
|
||||
case OB_SPEAKER:
|
||||
/* We do not export transforms for objects of these classes. */
|
||||
break;
|
||||
|
||||
default:
|
||||
exploreTransform(eval_ctx, ob, ob->parent, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWritersFlat()
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (export_object(&m_settings, ob) && object_is_shape(ob)) {
|
||||
std::string name = get_id_name(ob);
|
||||
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), 0, m_trans_sampling_index, m_settings);
|
||||
}
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent)
|
||||
{
|
||||
createTransformWriter(ob, parent, dupliObParent);
|
||||
|
||||
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
|
||||
|
||||
if (lb) {
|
||||
DupliObject *link = static_cast<DupliObject *>(lb->first);
|
||||
Object *dupli_ob = NULL;
|
||||
Object *dupli_parent = NULL;
|
||||
|
||||
while (link) {
|
||||
if (link->type == OB_DUPLIGROUP) {
|
||||
dupli_ob = link->ob;
|
||||
dupli_parent = (dupli_ob->parent) ? dupli_ob->parent : ob;
|
||||
|
||||
exploreTransform(eval_ctx, dupli_ob, dupli_parent, ob);
|
||||
}
|
||||
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
free_object_duplilist(lb);
|
||||
}
|
||||
|
||||
void AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent)
|
||||
{
|
||||
const std::string name = get_object_dag_path_name(ob, dupliObParent);
|
||||
|
||||
/* check if we have already created a transform writer for this object */
|
||||
if (m_xforms.find(name) != m_xforms.end()){
|
||||
std::cerr << "xform " << name << " already exists\n";
|
||||
return;
|
||||
}
|
||||
|
||||
AbcTransformWriter *parent_xform = NULL;
|
||||
|
||||
if (parent) {
|
||||
const std::string parentname = get_object_dag_path_name(parent, dupliObParent);
|
||||
parent_xform = getXForm(parentname);
|
||||
|
||||
if (!parent_xform) {
|
||||
if (parent->parent) {
|
||||
createTransformWriter(parent, parent->parent, dupliObParent);
|
||||
}
|
||||
else {
|
||||
createTransformWriter(parent, dupliObParent, dupliObParent);
|
||||
}
|
||||
|
||||
parent_xform = getXForm(parentname);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent_xform) {
|
||||
m_xforms[name] = new AbcTransformWriter(ob, parent_xform->alembicXform(), parent_xform, m_trans_sampling_index, m_settings);
|
||||
m_xforms[name]->setParent(parent);
|
||||
}
|
||||
else {
|
||||
m_xforms[name] = new AbcTransformWriter(ob, m_archive.getTop(), NULL, m_trans_sampling_index, m_settings);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::createShapeWriters(EvaluationContext *eval_ctx)
|
||||
{
|
||||
Base *base = static_cast<Base *>(m_scene->base.first);
|
||||
|
||||
while (base) {
|
||||
Object *ob = base->object;
|
||||
exploreObject(eval_ctx, ob, NULL);
|
||||
|
||||
base = base->next;
|
||||
}
|
||||
}
|
||||
|
||||
void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent)
|
||||
{
|
||||
ListBase *lb = object_duplilist(eval_ctx, m_scene, ob);
|
||||
|
||||
createShapeWriter(ob, dupliObParent);
|
||||
|
||||
if (lb) {
|
||||
DupliObject *dupliob = static_cast<DupliObject *>(lb->first);
|
||||
|
||||
while (dupliob) {
|
||||
if (dupliob->type == OB_DUPLIGROUP) {
|
||||
exploreObject(eval_ctx, dupliob->ob, ob);
|
||||
}
|
||||
|
||||
dupliob = dupliob->next;
|
||||
}
|
||||
}
|
||||
|
||||
free_object_duplilist(lb);
|
||||
}
|
||||
|
||||
void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent)
|
||||
{
|
||||
if (!object_is_shape(ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!export_object(&m_settings, ob)) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
if (m_settings.flatten_hierarchy) {
|
||||
name = get_id_name(ob);
|
||||
}
|
||||
else {
|
||||
name = get_object_dag_path_name(ob, dupliObParent);
|
||||
}
|
||||
|
||||
AbcTransformWriter *xform = getXForm(name);
|
||||
|
||||
if (!xform) {
|
||||
std::cerr << __func__ << ": xform " << name << " is NULL\n";
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first);
|
||||
|
||||
for (; psys; psys = psys->next) {
|
||||
if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (psys->part->type == PART_HAIR) {
|
||||
m_settings.export_child_hairs = true;
|
||||
m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
|
||||
}
|
||||
else if (psys->part->type == PART_EMITTER) {
|
||||
m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys));
|
||||
}
|
||||
}
|
||||
|
||||
switch(ob->type) {
|
||||
case OB_MESH:
|
||||
{
|
||||
Mesh *me = static_cast<Mesh *>(ob->data);
|
||||
|
||||
if (!me || me->totvert == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcMeshWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_SURF:
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(ob->data);
|
||||
|
||||
if (!cu) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcNurbsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_CURVE:
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(ob->data);
|
||||
|
||||
if (!cu) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_shapes.push_back(new AbcCurveWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
break;
|
||||
}
|
||||
case OB_CAMERA:
|
||||
{
|
||||
Camera *cam = static_cast<Camera *>(ob->data);
|
||||
|
||||
if (cam->type == CAM_PERSP) {
|
||||
m_shapes.push_back(new AbcCameraWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbcTransformWriter *AbcExporter::getXForm(const std::string &name)
|
||||
{
|
||||
std::map<std::string, AbcTransformWriter *>::iterator it = m_xforms.find(name);
|
||||
|
||||
if (it == m_xforms.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void AbcExporter::setCurrentFrame(Main *bmain, double t)
|
||||
{
|
||||
m_scene->r.cfra = std::floor(t);
|
||||
m_scene->r.subframe = t - m_scene->r.cfra;
|
||||
BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay);
|
||||
}
|
112
source/blender/alembic/intern/abc_exporter.h
Normal file
112
source/blender/alembic/intern/abc_exporter.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_EXPORTER_H__
|
||||
#define __ABC_EXPORTER_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
class AbcObjectWriter;
|
||||
class AbcTransformWriter;
|
||||
|
||||
struct EvaluationContext;
|
||||
struct Main;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
|
||||
struct ExportSettings {
|
||||
ExportSettings();
|
||||
|
||||
Scene *scene;
|
||||
|
||||
bool selected_only;
|
||||
bool visible_layers_only;
|
||||
bool renderable_only;
|
||||
|
||||
double frame_start, frame_end;
|
||||
double frame_step_xform;
|
||||
double frame_step_shape;
|
||||
double shutter_open;
|
||||
double shutter_close;
|
||||
float global_scale;
|
||||
|
||||
bool flatten_hierarchy;
|
||||
|
||||
bool export_normals;
|
||||
bool export_uvs;
|
||||
bool export_vcols;
|
||||
bool export_face_sets;
|
||||
bool export_vweigths;
|
||||
|
||||
bool apply_subdiv;
|
||||
bool use_subdiv_schema;
|
||||
bool export_child_hairs;
|
||||
bool export_ogawa;
|
||||
bool pack_uv;
|
||||
|
||||
bool do_convert_axis;
|
||||
float convert_matrix[3][3];
|
||||
};
|
||||
|
||||
class AbcExporter {
|
||||
ExportSettings &m_settings;
|
||||
|
||||
const char *m_filename;
|
||||
|
||||
Alembic::Abc::OArchive m_archive;
|
||||
unsigned int m_trans_sampling_index, m_shape_sampling_index;
|
||||
|
||||
Scene *m_scene;
|
||||
|
||||
std::map<std::string, AbcTransformWriter *> m_xforms;
|
||||
std::vector<AbcObjectWriter *> m_shapes;
|
||||
|
||||
public:
|
||||
AbcExporter(Scene *scene, const char *filename, ExportSettings &settings);
|
||||
~AbcExporter();
|
||||
|
||||
void operator()(Main *bmain, float &progress, bool &was_canceled);
|
||||
|
||||
private:
|
||||
void getShutterSamples(double step, bool time_relative, std::vector<double> &samples);
|
||||
|
||||
Alembic::Abc::TimeSamplingPtr createTimeSampling(double step);
|
||||
|
||||
void getFrameSet(double step, std::set<double> &frames);
|
||||
|
||||
void createTransformWritersHierarchy(EvaluationContext *eval_ctx);
|
||||
void createTransformWritersFlat();
|
||||
void createTransformWriter(Object *ob, Object *parent, Object *dupliObParent);
|
||||
void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL);
|
||||
void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent);
|
||||
void createShapeWriters(EvaluationContext *eval_ctx);
|
||||
void createShapeWriter(Object *ob, Object *dupliObParent);
|
||||
|
||||
AbcTransformWriter *getXForm(const std::string &name);
|
||||
|
||||
void setCurrentFrame(Main *bmain, double t);
|
||||
};
|
||||
|
||||
#endif /* __ABC_EXPORTER_H__ */
|
290
source/blender/alembic/intern/abc_hair.cc
Normal file
290
source/blender/alembic/intern/abc_hair.cc
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_hair.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_modifier_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
}
|
||||
|
||||
using Alembic::Abc::P3fArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::OCurves;
|
||||
using Alembic::AbcGeom::OCurvesSchema;
|
||||
using Alembic::AbcGeom::ON3fGeomParam;
|
||||
using Alembic::AbcGeom::OV2fGeomParam;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcHairWriter::AbcHairWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_psys = psys;
|
||||
|
||||
OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = curves.getSchema();
|
||||
}
|
||||
|
||||
void AbcHairWriter::do_write()
|
||||
{
|
||||
if (!m_psys) {
|
||||
return;
|
||||
}
|
||||
|
||||
ParticleSystemModifierData *psmd = psys_get_modifier(m_object, m_psys);
|
||||
|
||||
if (!psmd->dm_final) {
|
||||
return;
|
||||
}
|
||||
|
||||
DerivedMesh *dm = mesh_create_derived_view(m_scene, m_object, CD_MASK_MESH);
|
||||
DM_ensure_tessface(dm);
|
||||
DM_update_tessface_data(dm);
|
||||
|
||||
std::vector<Imath::V3f> verts;
|
||||
std::vector<int32_t> hvertices;
|
||||
std::vector<Imath::V2f> uv_values;
|
||||
std::vector<Imath::V3f> norm_values;
|
||||
|
||||
if (m_psys->pathcache) {
|
||||
ParticleSettings *part = m_psys->part;
|
||||
|
||||
write_hair_sample(dm, part, verts, norm_values, uv_values, hvertices);
|
||||
|
||||
if (m_settings.export_child_hairs && m_psys->childcache) {
|
||||
write_hair_child_sample(dm, part, verts, norm_values, uv_values, hvertices);
|
||||
}
|
||||
}
|
||||
|
||||
dm->release(dm);
|
||||
|
||||
Alembic::Abc::P3fArraySample iPos(verts);
|
||||
m_sample = OCurvesSchema::Sample(iPos, hvertices);
|
||||
m_sample.setBasis(Alembic::AbcGeom::kNoBasis);
|
||||
m_sample.setType(Alembic::AbcGeom::kLinear);
|
||||
m_sample.setWrap(Alembic::AbcGeom::kNonPeriodic);
|
||||
|
||||
if (!uv_values.empty()) {
|
||||
OV2fGeomParam::Sample uv_smp;
|
||||
uv_smp.setVals(uv_values);
|
||||
m_sample.setUVs(uv_smp);
|
||||
}
|
||||
|
||||
if (!norm_values.empty()) {
|
||||
ON3fGeomParam::Sample norm_smp;
|
||||
norm_smp.setVals(norm_values);
|
||||
m_sample.setNormals(norm_smp);
|
||||
}
|
||||
|
||||
m_sample.setSelfBounds(bounds());
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
void AbcHairWriter::write_hair_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices)
|
||||
{
|
||||
/* Get untransformed vertices, there's a xform under the hair. */
|
||||
float inv_mat[4][4];
|
||||
invert_m4_m4_safe(inv_mat, m_object->obmat);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
|
||||
MFace *mface = dm->getTessFaceArray(dm);
|
||||
MVert *mverts = dm->getVertArray(dm);
|
||||
|
||||
if (!mtface || !mface) {
|
||||
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
|
||||
}
|
||||
|
||||
ParticleData * pa = m_psys->particles;
|
||||
int k;
|
||||
|
||||
ParticleCacheKey **cache = m_psys->pathcache;
|
||||
ParticleCacheKey *path;
|
||||
float normal[3];
|
||||
Imath::V3f tmp_nor;
|
||||
|
||||
for (int p = 0; p < m_psys->totpart; ++p, ++pa) {
|
||||
/* underlying info for faces-only emission */
|
||||
path = cache[p];
|
||||
|
||||
if (part->from == PART_FROM_FACE && mtface) {
|
||||
const int num = pa->num_dmcache >= 0 ? pa->num_dmcache : pa->num;
|
||||
|
||||
if (num < dm->getNumTessFaces(dm)) {
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
|
||||
MTFace *tface = mtface + num;
|
||||
|
||||
if (mface) {
|
||||
float r_uv[2], mapfw[4], vec[3];
|
||||
|
||||
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
|
||||
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
|
||||
|
||||
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, normal, NULL, NULL, NULL, NULL);
|
||||
|
||||
copy_zup_yup(tmp_nor.getValue(), normal);
|
||||
norm_values.push_back(tmp_nor);
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::fprintf(stderr, "Particle to faces overflow (%d/%d)\n", num, dm->getNumTessFaces(dm));
|
||||
}
|
||||
}
|
||||
else if (part->from == PART_FROM_VERT && mtface) {
|
||||
/* vertex id */
|
||||
const int num = (pa->num_dmcache >= 0) ? pa->num_dmcache : pa->num;
|
||||
|
||||
/* iterate over all faces to find a corresponding underlying UV */
|
||||
for (int n = 0; n < dm->getNumTessFaces(dm); ++n) {
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, n, CD_MFACE));
|
||||
MTFace *tface = mtface + n;
|
||||
unsigned int vtx[4];
|
||||
vtx[0] = face->v1;
|
||||
vtx[1] = face->v2;
|
||||
vtx[2] = face->v3;
|
||||
vtx[3] = face->v4;
|
||||
bool found = false;
|
||||
|
||||
for (int o = 0; o < 4; ++o) {
|
||||
if (o > 2 && vtx[o] == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (vtx[o] == num) {
|
||||
uv_values.push_back(Imath::V2f(tface->uv[o][0], tface->uv[o][1]));
|
||||
|
||||
MVert *mv = mverts + vtx[o];
|
||||
|
||||
normal_short_to_float_v3(normal, mv->no);
|
||||
copy_zup_yup(tmp_nor.getValue(), normal);
|
||||
norm_values.push_back(tmp_nor);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int steps = path->segments + 1;
|
||||
hvertices.push_back(steps);
|
||||
|
||||
for (k = 0; k < steps; ++k) {
|
||||
float vert[3];
|
||||
copy_v3_v3(vert, path->co);
|
||||
mul_m4_v3(inv_mat, vert);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
|
||||
|
||||
++path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbcHairWriter::write_hair_child_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices)
|
||||
{
|
||||
/* Get untransformed vertices, there's a xform under the hair. */
|
||||
float inv_mat[4][4];
|
||||
invert_m4_m4_safe(inv_mat, m_object->obmat);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer(&dm->faceData, CD_MTFACE));
|
||||
MFace *mface = dm->getTessFaceArray(dm);
|
||||
MVert *mverts = dm->getVertArray(dm);
|
||||
|
||||
if (!mtface || !mface) {
|
||||
std::fprintf(stderr, "Warning, no UV set found for underlying geometry.\n");
|
||||
}
|
||||
|
||||
ParticleCacheKey **cache = m_psys->childcache;
|
||||
ParticleCacheKey *path;
|
||||
|
||||
ChildParticle *pc = m_psys->child;
|
||||
|
||||
for (int p = 0; p < m_psys->totchild; ++p, ++pc) {
|
||||
path = cache[p];
|
||||
|
||||
if (part->from == PART_FROM_FACE) {
|
||||
const int num = pc->num;
|
||||
|
||||
MFace *face = static_cast<MFace *>(dm->getTessFaceData(dm, num, CD_MFACE));
|
||||
MTFace *tface = mtface + num;
|
||||
|
||||
if (mface && mtface) {
|
||||
float r_uv[2], tmpnor[3], mapfw[4], vec[3];
|
||||
|
||||
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
|
||||
uv_values.push_back(Imath::V2f(r_uv[0], r_uv[1]));
|
||||
|
||||
psys_interpolate_face(mverts, face, tface, NULL, mapfw, vec, tmpnor, NULL, NULL, NULL, NULL);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
norm_values.push_back(Imath::V3f(tmpnor[0], tmpnor[2], -tmpnor[1]));
|
||||
}
|
||||
}
|
||||
|
||||
int steps = path->segments + 1;
|
||||
hvertices.push_back(steps);
|
||||
|
||||
for (int k = 0; k < steps; ++k) {
|
||||
float vert[3];
|
||||
copy_v3_v3(vert, path->co);
|
||||
mul_m4_v3(inv_mat, vert);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
verts.push_back(Imath::V3f(vert[0], vert[2], -vert[1]));
|
||||
|
||||
++path;
|
||||
}
|
||||
}
|
||||
}
|
66
source/blender/alembic/intern/abc_hair.h
Normal file
66
source/blender/alembic/intern/abc_hair.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_HAIR_H__
|
||||
#define __ABC_HAIR_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
struct DerivedMesh;
|
||||
struct ParticleSettings;
|
||||
struct ParticleSystem;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcHairWriter : public AbcObjectWriter {
|
||||
ParticleSystem *m_psys;
|
||||
|
||||
Alembic::AbcGeom::OCurvesSchema m_schema;
|
||||
Alembic::AbcGeom::OCurvesSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcHairWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
void write_hair_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices);
|
||||
|
||||
void write_hair_child_sample(DerivedMesh *dm,
|
||||
ParticleSettings *part,
|
||||
std::vector<Imath::V3f> &verts,
|
||||
std::vector<Imath::V3f> &norm_values,
|
||||
std::vector<Imath::V2f> &uv_values,
|
||||
std::vector<int32_t> &hvertices);
|
||||
};
|
||||
|
||||
#endif /* __ABC_HAIR_H__ */
|
1213
source/blender/alembic/intern/abc_mesh.cc
Normal file
1213
source/blender/alembic/intern/abc_mesh.cc
Normal file
File diff suppressed because it is too large
Load Diff
152
source/blender/alembic/intern/abc_mesh.h
Normal file
152
source/blender/alembic/intern/abc_mesh.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_MESH_H__
|
||||
#define __ABC_MESH_H__
|
||||
|
||||
#include "abc_customdata.h"
|
||||
#include "abc_object.h"
|
||||
|
||||
struct DerivedMesh;
|
||||
struct Mesh;
|
||||
struct ModifierData;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcMeshWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OPolyMeshSchema m_mesh_schema;
|
||||
Alembic::AbcGeom::OPolyMeshSchema::Sample m_mesh_sample;
|
||||
|
||||
Alembic::AbcGeom::OSubDSchema m_subdiv_schema;
|
||||
Alembic::AbcGeom::OSubDSchema::Sample m_subdiv_sample;
|
||||
|
||||
bool m_has_per_face_materials;
|
||||
Alembic::AbcGeom::OFaceSet m_face_set;
|
||||
Alembic::Abc::OArrayProperty m_mat_indices;
|
||||
|
||||
bool m_is_animated;
|
||||
ModifierData *m_subsurf_mod;
|
||||
|
||||
CDStreamConfig m_custom_data_config;
|
||||
|
||||
bool m_is_liquid;
|
||||
bool m_is_subd;
|
||||
|
||||
public:
|
||||
AbcMeshWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
~AbcMeshWriter();
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool isAnimated() const;
|
||||
|
||||
void writeMesh(DerivedMesh *dm);
|
||||
void writeSubD(DerivedMesh *dm);
|
||||
|
||||
void getMeshInfo(DerivedMesh *dm, std::vector<float> &points,
|
||||
std::vector<int32_t> &facePoints,
|
||||
std::vector<int32_t> &faceCounts,
|
||||
std::vector<int32_t> &creaseIndices,
|
||||
std::vector<int32_t> &creaseLengths,
|
||||
std::vector<float> &creaseSharpness);
|
||||
|
||||
DerivedMesh *getFinalMesh();
|
||||
void freeMesh(DerivedMesh *dm);
|
||||
|
||||
void getMaterialIndices(DerivedMesh *dm, std::vector<int32_t> &indices);
|
||||
|
||||
void writeArbGeoParams(DerivedMesh *dm);
|
||||
void getGeoGroups(DerivedMesh *dm, std::map<std::string, std::vector<int32_t> > &geoGroups);
|
||||
|
||||
/* fluid surfaces support */
|
||||
void getVelocities(DerivedMesh *dm, std::vector<Imath::V3f> &vels);
|
||||
|
||||
template <typename Schema>
|
||||
void writeCommonData(DerivedMesh *dm, Schema &schema);
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcMeshReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IPolyMeshSchema m_schema;
|
||||
|
||||
CDStreamConfig m_mesh_data;
|
||||
|
||||
public:
|
||||
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
|
||||
private:
|
||||
void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start,
|
||||
const Alembic::AbcGeom::ISampleSelector &sample_sel);
|
||||
};
|
||||
|
||||
void read_mesh_sample(ImportSettings *settings,
|
||||
const Alembic::AbcGeom::IPolyMeshSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
bool &do_normals);
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcSubDReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::ISubDSchema m_schema;
|
||||
|
||||
CDStreamConfig m_mesh_data;
|
||||
|
||||
public:
|
||||
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
void read_subd_sample(ImportSettings *settings,
|
||||
const Alembic::AbcGeom::ISubDSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config);
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
namespace utils {
|
||||
|
||||
void mesh_add_verts(struct Mesh *mesh, size_t len);
|
||||
|
||||
}
|
||||
|
||||
void read_mverts(MVert *mverts,
|
||||
const Alembic::AbcGeom::P3fArraySamplePtr &positions,
|
||||
const Alembic::AbcGeom::N3fArraySamplePtr &normals);
|
||||
|
||||
CDStreamConfig create_config(Mesh *mesh);
|
||||
|
||||
#endif /* __ABC_MESH_H__ */
|
367
source/blender/alembic/intern/abc_nurbs.cc
Normal file
367
source/blender/alembic/intern/abc_nurbs.cc
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_nurbs.h"
|
||||
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_object.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::bool_t;
|
||||
using Alembic::AbcGeom::FloatArraySample;
|
||||
using Alembic::AbcGeom::FloatArraySamplePtr;
|
||||
using Alembic::AbcGeom::MetaData;
|
||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
|
||||
using Alembic::AbcGeom::IBoolProperty;
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::INuPatch;
|
||||
using Alembic::AbcGeom::INuPatchSchema;
|
||||
using Alembic::AbcGeom::IObject;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OBoolProperty;
|
||||
using Alembic::AbcGeom::OCompoundProperty;
|
||||
using Alembic::AbcGeom::ONuPatch;
|
||||
using Alembic::AbcGeom::ONuPatchSchema;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcNurbsWriter::AbcNurbsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_is_animated = isAnimated();
|
||||
|
||||
/* if the object is static, use the default static time sampling */
|
||||
if (!m_is_animated) {
|
||||
m_time_sampling = 0;
|
||||
}
|
||||
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
size_t numNurbs = BLI_listbase_count(&curve->nurb);
|
||||
|
||||
for (size_t i = 0; i < numNurbs; ++i) {
|
||||
std::stringstream str;
|
||||
str << m_name << '_' << i;
|
||||
|
||||
while (parent->alembicXform().getChildHeader(str.str())) {
|
||||
str << "_";
|
||||
}
|
||||
|
||||
ONuPatch nurbs(parent->alembicXform(), str.str().c_str(), m_time_sampling);
|
||||
m_nurbs_schema.push_back(nurbs.getSchema());
|
||||
}
|
||||
}
|
||||
|
||||
bool AbcNurbsWriter::isAnimated() const
|
||||
{
|
||||
/* check if object has shape keys */
|
||||
Curve *cu = static_cast<Curve *>(m_object->data);
|
||||
return (cu->key != NULL);
|
||||
}
|
||||
|
||||
static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
|
||||
{
|
||||
if (num_knots <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add an extra knot at the beggining and end of the array since most apps
|
||||
* require/expect them. */
|
||||
knots.reserve(num_knots + 2);
|
||||
|
||||
knots.push_back(0.0f);
|
||||
|
||||
for (int i = 0; i < num_knots; ++i) {
|
||||
knots.push_back(nu_knots[i]);
|
||||
}
|
||||
|
||||
knots[0] = 2.0f * knots[1] - knots[2];
|
||||
knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
|
||||
}
|
||||
|
||||
void AbcNurbsWriter::do_write()
|
||||
{
|
||||
/* we have already stored a sample for this object. */
|
||||
if (!m_first_frame && !m_is_animated) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ELEM(m_object->type, OB_SURF, OB_CURVE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Curve *curve = static_cast<Curve *>(m_object->data);
|
||||
ListBase *nulb;
|
||||
|
||||
if (m_object->curve_cache->deformed_nurbs.first != NULL) {
|
||||
nulb = &m_object->curve_cache->deformed_nurbs;
|
||||
}
|
||||
else {
|
||||
nulb = BKE_curve_nurbs_get(curve);
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, ++count) {
|
||||
std::vector<float> knotsU;
|
||||
get_knots(knotsU, KNOTSU(nu), nu->knotsu);
|
||||
|
||||
std::vector<float> knotsV;
|
||||
get_knots(knotsV, KNOTSV(nu), nu->knotsv);
|
||||
|
||||
const int size = nu->pntsu * nu->pntsv;
|
||||
std::vector<Imath::V3f> positions(size);
|
||||
std::vector<float> weights(size);
|
||||
|
||||
const BPoint *bp = nu->bp;
|
||||
|
||||
for (int i = 0; i < size; ++i, ++bp) {
|
||||
copy_zup_yup(positions[i].getValue(), bp->vec);
|
||||
weights[i] = bp->vec[3];
|
||||
}
|
||||
|
||||
ONuPatchSchema::Sample sample;
|
||||
sample.setUOrder(nu->orderu + 1);
|
||||
sample.setVOrder(nu->orderv + 1);
|
||||
sample.setPositions(positions);
|
||||
sample.setPositionWeights(weights);
|
||||
sample.setUKnot(FloatArraySample(knotsU));
|
||||
sample.setVKnot(FloatArraySample(knotsV));
|
||||
sample.setNu(nu->pntsu);
|
||||
sample.setNv(nu->pntsv);
|
||||
|
||||
/* TODO(kevin): to accomodate other software we should duplicate control
|
||||
* points to indicate that a NURBS is cyclic. */
|
||||
OCompoundProperty user_props = m_nurbs_schema[count].getUserProperties();
|
||||
|
||||
if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
|
||||
OBoolProperty prop(user_props, "endpoint_u");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
|
||||
OBoolProperty prop(user_props, "endpoint_v");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
|
||||
OBoolProperty prop(user_props, "cyclic_u");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
|
||||
OBoolProperty prop(user_props, "cyclic_v");
|
||||
prop.set(true);
|
||||
}
|
||||
|
||||
m_nurbs_schema[count].set(sample);
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcNurbsReader::AbcNurbsReader(const IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
getNurbsPatches(m_iobject);
|
||||
get_min_max_time(m_schemas[0].first, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcNurbsReader::valid() const
|
||||
{
|
||||
if (m_schemas.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector< std::pair<INuPatchSchema, IObject> >::const_iterator it;
|
||||
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
|
||||
const INuPatchSchema &schema = it->first;
|
||||
|
||||
if (!schema.valid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_knots(const FloatArraySamplePtr &knots, float *&nu_knots)
|
||||
{
|
||||
if (!knots || knots->size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Skip first and last knots, as they are used for padding. */
|
||||
const size_t num_knots = knots->size() - 2;
|
||||
nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), "abc_setsplineknotsu"));
|
||||
|
||||
for (size_t i = 0; i < num_knots; ++i) {
|
||||
nu_knots[i] = (*knots)[i + 1];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbcNurbsReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Curve *cu = static_cast<Curve *>(BKE_curve_add(bmain, "abc_curve", OB_SURF));
|
||||
cu->actvert = CU_ACT_NONE;
|
||||
|
||||
std::vector< std::pair<INuPatchSchema, IObject> >::iterator it;
|
||||
|
||||
for (it = m_schemas.begin(); it != m_schemas.end(); ++it) {
|
||||
Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), "abc_getnurb"));
|
||||
nu->flag = CU_SMOOTH;
|
||||
nu->type = CU_NURBS;
|
||||
nu->resolu = cu->resolu;
|
||||
nu->resolv = cu->resolv;
|
||||
|
||||
const ISampleSelector sample_sel(time);
|
||||
const INuPatchSchema &schema = it->first;
|
||||
const INuPatchSchema::Sample smp = schema.getValue(sample_sel);
|
||||
|
||||
nu->orderu = smp.getUOrder() - 1;
|
||||
nu->orderv = smp.getVOrder() - 1;
|
||||
nu->pntsu = smp.getNumU();
|
||||
nu->pntsv = smp.getNumV();
|
||||
|
||||
/* Read positions and weights. */
|
||||
|
||||
const P3fArraySamplePtr positions = smp.getPositions();
|
||||
const FloatArraySamplePtr weights = smp.getPositionWeights();
|
||||
|
||||
const size_t num_points = positions->size();
|
||||
|
||||
nu->bp = static_cast<BPoint *>(MEM_callocN(num_points * sizeof(BPoint), "abc_setsplinetype"));
|
||||
|
||||
BPoint *bp = nu->bp;
|
||||
float posw_in = 1.0f;
|
||||
|
||||
for (int i = 0; i < num_points; ++i, ++bp) {
|
||||
const Imath::V3f &pos_in = (*positions)[i];
|
||||
|
||||
if (weights) {
|
||||
posw_in = (*weights)[i];
|
||||
}
|
||||
|
||||
copy_yup_zup(bp->vec, pos_in.getValue());
|
||||
bp->vec[3] = posw_in;
|
||||
bp->f1 = SELECT;
|
||||
bp->radius = 1.0f;
|
||||
bp->weight = 1.0f;
|
||||
}
|
||||
|
||||
/* Read knots. */
|
||||
|
||||
if (!set_knots(smp.getUKnot(), nu->knotsu)) {
|
||||
BKE_nurb_knot_calc_u(nu);
|
||||
}
|
||||
|
||||
if (!set_knots(smp.getVKnot(), nu->knotsv)) {
|
||||
BKE_nurb_knot_calc_v(nu);
|
||||
}
|
||||
|
||||
/* Read flags. */
|
||||
|
||||
ICompoundProperty user_props = schema.getUserProperties();
|
||||
|
||||
if (has_property(user_props, "enpoint_u")) {
|
||||
nu->flagu |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "enpoint_v")) {
|
||||
nu->flagv |= CU_NURB_ENDPOINT;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "cyclic_u")) {
|
||||
nu->flagu |= CU_NURB_CYCLIC;
|
||||
}
|
||||
|
||||
if (has_property(user_props, "cyclic_v")) {
|
||||
nu->flagv |= CU_NURB_CYCLIC;
|
||||
}
|
||||
|
||||
BLI_addtail(BKE_curve_nurbs_get(cu), nu);
|
||||
}
|
||||
|
||||
BLI_strncpy(cu->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1);
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_SURF, m_object_name.c_str());
|
||||
m_object->data = cu;
|
||||
}
|
||||
|
||||
void AbcNurbsReader::getNurbsPatches(const IObject &obj)
|
||||
{
|
||||
if (!obj.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int num_children = obj.getNumChildren();
|
||||
|
||||
if (num_children == 0) {
|
||||
INuPatch abc_nurb(obj, kWrapExisting);
|
||||
INuPatchSchema schem = abc_nurb.getSchema();
|
||||
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, obj));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
bool ok = true;
|
||||
IObject child(obj, obj.getChildHeader(i).getName());
|
||||
|
||||
if (!m_name.empty() && child.valid() && !begins_with(child.getFullName(), m_name)) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!child.valid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MetaData &md = child.getMetaData();
|
||||
|
||||
if (INuPatch::matches(md) && ok) {
|
||||
INuPatch abc_nurb(child, kWrapExisting);
|
||||
INuPatchSchema schem = abc_nurb.getSchema();
|
||||
m_schemas.push_back(std::pair<INuPatchSchema, IObject>(schem, child));
|
||||
}
|
||||
|
||||
getNurbsPatches(child);
|
||||
}
|
||||
}
|
63
source/blender/alembic/intern/abc_nurbs.h
Normal file
63
source/blender/alembic/intern/abc_nurbs.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_NURBS_H__
|
||||
#define __ABC_NURBS_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcNurbsWriter : public AbcObjectWriter {
|
||||
std::vector<Alembic::AbcGeom::ONuPatchSchema> m_nurbs_schema;
|
||||
bool m_is_animated;
|
||||
|
||||
public:
|
||||
AbcNurbsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool isAnimated() const;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcNurbsReader : public AbcObjectReader {
|
||||
std::vector< std::pair<Alembic::AbcGeom::INuPatchSchema, Alembic::Abc::IObject> > m_schemas;
|
||||
|
||||
public:
|
||||
AbcNurbsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
|
||||
private:
|
||||
void getNurbsPatches(const Alembic::Abc::IObject &obj);
|
||||
};
|
||||
|
||||
#endif /* __ABC_NURBS_H__ */
|
238
source/blender/alembic/intern/abc_object.cc
Normal file
238
source/blender/alembic/intern/abc_object.cc
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_space_types.h" /* for FILE_MAX */
|
||||
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::IObject;
|
||||
using Alembic::AbcGeom::IXform;
|
||||
using Alembic::AbcGeom::IXformSchema;
|
||||
|
||||
using Alembic::AbcGeom::OCompoundProperty;
|
||||
using Alembic::AbcGeom::ODoubleArrayProperty;
|
||||
using Alembic::AbcGeom::ODoubleProperty;
|
||||
using Alembic::AbcGeom::OFloatArrayProperty;
|
||||
using Alembic::AbcGeom::OFloatProperty;
|
||||
using Alembic::AbcGeom::OInt32ArrayProperty;
|
||||
using Alembic::AbcGeom::OInt32Property;
|
||||
using Alembic::AbcGeom::OStringArrayProperty;
|
||||
using Alembic::AbcGeom::OStringProperty;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcObjectWriter::AbcObjectWriter(Scene *scene,
|
||||
Object *ob,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
AbcObjectWriter *parent)
|
||||
: m_object(ob)
|
||||
, m_settings(settings)
|
||||
, m_scene(scene)
|
||||
, m_time_sampling(time_sampling)
|
||||
, m_first_frame(true)
|
||||
{
|
||||
m_name = get_id_name(m_object) + "Shape";
|
||||
|
||||
if (parent) {
|
||||
parent->addChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
AbcObjectWriter::~AbcObjectWriter()
|
||||
{}
|
||||
|
||||
void AbcObjectWriter::addChild(AbcObjectWriter *child)
|
||||
{
|
||||
m_children.push_back(child);
|
||||
}
|
||||
|
||||
Imath::Box3d AbcObjectWriter::bounds()
|
||||
{
|
||||
BoundBox *bb = BKE_object_boundbox_get(this->m_object);
|
||||
|
||||
if (!bb) {
|
||||
if (this->m_object->type != OB_CAMERA) {
|
||||
std::cerr << "Boundbox is null!\n";
|
||||
}
|
||||
|
||||
return Imath::Box3d();
|
||||
}
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
this->m_bounds.min.x = bb->vec[0][0];
|
||||
this->m_bounds.min.y = bb->vec[0][2];
|
||||
this->m_bounds.min.z = -bb->vec[0][1];
|
||||
|
||||
this->m_bounds.max.x = bb->vec[6][0];
|
||||
this->m_bounds.max.y = bb->vec[6][2];
|
||||
this->m_bounds.max.z = -bb->vec[6][1];
|
||||
|
||||
return this->m_bounds;
|
||||
}
|
||||
|
||||
void AbcObjectWriter::write()
|
||||
{
|
||||
do_write();
|
||||
m_first_frame = false;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings)
|
||||
: m_name("")
|
||||
, m_object_name("")
|
||||
, m_data_name("")
|
||||
, m_object(NULL)
|
||||
, m_iobject(object)
|
||||
, m_settings(&settings)
|
||||
, m_min_time(std::numeric_limits<chrono_t>::max())
|
||||
, m_max_time(std::numeric_limits<chrono_t>::min())
|
||||
{
|
||||
m_name = object.getFullName();
|
||||
std::vector<std::string> parts;
|
||||
split(m_name, '/', parts);
|
||||
|
||||
if (parts.size() >= 2) {
|
||||
m_object_name = parts[parts.size() - 2];
|
||||
m_data_name = parts[parts.size() - 1];
|
||||
}
|
||||
else {
|
||||
m_object_name = m_data_name = parts[parts.size() - 1];
|
||||
}
|
||||
}
|
||||
|
||||
AbcObjectReader::~AbcObjectReader()
|
||||
{}
|
||||
|
||||
const IObject &AbcObjectReader::iobject() const
|
||||
{
|
||||
return m_iobject;
|
||||
}
|
||||
|
||||
Object *AbcObjectReader::object() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
void AbcObjectReader::readObjectMatrix(const float time)
|
||||
{
|
||||
IXform ixform;
|
||||
bool has_alembic_parent = false;
|
||||
|
||||
/* Check that we have an empty object (locator, bone head/tail...). */
|
||||
if (IXform::matches(m_iobject.getMetaData())) {
|
||||
ixform = IXform(m_iobject, Alembic::AbcGeom::kWrapExisting);
|
||||
|
||||
/* See comment below. */
|
||||
has_alembic_parent = m_iobject.getParent().getParent().valid();
|
||||
}
|
||||
/* Check that we have an object with actual data. */
|
||||
else if (IXform::matches(m_iobject.getParent().getMetaData())) {
|
||||
ixform = IXform(m_iobject.getParent(), Alembic::AbcGeom::kWrapExisting);
|
||||
|
||||
/* This is a bit hackish, but we need to make sure that extra
|
||||
* transformations added to the matrix (rotation/scale) are only applied
|
||||
* to root objects. The way objects and their hierarchy are created will
|
||||
* need to be revisited at some point but for now this seems to do the
|
||||
* trick.
|
||||
*
|
||||
* Explanation of the trick:
|
||||
* The first getParent() will return this object's transformation matrix.
|
||||
* The second getParent() will get the parent of the transform, but this
|
||||
* might be the archive root ('/') which is valid, so we go passed it to
|
||||
* make sure that there is no parent.
|
||||
*/
|
||||
has_alembic_parent = m_iobject.getParent().getParent().getParent().valid();
|
||||
}
|
||||
/* Should not happen. */
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
const IXformSchema &schema(ixform.getSchema());
|
||||
|
||||
if (!schema.valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::ISampleSelector sample_sel(time);
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
schema.get(xs, sample_sel);
|
||||
|
||||
create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
|
||||
|
||||
invert_m4_m4(m_object->imat, m_object->obmat);
|
||||
|
||||
BKE_object_apply_mat4(m_object, m_object->obmat, false, false);
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE);
|
||||
bTransformCacheConstraint *data = static_cast<bTransformCacheConstraint *>(con->data);
|
||||
BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
|
||||
data->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&data->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
void AbcObjectReader::addCacheModifier() const
|
||||
{
|
||||
ModifierData *md = modifier_new(eModifierType_MeshSequenceCache);
|
||||
BLI_addtail(&m_object->modifiers, md);
|
||||
|
||||
MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
|
||||
|
||||
mcmd->cache_file = m_settings->cache_file;
|
||||
id_us_plus(&mcmd->cache_file->id);
|
||||
|
||||
BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX);
|
||||
}
|
||||
|
||||
chrono_t AbcObjectReader::minTime() const
|
||||
{
|
||||
return m_min_time;
|
||||
}
|
||||
|
||||
chrono_t AbcObjectReader::maxTime() const
|
||||
{
|
||||
return m_max_time;
|
||||
}
|
169
source/blender/alembic/intern/abc_object.h
Normal file
169
source/blender/alembic/intern/abc_object.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_OBJECT_H__
|
||||
#define __ABC_OBJECT_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
#include "abc_exporter.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_ID.h"
|
||||
}
|
||||
|
||||
class AbcTransformWriter;
|
||||
|
||||
struct Main;
|
||||
struct Object;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcObjectWriter {
|
||||
protected:
|
||||
Object *m_object;
|
||||
ExportSettings &m_settings;
|
||||
|
||||
Scene *m_scene;
|
||||
uint32_t m_time_sampling;
|
||||
|
||||
Imath::Box3d m_bounds;
|
||||
std::vector<AbcObjectWriter *> m_children;
|
||||
|
||||
std::vector< std::pair<std::string, IDProperty *> > m_props;
|
||||
|
||||
bool m_first_frame;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
AbcObjectWriter(Scene *scene,
|
||||
Object *ob,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
AbcObjectWriter *parent = NULL);
|
||||
|
||||
virtual ~AbcObjectWriter();
|
||||
|
||||
void addChild(AbcObjectWriter *child);
|
||||
|
||||
virtual Imath::Box3d bounds();
|
||||
|
||||
void write();
|
||||
|
||||
private:
|
||||
virtual void do_write() = 0;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class CacheFile;
|
||||
|
||||
struct ImportSettings {
|
||||
bool do_convert_mat;
|
||||
float conversion_mat[4][4];
|
||||
|
||||
int from_up;
|
||||
int from_forward;
|
||||
float scale;
|
||||
bool is_sequence;
|
||||
bool set_frame_range;
|
||||
|
||||
/* Length and frame offset of file sequences. */
|
||||
int sequence_len;
|
||||
int offset;
|
||||
|
||||
/* From MeshSeqCacheModifierData.read_flag */
|
||||
int read_flag;
|
||||
|
||||
bool validate_meshes;
|
||||
|
||||
CacheFile *cache_file;
|
||||
|
||||
ImportSettings()
|
||||
: do_convert_mat(false)
|
||||
, from_up(0)
|
||||
, from_forward(0)
|
||||
, scale(1.0f)
|
||||
, is_sequence(false)
|
||||
, set_frame_range(false)
|
||||
, sequence_len(1)
|
||||
, offset(0)
|
||||
, read_flag(0)
|
||||
, validate_meshes(false)
|
||||
, cache_file(NULL)
|
||||
{}
|
||||
};
|
||||
|
||||
template <typename Schema>
|
||||
static bool has_animations(Schema &schema, ImportSettings *settings)
|
||||
{
|
||||
if (settings->is_sequence) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
using Alembic::AbcCoreAbstract::chrono_t;
|
||||
|
||||
class AbcObjectReader {
|
||||
protected:
|
||||
std::string m_name;
|
||||
std::string m_object_name;
|
||||
std::string m_data_name;
|
||||
Object *m_object;
|
||||
Alembic::Abc::IObject m_iobject;
|
||||
|
||||
ImportSettings *m_settings;
|
||||
|
||||
chrono_t m_min_time;
|
||||
chrono_t m_max_time;
|
||||
|
||||
public:
|
||||
explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
virtual ~AbcObjectReader();
|
||||
|
||||
const Alembic::Abc::IObject &iobject() const;
|
||||
|
||||
Object *object() const;
|
||||
|
||||
virtual bool valid() const = 0;
|
||||
|
||||
virtual void readObjectData(Main *bmain, float time) = 0;
|
||||
|
||||
void readObjectMatrix(const float time);
|
||||
|
||||
void addCacheModifier() const;
|
||||
|
||||
chrono_t minTime() const;
|
||||
chrono_t maxTime() const;
|
||||
};
|
||||
|
||||
#endif /* __ABC_OBJECT_H__ */
|
198
source/blender/alembic/intern/abc_points.cc
Normal file
198
source/blender/alembic/intern/abc_points.cc
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#include "abc_points.h"
|
||||
|
||||
#include "abc_mesh.h"
|
||||
#include "abc_transform.h"
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "BKE_lattice.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_particle.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::kVertexScope;
|
||||
using Alembic::AbcGeom::kWrapExisting;
|
||||
using Alembic::AbcGeom::P3fArraySamplePtr;
|
||||
using Alembic::AbcGeom::N3fArraySamplePtr;
|
||||
|
||||
using Alembic::AbcGeom::ICompoundProperty;
|
||||
using Alembic::AbcGeom::IN3fArrayProperty;
|
||||
using Alembic::AbcGeom::IPoints;
|
||||
using Alembic::AbcGeom::IPointsSchema;
|
||||
using Alembic::AbcGeom::ISampleSelector;
|
||||
|
||||
using Alembic::AbcGeom::OPoints;
|
||||
using Alembic::AbcGeom::OPointsSchema;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcPointsWriter::AbcPointsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys)
|
||||
: AbcObjectWriter(scene, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_psys = psys;
|
||||
|
||||
OPoints points(parent->alembicXform(), m_name, m_time_sampling);
|
||||
m_schema = points.getSchema();
|
||||
}
|
||||
|
||||
void AbcPointsWriter::do_write()
|
||||
{
|
||||
if (!m_psys) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Imath::V3f> points;
|
||||
std::vector<Imath::V3f> velocities;
|
||||
std::vector<float> widths;
|
||||
std::vector<uint64_t> ids;
|
||||
|
||||
ParticleKey state;
|
||||
|
||||
ParticleSimulationData sim;
|
||||
sim.scene = m_scene;
|
||||
sim.ob = m_object;
|
||||
sim.psys = m_psys;
|
||||
|
||||
m_psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
|
||||
|
||||
uint64_t index = 0;
|
||||
for (int p = 0; p < m_psys->totpart; p++) {
|
||||
float pos[3], vel[3];
|
||||
|
||||
if (m_psys->particles[p].flag & (PARS_NO_DISP | PARS_UNEXIST)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
state.time = BKE_scene_frame_get(m_scene);
|
||||
|
||||
if (psys_get_particle_state(&sim, p, &state, 0) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* location */
|
||||
mul_v3_m4v3(pos, m_object->imat, state.co);
|
||||
|
||||
/* velocity */
|
||||
sub_v3_v3v3(vel, state.co, m_psys->particles[p].prev_state.co);
|
||||
|
||||
/* Convert Z-up to Y-up. */
|
||||
points.push_back(Imath::V3f(pos[0], pos[2], -pos[1]));
|
||||
velocities.push_back(Imath::V3f(vel[0], vel[2], -vel[1]));
|
||||
widths.push_back(m_psys->particles[p].size);
|
||||
ids.push_back(index++);
|
||||
}
|
||||
|
||||
if (m_psys->lattice_deform_data) {
|
||||
end_latt_deform(m_psys->lattice_deform_data);
|
||||
m_psys->lattice_deform_data = NULL;
|
||||
}
|
||||
|
||||
Alembic::Abc::P3fArraySample psample(points);
|
||||
Alembic::Abc::UInt64ArraySample idsample(ids);
|
||||
Alembic::Abc::V3fArraySample vsample(velocities);
|
||||
Alembic::Abc::FloatArraySample wsample_array(widths);
|
||||
Alembic::AbcGeom::OFloatGeomParam::Sample wsample(wsample_array, kVertexScope);
|
||||
|
||||
m_sample = OPointsSchema::Sample(psample, idsample, vsample, wsample);
|
||||
m_sample.setSelfBounds(bounds());
|
||||
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcPointsReader::AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
IPoints ipoints(m_iobject, kWrapExisting);
|
||||
m_schema = ipoints.getSchema();
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcPointsReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcPointsReader::readObjectData(Main *bmain, float time)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str());
|
||||
|
||||
const ISampleSelector sample_sel(time);
|
||||
m_sample = m_schema.getValue(sample_sel);
|
||||
|
||||
const P3fArraySamplePtr &positions = m_sample.getPositions();
|
||||
utils::mesh_add_verts(mesh, positions->size());
|
||||
|
||||
CDStreamConfig config = create_config(mesh);
|
||||
read_points_sample(m_schema, sample_sel, config, time);
|
||||
|
||||
if (m_settings->validate_meshes) {
|
||||
BKE_mesh_validate(mesh, false, false);
|
||||
}
|
||||
|
||||
m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str());
|
||||
m_object->data = mesh;
|
||||
|
||||
if (has_animations(m_schema, m_settings)) {
|
||||
addCacheModifier();
|
||||
}
|
||||
}
|
||||
|
||||
void read_points_sample(const IPointsSchema &schema,
|
||||
const ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
float time)
|
||||
{
|
||||
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
|
||||
|
||||
const P3fArraySamplePtr &positions = sample.getPositions();
|
||||
|
||||
ICompoundProperty prop = schema.getArbGeomParams();
|
||||
N3fArraySamplePtr vnormals;
|
||||
|
||||
if (has_property(prop, "N")) {
|
||||
const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time);
|
||||
|
||||
if (normals_prop) {
|
||||
vnormals = normals_prop.getValue(selector);
|
||||
}
|
||||
}
|
||||
|
||||
read_mverts(config.mvert, positions, vnormals);
|
||||
}
|
70
source/blender/alembic/intern/abc_points.h
Normal file
70
source/blender/alembic/intern/abc_points.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Kévin Dietrich.
|
||||
* All rights reserved.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ABC_POINTS_H__
|
||||
#define __ABC_POINTS_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
#include "abc_customdata.h"
|
||||
|
||||
class ParticleSystem;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcPointsWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OPointsSchema m_schema;
|
||||
Alembic::AbcGeom::OPointsSchema::Sample m_sample;
|
||||
ParticleSystem *m_psys;
|
||||
|
||||
public:
|
||||
AbcPointsWriter(Scene *scene,
|
||||
Object *ob,
|
||||
AbcTransformWriter *parent,
|
||||
uint32_t time_sampling,
|
||||
ExportSettings &settings,
|
||||
ParticleSystem *psys);
|
||||
|
||||
void do_write();
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcPointsReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IPointsSchema m_schema;
|
||||
Alembic::AbcGeom::IPointsSchema::Sample m_sample;
|
||||
|
||||
public:
|
||||
AbcPointsReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
|
||||
const Alembic::AbcGeom::ISampleSelector &selector,
|
||||
CDStreamConfig &config,
|
||||
float time);
|
||||
|
||||
#endif /* __ABC_POINTS_H__ */
|
152
source/blender/alembic/intern/abc_transform.cc
Normal file
152
source/blender/alembic/intern/abc_transform.cc
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_transform.h"
|
||||
|
||||
#include <OpenEXR/ImathBoxAlgo.h>
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_object.h"
|
||||
}
|
||||
|
||||
using Alembic::AbcGeom::OObject;
|
||||
using Alembic::AbcGeom::OXform;
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
static bool has_parent_camera(Object *ob)
|
||||
{
|
||||
if (!ob->parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *parent = ob->parent;
|
||||
|
||||
if (parent->type == OB_CAMERA) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return has_parent_camera(parent);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcTransformWriter::AbcTransformWriter(Object *ob,
|
||||
const OObject &abc_parent,
|
||||
AbcTransformWriter *parent,
|
||||
unsigned int time_sampling,
|
||||
ExportSettings &settings)
|
||||
: AbcObjectWriter(NULL, ob, time_sampling, settings, parent)
|
||||
{
|
||||
m_is_animated = hasAnimation(m_object);
|
||||
m_parent = NULL;
|
||||
|
||||
if (!m_is_animated) {
|
||||
time_sampling = 0;
|
||||
}
|
||||
|
||||
m_xform = OXform(abc_parent, get_id_name(m_object), time_sampling);
|
||||
m_schema = m_xform.getSchema();
|
||||
}
|
||||
|
||||
void AbcTransformWriter::do_write()
|
||||
{
|
||||
if (m_first_frame) {
|
||||
m_visibility = Alembic::AbcGeom::CreateVisibilityProperty(m_xform, m_xform.getSchema().getTimeSampling());
|
||||
}
|
||||
|
||||
m_visibility.set(!(m_object->restrictflag & OB_RESTRICT_VIEW));
|
||||
|
||||
if (!m_first_frame && !m_is_animated) {
|
||||
return;
|
||||
}
|
||||
|
||||
float mat[4][4];
|
||||
create_transform_matrix(m_object, mat);
|
||||
|
||||
/* Only apply rotation to root camera, parenting will propagate it. */
|
||||
if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) {
|
||||
float rot_mat[4][4];
|
||||
unit_m4(rot_mat);
|
||||
rotate_m4(rot_mat, 'X', -M_PI_2);
|
||||
mul_m4_m4m4(mat, mat, rot_mat);
|
||||
}
|
||||
|
||||
if (!m_object->parent) {
|
||||
/* Only apply scaling to root objects, parenting will propagate it. */
|
||||
float scale_mat[4][4];
|
||||
scale_m4_fl(scale_mat, m_settings.global_scale);
|
||||
mul_m4_m4m4(mat, mat, scale_mat);
|
||||
mul_v3_fl(mat[3], m_settings.global_scale);
|
||||
}
|
||||
|
||||
m_matrix = convert_matrix(mat);
|
||||
|
||||
m_sample.setMatrix(m_matrix);
|
||||
m_schema.set(m_sample);
|
||||
}
|
||||
|
||||
Imath::Box3d AbcTransformWriter::bounds()
|
||||
{
|
||||
Imath::Box3d bounds;
|
||||
|
||||
for (int i = 0; i < m_children.size(); ++i) {
|
||||
Imath::Box3d box(m_children[i]->bounds());
|
||||
bounds.extendBy(box);
|
||||
}
|
||||
|
||||
return Imath::transform(bounds, m_matrix);
|
||||
}
|
||||
|
||||
bool AbcTransformWriter::hasAnimation(Object */*ob*/) const
|
||||
{
|
||||
/* TODO(kevin): implement this. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
AbcEmptyReader::AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
|
||||
: AbcObjectReader(object, settings)
|
||||
{
|
||||
Alembic::AbcGeom::IXform xform(object, Alembic::AbcGeom::kWrapExisting);
|
||||
m_schema = xform.getSchema();
|
||||
|
||||
get_min_max_time(m_schema, m_min_time, m_max_time);
|
||||
}
|
||||
|
||||
bool AbcEmptyReader::valid() const
|
||||
{
|
||||
return m_schema.valid();
|
||||
}
|
||||
|
||||
void AbcEmptyReader::readObjectData(Main *bmain, float /*time*/)
|
||||
{
|
||||
m_object = BKE_object_add_only_object(bmain, OB_EMPTY, m_object_name.c_str());
|
||||
m_object->data = NULL;
|
||||
}
|
73
source/blender/alembic/intern/abc_transform.h
Normal file
73
source/blender/alembic/intern/abc_transform.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_TRANSFORM_H__
|
||||
#define __ABC_TRANSFORM_H__
|
||||
|
||||
#include "abc_object.h"
|
||||
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcTransformWriter : public AbcObjectWriter {
|
||||
Alembic::AbcGeom::OXform m_xform;
|
||||
Alembic::AbcGeom::OXformSchema m_schema;
|
||||
Alembic::AbcGeom::XformSample m_sample;
|
||||
Alembic::AbcGeom::OVisibilityProperty m_visibility;
|
||||
Alembic::Abc::M44d m_matrix;
|
||||
|
||||
bool m_is_animated;
|
||||
Object *m_parent;
|
||||
bool m_visible;
|
||||
|
||||
public:
|
||||
AbcTransformWriter(Object *ob,
|
||||
const Alembic::AbcGeom::OObject &abc_parent,
|
||||
AbcTransformWriter *parent,
|
||||
unsigned int time_sampling,
|
||||
ExportSettings &settings);
|
||||
|
||||
Alembic::AbcGeom::OXform &alembicXform() { return m_xform;}
|
||||
virtual Imath::Box3d bounds();
|
||||
void setParent(Object *p) { m_parent = p; }
|
||||
|
||||
private:
|
||||
virtual void do_write();
|
||||
|
||||
bool hasAnimation(Object *ob) const;
|
||||
};
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
class AbcEmptyReader : public AbcObjectReader {
|
||||
Alembic::AbcGeom::IXformSchema m_schema;
|
||||
|
||||
public:
|
||||
AbcEmptyReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
|
||||
|
||||
bool valid() const;
|
||||
|
||||
void readObjectData(Main *bmain, float time);
|
||||
};
|
||||
|
||||
#endif /* __ABC_TRANSFORM_H__ */
|
437
source/blender/alembic/intern/abc_util.cc
Normal file
437
source/blender/alembic/intern/abc_util.cc
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include "abc_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
extern "C" {
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
}
|
||||
|
||||
std::string get_id_name(Object *ob)
|
||||
{
|
||||
if (!ob) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return get_id_name(&ob->id);
|
||||
}
|
||||
|
||||
std::string get_id_name(ID *id)
|
||||
{
|
||||
std::string name(id->name + 2);
|
||||
std::replace(name.begin(), name.end(), ' ', '_');
|
||||
std::replace(name.begin(), name.end(), '.', '_');
|
||||
std::replace(name.begin(), name.end(), ':', '_');
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent)
|
||||
{
|
||||
std::string name = get_id_name(ob);
|
||||
|
||||
Object *p = ob->parent;
|
||||
|
||||
while (p) {
|
||||
name = get_id_name(p) + "/" + name;
|
||||
p = p->parent;
|
||||
}
|
||||
|
||||
if (dupli_parent && (ob != dupli_parent)) {
|
||||
name = get_id_name(dupli_parent) + "/" + name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool object_selected(Object *ob)
|
||||
{
|
||||
return ob->flag & SELECT;
|
||||
}
|
||||
|
||||
bool parent_selected(Object *ob)
|
||||
{
|
||||
if (object_selected(ob)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_export = false;
|
||||
|
||||
Object *parent = ob->parent;
|
||||
|
||||
while (parent != NULL) {
|
||||
if (object_selected(parent)) {
|
||||
do_export = true;
|
||||
break;
|
||||
}
|
||||
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
return do_export;
|
||||
}
|
||||
|
||||
Imath::M44d convert_matrix(float mat[4][4])
|
||||
{
|
||||
Imath::M44d m;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
m[i][j] = mat[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void split(const std::string &s, const char delim, std::vector<std::string> &tokens)
|
||||
{
|
||||
tokens.clear();
|
||||
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
|
||||
while (std::getline(ss, item, delim)) {
|
||||
if (!item.empty()) {
|
||||
tokens.push_back(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a rotation matrix for each axis from euler angles.
|
||||
* Euler angles are swaped to change coordinate system. */
|
||||
static void create_rotation_matrix(
|
||||
float rot_x_mat[3][3], float rot_y_mat[3][3],
|
||||
float rot_z_mat[3][3], const float euler[3], const bool to_yup)
|
||||
{
|
||||
const float rx = euler[0];
|
||||
const float ry = (to_yup) ? euler[2] : -euler[2];
|
||||
const float rz = (to_yup) ? -euler[1] : euler[1];
|
||||
|
||||
unit_m3(rot_x_mat);
|
||||
unit_m3(rot_y_mat);
|
||||
unit_m3(rot_z_mat);
|
||||
|
||||
rot_x_mat[1][1] = cos(rx);
|
||||
rot_x_mat[2][1] = -sin(rx);
|
||||
rot_x_mat[1][2] = sin(rx);
|
||||
rot_x_mat[2][2] = cos(rx);
|
||||
|
||||
rot_y_mat[2][2] = cos(ry);
|
||||
rot_y_mat[0][2] = -sin(ry);
|
||||
rot_y_mat[2][0] = sin(ry);
|
||||
rot_y_mat[0][0] = cos(ry);
|
||||
|
||||
rot_z_mat[0][0] = cos(rz);
|
||||
rot_z_mat[1][0] = -sin(rz);
|
||||
rot_z_mat[0][1] = sin(rz);
|
||||
rot_z_mat[1][1] = cos(rz);
|
||||
}
|
||||
|
||||
/* Recompute transform matrix of object in new coordinate system
|
||||
* (from Y-Up to Z-Up). */
|
||||
void create_transform_matrix(float r_mat[4][4])
|
||||
{
|
||||
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], transform_mat[4][4];
|
||||
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
|
||||
float loc[3], scale[3], euler[3];
|
||||
|
||||
zero_v3(loc);
|
||||
zero_v3(scale);
|
||||
zero_v3(euler);
|
||||
unit_m3(rot);
|
||||
unit_m3(rot_mat);
|
||||
unit_m4(scale_mat);
|
||||
unit_m4(transform_mat);
|
||||
unit_m4(invmat);
|
||||
|
||||
/* Compute rotation matrix. */
|
||||
|
||||
/* Extract location, rotation, and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, r_mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, false);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
/* Add rotation matrix to transformation matrix. */
|
||||
copy_m4_m3(transform_mat, rot_mat);
|
||||
|
||||
/* Add translation to transformation matrix. */
|
||||
copy_yup_zup(transform_mat[3], loc);
|
||||
|
||||
/* Create scale matrix. */
|
||||
scale_mat[0][0] = scale[0];
|
||||
scale_mat[1][1] = scale[2];
|
||||
scale_mat[2][2] = scale[1];
|
||||
|
||||
/* Add scale to transformation matrix. */
|
||||
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
|
||||
|
||||
copy_m4_m4(r_mat, transform_mat);
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent)
|
||||
{
|
||||
|
||||
const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
ixform_schema.get(xs, sample_sel);
|
||||
const Imath::M44d &xform = xs.getMatrix();
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
r_mat[i][j] = xform[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->type == OB_CAMERA) {
|
||||
float cam_to_yup[4][4];
|
||||
unit_m4(cam_to_yup);
|
||||
rotate_m4(cam_to_yup, 'X', M_PI_2);
|
||||
mul_m4_m4m4(r_mat, r_mat, cam_to_yup);
|
||||
}
|
||||
|
||||
create_transform_matrix(r_mat);
|
||||
|
||||
if (ob->parent) {
|
||||
mul_m4_m4m4(r_mat, ob->parent->obmat, r_mat);
|
||||
}
|
||||
/* TODO(kevin) */
|
||||
else if (!has_alembic_parent) {
|
||||
/* Only apply scaling to root objects, parenting will propagate it. */
|
||||
float scale_mat[4][4];
|
||||
scale_m4_fl(scale_mat, scale);
|
||||
mul_m4_m4m4(r_mat, r_mat, scale_mat);
|
||||
mul_v3_fl(r_mat[3], scale);
|
||||
}
|
||||
}
|
||||
|
||||
/* Recompute transform matrix of object in new coordinate system (from Z-Up to Y-Up). */
|
||||
void create_transform_matrix(Object *obj, float transform_mat[4][4])
|
||||
{
|
||||
float rot_mat[3][3], rot[3][3], scale_mat[4][4], invmat[4][4], mat[4][4];
|
||||
float rot_x_mat[3][3], rot_y_mat[3][3], rot_z_mat[3][3];
|
||||
float loc[3], scale[3], euler[3];
|
||||
|
||||
zero_v3(loc);
|
||||
zero_v3(scale);
|
||||
zero_v3(euler);
|
||||
unit_m3(rot);
|
||||
unit_m3(rot_mat);
|
||||
unit_m4(scale_mat);
|
||||
unit_m4(transform_mat);
|
||||
unit_m4(invmat);
|
||||
unit_m4(mat);
|
||||
|
||||
/* get local matrix. */
|
||||
if (obj->parent) {
|
||||
invert_m4_m4(invmat, obj->parent->obmat);
|
||||
mul_m4_m4m4(mat, invmat, obj->obmat);
|
||||
}
|
||||
else {
|
||||
copy_m4_m4(mat, obj->obmat);
|
||||
}
|
||||
|
||||
/* Compute rotation matrix. */
|
||||
switch (obj->rotmode) {
|
||||
case ROT_MODE_AXISANGLE:
|
||||
{
|
||||
/* Get euler angles from axis angle rotation. */
|
||||
axis_angle_to_eulO(euler, ROT_MODE_XYZ, obj->rotAxis, obj->rotAngle);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
/* Extract location and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_QUAT:
|
||||
{
|
||||
float q[4];
|
||||
copy_v4_v4(q, obj->quat);
|
||||
|
||||
/* Swap axis. */
|
||||
q[2] = obj->quat[3];
|
||||
q[3] = -obj->quat[2];
|
||||
|
||||
/* Compute rotation matrix from quaternion. */
|
||||
quat_to_mat3(rot_mat, q);
|
||||
|
||||
/* Extract location and scale from matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_XYZ:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XYZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_XZY:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_XZY, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_YXZ:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_YXZ, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_YZX:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_YZX, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_ZXY:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_ZXY, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
case ROT_MODE_ZYX:
|
||||
{
|
||||
/* Extract location, rotation, and scale form matrix. */
|
||||
mat4_to_loc_rot_size(loc, rot, scale, mat);
|
||||
|
||||
/* Get euler angles from rotation matrix. */
|
||||
mat3_to_eulO(euler, ROT_MODE_ZYX, rot);
|
||||
|
||||
/* Create X, Y, Z rotation matrices from euler angles. */
|
||||
create_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, true);
|
||||
|
||||
/* Concatenate rotation matrices. */
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_x_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_z_mat);
|
||||
mul_m3_m3m3(rot_mat, rot_mat, rot_y_mat);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add rotation matrix to transformation matrix. */
|
||||
copy_m4_m3(transform_mat, rot_mat);
|
||||
|
||||
/* Add translation to transformation matrix. */
|
||||
copy_zup_yup(transform_mat[3], loc);
|
||||
|
||||
/* Create scale matrix. */
|
||||
scale_mat[0][0] = scale[0];
|
||||
scale_mat[1][1] = scale[2];
|
||||
scale_mat[2][2] = scale[1];
|
||||
|
||||
/* Add scale to transformation matrix. */
|
||||
mul_m4_m4m4(transform_mat, transform_mat, scale_mat);
|
||||
}
|
||||
|
||||
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name)
|
||||
{
|
||||
if (!prop.valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return prop.getPropertyHeader(name) != NULL;
|
||||
}
|
125
source/blender/alembic/intern/abc_util.h
Normal file
125
source/blender/alembic/intern/abc_util.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Contributor(s): Esteban Tovagliari, Cedric Paille, Kevin Dietrich
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __ABC_UTIL_H__
|
||||
#define __ABC_UTIL_H__
|
||||
|
||||
#include <Alembic/Abc/All.h>
|
||||
#include <Alembic/AbcGeom/All.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define ABC_INLINE static __forceinline
|
||||
#else
|
||||
# define ABC_INLINE static inline
|
||||
#endif
|
||||
|
||||
using Alembic::Abc::chrono_t;
|
||||
|
||||
class ImportSettings;
|
||||
|
||||
struct ID;
|
||||
struct Object;
|
||||
|
||||
std::string get_id_name(ID *id);
|
||||
std::string get_id_name(Object *ob);
|
||||
std::string get_object_dag_path_name(Object *ob, Object *dupli_parent);
|
||||
|
||||
bool object_selected(Object *ob);
|
||||
bool parent_selected(Object *ob);
|
||||
|
||||
Imath::M44d convert_matrix(float mat[4][4]);
|
||||
void create_transform_matrix(float r_mat[4][4]);
|
||||
void create_transform_matrix(Object *obj, float transform_mat[4][4]);
|
||||
|
||||
void split(const std::string &s, const char delim, std::vector<std::string> &tokens);
|
||||
|
||||
template<class TContainer>
|
||||
bool begins_with(const TContainer &input, const TContainer &match)
|
||||
{
|
||||
return input.size() >= match.size()
|
||||
&& std::equal(match.begin(), match.end(), input.begin());
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent = false);
|
||||
|
||||
template <typename Schema>
|
||||
void get_min_max_time(const Schema &schema, chrono_t &min, chrono_t &max)
|
||||
{
|
||||
const Alembic::Abc::TimeSamplingPtr &time_samp = schema.getTimeSampling();
|
||||
|
||||
if (!schema.isConstant()) {
|
||||
const size_t num_samps = schema.getNumSamples();
|
||||
|
||||
if (num_samps > 0) {
|
||||
const chrono_t min_time = time_samp->getSampleTime(0);
|
||||
min = std::min(min, min_time);
|
||||
|
||||
const chrono_t max_time = time_samp->getSampleTime(num_samps - 1);
|
||||
max = std::max(max, max_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
|
||||
|
||||
/* ************************** */
|
||||
|
||||
/* TODO(kevin): for now keeping these transformations hardcoded to make sure
|
||||
* everything works properly, and also because Alembic is almost exclusively
|
||||
* used in Y-up software, but eventually they'll be set by the user in the UI
|
||||
* like other importers/exporters do, to support other axis. */
|
||||
|
||||
/* Copy from Y-up to Z-up. */
|
||||
|
||||
ABC_INLINE void copy_yup_zup(float zup[3], const float yup[3])
|
||||
{
|
||||
zup[0] = yup[0];
|
||||
zup[1] = -yup[2];
|
||||
zup[2] = yup[1];
|
||||
}
|
||||
|
||||
ABC_INLINE void copy_yup_zup(short zup[3], const short yup[3])
|
||||
{
|
||||
zup[0] = yup[0];
|
||||
zup[1] = -yup[2];
|
||||
zup[2] = yup[1];
|
||||
}
|
||||
|
||||
/* Copy from Z-up to Y-up. */
|
||||
|
||||
ABC_INLINE void copy_zup_yup(float yup[3], const float zup[3])
|
||||
{
|
||||
yup[0] = zup[0];
|
||||
yup[1] = zup[2];
|
||||
yup[2] = -zup[1];
|
||||
}
|
||||
|
||||
ABC_INLINE void copy_zup_yup(short yup[3], const short zup[3])
|
||||
{
|
||||
yup[0] = zup[0];
|
||||
yup[1] = zup[2];
|
||||
yup[2] = -zup[1];
|
||||
}
|
||||
|
||||
#endif /* __ABC_UTIL_H__ */
|
1136
source/blender/alembic/intern/alembic_capi.cc
Normal file
1136
source/blender/alembic/intern/alembic_capi.cc
Normal file
File diff suppressed because it is too large
Load Diff
67
source/blender/blenkernel/BKE_cachefile.h
Normal file
67
source/blender/blenkernel/BKE_cachefile.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Kevin Dietrich.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __BKE_CACHEFILE_H__
|
||||
#define __BKE_CACHEFILE_H__
|
||||
|
||||
/** \file BKE_cachefile.h
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct CacheFile;
|
||||
struct Main;
|
||||
struct Scene;
|
||||
|
||||
void *BKE_cachefile_add(struct Main *bmain, const char *name);
|
||||
|
||||
void BKE_cachefile_init(struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_free(struct CacheFile *cache_file);
|
||||
|
||||
struct CacheFile *BKE_cachefile_copy(struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_make_local(struct Main *bmain, struct CacheFile *cache_file, const bool lib_local);
|
||||
|
||||
void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, float ctime, const float fps);
|
||||
|
||||
bool BKE_cachefile_filepath_get(
|
||||
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
|
||||
char r_filename[1024]);
|
||||
|
||||
float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BKE_CACHEFILE_H__ */
|
@@ -39,6 +39,7 @@ extern "C" {
|
||||
|
||||
struct ARegion;
|
||||
struct bScreen;
|
||||
struct CacheFile;
|
||||
struct ListBase;
|
||||
struct Main;
|
||||
struct Object;
|
||||
@@ -271,6 +272,8 @@ struct Text *CTX_data_edit_text(const bContext *C);
|
||||
struct MovieClip *CTX_data_edit_movieclip(const bContext *C);
|
||||
struct Mask *CTX_data_edit_mask(const bContext *C);
|
||||
|
||||
struct CacheFile *CTX_data_edit_cachefile(const bContext *C);
|
||||
|
||||
int CTX_data_selected_nodes(const bContext *C, ListBase *list);
|
||||
|
||||
struct EditBone *CTX_data_active_bone(const bContext *C);
|
||||
|
@@ -43,36 +43,36 @@ struct Main;
|
||||
|
||||
/* ------------ Grease-Pencil API ------------------ */
|
||||
|
||||
void free_gpencil_stroke(struct bGPDstroke *gps);
|
||||
bool free_gpencil_strokes(struct bGPDframe *gpf);
|
||||
void free_gpencil_frames(struct bGPDlayer *gpl);
|
||||
void free_gpencil_layers(struct ListBase *list);
|
||||
void free_gpencil_brushes(struct ListBase *list);
|
||||
void free_gpencil_palettes(struct ListBase *list);
|
||||
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
|
||||
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
|
||||
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
|
||||
void BKE_gpencil_free_layers(struct ListBase *list);
|
||||
void BKE_gpencil_free_brushes(struct ListBase *list);
|
||||
void BKE_gpencil_free_palettes(struct ListBase *list);
|
||||
void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
|
||||
|
||||
void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
|
||||
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
|
||||
|
||||
struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDframe *gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
|
||||
struct bGPdata *gpencil_data_addnew(const char name[]);
|
||||
struct bGPDframe *BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDframe *BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDlayer *BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive);
|
||||
struct bGPdata *BKE_gpencil_data_addnew(const char name[]);
|
||||
|
||||
struct bGPDframe *gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
|
||||
struct bGPDlayer *gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
|
||||
struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
|
||||
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
|
||||
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
|
||||
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy);
|
||||
|
||||
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
|
||||
|
||||
void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
|
||||
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
|
||||
|
||||
struct bGPDpalette *gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
|
||||
struct bGPDpalette *gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
|
||||
struct bGPDpalettecolor *gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
|
||||
struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
|
||||
struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
|
||||
struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
|
||||
|
||||
struct bGPDbrush *gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
|
||||
struct bGPDbrush *gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
|
||||
void gpencil_brush_init_presets(struct ToolSettings *ts);
|
||||
struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
|
||||
struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
|
||||
void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
|
||||
|
||||
|
||||
/* Stroke and Fill - Alpha Visibility Threshold */
|
||||
@@ -94,28 +94,28 @@ typedef enum eGP_GetFrame_Mode {
|
||||
GP_GETFRAME_ADD_COPY = 2
|
||||
} eGP_GetFrame_Mode;
|
||||
|
||||
struct bGPDframe *gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
|
||||
struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew);
|
||||
struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe);
|
||||
bool gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
|
||||
bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf);
|
||||
|
||||
struct bGPDlayer *gpencil_layer_getactive(struct bGPdata *gpd);
|
||||
void gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
|
||||
void gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
|
||||
struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
|
||||
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
|
||||
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
|
||||
|
||||
struct bGPDbrush *gpencil_brush_getactive(struct ToolSettings *ts);
|
||||
void gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
|
||||
void gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
|
||||
struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
|
||||
void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
|
||||
void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette);
|
||||
|
||||
struct bGPDpalette *gpencil_palette_getactive(struct bGPdata *gpd);
|
||||
void gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
|
||||
void gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
|
||||
void gpencil_palette_change_strokes(struct bGPdata *gpd);
|
||||
struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
|
||||
void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
|
||||
void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
|
||||
void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
|
||||
|
||||
struct bGPDpalettecolor *gpencil_palettecolor_getactive(struct bGPDpalette *palette);
|
||||
void gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
|
||||
void gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
|
||||
struct bGPDpalettecolor *gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
|
||||
void gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
|
||||
void gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
|
||||
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
|
||||
void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
|
||||
void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
|
||||
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
|
||||
void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
|
||||
void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
|
||||
|
||||
#endif /* __BKE_GPENCIL_H__ */
|
||||
|
@@ -94,7 +94,7 @@ void id_clear_lib_data_ex(struct Main *bmain, struct ID *id, const bool id_in_ma
|
||||
|
||||
struct ListBase *which_libbase(struct Main *mainlib, short type);
|
||||
|
||||
#define MAX_LIBARRAY 34
|
||||
#define MAX_LIBARRAY 35
|
||||
int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
|
||||
|
||||
/* Main API */
|
||||
|
@@ -102,6 +102,7 @@ typedef struct Main {
|
||||
ListBase movieclip;
|
||||
ListBase mask;
|
||||
ListBase linestyle;
|
||||
ListBase cachefiles;
|
||||
|
||||
char id_tag_update[256];
|
||||
|
||||
|
@@ -63,6 +63,8 @@ struct BVHTreeRay;
|
||||
struct BVHTreeRayHit;
|
||||
struct EdgeHash;
|
||||
|
||||
#define PARTICLE_COLLISION_MAX_COLLISIONS 10
|
||||
|
||||
#define PARTICLE_P ParticleData * pa; int p
|
||||
#define LOOP_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++)
|
||||
#define LOOP_EXISTING_PARTICLES for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) if (!(pa->flag & PARS_UNEXIST))
|
||||
@@ -205,8 +207,7 @@ typedef struct ParticleCollisionElement {
|
||||
typedef struct ParticleCollision {
|
||||
struct Object *current;
|
||||
struct Object *hit;
|
||||
struct Object *prev;
|
||||
struct Object *skip;
|
||||
struct Object *skip[PARTICLE_COLLISION_MAX_COLLISIONS+1];
|
||||
struct Object *emitter;
|
||||
|
||||
struct CollisionModifierData *md; // collision modifier for current object;
|
||||
@@ -218,7 +219,7 @@ typedef struct ParticleCollision {
|
||||
|
||||
float original_ray_length; //original length of co2-co1, needed for collision time evaluation
|
||||
|
||||
int prev_index;
|
||||
int skip_count;
|
||||
|
||||
ParticleCollisionElement pce;
|
||||
|
||||
|
@@ -81,6 +81,7 @@ set(SRC
|
||||
intern/brush.c
|
||||
intern/bullet.c
|
||||
intern/bvhutils.c
|
||||
intern/cachefile.c
|
||||
intern/camera.c
|
||||
intern/cdderivedmesh.c
|
||||
intern/cloth.c
|
||||
@@ -207,6 +208,7 @@ set(SRC
|
||||
BKE_brush.h
|
||||
BKE_bullet.h
|
||||
BKE_bvhutils.h
|
||||
BKE_cachefile.h
|
||||
BKE_camera.h
|
||||
BKE_ccg.h
|
||||
BKE_cdderivedmesh.h
|
||||
@@ -500,6 +502,13 @@ if(WITH_FREESTYLE)
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
list(APPEND INC
|
||||
../alembic
|
||||
)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENSUBDIV)
|
||||
add_definitions(-DWITH_OPENSUBDIV)
|
||||
list(APPEND INC_SYS
|
||||
|
@@ -97,6 +97,7 @@ bool id_type_can_have_animdata(const short id_type)
|
||||
case ID_MC:
|
||||
case ID_MSK:
|
||||
case ID_GD:
|
||||
case ID_CF:
|
||||
return true;
|
||||
|
||||
/* no AnimData */
|
||||
@@ -1160,6 +1161,9 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
|
||||
|
||||
/* grease pencil */
|
||||
ANIMDATA_IDS_CB(mainptr->gpencil.first);
|
||||
|
||||
/* cache files */
|
||||
ANIMDATA_IDS_CB(mainptr->cachefiles.first);
|
||||
}
|
||||
|
||||
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
|
||||
@@ -1250,6 +1254,9 @@ void BKE_animdata_fix_paths_rename_all(ID *ref_id, const char *prefix, const cha
|
||||
|
||||
/* grease pencil */
|
||||
RENAMEFIX_ANIM_IDS(mainptr->gpencil.first);
|
||||
|
||||
/* cache files */
|
||||
RENAMEFIX_ANIM_IDS(mainptr->cachefiles.first);
|
||||
|
||||
/* scenes */
|
||||
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
|
||||
@@ -2873,6 +2880,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
|
||||
|
||||
/* grease pencil */
|
||||
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
|
||||
|
||||
/* cache files */
|
||||
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);
|
||||
|
||||
/* objects */
|
||||
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
|
||||
|
@@ -48,6 +48,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
@@ -653,6 +654,12 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
|
||||
rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
|
||||
break;
|
||||
}
|
||||
case ID_CF:
|
||||
{
|
||||
CacheFile *cache_file = (CacheFile *)id;
|
||||
rewrite_path_fixed(cache_file->filepath, visit_cb, absbase, bpath_user_data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Nothing to do for other IDs that don't contain file paths. */
|
||||
break;
|
||||
|
173
source/blender/blenkernel/intern/cachefile.c
Normal file
173
source/blender/blenkernel/intern/cachefile.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2016 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Contributor(s): Kevin Dietrich.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/blenkernel/intern/cachefile.c
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_animsys.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "ABC_alembic.h"
|
||||
#endif
|
||||
|
||||
void *BKE_cachefile_add(Main *bmain, const char *name)
|
||||
{
|
||||
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
|
||||
|
||||
BKE_cachefile_init(cache_file);
|
||||
|
||||
return cache_file;
|
||||
}
|
||||
|
||||
void BKE_cachefile_init(CacheFile *cache_file)
|
||||
{
|
||||
cache_file->handle = NULL;
|
||||
cache_file->filepath[0] = '\0';
|
||||
cache_file->override_frame = false;
|
||||
cache_file->frame = 0.0f;
|
||||
cache_file->is_sequence = false;
|
||||
cache_file->scale = 1.0f;
|
||||
}
|
||||
|
||||
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
|
||||
void BKE_cachefile_free(CacheFile *cache_file)
|
||||
{
|
||||
BKE_animdata_free((ID *)cache_file, false);
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
#endif
|
||||
|
||||
BLI_freelistN(&cache_file->object_paths);
|
||||
}
|
||||
|
||||
CacheFile *BKE_cachefile_copy(Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
CacheFile *new_cache_file = BKE_libblock_copy(bmain, &cache_file->id);
|
||||
new_cache_file->handle = NULL;
|
||||
|
||||
BLI_listbase_clear(&cache_file->object_paths);
|
||||
|
||||
BKE_id_copy_ensure_local(bmain, &cache_file->id, &new_cache_file->id);
|
||||
|
||||
return new_cache_file;
|
||||
}
|
||||
|
||||
void BKE_cachefile_make_local(Main *bmain, CacheFile *cache_file, const bool lib_local)
|
||||
{
|
||||
BKE_id_make_local_generic(bmain, &cache_file->id, true, lib_local);
|
||||
}
|
||||
|
||||
void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
char filepath[FILE_MAX];
|
||||
|
||||
BLI_strncpy(filepath, cache_file->filepath, sizeof(filepath));
|
||||
BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
if (cache_file->handle) {
|
||||
ABC_free_handle(cache_file->handle);
|
||||
}
|
||||
|
||||
cache_file->handle = ABC_create_handle(filepath, &cache_file->object_paths);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
|
||||
{
|
||||
if (cache_file->handle == NULL) {
|
||||
BKE_cachefile_reload(bmain, cache_file);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
|
||||
{
|
||||
CacheFile *cache_file;
|
||||
char filename[FILE_MAX];
|
||||
|
||||
for (cache_file = bmain->cachefiles.first; cache_file; cache_file = cache_file->id.next) {
|
||||
/* Execute drivers only, as animation has already been done. */
|
||||
BKE_animsys_evaluate_animdata(scene, &cache_file->id, cache_file->adt, ctime, ADT_RECALC_DRIVERS);
|
||||
|
||||
if (!cache_file->is_sequence) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float time = BKE_cachefile_time_offset(cache_file, ctime, fps);
|
||||
|
||||
if (BKE_cachefile_filepath_get(bmain, cache_file, time, filename)) {
|
||||
#ifdef WITH_ALEMBIC
|
||||
ABC_free_handle(cache_file->handle);
|
||||
cache_file->handle = ABC_create_handle(filename, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_cachefile_filepath_get(
|
||||
const Main *bmain, const CacheFile *cache_file, float frame,
|
||||
char r_filepath[FILE_MAX])
|
||||
{
|
||||
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
|
||||
BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
|
||||
int fframe;
|
||||
int frame_len;
|
||||
|
||||
if (cache_file->is_sequence && BLI_path_frame_get(r_filepath, &fframe, &frame_len)) {
|
||||
char ext[32];
|
||||
BLI_path_frame_strip(r_filepath, true, ext);
|
||||
BLI_path_frame(r_filepath, frame, frame_len);
|
||||
BLI_ensure_extension(r_filepath, FILE_MAX, ext);
|
||||
|
||||
/* TODO(kevin): store sequence range? */
|
||||
return BLI_exists(r_filepath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const float fps)
|
||||
{
|
||||
const float frame = (cache_file->override_frame ? cache_file->frame : time);
|
||||
return cache_file->is_sequence ? frame : frame / fps;
|
||||
}
|
@@ -3402,7 +3402,7 @@ void CDDM_calc_edges(DerivedMesh *dm)
|
||||
BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
|
||||
j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
|
||||
|
||||
if (j == 0) {
|
||||
if (j == 0 || !eindex) {
|
||||
med->flag = ME_EDGEDRAW | ME_EDGERENDER;
|
||||
*index = ORIGINDEX_NONE;
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_constraint_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@@ -63,6 +64,7 @@
|
||||
#include "BKE_anim.h" /* for the curve calculation part */
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_cachefile.h"
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_constraint.h"
|
||||
#include "BKE_curve.h"
|
||||
@@ -86,6 +88,10 @@
|
||||
# include "BPY_extern.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ALEMBIC
|
||||
# include "ABC_alembic.h"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Useful macros for testing various common flag combinations */
|
||||
|
||||
@@ -4333,6 +4339,73 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
|
||||
objectsolver_evaluate /* evaluate */
|
||||
};
|
||||
|
||||
/* ----------- Transform Cache ------------- */
|
||||
|
||||
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
|
||||
{
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
func(con, (ID **)&data->cache_file, false, userdata);
|
||||
}
|
||||
|
||||
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
Scene *scene = cob->scene;
|
||||
|
||||
const float frame = BKE_scene_frame_get(scene);
|
||||
const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
|
||||
|
||||
CacheFile *cache_file = data->cache_file;
|
||||
|
||||
BKE_cachefile_ensure_handle(G.main, cache_file);
|
||||
|
||||
ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
|
||||
cob->matrix, time, cache_file->scale);
|
||||
#else
|
||||
UNUSED_VARS(con, cob);
|
||||
#endif
|
||||
|
||||
UNUSED_VARS(targets);
|
||||
}
|
||||
|
||||
static void transformcache_copy(bConstraint *con, bConstraint *srccon)
|
||||
{
|
||||
bTransformCacheConstraint *src = srccon->data;
|
||||
bTransformCacheConstraint *dst = con->data;
|
||||
|
||||
BLI_strncpy(dst->object_path, src->object_path, sizeof(dst->object_path));
|
||||
dst->cache_file = src->cache_file;
|
||||
|
||||
if (dst->cache_file) {
|
||||
id_us_plus(&dst->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
static void transformcache_free(bConstraint *con)
|
||||
{
|
||||
bTransformCacheConstraint *data = con->data;
|
||||
|
||||
if (data->cache_file) {
|
||||
id_us_min(&data->cache_file->id);
|
||||
}
|
||||
}
|
||||
|
||||
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
|
||||
CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
|
||||
sizeof(bTransformCacheConstraint), /* size */
|
||||
"Transform Cache", /* name */
|
||||
"bTransformCacheConstraint", /* struct name */
|
||||
transformcache_free, /* free data */
|
||||
transformcache_id_looper, /* id looper */
|
||||
transformcache_copy, /* copy data */
|
||||
NULL, /* new data */
|
||||
NULL, /* get constraint targets */
|
||||
NULL, /* flush constraint targets */
|
||||
NULL, /* get target matrix */
|
||||
transformcache_evaluate /* evaluate */
|
||||
};
|
||||
|
||||
/* ************************* Constraints Type-Info *************************** */
|
||||
/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
|
||||
* and operations that involve constraint specific code.
|
||||
@@ -4374,6 +4447,7 @@ static void constraints_init_typeinfo(void)
|
||||
constraintsTypeInfo[26] = &CTI_FOLLOWTRACK; /* Follow Track Constraint */
|
||||
constraintsTypeInfo[27] = &CTI_CAMERASOLVER; /* Camera Solver Constraint */
|
||||
constraintsTypeInfo[28] = &CTI_OBJECTSOLVER; /* Object Solver Constraint */
|
||||
constraintsTypeInfo[29] = &CTI_TRANSFORM_CACHE; /* Transform Cache Constraint */
|
||||
}
|
||||
|
||||
/* This function should be used for getting the appropriate type-info when only
|
||||
|
@@ -1067,6 +1067,11 @@ struct EditBone *CTX_data_active_bone(const bContext *C)
|
||||
return ctx_data_pointer_get(C, "active_bone");
|
||||
}
|
||||
|
||||
struct CacheFile *CTX_data_edit_cachefile(const bContext *C)
|
||||
{
|
||||
return ctx_data_pointer_get(C, "edit_cachefile");
|
||||
}
|
||||
|
||||
int CTX_data_selected_bones(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "selected_bones", list);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user