Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
371 changed files with 5016 additions and 2972 deletions
Showing only changes of commit d902497e04 - Show all commits

View File

@ -6,15 +6,24 @@
set(EMBREE_EXTRA_ARGS
-DEMBREE_ISPC_SUPPORT=OFF
-DEMBREE_TUTORIALS=OFF
-DEMBREE_STATIC_LIB=ON
-DEMBREE_STATIC_LIB=OFF
-DEMBREE_RAY_MASK=ON
-DEMBREE_FILTER_FUNCTION=ON
-DEMBREE_BACKFACE_CULLING=OFF
-DEMBREE_BACKFACE_CULLING_CURVES=ON
-DEMBREE_BACKFACE_CULLING_SPHERES=ON
-DEMBREE_TASKING_SYSTEM=TBB
-DEMBREE_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
)
if(WIN32)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
-DCMAKE_DEBUG_POSTFIX=_d
)
endif()
if(NOT BLENDER_PLATFORM_ARM)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
@ -45,25 +54,19 @@ add_dependencies(
)
if(WIN32)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree ${HARVEST_TARGET}/embree
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/include ${HARVEST_TARGET}/embree/include
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/lib ${HARVEST_TARGET}/embree/lib
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/embree/share ${HARVEST_TARGET}/embree/share
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4.dll ${HARVEST_TARGET}/embree/bin/embree4.dll
DEPENDEES install
)
else()
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree3.lib ${HARVEST_TARGET}/embree/lib/embree3_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_avx.lib ${HARVEST_TARGET}/embree/lib/embree_avx_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_avx2.lib ${HARVEST_TARGET}/embree/lib/embree_avx2_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree_sse42.lib ${HARVEST_TARGET}/embree/lib/embree_sse42_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/lexers.lib ${HARVEST_TARGET}/embree/lib/lexers_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/math.lib ${HARVEST_TARGET}/embree/lib/math_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/simd.lib ${HARVEST_TARGET}/embree/lib/simd_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/sys.lib ${HARVEST_TARGET}/embree/lib/sys_d.lib
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/tasking.lib ${HARVEST_TARGET}/embree/lib/tasking_d.lib
DEPENDEES install
)
endif()
ExternalProject_Add_Step(external_embree after_install
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/bin/embree4_d.dll ${HARVEST_TARGET}/embree/bin/embree4_d.dll
COMMAND ${CMAKE_COMMAND} -E copy ${LIBDIR}/embree/lib/embree4_d.lib ${HARVEST_TARGET}/embree/lib/embree4_d.lib
DEPENDEES install
)
endif()
endif()

View File

@ -218,6 +218,7 @@ else()
harvest(openimagedenoise/lib openimagedenoise/lib "*.a")
harvest(embree/include embree/include "*.h")
harvest(embree/lib embree/lib "*.a")
harvest(embree/lib embree/lib "*${SHAREDLIBEXT}*")
harvest(openpgl/include openpgl/include "*.h")
harvest(openpgl/lib openpgl/lib "*.a")
harvest(openpgl/lib/cmake/openpgl-${OPENPGL_SHORT_VERSION} openpgl/lib/cmake/openpgl "*.cmake")

View File

@ -478,9 +478,9 @@ set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-autoconf-${SQLLITE_LONG_VERSION}.tar.gz)
set(SQLITE_CPE "cpe:2.3:a:sqlite:sqlite:${SQLITE_VERSION}:*:*:*:*:*:*:*")
set(EMBREE_VERSION 3.13.4)
set(EMBREE_VERSION 4.0.1)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
set(EMBREE_HASH 52d0be294d6c88ba7a6c9e046796e7be)
set(EMBREE_HASH dd26617719a587e126b341d1b32f7fd0)
set(EMBREE_HASH_TYPE MD5)
set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)
@ -534,10 +534,10 @@ set(WL_PROTOCOLS_URI https://gitlab.freedesktop.org/wayland/wayland-protocols/-/
set(WL_PROTOCOLS_HASH a28ff59a56e2ebb746048b6ef8d931d6)
set(WL_PROTOCOLS_HASH_TYPE MD5)
set(WAYLAND_VERSION 1.21.0)
set(WAYLAND_VERSION 1.22.0)
set(WAYLAND_FILE wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.21.0/downloads/wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_HASH f2653a2293bcd882d756c6a83d278903)
set(WAYLAND_URI https://gitlab.freedesktop.org/wayland/wayland/-/releases/${WAYLAND_VERSION}/downloads/wayland-${WAYLAND_VERSION}.tar.xz)
set(WAYLAND_HASH 7410ab549e3928fce9381455b17b0803)
set(WAYLAND_HASH_TYPE MD5)
set(WAYLAND_LIBDECOR_VERSION 0.1.0)

View File

@ -1,19 +1,8 @@
diff -Naur org/kernels/rtcore_config.h.in embree-3.13.4/kernels/rtcore_config.h.in
--- org/kernels/rtcore_config.h.in 2022-06-14 22:13:52 -0600
+++ embree-3.13.4/kernels/rtcore_config.h.in 2022-06-24 15:20:12 -0600
@@ -14,6 +14,7 @@
#cmakedefine01 EMBREE_MIN_WIDTH
#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+#cmakedefine EMBREE_STATIC_LIB
#cmakedefine EMBREE_API_NAMESPACE
#if defined(EMBREE_API_NAMESPACE)
diff --git a/kernels/CMakeLists.txt b/kernels/CMakeLists.txt
index 7c2f43d..106b1d5 100644
--- a/kernels/CMakeLists.txt
+++ b/kernels/CMakeLists.txt
@@ -201,6 +201,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512})
@@ -208,6 +208,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512})
#message("AVX2: ${EMBREE_LIBRARY_FILES_AVX2}")
#message("AVX512: ${EMBREE_LIBRARY_FILES_AVX512}")
@ -26,7 +15,7 @@ index 7c2f43d..106b1d5 100644
# replaces all .cpp files with a dummy file that includes that .cpp file
# this is to work around an ICC name mangling issue related to lambda functions under windows
MACRO (CreateISADummyFiles list isa)
@@ -277,7 +283,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX)
@@ -311,7 +317,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX)
ENDIF()
ENDIF()
@ -35,3 +24,128 @@ index 7c2f43d..106b1d5 100644
DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2})
ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2})
TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking)
diff --git a/include/embree4/rtcore_device.h b/include/embree4/rtcore_device.h
index 45bf95583..62ee7787d 100644
--- a/include/embree4/rtcore_device.h
+++ b/include/embree4/rtcore_device.h
@@ -55,6 +55,7 @@ enum RTCDeviceProperty
RTC_DEVICE_PROPERTY_FILTER_FUNCTION_SUPPORTED = 66,
RTC_DEVICE_PROPERTY_IGNORE_INVALID_RAYS_ENABLED = 67,
RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED = 68,
+ RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED = 69,
RTC_DEVICE_PROPERTY_TRIANGLE_GEOMETRY_SUPPORTED = 96,
RTC_DEVICE_PROPERTY_QUAD_GEOMETRY_SUPPORTED = 97,
diff --git a/kernels/common/device.cpp b/kernels/common/device.cpp
index 3ffac7e37..215ccc961 100644
--- a/kernels/common/device.cpp
+++ b/kernels/common/device.cpp
@@ -170,6 +170,9 @@ namespace embree
#if defined (EMBREE_BACKFACE_CULLING_CURVES)
v += "backfacecullingcurves ";
#endif
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ v += "backfacecullingspheres ";
+#endif
#if defined(EMBREE_FILTER_FUNCTION)
v += "intersection_filter ";
#endif
@@ -477,6 +480,12 @@ namespace embree
case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0;
#endif
+#if defined(EMBREE_BACKFACE_CULLING_SPHERES)
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 1;
+#else
+ case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 0;
+#endif
+
#if defined(EMBREE_COMPACT_POLYS)
case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1;
#else
diff --git a/kernels/config.h.in b/kernels/config.h.in
index f02c90360..ba9acde56 100644
--- a/kernels/config.h.in
+++ b/kernels/config.h.in
@@ -5,6 +5,7 @@
#cmakedefine EMBREE_STAT_COUNTERS
#cmakedefine EMBREE_BACKFACE_CULLING
#cmakedefine EMBREE_BACKFACE_CULLING_CURVES
+#cmakedefine EMBREE_BACKFACE_CULLING_SPHERES
#cmakedefine EMBREE_FILTER_FUNCTION
#cmakedefine EMBREE_IGNORE_INVALID_RAYS
#cmakedefine EMBREE_GEOMETRY_TRIANGLE
diff --git a/kernels/geometry/sphere_intersector.h b/kernels/geometry/sphere_intersector.h
index 074f910a2..30f490818 100644
--- a/kernels/geometry/sphere_intersector.h
+++ b/kernels/geometry/sphere_intersector.h
@@ -106,8 +106,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar);
const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -120,7 +125,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar);
@@ -131,7 +137,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
@@ -186,8 +194,13 @@ namespace embree
const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]);
const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]);
+#if defined (EMBREE_BACKFACE_CULLING_SPHERES)
+ /* check if there is a first hit */
+ const vbool<M> valid_first = valid_front;
+#else
/* check if there is a first hit */
const vbool<M> valid_first = valid_front | valid_back;
+#endif
if (unlikely(none(valid_first)))
return false;
@@ -200,7 +213,8 @@ namespace embree
/* invoke intersection filter for first hit */
const bool is_hit_first = epilog(valid_first, hit);
-
+
+#if !defined (EMBREE_BACKFACE_CULLING_SPHERES)
/* check for possible second hits before potentially accepted hit */
const vfloat<M> t_second = t_back;
const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]);
@@ -211,7 +225,9 @@ namespace embree
const Vec3vf<M> Ng_second = td_back * ray_dir - perp;
hit = SphereIntersectorHitM<M> (t_second, Ng_second);
const bool is_hit_second = epilog(valid_second, hit);
-
+#else
+ constexpr bool is_hit_second = false;
+#endif
return is_hit_first | is_hit_second;
}
};

View File

@ -23,6 +23,7 @@ SET(_embree_SEARCH_DIRS
FIND_PATH(EMBREE_INCLUDE_DIR
NAMES
embree4/rtcore.h
embree3/rtcore.h
HINTS
${_embree_SEARCH_DIRS}
@ -30,28 +31,67 @@ FIND_PATH(EMBREE_INCLUDE_DIR
include
)
IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
SET(_embree_SIMD_COMPONENTS
embree_sse42
embree_avx
embree_avx2
)
IF(EXISTS ${EMBREE_INCLUDE_DIR}/embree4/rtcore_config.h)
SET(EMBREE_MAJOR_VERSION 4)
ELSE()
SET(EMBREE_MAJOR_VERSION 3)
ENDIF()
SET(_embree_FIND_COMPONENTS
embree3
${_embree_SIMD_COMPONENTS}
lexers
math
simd
sys
tasking
)
IF(EMBREE_INCLUDE_DIR)
FILE(READ ${EMBREE_INCLUDE_DIR}/embree${EMBREE_MAJOR_VERSION}/rtcore_config.h _embree_config_header)
IF(_embree_config_header MATCHES "#define EMBREE_STATIC_LIB")
SET(EMBREE_STATIC_LIB TRUE)
ELSE()
SET(EMBREE_STATIC_LIB FALSE)
ENDIF()
IF(_embree_config_header MATCHES "#define EMBREE_SYCL_SUPPORT")
SET(EMBREE_SYCL_SUPPORT TRUE)
ELSE()
SET(EMBREE_SYCL_SUPPORT FALSE)
ENDIF()
UNSET(_embree_config_header)
ENDIF()
IF(EMBREE_STATIC_LIB)
IF(NOT (("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "aarch64") OR (APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64"))))
SET(_embree_SIMD_COMPONENTS
embree_sse42
embree_avx
embree_avx2
)
ENDIF()
IF(EMBREE_SYCL_SUPPORT)
SET(_embree_GPU_COMPONENTS
embree4_sycl
embree_rthwif
)
ENDIF()
SET(_embree_FIND_COMPONENTS
embree${EMBREE_MAJOR_VERSION}
${_embree_SIMD_COMPONENTS}
${_embree_GPU_COMPONENTS}
lexers
math
simd
sys
tasking
)
ELSE()
SET(_embree_FIND_COMPONENTS
embree${EMBREE_MAJOR_VERSION}
)
IF(EMBREE_SYCL_SUPPORT)
LIST(APPEND _embree_FIND_COMPONENTS
embree4_sycl
)
ENDIF()
ENDIF()
SET(_embree_LIBRARIES)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
FIND_LIBRARY(EMBREE_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
@ -60,18 +100,9 @@ FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})
PATH_SUFFIXES
lib64 lib
)
IF(NOT EMBREE_${UPPERCOMPONENT}_LIBRARY)
IF(EMBREE_EMBREE3_LIBRARY)
# If we can't find all the static libraries, try to fall back to the shared library if found.
# This allows building with a shared embree library
SET(_embree_LIBRARIES ${EMBREE_EMBREE3_LIBRARY})
BREAK()
ENDIF()
ENDIF()
LIST(APPEND _embree_LIBRARIES "${EMBREE_${UPPERCOMPONENT}_LIBRARY}")
ENDFOREACH()
# handle the QUIETLY and REQUIRED arguments and set EMBREE_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
@ -85,6 +116,9 @@ ENDIF()
MARK_AS_ADVANCED(
EMBREE_INCLUDE_DIR
EMBREE_MAJOR_VERSION
EMBREE_SYCL_SUPPORT
EMBREE_STATIC_LIB
)
FOREACH(COMPONENT ${_embree_FIND_COMPONENTS})

View File

@ -108,6 +108,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL
IF(SYCL_FOUND)
SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${SYCL_INCLUDE_DIR}/sycl)
SET(SYCL_LIBRARIES ${SYCL_LIBRARY})
ELSE()
SET(SYCL_SYCL_FOUND FALSE)
ENDIF()

View File

@ -330,6 +330,7 @@ if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
endforeach()
set(EMBREE_LIBRARIES ${_embree_libraries_force_load})
endif()
add_bundled_libraries(embree/lib)
if(WITH_OPENIMAGEDENOISE)
find_package(OpenImageDenoise REQUIRED)

View File

@ -317,7 +317,7 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
endif()
endif()
if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
if(WITH_CYCLES AND (WITH_CYCLES_DEVICE_ONEAPI OR (WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)))
set(CYCLES_LEVEL_ZERO ${LIBDIR}/level-zero CACHE PATH "Path to Level Zero installation")
if(EXISTS ${CYCLES_LEVEL_ZERO} AND NOT LEVEL_ZERO_ROOT_DIR)
set(LEVEL_ZERO_ROOT_DIR ${CYCLES_LEVEL_ZERO})
@ -453,6 +453,7 @@ add_bundled_libraries(opencolorio/lib)
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
find_package(Embree 3.8.0 REQUIRED)
endif()
add_bundled_libraries(embree/lib)
if(WITH_OPENIMAGEDENOISE)
find_package_wrapper(OpenImageDenoise)

View File

@ -850,27 +850,75 @@ endif()
if(WITH_CYCLES AND WITH_CYCLES_EMBREE)
windows_find_package(Embree)
if(NOT Embree_FOUND)
set(EMBREE_ROOT_DIR ${LIBDIR}/embree)
set(EMBREE_INCLUDE_DIRS ${LIBDIR}/embree/include)
set(EMBREE_LIBRARIES
optimized ${LIBDIR}/embree/lib/embree3.lib
optimized ${LIBDIR}/embree/lib/embree_avx2.lib
optimized ${LIBDIR}/embree/lib/embree_avx.lib
optimized ${LIBDIR}/embree/lib/embree_sse42.lib
optimized ${LIBDIR}/embree/lib/lexers.lib
optimized ${LIBDIR}/embree/lib/math.lib
optimized ${LIBDIR}/embree/lib/simd.lib
optimized ${LIBDIR}/embree/lib/sys.lib
optimized ${LIBDIR}/embree/lib/tasking.lib
debug ${LIBDIR}/embree/lib/embree3_d.lib
debug ${LIBDIR}/embree/lib/embree_avx2_d.lib
debug ${LIBDIR}/embree/lib/embree_avx_d.lib
debug ${LIBDIR}/embree/lib/embree_sse42_d.lib
debug ${LIBDIR}/embree/lib/lexers_d.lib
debug ${LIBDIR}/embree/lib/math_d.lib
debug ${LIBDIR}/embree/lib/simd_d.lib
debug ${LIBDIR}/embree/lib/sys_d.lib
debug ${LIBDIR}/embree/lib/tasking_d.lib
if(EXISTS ${LIBDIR}/embree/include/embree4/rtcore_config.h)
set(EMBREE_MAJOR_VERSION 4)
else()
set(EMBREE_MAJOR_VERSION 3)
endif()
file(READ ${LIBDIR}/embree/include/embree${EMBREE_MAJOR_VERSION}/rtcore_config.h _embree_config_header)
if(_embree_config_header MATCHES "#define EMBREE_STATIC_LIB")
set(EMBREE_STATIC_LIB TRUE)
else()
set(EMBREE_STATIC_LIB FALSE)
endif()
if(_embree_config_header MATCHES "#define EMBREE_SYCL_SUPPORT")
set(EMBREE_SYCL_SUPPORT TRUE)
else()
set(EMBREE_SYCL_SUPPORT FALSE)
endif()
set(EMBREE_LIBRARIES
optimized ${LIBDIR}/embree/lib/embree${EMBREE_MAJOR_VERSION}.lib
debug ${LIBDIR}/embree/lib/embree${EMBREE_MAJOR_VERSION}_d.lib
)
if(EMBREE_SYCL_SUPPORT)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree4_sycl.lib
debug ${LIBDIR}/embree/lib/embree4_sycl_d.lib
)
endif()
if(EMBREE_STATIC_LIB)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree_avx2.lib
optimized ${LIBDIR}/embree/lib/embree_avx.lib
optimized ${LIBDIR}/embree/lib/embree_sse42.lib
optimized ${LIBDIR}/embree/lib/lexers.lib
optimized ${LIBDIR}/embree/lib/math.lib
optimized ${LIBDIR}/embree/lib/simd.lib
optimized ${LIBDIR}/embree/lib/sys.lib
optimized ${LIBDIR}/embree/lib/tasking.lib
debug ${LIBDIR}/embree/lib/embree_avx2_d.lib
debug ${LIBDIR}/embree/lib/embree_avx_d.lib
debug ${LIBDIR}/embree/lib/embree_sse42_d.lib
debug ${LIBDIR}/embree/lib/lexers_d.lib
debug ${LIBDIR}/embree/lib/math_d.lib
debug ${LIBDIR}/embree/lib/simd_d.lib
debug ${LIBDIR}/embree/lib/sys_d.lib
debug ${LIBDIR}/embree/lib/tasking_d.lib
)
if(EMBREE_SYCL_SUPPORT)
set(EMBREE_LIBRARIES
${EMBREE_LIBRARIES}
optimized ${LIBDIR}/embree/lib/embree_rthwif.lib
debug ${LIBDIR}/embree/lib/embree_rthwif_d.lib
)
endif()
endif()
endif()
if(NOT EMBREE_STATIC_LIB)
list(APPEND PLATFORM_BUNDLED_LIBRARIES
RELEASE ${EMBREE_ROOT_DIR}/bin/embree${EMBREE_MAJOR_VERSION}.dll
DEBUG ${EMBREE_ROOT_DIR}/bin/embree${EMBREE_MAJOR_VERSION}_d.dll
)
endif()
endif()
@ -1029,7 +1077,7 @@ endif()
set(ZSTD_INCLUDE_DIRS ${LIBDIR}/zstd/include)
set(ZSTD_LIBRARIES ${LIBDIR}/zstd/lib/zstd_static.lib)
if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
if(WITH_CYCLES AND (WITH_CYCLES_DEVICE_ONEAPI OR (WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)))
set(LEVEL_ZERO_ROOT_DIR ${LIBDIR}/level_zero)
set(CYCLES_SYCL ${LIBDIR}/dpcpp CACHE PATH "Path to oneAPI DPC++ compiler")
if(EXISTS ${CYCLES_SYCL} AND NOT SYCL_ROOT_DIR)
@ -1040,7 +1088,7 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
${SYCL_ROOT_DIR}/bin/sycl[0-9].dll
)
foreach(sycl_runtime_library IN LISTS _sycl_runtime_libraries_glob)
string(REPLACE ".dll" "_d.dll" sycl_runtime_library_debug ${sycl_runtime_library})
string(REPLACE ".dll" "d.dll" sycl_runtime_library_debug ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries RELEASE ${sycl_runtime_library})
list(APPEND _sycl_runtime_libraries DEBUG ${sycl_runtime_library_debug})
endforeach()
@ -1055,6 +1103,8 @@ if(WITH_CYCLES AND WITH_CYCLES_DEVICE_ONEAPI)
list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_sycl_runtime_libraries})
unset(_sycl_runtime_libraries)
set(SYCL_LIBRARIES optimized ${SYCL_LIBRARY} debug ${SYCL_LIBRARY_DEBUG})
endif()

View File

@ -112,6 +112,7 @@ def create_manifest(
print(f'Building manifest of files: "{outpath}"...', end="", flush=True)
with outpath.open("w", encoding="utf-8") as outfile:
main_files_to_manifest(blender_srcdir, outfile)
assets_to_manifest(blender_srcdir, outfile)
submodules_to_manifest(blender_srcdir, version, outfile)
if packages_dir:
@ -140,6 +141,18 @@ def submodules_to_manifest(
print(path, file=outfile)
def assets_to_manifest(blender_srcdir: Path, outfile: TextIO) -> None:
assert not blender_srcdir.is_absolute()
assets_dir = blender_srcdir.parent / "lib" / "assets"
for path in assets_dir.glob("*"):
if path.name == "working":
continue
if path.name in SKIP_NAMES:
continue
print(path, file=outfile)
def packages_to_manifest(outfile: TextIO, packages_dir: Path) -> None:
for path in packages_dir.glob("*"):
if not path.is_file():
@ -170,7 +183,9 @@ def create_tarball(
command += [
"--transform",
f"s,^{blender_srcdir.name}/,blender-{version}/,g",
"--use-compress-program=xz -9",
"--transform",
f"s,^lib/assets/,blender-{version}/release/datafiles/assets/,g",
"--use-compress-program=xz -1",
"--create",
f"--file={tarball}",
f"--files-from={manifest}",

View File

@ -1853,8 +1853,6 @@ def pyrna2sphinx(basepath):
fw(" %s\n\n" % operator_description)
for prop in op.args:
write_param(" ", fw, prop)
if op.args:
fw("\n")
location = op.get_location()
if location != (None, None):
@ -1865,9 +1863,12 @@ def pyrna2sphinx(basepath):
else:
url_base = API_BASEURL
fw(" :file:`%s\\:%d <%s/%s#L%d>`_\n\n" %
fw(" :File: `%s\\:%d <%s/%s#L%d>`__\n\n" %
(location[0], location[1], url_base, location[0], location[1]))
if op.args:
fw("\n")
file.close()
if "bpy.ops" not in EXCLUDE_MODULES:

View File

@ -14,3 +14,13 @@ The first three of them were employed by the Blender Foundation during that time
Some features (random sounds, dynamic music, playback manager, convolution and HRTFs support) were added as part of the VALS (Virtual Alliances for Learning Society) project by
- Juan Francisco Crespo Galán <dethon_5@outlook.com>
The Equalizer sound effect has been added by
- Marcos Perez
Several people provided fixes:
- Aaron Carlisle
- Sebastian Parborg
- Leon Zandman

View File

@ -1,3 +1,104 @@
Audaspace 1.4
- Support for OS specific/native audio devices/backends has been added, that is PulseAudio (Linux), WASAPI (Windows) and CoreAudio (MacOS).
- New sound effects have been added, namely Modulator and Equalizer. Thanks to Marcos Perez for contributing the Equalizer.
- File stream info: if an audio file contains multiple streams you can choose which one to process instead of taking the first one (this feature is only supported by ffmpeg, not libsndfile).
- API Change: double instead of float for time values for more precise timing control.
- There have been lots of bugfixes, which are basically the majority of all changes.
- And some other minor improvements were implemented as well.
Detailed list of changes:
d4042d9 Port changes in Blender to upstream.
b60fb45 Equalizer
ab04e84 Fixes
8f0c305 Fix build error with MSVC 17.4+ ported from Blender.
ce44342 Minor documentation update.
cdcb3f4 Migrate from distuils to setuptools for python module.
21eccef Fix FindFFTW to find the float version fftw3f.
ab15e2f Bugfix: API change in new ffmpeg version.
a097be8 Clang format file added, valid from now on.
2fc9fb7 Porting bugfix from Blender upstream.
bb655b7 Bugfix: wrong sample size computation for PulseAudio.
a150495 Bugfix: Buffer did not support buffers > 2 GB.
034645c Update for ffmpeg 5.
932739c Bugfix: WASAPI hangs.
4fcd47c WASAPI: fix bug when switching the default device while there is no playback.
a16fbd2 Python API: fix to get convolution in the python API.
27ac5c1 WASAPI: always switch to default audio device.
1b03e6c Bugfix: catch exception if file cannot be read.
369ff6e PulseAudio: remove unused underflow callback.
2d8bf3a PulseAudio: improve synchronization accuracy.
4868e14 Revert PulseAudioDevice back from ThreadedDevice to threaded mainloop.
6a04446 Adding a jack style mixing thread with a ring buffer for pulseaudio.
5d4b57b Implement RingBuffer class.
e02d3aa FFMPEG: fix seeking and duration calculation.
07b9fa0 Adding file stream functionality.
5a8ad27 Porting changes from Blender.
fa47258 Bugfix: PulseAudio writing to little data on request.
ca3edb5 PulseAudio: increase buffersize.
6d36f3e Pulseaudio: may fix crackling playback start bug.
dbeac4b WASAPI: reinitialize device when lost.
0cba4d3 Bugfix Pulseaudio: might hang.
b73dc6d Bugfix: ffmpeg 4.4 requires channels to be set.
f1ecbe0 Fixed typo.
09e4f27 Rewrite PulseAudioDevice to use ThreadedDevice.
9516924 WASAPI: refactor to simplify and use ThreadedDevice.
749c974 Add ThreadedDevice.
e68b355 Fix some locks in SoftwareDevice.
44b57af Bugfix for deadlock in WASAPIDevice.
8c4b266 CMake: fix ERROR to FATAL_ERROR in MESSAGE.
5a17338 Rename NullDevice's reported name to None.
cd138d7 PulseAudio: add dynamic loading and threading fixes.
6e0250f CoreAudio: add CoreAudioClock as synchronizer.
43aff35 Fix leakage in CoreAudioDevice.cpp
7f6f059 Remove unnecessary cmake code.
a5c1a02 Add CoreAudio device for Apple.
af96f67 Indentation fix.
eec8fd5 WASAPI: use padding also for first buffer submission.
c63bd9b WASAPI: deal with IsFormatSupported case.
079cccb Hide WITH_PULSEAUDIO when not on Linux.
67b5013 Add mingw64 cross compilation toolchain on Linux.
a7bfa58 Add WASAPI backend for Windows.
be1cb25 Allow AUD_init with nullptr to use default device.
fc68868 Compilation fix for mingw.
bb79d25 Add a PulseAudio output device.
a11f593 Bugfix for unwanted volume fading at the beginning of sounds.
8510acf Bugfix: more accurate positioning of sequences.
cb816c1 Fix API docs for python playback manager play function
d125fa2 Add callback for mixing down audio.
789832e Fix numpy import.
9a6a802 Bugfix: JOS resampling type bugfix caused integer underflow.
ece0842 Fix corrupted document in python bindings
28b2ea2 SDL 2: support more audio formats.
a39b7e3 Trying to fix Travis CI build for OS X.
c924007 Some more changes of times from flaot to double.
659afd4 Porting fixes from blender.
8e5e2e6 Fix documentation warnings.
7a6054f API: All times are now double instead of float.
452a724 Mixer sample buffer added channels twice
8ddb6c1 Docs: Cleanup Line Wrapping for python examples
a0c37b2 Docs: Use class methods for api docs
2f8b2e3 Bugfix for invalid offsets provided by ffmpeg's seeking code.
20a7a28 Bug fixes for files with more than 8 channels.
94dc527 Bugfix: Fading from full volume.
2fb9862 Fix: Missing include in FileManager.h.
afadb94 Minor CMakeLists.txt formatting fixes.
734ef03 Add sample rate parameter to silence generation.
ed50f3b Bugfix: Return correct length for modulator and superpose.
cb7a314 Adding a modulator sound effect.
101c714 Bugfix: don't add non-existing devices to the device manager.
7ad99df OpenAL: recreate device if disconnected.
a2ff4e8 Bugfix: memory leak in python API.
5fb21bb Silence some warnings.
9b38605 Some fixes backported from Blender.
40a0a34 Udpate for travis.ci.
212b4b6 Support newer ffmpeg versions.
d27746c Build option: configure whether to build versioned plugins.
19c8d9f Make fftw3 optional.
aa11968 Bugfix for building with gcc7.
10413c5 Fix for seeking with modified pitch.
Audaspace 1.3
=============
@ -10,6 +111,8 @@ Audaspace 1.3
- filter python API parameter check
- finding ffmpeg with pkgconfig
Detailed list of changes:
64884a7 Windows fixes.
53ba3e6 Implemented JACK dynamic loading.
5ee0ee1 Continues last commit.
@ -46,6 +149,8 @@ Audaspace 1.2
- assuring numpy is installed
- building the Python module on Mac OS X with CMake
Detailed list of changes:
a6b6e70 Changing default sample rate from 44.1 to 48 kHz.
20f0164 Bugfix: CMake custom command for python module on OS X.
98679a2 Bugfix: using standard library (s)rand.

View File

@ -23,7 +23,7 @@ endif()
project(audaspace)
set(AUDASPACE_VERSION 1.3)
set(AUDASPACE_VERSION 1.4)
set(AUDASPACE_LONG_VERSION ${AUDASPACE_VERSION}.0)
if(DEFINED AUDASPACE_CMAKE_CFG)

View File

@ -15,7 +15,7 @@ Audaspace is written in C++ 11 so a fairly recent compiler (g++ 4.8.2, clang 3.3
- Jack (output device)
- libsndfile (file access)
- ffmpeg (file access)
- Python (language binding)
- Python (language binding, needs NumPy as well)
Getting the Code
----------------

View File

@ -32,7 +32,7 @@ The following (probably incomplete) features are supported by audaspace:
License
-------
> Copyright © 2009-2015 Jörg Müller. All rights reserved.
> Copyright © 2009-2023 Jörg Müller. All rights reserved.
>
> Licensed under the Apache License, Version 2.0 (the "License");
> you may not use this file except in compliance with the License.

View File

@ -165,6 +165,12 @@ AUD_API void AUD_SequenceEntry_move(AUD_SequenceEntry* entry, double begin, doub
(*entry)->move(begin, end, skip);
}
AUD_API void AUD_SequenceEntry_setConstantRangeAnimationData(AUD_SequenceEntry* entry, AUD_AnimateablePropertyType type, int frame_start, int frame_end, float* data)
{
AnimateableProperty* prop = (*entry)->getAnimProperty(static_cast<AnimateablePropertyType>(type));
prop->writeConstantRange(data, frame_start, frame_end);
}
AUD_API void AUD_SequenceEntry_setAnimationData(AUD_SequenceEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated)
{
AnimateableProperty* prop = (*entry)->getAnimProperty(static_cast<AnimateablePropertyType>(type));

View File

@ -68,6 +68,16 @@ extern AUD_API void AUD_Sequence_remove(AUD_Sound* sequence, AUD_SequenceEntry*
* Writes animation data to a sequence.
* \param sequence The sound scene.
* \param type The type of animation data.
* \param frame_start Start of the frame range.
* \param frame_end End of the frame range.
* \param data The data to write.
*/
AUD_API void AUD_SequenceEntry_setConstantRangeAnimationData(AUD_SequenceEntry* entry, AUD_AnimateablePropertyType type, int frame_start, int frame_end, float* data);
/**
* Writes animation data to a sequenced entry.
* \param entry The sequenced entry.
* \param type The type of animation data.
* \param frame The frame this data is for.
* \param data The data to write.
* \param animated Whether the attribute is animated.

View File

@ -112,6 +112,14 @@ public:
*/
void write(const float* data, int position, int count);
/**
* Fills the properties frame range with constant value and marks it animated.
* \param data The new value.
* \param position_start The start position in the animation in frames.
* \param position_end The end position in the animation in frames.
*/
void writeConstantRange(const float* data, int position_start, int position_end);
/**
* Reads the properties value.
* \param position The position in the animation in frames.

View File

@ -198,12 +198,13 @@ public:
/**
* Adds a new entry to the scene.
* \param sound The sound this entry should play.
* \param sequence_data Reference to sequence_data. Mainly needed to get the FPS of the scene.
* \param begin The start time.
* \param end The end time or a negative value if determined by the sound.
* \param skip How much seconds should be skipped at the beginning.
* \return The entry added.
*/
std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, double begin, double end, double skip);
std::shared_ptr<SequenceEntry> add(std::shared_ptr<ISound> sound, std::shared_ptr<SequenceData> sequence_data, double begin, double end, double skip);
/**
* Removes an entry from the scene.

View File

@ -23,6 +23,7 @@
*/
#include "sequence/AnimateableProperty.h"
#include "sequence/SequenceData.h"
#include "util/ILockable.h"
#include <mutex>
@ -63,6 +64,9 @@ private:
/// How many seconds are skipped at the beginning.
double m_skip;
/// reference to sequence_data. Mainly needed to get the FPS of the scene.
std::shared_ptr<SequenceData> m_sequence_data;
/// Whether the entry is muted.
bool m_muted;
@ -122,9 +126,10 @@ public:
* \param begin The start time.
* \param end The end time or a negative value if determined by the sound.
* \param skip How much seconds should be skipped at the beginning.
* \param sequence_data Reference to sequence_data. Mainly needed to get the FPS of the scene.
* \param id The ID of the entry.
*/
SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, int id);
SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, std::shared_ptr<SequenceData> sequence_data, int id);
virtual ~SequenceEntry();
/**

View File

@ -65,6 +65,19 @@ void AnimateableProperty::write(const float* data)
std::memcpy(getBuffer(), data, m_count * sizeof(float));
}
void AnimateableProperty::writeConstantRange(const float* data, int position_start, int position_end)
{
assureSize(position_end * m_count * sizeof(float), true);
float* buffer = getBuffer();
for(int i = position_start; i < position_end; i++)
{
std::memcpy(buffer + i * m_count, data, m_count * sizeof(float));
}
m_isAnimated = true;
}
void AnimateableProperty::write(const float* data, int position, int count)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);

View File

@ -92,7 +92,7 @@ AnimateableProperty* Sequence::getAnimProperty(AnimateablePropertyType type)
std::shared_ptr<SequenceEntry> Sequence::add(std::shared_ptr<ISound> sound, double begin, double end, double skip)
{
return m_sequence->add(sound, begin, end, skip);
return m_sequence->add(sound, m_sequence, begin, end, skip);
}
void Sequence::remove(std::shared_ptr<SequenceEntry> entry)

View File

@ -149,11 +149,11 @@ AnimateableProperty* SequenceData::getAnimProperty(AnimateablePropertyType type)
}
}
std::shared_ptr<SequenceEntry> SequenceData::add(std::shared_ptr<ISound> sound, double begin, double end, double skip)
std::shared_ptr<SequenceEntry> SequenceData::add(std::shared_ptr<ISound> sound, std::shared_ptr<SequenceData> sequence_data, double begin, double end, double skip)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
std::shared_ptr<SequenceEntry> entry = std::shared_ptr<SequenceEntry>(new SequenceEntry(sound, begin, end, skip, m_id++));
std::shared_ptr<SequenceEntry> entry = std::shared_ptr<SequenceEntry>(new SequenceEntry(sound, begin, end, skip, sequence_data, m_id++));
m_entries.push_back(entry);
m_entry_status++;

View File

@ -22,7 +22,7 @@
AUD_NAMESPACE_BEGIN
SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, int id) :
SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, double begin, double end, double skip, std::shared_ptr<SequenceData> sequence_data, int id) :
m_status(0),
m_pos_status(1),
m_sound_status(0),
@ -31,6 +31,7 @@ SequenceEntry::SequenceEntry(std::shared_ptr<ISound> sound, double begin, double
m_begin(begin),
m_end(end),
m_skip(skip),
m_sequence_data(sequence_data),
m_muted(false),
m_relative(true),
m_volume_max(1.0f),

View File

@ -241,10 +241,38 @@ bool SequenceHandle::seek(double position)
return false;
std::lock_guard<ILockable> lock(*m_entry);
double seekpos = position - m_entry->m_begin;
if(seekpos < 0)
seekpos = 0;
seekpos += m_entry->m_skip;
double seek_frame = (position - m_entry->m_begin) * m_entry->m_sequence_data->getFPS();
if(seek_frame < 0)
seek_frame = 0;
seek_frame += m_entry->m_skip * m_entry->m_sequence_data->getFPS();
AnimateableProperty* pitch_property = m_entry->getAnimProperty(AP_PITCH);
double target_frame = 0;
if(pitch_property != nullptr)
{
int frame_start = (m_entry->m_begin - m_entry->m_skip) * m_entry->m_sequence_data->getFPS();
for(int i = 0; seek_frame > 0; i++)
{
float pitch;
pitch_property->read(frame_start + i, &pitch);
const double factor = seek_frame > 1.0 ? 1.0 : seek_frame;
target_frame += pitch * factor;
seek_frame--;
}
}
else
{
target_frame = seek_frame;
}
double seekpos = target_frame / m_entry->m_sequence_data->getFPS();
m_handle->setPitch(1.0f);
m_handle->seek(seekpos);

View File

@ -127,7 +127,7 @@ typedef uint32_t cuuint32_t;
typedef uint64_t cuuint64_t;
#endif
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__)
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__) || defined(__ppc64__) || defined(__PPC64__)
typedef unsigned long long CUdeviceptr;
#else
typedef unsigned int CUdeviceptr;

View File

@ -84,7 +84,7 @@ typedef uint32_t hipuint32_t;
typedef uint64_t hipuint64_t;
#endif
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__)
#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) || defined (__aarch64__) || defined(__ppc64__) || defined(__PPC64__)
typedef unsigned long long hipDeviceptr_t;
#else
typedef unsigned int hipDeviceptr_t;

View File

@ -281,6 +281,7 @@ endif()
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
add_definitions(-DEMBREE_MAJOR_VERSION=${EMBREE_MAJOR_VERSION})
include_directories(
SYSTEM
${EMBREE_INCLUDE_DIRS}

View File

@ -51,6 +51,12 @@ if(WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI)
endif()
if(WITH_USD)
# Silence warning from USD headers using deprecated TBB header.
add_definitions(
-D__TBB_show_deprecation_message_atomic_H
-D__TBB_show_deprecation_message_task_H
)
list(APPEND INC_SYS
${USD_INCLUDE_DIRS}
)

View File

@ -403,7 +403,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
time_limit: FloatProperty(
name="Time Limit",
description="Limit the render time (excluding synchronization time)."
description="Limit the render time (excluding synchronization time). "
"Zero disables the limit",
min=0.0,
default=0.0,

View File

@ -609,59 +609,60 @@ void BlenderSync::sync_particle_hair(
}
}
static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Curves b_curves)
static const float *find_radius_attribute(BL::Curves b_curves)
{
for (BL::Attribute &b_attribute : b_curves.attributes) {
if (b_attribute.name() != "radius") {
continue;
}
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
return BL::FloatAttribute{b_attribute};
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return std::nullopt;
return nullptr;
}
static BL::FloatVectorAttribute find_curves_position_attribute(BL::Curves b_curves)
static const float (*find_position_attribute(BL::Curves b_curves))[3]
{
for (BL::Attribute &b_attribute : b_curves.attributes) {
if (b_attribute.name() != "position") {
continue;
}
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
continue;
}
return BL::FloatVectorAttribute{b_attribute};
BL::FloatVectorAttribute b_float3_attribute{b_attribute};
if (b_float3_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float(*)[3]>(b_float3_attribute.data[0].ptr.data);
}
/* The position attribute must exist. */
assert(false);
return BL::FloatVectorAttribute{b_curves.attributes[0]};
return nullptr;
}
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::Curves &b_curves,
static void fill_generic_attribute(const int num_curves,
const int num_points,
TypeInCycles *data,
const AttributeElement element,
const GetValueAtIndex &get_value_at_index)
{
switch (element) {
case ATTR_ELEMENT_CURVE_KEY: {
const int num_points = b_curves.points.length();
for (int i = 0; i < num_points; i++) {
data[i] = get_value_at_index(i);
}
break;
}
case ATTR_ELEMENT_CURVE: {
const int num_verts = b_curves.curves.length();
for (int i = 0; i < num_verts; i++) {
for (int i = 0; i < num_curves; i++) {
data[i] = get_value_at_index(i);
}
break;
@ -681,6 +682,7 @@ static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const flo
}
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
const int num_curve_keys = hair->get_curve_keys().size();
/* Find or add attribute */
@ -698,23 +700,24 @@ static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const flo
float3 *mP = attr_mP->data_float3() + step * num_curve_keys;
for (int i = 0; i < num_curve_keys; i++) {
mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
mP[i] = P[i] + make_float3(src[i][0], src[i][1], src[i][2]) * relative_time;
}
}
}
static void attr_create_uv(AttributeSet &attributes,
BL::Curves &b_curves,
const int num_curves,
const int num_points,
BL::Attribute &b_attribute,
const ustring name)
{
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(ATTR_STD_UV, name);
float2 *data = attr->data_float2();
fill_generic_attribute(b_curves, data, ATTR_ELEMENT_CURVE, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
fill_generic_attribute(num_curves, num_points, data, ATTR_ELEMENT_CURVE, [&](int i) {
return make_float2(src[i][0], src[i][1]);
});
}
@ -724,6 +727,9 @@ static void attr_create_generic(Scene *scene,
const bool need_motion,
const float motion_scale)
{
const int num_keys = b_curves.points.length();
const int num_curves = b_curves.curves.length();
AttributeSet &attributes = hair->attributes;
static const ustring u_velocity("velocity");
const bool need_uv = hair->need_attribute(scene, ATTR_STD_UV);
@ -743,7 +749,7 @@ static void attr_create_generic(Scene *scene,
/* Weak, use first float2 attribute as standard UV. */
if (need_uv && !have_uv && b_data_type == BL::Attribute::data_type_FLOAT2 &&
b_domain == BL::Attribute::domain_CURVE) {
attr_create_uv(attributes, b_curves, b_attribute, name);
attr_create_uv(attributes, num_curves, num_keys, b_attribute, name);
have_uv = true;
continue;
}
@ -773,57 +779,70 @@ static void attr_create_generic(Scene *scene,
switch (b_data_type) {
case BL::Attribute::data_type_FLOAT: {
BL::FloatAttribute b_float_attribute{b_attribute};
const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_curves, data, element, [&](int i) { return b_float_attribute.data[i].value(); });
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) { return src[i]; });
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
const bool *src = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_curves, data, element, [&](int i) {
return (float)b_bool_attribute.data[i].value();
});
fill_generic_attribute(
num_curves, num_keys, data, element, [&](int i) { return float(src[i]); });
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
const int *src = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_curves, data, element, [&](int i) {
return (float)b_int_attribute.data[i].value();
});
fill_generic_attribute(
num_curves, num_keys, data, element, [&](int i) { return float(src[i]); });
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(b_curves, data, element, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float3(src[i][0], src[i][1], src[i][2]);
});
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
const uchar(*src)[4] = static_cast<const uchar(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float4(color_srgb_to_linear(byte_to_float(src[i][0])),
color_srgb_to_linear(byte_to_float(src[i][1])),
color_srgb_to_linear(byte_to_float(src[i][2])),
color_srgb_to_linear(byte_to_float(src[i][3])));
});
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
const float(*src)[4] = static_cast<const float(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
fill_generic_attribute(b_curves, data, element, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float4(src[i][0], src[i][1], src[i][2], src[i][3]);
});
break;
}
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_curves, data, element, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float2(src[i][0], src[i][1]);
});
break;
}
@ -834,27 +853,28 @@ static void attr_create_generic(Scene *scene,
}
}
static float4 hair_point_as_float4(BL::FloatVectorAttribute b_attr_position,
std::optional<BL::FloatAttribute> b_attr_radius,
const int index)
static float4 curve_point_as_float4(const float (*b_attr_position)[3],
const float *b_attr_radius,
const int index)
{
float4 mP = float3_to_float4(get_float3(b_attr_position.data[index].vector()));
mP.w = b_attr_radius ? b_attr_radius->data[index].value() : 0.005f;
float4 mP = make_float4(
b_attr_position[index][0], b_attr_position[index][1], b_attr_position[index][2], 0.0f);
mP.w = b_attr_radius ? b_attr_radius[index] : 0.005f;
return mP;
}
static float4 interpolate_hair_points(BL::FloatVectorAttribute b_attr_position,
std::optional<BL::FloatAttribute> b_attr_radius,
const int first_point_index,
const int num_points,
const float step)
static float4 interpolate_curve_points(const float (*b_attr_position)[3],
const float *b_attr_radius,
const int first_point_index,
const int num_points,
const float step)
{
const float curve_t = step * (num_points - 1);
const int point_a = clamp((int)curve_t, 0, num_points - 1);
const int point_b = min(point_a + 1, num_points - 1);
const float t = curve_t - (float)point_a;
return lerp(hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
return lerp(curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
t);
}
@ -864,8 +884,6 @@ static void export_hair_curves(Scene *scene,
const bool need_motion,
const float motion_scale)
{
/* TODO: optimize so we can straight memcpy arrays from Blender? */
const int num_keys = b_curves.points.length();
const int num_curves = b_curves.curves.length();
@ -879,7 +897,6 @@ static void export_hair_curves(Scene *scene,
/* Add requested attributes. */
float *attr_intercept = NULL;
float *attr_length = NULL;
float *attr_random = NULL;
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT)->data_float();
@ -888,28 +905,40 @@ static void export_hair_curves(Scene *scene,
attr_length = hair->attributes.add(ATTR_STD_CURVE_LENGTH)->data_float();
}
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM)->data_float();
float *attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM)->data_float();
for (int i = 0; i < num_curves; i++) {
attr_random[i] = hash_uint2_to_float(i, 0);
}
}
BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data);
const float(*b_attr_position)[3] = find_position_attribute(b_curves);
const float *b_attr_radius = find_radius_attribute(b_curves);
std::copy(point_offsets, point_offsets + num_curves, curve_first_key);
std::fill(curve_shader, curve_shader + num_curves, 0);
if (b_attr_radius) {
std::copy(b_attr_radius, b_attr_radius + num_keys, curve_radius);
}
else {
std::fill(curve_radius, curve_radius + num_curves, 0.005f);
}
/* Export curves and points. */
for (int i = 0; i < num_curves; i++) {
const int first_point_index = b_curves.curve_offset_data[i].value();
const int num_points = b_curves.curve_offset_data[i + 1].value() - first_point_index;
const int first_point_index = point_offsets[i];
const int num_points = point_offsets[i + 1] - first_point_index;
float3 prev_co = zero_float3();
float length = 0.0f;
/* Position and radius. */
for (int j = 0; j < num_points; j++) {
const int point_offset = first_point_index + j;
const float3 co = get_float3(b_attr_position.data[point_offset].vector());
const float radius = b_attr_radius ? b_attr_radius->data[point_offset].value() : 0.005f;
const int point = first_point_index + j;
const float3 co = make_float3(
b_attr_position[point][0], b_attr_position[point][1], b_attr_position[point][2]);
curve_keys[point_offset] = co;
curve_radius[point_offset] = radius;
curve_keys[point] = co;
if (attr_length || attr_intercept) {
if (j > 0) {
@ -918,7 +947,7 @@ static void export_hair_curves(Scene *scene,
prev_co = co;
if (attr_intercept) {
attr_intercept[point_offset] = length;
attr_intercept[point] = length;
}
}
}
@ -926,8 +955,8 @@ static void export_hair_curves(Scene *scene,
/* Normalized 0..1 attribute along curve. */
if (attr_intercept && length > 0.0f) {
for (int j = 1; j < num_points; j++) {
const int point_offset = first_point_index + j;
attr_intercept[point_offset] /= length;
const int point = first_point_index + j;
attr_intercept[point] /= length;
}
}
@ -935,15 +964,6 @@ static void export_hair_curves(Scene *scene,
if (attr_length) {
attr_length[i] = length;
}
/* Random number per curve. */
if (attr_random != NULL) {
attr_random[i] = hash_uint2_to_float(i, 0);
}
/* Curve. */
curve_shader[i] = 0;
curve_first_key[i] = first_point_index;
}
attr_create_generic(scene, hair, b_curves, need_motion, motion_scale);
@ -968,12 +988,13 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
int num_motion_keys = 0;
int curve_index = 0;
BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data);
const float(*b_attr_position)[3] = find_position_attribute(b_curves);
const float *b_attr_radius = find_radius_attribute(b_curves);
for (int i = 0; i < num_curves; i++) {
const int first_point_index = b_curves.curve_offset_data[i].value();
const int num_points = b_curves.curve_offset_data[i + 1].value() - first_point_index;
const int first_point_index = point_offsets[i];
const int num_points = point_offsets[i + 1] - first_point_index;
Hair::Curve curve = hair->get_curve(curve_index);
curve_index++;
@ -981,10 +1002,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
if (num_points == curve.num_keys) {
/* Number of keys matches. */
for (int i = 0; i < num_points; i++) {
int point_index = first_point_index + i;
int point = first_point_index + i;
if (point_index < num_keys) {
mP[num_motion_keys] = hair_point_as_float4(b_attr_position, b_attr_radius, point_index);
if (point < num_keys) {
mP[num_motion_keys] = curve_point_as_float4(b_attr_position, b_attr_radius, point);
num_motion_keys++;
if (!have_motion) {
@ -1003,7 +1024,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
for (int i = 0; i < curve.num_keys; i++) {
const float step = i * step_size;
mP[num_motion_keys] = interpolate_hair_points(
mP[num_motion_keys] = interpolate_curve_points(
b_attr_position, b_attr_radius, first_point_index, num_points, step);
num_motion_keys++;
}

View File

@ -10,22 +10,12 @@
#include "blender/sync.h"
#include "blender/util.h"
#include "util/color.h"
#include "util/foreach.h"
#include "util/hash.h"
CCL_NAMESPACE_BEGIN
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
TypeInCycles *data,
const GetValueAtIndex &get_value_at_index)
{
const int num_points = b_pointcloud.points.length();
for (int i = 0; i < num_points; i++) {
data[i] = get_value_at_index(i);
}
}
static void attr_create_motion(PointCloud *pointcloud,
BL::Attribute &b_attribute,
const float motion_scale)
@ -63,6 +53,11 @@ static void copy_attributes(PointCloud *pointcloud,
const bool need_motion,
const float motion_scale)
{
const int num_points = b_pointcloud.points.length();
if (num_points == 0) {
return;
}
AttributeSet &attributes = pointcloud->attributes;
static const ustring u_velocity("velocity");
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
@ -81,56 +76,73 @@ static void copy_attributes(PointCloud *pointcloud,
switch (b_data_type) {
case BL::Attribute::data_type_FLOAT: {
BL::FloatAttribute b_float_attribute{b_attribute};
const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_pointcloud, data, [&](int i) { return b_float_attribute.data[i].value(); });
std::copy(src, src + num_points, data);
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
const bool *src = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_pointcloud, data, [&](int i) { return (float)b_bool_attribute.data[i].value(); });
for (int i = 0; i < num_points; i++) {
data[i] = float(src[i]);
}
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
const int *src = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_pointcloud, data, [&](int i) { return (float)b_int_attribute.data[i].value(); });
for (int i = 0; i < num_points; i++) {
data[i] = float(src[i]);
}
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(b_pointcloud, data, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
});
for (int i = 0; i < num_points; i++) {
data[i] = make_float3(src[i][0], src[i][1], src[i][2]);
}
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
const uchar(*src)[4] = static_cast<const uchar(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
for (int i = 0; i < num_points; i++) {
data[i] = make_float4(color_srgb_to_linear(byte_to_float(src[i][0])),
color_srgb_to_linear(byte_to_float(src[i][1])),
color_srgb_to_linear(byte_to_float(src[i][2])),
color_srgb_to_linear(byte_to_float(src[i][3])));
}
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
const float(*src)[4] = static_cast<const float(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
fill_generic_attribute(b_pointcloud, data, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
});
for (int i = 0; i < num_points; i++) {
data[i] = make_float4(src[i][0], src[i][1], src[i][2], src[i][3]);
}
break;
}
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_pointcloud, data, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
});
for (int i = 0; i < num_points; i++) {
data[i] = make_float2(src[i][0], src[i][1]);
}
break;
}
default:
@ -140,7 +152,7 @@ static void copy_attributes(PointCloud *pointcloud,
}
}
static std::optional<BL::FloatAttribute> find_radius_attribute(BL::PointCloud b_pointcloud)
static const float *find_radius_attribute(BL::PointCloud b_pointcloud)
{
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
if (b_attribute.name() != "radius") {
@ -149,12 +161,16 @@ static std::optional<BL::FloatAttribute> find_radius_attribute(BL::PointCloud b_
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
return BL::FloatAttribute{b_attribute};
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return std::nullopt;
return nullptr;
}
static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud)
static const float (*find_position_attribute(BL::PointCloud b_pointcloud))[3]
{
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
if (b_attribute.name() != "position") {
@ -163,11 +179,15 @@ static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcl
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
continue;
}
return BL::FloatVectorAttribute{b_attribute};
BL::FloatVectorAttribute b_float3_attribute{b_attribute};
if (b_float3_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float(*)[3]>(b_float3_attribute.data[0].ptr.data);
}
/* The position attribute must exist. */
assert(false);
return BL::FloatVectorAttribute{b_pointcloud.attributes[0]};
return nullptr;
}
static void export_pointcloud(Scene *scene,
@ -176,34 +196,36 @@ static void export_pointcloud(Scene *scene,
const bool need_motion,
const float motion_scale)
{
/* TODO: optimize so we can straight memcpy arrays from Blender? */
const int num_points = b_pointcloud.points.length();
pointcloud->resize(num_points);
/* Add requested attributes. */
Attribute *attr_random = NULL;
if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud);
float3 *points = pointcloud->get_points().data();
for (int i = 0; i < num_points; i++) {
points[i] = make_float3(b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]);
}
/* Reserve memory. */
const int num_points = b_pointcloud.points.length();
pointcloud->reserve(num_points);
const float *b_attr_radius = find_radius_attribute(b_pointcloud);
float *radius = pointcloud->get_radius().data();
if (b_attr_radius) {
std::copy(b_attr_radius, b_attr_radius + num_points, radius);
}
else {
std::fill(radius, radius + num_points, 0.01f);
}
BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
int *shader = pointcloud->get_shader().data();
std::fill(shader, shader + num_points, 0);
/* Export points. */
for (int i = 0; i < num_points; i++) {
const float3 co = get_float3(b_attr_position.data[i].vector());
const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f;
pointcloud->add_point(co, radius);
/* Random number per point. */
if (attr_random != NULL) {
attr_random->add(hash_uint2_to_float(i, 0));
if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
float *data = attr_random->data_float();
for (int i = 0; i < num_points; i++) {
data[i] = hash_uint2_to_float(i, 0);
}
}
/* Export attributes */
copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
}
@ -220,22 +242,22 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
new_attribute = true;
}
/* Export motion points. */
const int num_points = pointcloud->num_points();
// Point cloud attributes are stored as float4 with the radius
// in the w element. This is explict now as float3 is no longer
// interchangeable with float4 as it is packed now.
/* Point cloud attributes are stored as float4 with the radius in the w element.
* This is explict now as float3 is no longer interchangeable with float4 as it
* is packed now. */
float4 *mP = attr_mP->data_float4() + motion_step * num_points;
bool have_motion = false;
const array<float3> &pointcloud_points = pointcloud->get_points();
const int b_points_num = b_pointcloud.points.length();
BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud);
const float *b_attr_radius = find_radius_attribute(b_pointcloud);
for (int i = 0; i < std::min(num_points, b_points_num); i++) {
const float3 P = get_float3(b_attr_position.data[i].vector());
const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.01f;
const float3 P = make_float3(
b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]);
const float radius = b_attr_radius ? b_attr_radius[i] : 0.01f;
mP[i] = make_float4(P.x, P.y, P.z, radius);
have_motion = have_motion || (P != pointcloud_points[i]);
}
@ -277,7 +299,7 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
0.0f;
export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale);
/* update original sockets */
/* Update original sockets. */
for (const SocketType &socket : new_pointcloud.type->inputs) {
/* Those sockets are updated in sync_object, so do not modify them. */
if (socket.name == "use_motion_blur" || socket.name == "motion_steps" ||
@ -292,7 +314,7 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
pointcloud->attributes.attributes.push_back(std::move(attr));
}
/* tag update */
/* Tag update. */
const bool rebuild = (pointcloud && old_numpoints != pointcloud->num_points());
pointcloud->tag_update(scene, rebuild);
}

View File

@ -61,6 +61,11 @@ if(WITH_CYCLES_EMBREE)
list(APPEND LIB
${EMBREE_LIBRARIES}
)
if(EMBREE_SYCL_SUPPORT)
list(APPEND LIB
${SYCL_LIBRARIES}
)
endif()
endif()
cycles_add_library(cycles_bvh "${LIB}" ${SRC} ${SRC_HEADERS})

View File

@ -17,7 +17,11 @@
#ifdef WITH_EMBREE
# include <embree3/rtcore_geometry.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore_geometry.h>
# else
# include <embree3/rtcore_geometry.h>
# endif
# include "bvh/embree.h"
@ -128,7 +132,11 @@ void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
scene = rtcNewScene(rtc_device);
const RTCSceneFlags scene_flags = (dynamic ? RTC_SCENE_FLAG_DYNAMIC : RTC_SCENE_FLAG_NONE) |
(compact ? RTC_SCENE_FLAG_COMPACT : RTC_SCENE_FLAG_NONE) |
RTC_SCENE_FLAG_ROBUST;
RTC_SCENE_FLAG_ROBUST
# if EMBREE_MAJOR_VERSION >= 4
| RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS
# endif
;
rtcSetSceneFlags(scene, scene_flags);
build_quality = dynamic ? RTC_BUILD_QUALITY_LOW :
(params.use_spatial_split ? RTC_BUILD_QUALITY_HIGH :
@ -226,6 +234,9 @@ void BVHEmbree::add_instance(Object *ob, int i)
rtcSetGeometryUserData(geom_id, (void *)instance_bvh->scene);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -267,9 +278,13 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
set_tri_vertex_buffer(geom_id, mesh, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -494,9 +509,13 @@ void BVHEmbree::add_points(const Object *ob, const PointCloud *pointcloud, int i
set_point_vertex_buffer(geom_id, pointcloud, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_func_backface_cull);
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func_backface_cull);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2);
@ -553,6 +572,10 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
set_curve_vertex_buffer(geom_id, hair, false);
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# if EMBREE_MAJOR_VERSION >= 4
rtcSetGeometryEnableFilterFunctionFromArguments(geom_id, true);
# else
if (hair->curve_shape == CURVE_RIBBON) {
rtcSetGeometryIntersectFilterFunction(geom_id, kernel_embree_filter_intersection_func);
rtcSetGeometryOccludedFilterFunction(geom_id, kernel_embree_filter_occluded_func);
@ -562,7 +585,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i)
rtcSetGeometryOccludedFilterFunction(geom_id,
kernel_embree_filter_occluded_func_backface_cull);
}
rtcSetGeometryMask(geom_id, ob->visibility_for_tracing());
# endif
rtcCommitGeometry(geom_id);
rtcAttachGeometryByID(scene, geom_id, i * 2 + 1);

View File

@ -6,8 +6,13 @@
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# include <embree4/rtcore_scene.h>
# else
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# endif
# include "bvh/bvh.h"
# include "bvh/params.h"

View File

@ -176,12 +176,10 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
else()
set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/../kernel/libcycles_kernel_oneapi${cycles_kernel_oneapi_lib_suffix}.so)
endif()
list(APPEND LIB ${cycles_kernel_oneapi_lib})
if(WIN32)
list(APPEND LIB debug ${SYCL_LIBRARY_DEBUG} optimized ${SYCL_LIBRARY})
else()
list(APPEND LIB ${SYCL_LIBRARY})
endif()
list(APPEND LIB
${cycles_kernel_oneapi_lib}
${SYCL_LIBRARIES}
)
list(APPEND SRC
${SRC_ONEAPI}
)

View File

@ -14,7 +14,11 @@
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# else
# include <embree3/rtcore.h>
# endif
#endif
#include "device/cpu/kernel.h"

View File

@ -11,7 +11,11 @@
#endif
#ifdef WITH_EMBREE
# include <embree3/rtcore.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# else
# include <embree3/rtcore.h>
# endif
#endif
#include "device/cpu/kernel.h"

View File

@ -445,12 +445,10 @@ void MetalKernelPipeline::compile()
const std::string function_name = std::string("cycles_metal_") +
device_kernel_as_string(device_kernel);
NSString *entryPoint = [@(function_name.c_str()) copy];
NSError *error = NULL;
if (@available(macOS 11.0, *)) {
MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
func_desc.name = entryPoint;
func_desc.name = [@(function_name.c_str()) copy];
if (pso_type != PSO_GENERIC) {
func_desc.constantValues = GetConstantValues(&kernel_data_);
@ -462,8 +460,6 @@ void MetalKernelPipeline::compile()
function = [mtlLibrary newFunctionWithDescriptor:func_desc error:&error];
}
[entryPoint release];
if (function == nil) {
NSString *err = [error localizedDescription];
string errors = [err UTF8String];
@ -471,7 +467,7 @@ void MetalKernelPipeline::compile()
return;
}
function.label = [entryPoint copy];
function.label = [@(function_name.c_str()) copy];
if (use_metalrt) {
if (@available(macOS 11.0, *)) {

View File

@ -80,6 +80,12 @@ if(EXISTS ${USD_INCLUDE_DIR}/pxr/imaging/hgiGL)
list(APPEND SRC_HD_CYCLES_HEADERS display_driver.h)
endif()
# Silence warning from USD headers using deprecated TBB header.
add_definitions(
-D__TBB_show_deprecation_message_atomic_H
-D__TBB_show_deprecation_message_task_H
)
include_directories(${INC})
include_directories(SYSTEM ${INC_SYS})

View File

@ -4,6 +4,12 @@
#ifdef _WIN32
// Include first to avoid "NOGDI" definition set in Cycles headers
# ifndef NOMINMAX
# define NOMINMAX
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <Windows.h>
#endif

View File

@ -370,6 +370,16 @@ VtValue convertFromCyclesArray(const array<SrcType> &value)
return VtValue(convertedValue);
}
template<> VtValue convertFromCyclesArray<float2, GfVec2f>(const array<float2> &value)
{
VtVec2fArray convertedValue;
convertedValue.reserve(value.size());
for (const auto &element : value) {
convertedValue.push_back(GfVec2f(element.x, element.y));
}
return VtValue(convertedValue);
}
template<> VtValue convertFromCyclesArray<float3, GfVec3f>(const array<float3> &value)
{
VtVec3fArray convertedValue;

View File

@ -7,6 +7,7 @@
#include "device/device.h"
#include "device/memory.h"
#include "device/queue.h"
#include "integrator/pass_accessor_gpu.h"
#include "session/buffers.h"
#include "util/log.h"
#include "util/progress.h"
@ -105,4 +106,220 @@ Device *DenoiserGPU::ensure_denoiser_device(Progress *progress)
return denoiser_device;
}
DenoiserGPU::DenoiseContext::DenoiseContext(Device *device, const DenoiseTask &task)
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
if (denoise_params.use_pass_albedo) {
num_input_passes += 1;
use_pass_albedo = true;
pass_denoising_albedo = buffer_params.get_pass_offset(PASS_DENOISING_ALBEDO);
if (denoise_params.use_pass_normal) {
num_input_passes += 1;
use_pass_normal = true;
pass_denoising_normal = buffer_params.get_pass_offset(PASS_DENOISING_NORMAL);
}
}
if (denoise_params.temporally_stable) {
prev_output.device_pointer = render_buffers->buffer.device_pointer;
prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
prev_output.stride = buffer_params.stride;
prev_output.pass_stride = buffer_params.pass_stride;
num_input_passes += 1;
use_pass_motion = true;
pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
}
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
}
else {
guiding_params.pass_stride = 0;
if (use_pass_albedo) {
guiding_params.pass_albedo = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_normal) {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_motion) {
guiding_params.pass_flow = guiding_params.pass_stride;
guiding_params.pass_stride += 2;
}
guiding_params.stride = buffer_params.width;
guiding_buffer.alloc_to_device(buffer_params.width * buffer_params.height *
guiding_params.pass_stride);
guiding_params.device_pointer = guiding_buffer.device_pointer;
}
}
pass_sample_count = buffer_params.get_pass_offset(PASS_SAMPLE_COUNT);
}
bool DenoiserGPU::denoise_filter_color_postprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&context.num_samples,
&pass.noisy_offset,
&pass.denoised_offset,
&context.pass_sample_count,
&pass.num_components,
&pass.use_compositing);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
bool DenoiserGPU::denoise_filter_color_preprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&pass.denoised_offset);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
bool DenoiserGPU::denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.guiding_params.device_pointer,
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&buffer_params.width,
&buffer_params.height);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
void DenoiserGPU::denoise_color_read(const DenoiseContext &context, const DenoisePass &pass)
{
PassAccessor::PassAccessInfo pass_access_info;
pass_access_info.type = pass.type;
pass_access_info.mode = PassMode::NOISY;
pass_access_info.offset = pass.noisy_offset;
/* Denoiser operates on passes which are used to calculate the approximation, and is never used
* on the approximation. The latter is not even possible because OptiX does not support
* denoising of semi-transparent pixels. */
pass_access_info.use_approximate_shadow_catcher = false;
pass_access_info.use_approximate_shadow_catcher_background = false;
pass_access_info.show_active_pixels = false;
/* TODO(sergey): Consider adding support of actual exposure, to avoid clamping in extreme cases.
*/
const PassAccessorGPU pass_accessor(
denoiser_queue_.get(), pass_access_info, 1.0f, context.num_samples);
PassAccessor::Destination destination(pass_access_info.type);
destination.d_pixels = context.render_buffers->buffer.device_pointer +
pass.denoised_offset * sizeof(float);
destination.num_components = 3;
destination.pixel_stride = context.buffer_params.pass_stride;
BufferParams buffer_params = context.buffer_params;
buffer_params.window_x = 0;
buffer_params.window_y = 0;
buffer_params.window_width = buffer_params.width;
buffer_params.window_height = buffer_params.height;
pass_accessor.get_render_tile_pixels(context.render_buffers, buffer_params, destination);
}
void DenoiserGPU::denoise_pass(DenoiseContext &context, PassType pass_type)
{
const BufferParams &buffer_params = context.buffer_params;
const DenoisePass pass(pass_type, buffer_params);
if (pass.noisy_offset == PASS_UNUSED) {
return;
}
if (pass.denoised_offset == PASS_UNUSED) {
LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
return;
}
if (pass.use_denoising_albedo) {
if (context.albedo_replaced_with_fake) {
LOG(ERROR) << "Pass which requires albedo is denoised after fake albedo has been set.";
return;
}
}
else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
return;
}
}
/* Read and preprocess noisy color input pass. */
denoise_color_read(context, pass);
if (!denoise_filter_color_preprocess(context, pass)) {
LOG(ERROR) << "Error converting denoising passes to RGB buffer.";
return;
}
if (!denoise_run(context, pass)) {
LOG(ERROR) << "Error running denoiser.";
return;
}
/* Store result in the combined pass of the render buffer.
*
* This will scale the denoiser result up to match the number of, possibly per-pixel, samples. */
if (!denoise_filter_color_postprocess(context, pass)) {
LOG(ERROR) << "Error copying denoiser result to the denoised pass.";
return;
}
denoiser_queue_->synchronize();
}
CCL_NAMESPACE_END

View File

@ -21,6 +21,9 @@ class DenoiserGPU : public Denoiser {
bool allow_inplace_modification) override;
protected:
class DenoisePass;
class DenoiseContext;
/* All the parameters needed to perform buffer denoising on a device.
* Is not really a task in its canonical terms (as in, is not an asynchronous running task). Is
* more like a wrapper for all the arguments and parameters needed to perform denoising. Is a
@ -41,12 +44,105 @@ class DenoiserGPU : public Denoiser {
bool allow_inplace_modification;
};
/* Read input color pass from the render buffer into the memory which corresponds to the noisy
* input within the given context. Pixels are scaled to the number of samples, but are not
* preprocessed yet. */
void denoise_color_read(const DenoiseContext &context, const DenoisePass &pass);
/* Run corresponding filter kernels, preparing data for the denoiser or copying data from the
* denoiser result to the render buffer. */
bool denoise_filter_color_preprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_color_postprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
void denoise_pass(DenoiseContext &context, PassType pass_type);
/* Returns true if task is fully handled. */
virtual bool denoise_buffer(const DenoiseTask & /*task*/) = 0;
virtual bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) = 0;
virtual Device *ensure_denoiser_device(Progress *progress) override;
unique_ptr<DeviceQueue> denoiser_queue_;
class DenoisePass {
public:
DenoisePass(const PassType type, const BufferParams &buffer_params) : type(type)
{
noisy_offset = buffer_params.get_pass_offset(type, PassMode::NOISY);
denoised_offset = buffer_params.get_pass_offset(type, PassMode::DENOISED);
const PassInfo pass_info = Pass::get_info(type);
num_components = pass_info.num_components;
use_compositing = pass_info.use_compositing;
use_denoising_albedo = pass_info.use_denoising_albedo;
}
PassType type;
int noisy_offset;
int denoised_offset;
int num_components;
bool use_compositing;
bool use_denoising_albedo;
};
class DenoiseContext {
public:
explicit DenoiseContext(Device *device, const DenoiseTask &task);
const DenoiseParams &denoise_params;
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
/* Previous output. */
struct {
device_ptr device_pointer = 0;
int offset = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} prev_output;
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
struct {
device_ptr device_pointer = 0;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} guiding_params;
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
bool use_pass_motion = false;
int num_samples = 0;
int pass_sample_count = PASS_UNUSED;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake = false;
};
};
CCL_NAMESPACE_END

View File

@ -218,154 +218,6 @@ uint OptiXDenoiser::get_device_type_mask() const
return DEVICE_MASK_OPTIX;
}
class OptiXDenoiser::DenoiseContext {
public:
explicit DenoiseContext(OptiXDevice *device, const DenoiseTask &task)
: denoise_params(task.params),
render_buffers(task.render_buffers),
buffer_params(task.buffer_params),
guiding_buffer(device, "denoiser guiding passes buffer", true),
num_samples(task.num_samples)
{
num_input_passes = 1;
if (denoise_params.use_pass_albedo) {
num_input_passes += 1;
use_pass_albedo = true;
pass_denoising_albedo = buffer_params.get_pass_offset(PASS_DENOISING_ALBEDO);
if (denoise_params.use_pass_normal) {
num_input_passes += 1;
use_pass_normal = true;
pass_denoising_normal = buffer_params.get_pass_offset(PASS_DENOISING_NORMAL);
}
}
if (denoise_params.temporally_stable) {
prev_output.device_pointer = render_buffers->buffer.device_pointer;
prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
prev_output.stride = buffer_params.stride;
prev_output.pass_stride = buffer_params.pass_stride;
num_input_passes += 1;
use_pass_motion = true;
pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
}
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
if (task.allow_inplace_modification) {
guiding_params.device_pointer = render_buffers->buffer.device_pointer;
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
}
else {
guiding_params.pass_stride = 0;
if (use_pass_albedo) {
guiding_params.pass_albedo = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_normal) {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
if (use_pass_motion) {
guiding_params.pass_flow = guiding_params.pass_stride;
guiding_params.pass_stride += 2;
}
guiding_params.stride = buffer_params.width;
guiding_buffer.alloc_to_device(buffer_params.width * buffer_params.height *
guiding_params.pass_stride);
guiding_params.device_pointer = guiding_buffer.device_pointer;
}
}
pass_sample_count = buffer_params.get_pass_offset(PASS_SAMPLE_COUNT);
}
const DenoiseParams &denoise_params;
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
/* Previous output. */
struct {
device_ptr device_pointer = 0;
int offset = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} prev_output;
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
struct {
device_ptr device_pointer = 0;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
} guiding_params;
/* Number of input passes. Including the color and extra auxiliary passes. */
int num_input_passes = 0;
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
bool use_pass_motion = false;
int num_samples = 0;
int pass_sample_count = PASS_UNUSED;
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
* the fake values and denoising of passes which do need albedo can no longer happen. */
bool albedo_replaced_with_fake = false;
};
class OptiXDenoiser::DenoisePass {
public:
DenoisePass(const PassType type, const BufferParams &buffer_params) : type(type)
{
noisy_offset = buffer_params.get_pass_offset(type, PassMode::NOISY);
denoised_offset = buffer_params.get_pass_offset(type, PassMode::DENOISED);
const PassInfo pass_info = Pass::get_info(type);
num_components = pass_info.num_components;
use_compositing = pass_info.use_compositing;
use_denoising_albedo = pass_info.use_denoising_albedo;
}
PassType type;
int noisy_offset;
int denoised_offset;
int num_components;
bool use_compositing;
bool use_denoising_albedo;
};
bool OptiXDenoiser::denoise_buffer(const DenoiseTask &task)
{
OptiXDevice *const optix_device = static_cast<OptiXDevice *>(denoiser_device_);
@ -421,151 +273,6 @@ bool OptiXDenoiser::denoise_filter_guiding_preprocess(const DenoiseContext &cont
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.guiding_params.device_pointer,
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&buffer_params.width,
&buffer_params.height);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO, work_size, args);
}
void OptiXDenoiser::denoise_pass(DenoiseContext &context, PassType pass_type)
{
const BufferParams &buffer_params = context.buffer_params;
const DenoisePass pass(pass_type, buffer_params);
if (pass.noisy_offset == PASS_UNUSED) {
return;
}
if (pass.denoised_offset == PASS_UNUSED) {
LOG(DFATAL) << "Missing denoised pass " << pass_type_as_string(pass_type);
return;
}
if (pass.use_denoising_albedo) {
if (context.albedo_replaced_with_fake) {
LOG(ERROR) << "Pass which requires albedo is denoised after fake albedo has been set.";
return;
}
}
else if (context.use_guiding_passes && !context.albedo_replaced_with_fake) {
context.albedo_replaced_with_fake = true;
if (!denoise_filter_guiding_set_fake_albedo(context)) {
LOG(ERROR) << "Error replacing real albedo with the fake one.";
return;
}
}
/* Read and preprocess noisy color input pass. */
denoise_color_read(context, pass);
if (!denoise_filter_color_preprocess(context, pass)) {
LOG(ERROR) << "Error converting denoising passes to RGB buffer.";
return;
}
if (!denoise_run(context, pass)) {
LOG(ERROR) << "Error running OptiX denoiser.";
return;
}
/* Store result in the combined pass of the render buffer.
*
* This will scale the denoiser result up to match the number of, possibly per-pixel, samples. */
if (!denoise_filter_color_postprocess(context, pass)) {
LOG(ERROR) << "Error copying denoiser result to the denoised pass.";
return;
}
denoiser_queue_->synchronize();
}
void OptiXDenoiser::denoise_color_read(const DenoiseContext &context, const DenoisePass &pass)
{
PassAccessor::PassAccessInfo pass_access_info;
pass_access_info.type = pass.type;
pass_access_info.mode = PassMode::NOISY;
pass_access_info.offset = pass.noisy_offset;
/* Denoiser operates on passes which are used to calculate the approximation, and is never used
* on the approximation. The latter is not even possible because OptiX does not support
* denoising of semi-transparent pixels. */
pass_access_info.use_approximate_shadow_catcher = false;
pass_access_info.use_approximate_shadow_catcher_background = false;
pass_access_info.show_active_pixels = false;
/* TODO(sergey): Consider adding support of actual exposure, to avoid clamping in extreme cases.
*/
const PassAccessorGPU pass_accessor(
denoiser_queue_.get(), pass_access_info, 1.0f, context.num_samples);
PassAccessor::Destination destination(pass_access_info.type);
destination.d_pixels = context.render_buffers->buffer.device_pointer +
pass.denoised_offset * sizeof(float);
destination.num_components = 3;
destination.pixel_stride = context.buffer_params.pass_stride;
BufferParams buffer_params = context.buffer_params;
buffer_params.window_x = 0;
buffer_params.window_y = 0;
buffer_params.window_width = buffer_params.width;
buffer_params.window_height = buffer_params.height;
pass_accessor.get_render_tile_pixels(context.render_buffers, buffer_params, destination);
}
bool OptiXDenoiser::denoise_filter_color_preprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&pass.denoised_offset);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_PREPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_filter_color_postprocess(const DenoiseContext &context,
const DenoisePass &pass)
{
const BufferParams &buffer_params = context.buffer_params;
const int work_size = buffer_params.width * buffer_params.height;
DeviceKernelArguments args(&context.render_buffers->buffer.device_pointer,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
&buffer_params.height,
&buffer_params.offset,
&buffer_params.stride,
&buffer_params.pass_stride,
&context.num_samples,
&pass.noisy_offset,
&pass.denoised_offset,
&context.pass_sample_count,
&pass.num_components,
&pass.use_compositing);
return denoiser_queue_->enqueue(DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS, work_size, args);
}
bool OptiXDenoiser::denoise_ensure(DenoiseContext &context)
{
if (!denoise_create_if_needed(context)) {

View File

@ -21,9 +21,6 @@ class OptiXDenoiser : public DenoiserGPU {
virtual uint get_device_type_mask() const override;
private:
class DenoiseContext;
class DenoisePass;
virtual bool denoise_buffer(const DenoiseTask &task) override;
/* Read guiding passes from the render buffers, preprocess them in a way which is expected by
@ -36,19 +33,6 @@ class OptiXDenoiser : public DenoiserGPU {
/* Set fake albedo pixels in the albedo guiding pass storage.
* After this point only passes which do not need albedo for denoising can be processed. */
bool denoise_filter_guiding_set_fake_albedo(const DenoiseContext &context);
void denoise_pass(DenoiseContext &context, PassType pass_type);
/* Read input color pass from the render buffer into the memory which corresponds to the noisy
* input within the given context. Pixels are scaled to the number of samples, but are not
* preprocessed yet. */
void denoise_color_read(const DenoiseContext &context, const DenoisePass &pass);
/* Run corresponding filter kernels, preparing data for the denoiser or copying data from the
* denoiser result to the render buffer. */
bool denoise_filter_color_preprocess(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_filter_color_postprocess(const DenoiseContext &context, const DenoisePass &pass);
/* Make sure the OptiX denoiser is created and configured. */
bool denoise_ensure(DenoiseContext &context);
@ -61,7 +45,7 @@ class OptiXDenoiser : public DenoiserGPU {
bool denoise_configure_if_needed(DenoiseContext &context);
/* Run configured denoiser. */
bool denoise_run(const DenoiseContext &context, const DenoisePass &pass);
bool denoise_run(const DenoiseContext &context, const DenoisePass &pass) override;
OptixDenoiser optix_denoiser_ = nullptr;

View File

@ -109,6 +109,11 @@ class PassAccessor {
/* Set pass data for the given render buffers. Used for baking to read from passes. */
bool set_render_tile_pixels(RenderBuffers *render_buffers, const Source &source);
const PassAccessInfo &get_pass_access_info() const
{
return pass_access_info_;
}
protected:
virtual void init_kernel_film_convert(KernelFilmConvert *kfilm_convert,
const BufferParams &buffer_params,

View File

@ -1036,7 +1036,12 @@ bool PathTrace::get_render_tile_pixels(const PassAccessor &pass_accessor,
}
if (big_tile_denoise_work_ && render_state_.has_denoised_result) {
return big_tile_denoise_work_->get_render_tile_pixels(pass_accessor, destination);
/* Only use the big tile denoised buffer to access the denoised passes.
* The guiding passes are allowed to be modified in-place for the needs of the denoiser,
* so copy those from the original devices buffers. */
if (pass_accessor.get_pass_access_info().mode == PassMode::DENOISED) {
return big_tile_denoise_work_->get_render_tile_pixels(pass_accessor, destination);
}
}
bool success = true;

View File

@ -362,7 +362,7 @@ void PathTraceWorkCPU::guiding_push_sample_data_to_global_storage(
# endif
# ifdef WITH_CYCLES_DEBUG
/* Check if the training/radiance samples generated py the path segment storage are valid.*/
/* Check if the training/radiance samples generated by the path segment storage are valid. */
if (VLOG_WORK_IS_ON) {
const bool validSamples = kg->opgl_path_segment_storage->ValidateSamples();
if (!validSamples) {

View File

@ -5,8 +5,13 @@
#pragma once
#include <embree3/rtcore_ray.h>
#include <embree3/rtcore_scene.h>
#if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore_ray.h>
# include <embree4/rtcore_scene.h>
#else
# include <embree3/rtcore_ray.h>
# include <embree3/rtcore_scene.h>
#endif
#include "kernel/device/cpu/compat.h"
#include "kernel/device/cpu/globals.h"
@ -28,11 +33,84 @@ using numhit_t = uint8_t;
using numhit_t = uint32_t;
#endif
#define CYCLES_EMBREE_USED_FEATURES \
(RTCFeatureFlags)(RTC_FEATURE_FLAG_TRIANGLE | RTC_FEATURE_FLAG_INSTANCE | \
RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | RTC_FEATURE_FLAG_POINT | \
RTC_FEATURE_FLAG_MOTION_BLUR | RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | \
RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE)
#define EMBREE_IS_HAIR(x) (x & 1)
#if EMBREE_MAJOR_VERSION < 4
# define rtcGetGeometryUserDataFromScene(scene, id) \
(rtcGetGeometryUserData(rtcGetGeometry(scene, id)))
#endif
/* Intersection context. */
struct CCLIntersectContext {
struct CCLFirstHitContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
KernelGlobals kg;
/* For avoiding self intersections */
const Ray *ray;
};
struct CCLShadowContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
#endif
IntegratorShadowState isect_s;
float throughput;
bool opaque_hit;
numhit_t max_hits;
numhit_t num_hits;
numhit_t num_recorded_hits;
};
struct CCLLocalContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
numhit_t max_hits;
#endif
int local_object_id;
LocalIntersection *local_isect;
uint *lcg_state;
bool is_sss;
};
struct CCLVolumeContext
#if EMBREE_MAJOR_VERSION >= 4
: public RTCRayQueryContext
#endif
{
#if EMBREE_MAJOR_VERSION >= 4
KernelGlobals kg;
const Ray *ray;
numhit_t max_hits;
numhit_t num_hits;
#endif
Intersection *vol_isect;
};
#if EMBREE_MAJOR_VERSION < 4
struct CCLIntersectContext : public RTCIntersectContext,
public CCLFirstHitContext,
public CCLShadowContext,
public CCLLocalContext,
public CCLVolumeContext {
typedef enum {
RAY_REGULAR = 0,
RAY_SHADOW_ALL = 1,
@ -41,28 +119,8 @@ struct CCLIntersectContext {
RAY_VOLUME_ALL = 4,
} RayType;
KernelGlobals kg;
RayType type;
/* For avoiding self intersections */
const Ray *ray;
/* for shadow rays */
IntegratorShadowState isect_s;
numhit_t max_hits;
numhit_t num_hits;
numhit_t num_recorded_hits;
float throughput;
bool opaque_hit;
/* for SSS Rays: */
LocalIntersection *local_isect;
int local_object_id;
uint *lcg_state;
/* for Volume */
Intersection *vol_isect;
CCLIntersectContext(KernelGlobals kg_, RayType type_)
{
kg = kg_;
@ -79,17 +137,7 @@ struct CCLIntersectContext {
lcg_state = NULL;
}
};
class IntersectContext {
public:
IntersectContext(CCLIntersectContext *ctx)
{
rtcInitIntersectContext(&context);
userRayExt = ctx;
}
RTCIntersectContext context;
CCLIntersectContext *userRayExt;
};
#endif
/* Utilities. */
@ -173,13 +221,12 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
{
intptr_t prim_offset;
if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
prim_offset = intptr_t(rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)));
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
hit->instID[0]);
prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(inst_scene, hit->geomID));
}
else {
prim_offset = intptr_t(
rtcGetGeometryUserData(rtcGetGeometry(kernel_data.device_bvh, hit->geomID)));
prim_offset = intptr_t(rtcGetGeometryUserDataFromScene(kernel_data.device_bvh, hit->geomID));
}
kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset);
}
@ -211,7 +258,11 @@ ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNA
assert(args->N == 1);
RTCHit *hit = (RTCHit *)args->hit;
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
#if EMBREE_MAJOR_VERSION >= 4
CCLFirstHitContext *ctx = (CCLFirstHitContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
@ -226,205 +277,257 @@ ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNA
* as well as filtering for volume objects happen here.
* Cycles' own BVH does that directly inside the traversal calls.
*/
ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
ccl_device void kernel_embree_filter_occluded_shadow_all_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
#if EMBREE_MAJOR_VERSION >= 4
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
/* If no transparent shadows or max number of hits exceeded, all light is blocked. */
const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
ctx->opaque_hit = true;
return;
}
++ctx->num_hits;
/* Always use baked shadow transparency for curves. */
if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
ctx->opaque_hit = true;
return;
}
else {
*args->valid = 0;
return;
}
}
/* Test if we need to record this transparent intersection. */
const numhit_t max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
if (ctx->num_recorded_hits < max_record_hits) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
numhit_t isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
ray->tfar = max(current_isect.t, max_t);
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
++ctx->num_recorded_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
ccl_device_forceinline void kernel_embree_filter_occluded_local_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
#if EMBREE_MAJOR_VERSION >= 4
CCLLocalContext *ctx = (CCLLocalContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
/* Check if it's hitting the correct object. */
Intersection current_isect;
if (ctx->is_sss) {
kernel_embree_convert_sss_hit(kg,
ray,
hit,
&current_isect,
ctx->local_object_id,
reinterpret_cast<intptr_t>(args->geometryUserPtr));
}
else {
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (ctx->local_object_id != current_isect.object) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
*args->valid = 0;
return;
}
/* No intersection information requested, just return a hit. */
if (ctx->max_hits == 0) {
return;
}
/* Ignore curves. */
if (EMBREE_IS_HAIR(hit->geomID)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
LocalIntersection *local_isect = ctx->local_isect;
int hit_idx = 0;
if (ctx->lcg_state) {
/* See triangle_intersect_subsurface() for the native equivalent. */
for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
if (local_isect->hits[i].t == ray->tfar) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
local_isect->num_hits++;
if (local_isect->num_hits <= ctx->max_hits) {
hit_idx = local_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
if (hit_idx >= ctx->max_hits) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
}
else {
/* Record closest intersection only. */
if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
*args->valid = 0;
return;
}
local_isect->num_hits = 1;
}
/* record intersection */
local_isect->hits[hit_idx] = current_isect;
local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
const RTCRay *ray = (RTCRay *)args->ray;
RTCHit *hit = (RTCHit *)args->hit;
#if EMBREE_MAJOR_VERSION >= 4
CCLVolumeContext *ctx = (CCLVolumeContext *)(args->context);
#else
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
#endif
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
Intersection *isect = &ctx->vol_isect[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = isect->object;
int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
}
#if EMBREE_MAJOR_VERSION < 4
ccl_device_forceinline void kernel_embree_filter_occluded_func(
const RTCFilterFunctionNArguments *args)
{
/* Current implementation in Cycles assumes only single-ray intersection queries. */
assert(args->N == 1);
CCLIntersectContext *ctx = (CCLIntersectContext *)(args->context);
switch (ctx->type) {
case CCLIntersectContext::RAY_SHADOW_ALL: {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
/* If no transparent shadows or max number of hits exceeded, all light is blocked. */
const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
ctx->opaque_hit = true;
return;
}
++ctx->num_hits;
/* Always use baked shadow transparency for curves. */
if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
ctx->opaque_hit = true;
return;
}
else {
*args->valid = 0;
return;
}
}
/* Test if we need to record this transparent intersection. */
const numhit_t max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
if (ctx->num_recorded_hits < max_record_hits) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
numhit_t isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
numhit_t max_recorded_hit = numhit_t(0);
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
ray->tfar = max(current_isect.t, max_t);
}
integrator_state_write_shadow_isect(ctx->isect_s, &current_isect, isect_index);
}
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
++ctx->num_recorded_hits;
/* This tells Embree to continue tracing. */
*args->valid = 0;
case CCLIntersectContext::RAY_SHADOW_ALL:
kernel_embree_filter_occluded_shadow_all_func(args);
break;
}
case CCLIntersectContext::RAY_LOCAL:
case CCLIntersectContext::RAY_SSS: {
/* Check if it's hitting the correct object. */
Intersection current_isect;
if (ctx->type == CCLIntersectContext::RAY_SSS) {
kernel_embree_convert_sss_hit(kg,
ray,
hit,
&current_isect,
ctx->local_object_id,
reinterpret_cast<intptr_t>(args->geometryUserPtr));
}
else {
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (ctx->local_object_id != current_isect.object) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
}
if (intersection_skip_self_local(cray->self, current_isect.prim)) {
*args->valid = 0;
return;
}
/* No intersection information requested, just return a hit. */
if (ctx->max_hits == 0) {
break;
}
/* Ignore curves. */
if (EMBREE_IS_HAIR(hit->geomID)) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
break;
}
LocalIntersection *local_isect = ctx->local_isect;
int hit_idx = 0;
if (ctx->lcg_state) {
/* See triangle_intersect_subsurface() for the native equivalent. */
for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
if (local_isect->hits[i].t == ray->tfar) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
local_isect->num_hits++;
if (local_isect->num_hits <= ctx->max_hits) {
hit_idx = local_isect->num_hits - 1;
}
else {
/* reservoir sampling: if we are at the maximum number of
* hits, randomly replace element or skip it */
hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
if (hit_idx >= ctx->max_hits) {
/* This tells Embree to continue tracing. */
*args->valid = 0;
return;
}
}
}
else {
/* Record closest intersection only. */
if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
*args->valid = 0;
return;
}
local_isect->num_hits = 1;
}
/* record intersection */
local_isect->hits[hit_idx] = current_isect;
local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
/* This tells Embree to continue tracing. */
*args->valid = 0;
case CCLIntersectContext::RAY_SSS:
kernel_embree_filter_occluded_local_func(args);
break;
}
case CCLIntersectContext::RAY_VOLUME_ALL: {
/* Append the intersection to the end of the array. */
if (ctx->num_hits < ctx->max_hits) {
Intersection current_isect;
kernel_embree_convert_hit(
kg, ray, hit, &current_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
*args->valid = 0;
return;
}
Intersection *isect = &ctx->vol_isect[ctx->num_hits];
++ctx->num_hits;
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = isect->object;
int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
/* This tells Embree to continue tracing. */
*args->valid = 0;
}
case CCLIntersectContext::RAY_VOLUME_ALL:
kernel_embree_filter_occluded_volume_all_func(args);
break;
}
case CCLIntersectContext::RAY_REGULAR:
default:
if (kernel_embree_is_self_intersection(
kg, hit, cray, reinterpret_cast<intptr_t>(args->geometryUserPtr))) {
*args->valid = 0;
return;
}
/* We should never reach this point, because
* REGULAR intersection is handled in intersection filter. */
kernel_assert(false);
break;
}
}
@ -441,7 +544,7 @@ ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionN
return;
}
CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
CCLIntersectContext *ctx = ((CCLIntersectContext *)args->context);
const KernelGlobalsCPU *kg = ctx->kg;
const Ray *cray = ctx->ray;
@ -467,6 +570,8 @@ ccl_device void kernel_embree_filter_occluded_func_backface_cull(
kernel_embree_filter_occluded_func(args);
}
#endif
/* Scene intersection. */
ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg,
@ -475,12 +580,29 @@ ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg,
ccl_private Intersection *isect)
{
isect->t = ray->tmax;
#if EMBREE_MAJOR_VERSION >= 4
CCLFirstHitContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
#else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
IntersectContext rtc_ctx(&ctx);
rtcInitIntersectContext(&ctx);
#endif
RTCRayHit ray_hit;
ctx.ray = ray;
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
rtcIntersect1(kernel_data.device_bvh, &rtc_ctx.context, &ray_hit);
#if EMBREE_MAJOR_VERSION >= 4
RTCIntersectArguments args;
rtcInitIntersectArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_intersection_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcIntersect1(kernel_data.device_bvh, &ray_hit, &args);
#else
rtcIntersect1(kernel_data.device_bvh, &ctx, &ray_hit);
#endif
if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID) {
return false;
@ -500,8 +622,16 @@ ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
{
const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
SD_OBJECT_TRANSFORM_APPLIED);
# if EMBREE_MAJOR_VERSION >= 4
CCLLocalContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg,
has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
rtcInitIntersectContext(&ctx);
# endif
ctx.is_sss = has_bvh;
ctx.lcg_state = lcg_state;
ctx.max_hits = max_hits;
ctx.ray = ray;
@ -510,36 +640,49 @@ ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
local_isect->num_hits = 0;
}
ctx.local_object_id = local_object;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, PATH_RAY_ALL_VISIBILITY);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)(kernel_embree_filter_occluded_local_func);
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
# endif
/* If this object has its own BVH, use it. */
if (has_bvh) {
RTCGeometry geom = rtcGetGeometry(kernel_data.device_bvh, local_object * 2);
if (geom) {
float3 P = ray->P;
float3 dir = ray->D;
float3 idir = ray->D;
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
float3 P = ray->P;
float3 dir = ray->D;
float3 idir = ray->D;
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
rtc_ray.org_x = P.x;
rtc_ray.org_y = P.y;
rtc_ray.org_z = P.z;
rtc_ray.dir_x = dir.x;
rtc_ray.dir_y = dir.y;
rtc_ray.dir_z = dir.z;
rtc_ray.tnear = ray->tmin;
rtc_ray.tfar = ray->tmax;
RTCScene scene = (RTCScene)rtcGetGeometryUserData(geom);
kernel_assert(scene);
if (scene) {
rtcOccluded1(scene, &rtc_ctx.context, &rtc_ray);
}
rtc_ray.org_x = P.x;
rtc_ray.org_y = P.y;
rtc_ray.org_z = P.z;
rtc_ray.dir_x = dir.x;
rtc_ray.dir_y = dir.y;
rtc_ray.dir_z = dir.z;
rtc_ray.tnear = ray->tmin;
rtc_ray.tfar = ray->tmax;
RTCScene scene = (RTCScene)rtcGetGeometryUserDataFromScene(kernel_data.device_bvh,
local_object * 2);
kernel_assert(scene);
if (scene) {
# if EMBREE_MAJOR_VERSION >= 4
rtcOccluded1(scene, &rtc_ray, &args);
# else
rtcOccluded1(scene, &ctx, &rtc_ray);
# endif
}
}
else {
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
}
/* rtcOccluded1 sets tfar to -inf if a hit was found. */
@ -556,14 +699,32 @@ ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
ccl_private uint *num_recorded_hits,
ccl_private float *throughput)
{
# if EMBREE_MAJOR_VERSION >= 4
CCLShadowContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
rtcInitIntersectContext(&ctx);
# endif
ctx.num_hits = ctx.num_recorded_hits = numhit_t(0);
ctx.throughput = 1.0f;
ctx.opaque_hit = false;
ctx.isect_s = state;
ctx.max_hits = numhit_t(max_hits);
ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_occluded_shadow_all_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
*num_recorded_hits = ctx.num_recorded_hits;
*throughput = ctx.throughput;
@ -578,15 +739,30 @@ ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
const uint max_hits,
const uint visibility)
{
# if EMBREE_MAJOR_VERSION >= 4
CCLVolumeContext ctx;
rtcInitRayQueryContext(&ctx);
ctx.kg = kg;
# else
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
rtcInitIntersectContext(&ctx);
# endif
ctx.vol_isect = isect;
ctx.max_hits = numhit_t(max_hits);
ctx.num_hits = numhit_t(0);
ctx.ray = ray;
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
# if EMBREE_MAJOR_VERSION >= 4
RTCOccludedArguments args;
rtcInitOccludedArguments(&args);
args.filter = (RTCFilterFunctionN)kernel_embree_filter_occluded_volume_all_func;
args.feature_mask = CYCLES_EMBREE_USED_FEATURES;
args.context = &ctx;
rtcOccluded1(kernel_data.device_bvh, &rtc_ray, &args);
# else
rtcOccluded1(kernel_data.device_bvh, &ctx, &rtc_ray);
# endif
return ctx.num_hits;
}
#endif

View File

@ -74,57 +74,43 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
}
}
ccl_device_inline void motion_triangle_vertices(
KernelGlobals kg, int object, int prim, float time, float3 verts[3])
ccl_device_inline void motion_triangle_compute_info(KernelGlobals kg,
int object,
float time,
int prim,
ccl_private uint3 *tri_vindex,
ccl_private int *numsteps,
ccl_private int *numverts,
ccl_private int *step,
ccl_private float *t)
{
/* get motion info */
int numsteps, numverts;
object_motion_info(kg, object, &numsteps, &numverts, NULL);
/* figure out which steps we need to fetch and their interpolation factor */
int maxstep = numsteps * 2;
int step = min((int)(time * maxstep), maxstep - 1);
float t = time * maxstep - step;
/* find attribute */
int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* fetch vertex coordinates */
float3 next_verts[3];
uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
/* interpolate between steps */
verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
}
ccl_device_inline void motion_triangle_vertices_and_normals(
KernelGlobals kg, int object, int prim, float time, float3 verts[3], float3 normals[3])
{
/* get motion info */
int numsteps, numverts;
object_motion_info(kg, object, &numsteps, &numverts, NULL);
/* Get object motion info. */
object_motion_info(kg, object, numsteps, numverts, NULL);
/* Figure out which steps we need to fetch and their interpolation factor. */
int maxstep = numsteps * 2;
int step = min((int)(time * maxstep), maxstep - 1);
float t = time * maxstep - step;
int maxstep = *numsteps * 2;
*step = min((int)(time * maxstep), maxstep - 1);
*t = time * maxstep - *step;
/* Get triangle indices. */
*tri_vindex = kernel_data_fetch(tri_vindex, prim);
}
ccl_device_inline void motion_triangle_vertices(KernelGlobals kg,
int object,
uint3 tri_vindex,
int numsteps,
int numverts,
int step,
float t,
float3 verts[3])
{
/* Find attribute. */
int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* Fetch vertex coordinates. */
float3 next_verts[3];
uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
@ -132,60 +118,90 @@ ccl_device_inline void motion_triangle_vertices_and_normals(
verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
}
/* Compute smooth normal. */
ccl_device_inline void motion_triangle_vertices(
KernelGlobals kg, int object, int prim, float time, float3 verts[3])
{
int numsteps, numverts, step;
float t;
uint3 tri_vindex;
motion_triangle_compute_info(
kg, object, time, prim, &tri_vindex, &numsteps, &numverts, &step, &t);
motion_triangle_vertices(kg, object, tri_vindex, numsteps, numverts, step, t, verts);
}
ccl_device_inline void motion_triangle_normals(KernelGlobals kg,
int object,
uint3 tri_vindex,
int numsteps,
int numverts,
int step,
float t,
float3 normals[3])
{
/* Find attribute. */
offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* Fetch vertex coordinates. */
/* Fetch normals. */
float3 next_normals[3];
motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
/* Interpolate between steps. */
normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
normals[0] = normalize((1.0f - t) * normals[0] + t * next_normals[0]);
normals[1] = normalize((1.0f - t) * normals[1] + t * next_normals[1]);
normals[2] = normalize((1.0f - t) * normals[2] + t * next_normals[2]);
}
ccl_device_inline void motion_triangle_vertices_and_normals(
KernelGlobals kg, int object, int prim, float time, float3 verts[3], float3 normals[3])
{
int numsteps, numverts, step;
float t;
uint3 tri_vindex;
motion_triangle_compute_info(
kg, object, time, prim, &tri_vindex, &numsteps, &numverts, &step, &t);
motion_triangle_vertices(kg, object, tri_vindex, numsteps, numverts, step, t, verts);
motion_triangle_normals(kg, object, tri_vindex, numsteps, numverts, step, t, normals);
}
ccl_device_inline float3 motion_triangle_smooth_normal(KernelGlobals kg,
float3 Ng,
int object,
uint3 tri_vindex,
int numsteps,
int numverts,
int step,
float t,
float u,
float v)
{
float3 normals[3];
motion_triangle_normals(kg, object, tri_vindex, numsteps, numverts, step, t, normals);
/* Interpolate between normals. */
float w = 1.0f - u - v;
float3 N = safe_normalize(w * normals[0] + u * normals[1] + v * normals[2]);
return is_zero(N) ? Ng : N;
}
ccl_device_inline float3 motion_triangle_smooth_normal(
KernelGlobals kg, float3 Ng, int object, int prim, float u, float v, float time)
{
/* get motion info */
int numsteps, numverts;
object_motion_info(kg, object, &numsteps, &numverts, NULL);
int numsteps, numverts, step;
float t;
uint3 tri_vindex;
motion_triangle_compute_info(
kg, object, time, prim, &tri_vindex, &numsteps, &numverts, &step, &t);
/* figure out which steps we need to fetch and their interpolation factor */
int maxstep = numsteps * 2;
int step = min((int)(time * maxstep), maxstep - 1);
float t = time * maxstep - step;
/* find attribute */
int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_NORMAL);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* fetch normals */
float3 normals[3], next_normals[3];
uint3 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
/* interpolate between steps */
normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
/* interpolate between vertices */
float w = 1.0f - u - v;
float3 N = safe_normalize(u * normals[0] + v * normals[1] + w * normals[2]);
return is_zero(N) ? Ng : N;
return motion_triangle_smooth_normal(
kg, Ng, object, tri_vindex, numsteps, numverts, step, t, u, v);
}
CCL_NAMESPACE_END

View File

@ -32,30 +32,17 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
{
/* Get shader. */
sd->shader = kernel_data_fetch(tri_shader, sd->prim);
/* Get motion info. */
/* TODO(sergey): This logic is really similar to motion_triangle_vertices(),
* can we de-duplicate something here?
*/
int numsteps, numverts;
object_motion_info(kg, sd->object, &numsteps, &numverts, NULL);
/* Figure out which steps we need to fetch and their interpolation factor. */
int maxstep = numsteps * 2;
int step = min((int)(sd->time * maxstep), maxstep - 1);
float t = sd->time * maxstep - step;
/* Find attribute. */
int offset = intersection_find_attribute(kg, sd->object, ATTR_STD_MOTION_VERTEX_POSITION);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* Fetch vertex coordinates. */
float3 verts[3], next_verts[3];
uint3 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
/* Compute motion info. */
int numsteps, numverts, step;
float t;
uint3 tri_vindex;
motion_triangle_compute_info(
kg, sd->object, sd->time, sd->prim, &tri_vindex, &numsteps, &numverts, &step, &t);
float3 verts[3];
motion_triangle_vertices(kg, sd->object, tri_vindex, numsteps, numverts, step, t, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
/* Interpolate between steps. */
verts[0] = (1.0f - t) * verts[0] + t * next_verts[0];
verts[1] = (1.0f - t) * verts[1] + t * next_verts[1];
verts[2] = (1.0f - t) * verts[2] + t * next_verts[2];
/* Compute refined position. */
sd->P = motion_triangle_point_from_uv(kg, sd, isect_object, isect_prim, sd->u, sd->v, verts);
/* Compute face normal. */
@ -75,23 +62,8 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
#endif
/* Compute smooth normal. */
if (sd->shader & SHADER_SMOOTH_NORMAL) {
/* Find attribute. */
int offset = intersection_find_attribute(kg, sd->object, ATTR_STD_MOTION_VERTEX_NORMAL);
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* Fetch vertex coordinates. */
float3 normals[3], next_normals[3];
motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
kg, tri_vindex, offset, numverts, numsteps, step + 1, next_normals);
/* Interpolate between steps. */
normals[0] = (1.0f - t) * normals[0] + t * next_normals[0];
normals[1] = (1.0f - t) * normals[1] + t * next_normals[1];
normals[2] = (1.0f - t) * normals[2] + t * next_normals[2];
/* Interpolate between vertices. */
float u = sd->u;
float v = sd->v;
float w = 1.0f - u - v;
sd->N = (w * normals[0] + u * normals[1] + v * normals[2]);
sd->N = motion_triangle_smooth_normal(
kg, Ng, sd->object, tri_vindex, numsteps, numverts, step, t, sd->u, sd->v);
}
}

View File

@ -18,7 +18,7 @@ ccl_device_noinline int svm_node_tex_coord(KernelGlobals kg,
uint4 node,
int offset)
{
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;
@ -100,7 +100,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
int offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;
@ -185,7 +185,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
int offset)
{
#ifdef __RAY_DIFFERENTIALS__
float3 data;
float3 data = zero_float3();
uint type = node.y;
uint out_offset = node.z;

View File

@ -4,8 +4,13 @@
#pragma once
#if !defined(__KERNEL_GPU__) && defined(WITH_EMBREE)
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# if EMBREE_MAJOR_VERSION >= 4
# include <embree4/rtcore.h>
# include <embree4/rtcore_scene.h>
# else
# include <embree3/rtcore.h>
# include <embree3/rtcore_scene.h>
# endif
# define __EMBREE__
#endif

View File

@ -247,13 +247,16 @@ size_t CachedData::memory_used() const
static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
{
V3d scale, shear, rotation, translation;
extractSHRT(mtx,
scale,
shear,
rotation,
translation,
true,
IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
if (!extractSHRT(mtx,
scale,
shear,
rotation,
translation,
true,
IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY)) {
return mtx;
}
M44d rot_mat, scale_mat, trans_mat;
rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));

View File

@ -531,7 +531,7 @@ PrimitiveType Hair::primitive_type() const
/* Fill in coordinates for curve transparency shader evaluation on device. */
static int fill_shader_input(const Hair *hair,
const int object_index,
const size_t object_index,
device_vector<KernelShaderEvalInput> &d_input)
{
int d_input_size = 0;

View File

@ -86,7 +86,7 @@ ImageHandle::ImageHandle(const ImageHandle &other)
: tile_slots(other.tile_slots), manager(other.manager)
{
/* Increase image user count. */
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->add_image_user(slot);
}
}
@ -97,7 +97,7 @@ ImageHandle &ImageHandle::operator=(const ImageHandle &other)
manager = other.manager;
tile_slots = other.tile_slots;
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->add_image_user(slot);
}
@ -111,7 +111,7 @@ ImageHandle::~ImageHandle()
void ImageHandle::clear()
{
foreach (const int slot, tile_slots) {
foreach (const size_t slot, tile_slots) {
manager->remove_image_user(slot);
}
@ -165,7 +165,7 @@ vector<int4> ImageHandle::get_svm_slots() const
for (size_t i = 0; i < num_nodes; i++) {
int4 node;
int slot = tile_slots[2 * i];
size_t slot = tile_slots[2 * i];
node.x = manager->images[slot]->loader->get_tile_number();
node.y = slot;
@ -387,7 +387,7 @@ void ImageManager::load_image_metadata(Image *img)
ImageHandle ImageManager::add_image(const string &filename, const ImageParams &params)
{
const int slot = add_image_slot(new OIIOImageLoader(filename), params, false);
const size_t slot = add_image_slot(new OIIOImageLoader(filename), params, false);
ImageHandle handle;
handle.tile_slots.push_back(slot);
@ -408,13 +408,13 @@ ImageHandle ImageManager::add_image(const string &filename,
/* Since we don't have information about the exact tile format used in this code location,
* just attempt all replacement patterns that Blender supports. */
if (tile != 0) {
string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
string_replace(tile_filename, "<UDIM>", string_printf("%04d", (int)tile));
int u = ((tile - 1001) % 10);
int v = ((tile - 1001) / 10);
string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
}
const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
const size_t slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
handle.tile_slots.push_back(slot);
}
@ -425,7 +425,7 @@ ImageHandle ImageManager::add_image(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
{
const int slot = add_image_slot(loader, params, builtin);
const size_t slot = add_image_slot(loader, params, builtin);
ImageHandle handle;
handle.tile_slots.push_back(slot);
@ -438,7 +438,7 @@ ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
{
ImageHandle handle;
for (ImageLoader *loader : loaders) {
const int slot = add_image_slot(loader, params, true);
const size_t slot = add_image_slot(loader, params, true);
handle.tile_slots.push_back(slot);
}
@ -446,9 +446,9 @@ ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
return handle;
}
int ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
size_t ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
{
Image *img;
size_t slot;
@ -492,7 +492,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
return slot;
}
void ImageManager::add_image_user(int slot)
void ImageManager::add_image_user(size_t slot)
{
thread_scoped_lock device_lock(images_mutex);
Image *image = images[slot];
@ -501,7 +501,7 @@ void ImageManager::add_image_user(int slot)
image->users++;
}
void ImageManager::remove_image_user(int slot)
void ImageManager::remove_image_user(size_t slot)
{
thread_scoped_lock device_lock(images_mutex);
Image *image = images[slot];
@ -682,7 +682,7 @@ bool ImageManager::file_load_image(Image *img, int texture_limit)
return true;
}
void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Progress *progress)
void ImageManager::device_load_image(Device *device, Scene *scene, size_t slot, Progress *progress)
{
if (progress->get_cancel()) {
return;
@ -698,7 +698,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
ImageDataType type = img->metadata.type;
/* Name for debugging. */
img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), slot);
img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), (int)slot);
/* Free previous texture in slot. */
if (img->mem) {
@ -819,7 +819,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
img->need_load = false;
}
void ImageManager::device_free_image(Device *, int slot)
void ImageManager::device_free_image(Device *, size_t slot)
{
Image *img = images[slot];
if (img == NULL) {
@ -874,7 +874,10 @@ void ImageManager::device_update(Device *device, Scene *scene, Progress &progres
need_update_ = false;
}
void ImageManager::device_update_slot(Device *device, Scene *scene, int slot, Progress *progress)
void ImageManager::device_update_slot(Device *device,
Scene *scene,
size_t slot,
Progress *progress)
{
Image *img = images[slot];
assert(img != NULL);

View File

@ -156,7 +156,7 @@ class ImageHandle {
ImageManager *get_manager() const;
protected:
vector<int> tile_slots;
vector<size_t> tile_slots;
ImageManager *manager;
friend class ImageManager;
@ -179,7 +179,7 @@ class ImageManager {
ImageHandle add_image(const vector<ImageLoader *> &loaders, const ImageParams &params);
void device_update(Device *device, Scene *scene, Progress &progress);
void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
void device_update_slot(Device *device, Scene *scene, size_t slot, Progress *progress);
void device_free(Device *device);
void device_load_builtin(Device *device, Scene *scene, Progress &progress);
@ -223,17 +223,17 @@ class ImageManager {
vector<Image *> images;
void *osl_texture_system;
int add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
void add_image_user(int slot);
void remove_image_user(int slot);
size_t add_image_slot(ImageLoader *loader, const ImageParams &params, const bool builtin);
void add_image_user(size_t slot);
void remove_image_user(size_t slot);
void load_image_metadata(Image *img);
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
bool file_load_image(Image *img, int texture_limit);
void device_load_image(Device *device, Scene *scene, int slot, Progress *progress);
void device_free_image(Device *device, int slot);
void device_load_image(Device *device, Scene *scene, size_t slot, Progress *progress);
void device_free_image(Device *device, size_t slot);
friend class ImageHandle;
};

View File

@ -264,9 +264,9 @@ void LightManager::device_update_distribution(Device *,
/* Count emissive triangles. */
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
size_t mesh_num_triangles = mesh->num_triangles();
int mesh_num_triangles = static_cast<int>(mesh->num_triangles());
for (size_t i = 0; i < mesh_num_triangles; i++) {
for (int i = 0; i < mesh_num_triangles; i++) {
int shader_index = mesh->get_shader()[i];
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :

View File

@ -370,9 +370,11 @@ bool LightTree::should_split(LightTreeEmitter *emitters,
int &split_dim)
{
const int num_emitters = end - start;
if (num_emitters == 1) {
/* Do not try to split if there is only one emitter. */
measure = (emitters + start)->measure;
if (num_emitters < 2) {
if (num_emitters) {
/* Do not try to split if there is only one emitter. */
measure = (emitters + start)->measure;
}
return false;
}

View File

@ -35,7 +35,7 @@ static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts)
/* Fill in coordinates for mesh displacement shader evaluation on device. */
static int fill_shader_input(const Scene *scene,
const Mesh *mesh,
const int object_index,
const size_t object_index,
device_vector<KernelShaderEvalInput> &d_input)
{
int d_input_size = 0;

View File

@ -40,7 +40,7 @@ ccl_device_inline float half_to_float(half h_in)
* unsigned shorts. */
class half {
public:
half() : v(0) {}
half() = default;
half(const unsigned short &i) : v(i) {}
operator unsigned short()
{

View File

@ -14,62 +14,62 @@ set(INC_SYS
)
set(SRC
intern/GHOST_Buttons.cpp
intern/GHOST_C-api.cpp
intern/GHOST_CallbackEventConsumer.cpp
intern/GHOST_Context.cpp
intern/GHOST_ContextNone.cpp
intern/GHOST_DisplayManager.cpp
intern/GHOST_EventManager.cpp
intern/GHOST_ISystem.cpp
intern/GHOST_ISystemPaths.cpp
intern/GHOST_ModifierKeys.cpp
intern/GHOST_Path-api.cpp
intern/GHOST_PathUtils.cpp
intern/GHOST_Rect.cpp
intern/GHOST_System.cpp
intern/GHOST_TimerManager.cpp
intern/GHOST_Window.cpp
intern/GHOST_WindowManager.cpp
intern/GHOST_Buttons.cc
intern/GHOST_C-api.cc
intern/GHOST_CallbackEventConsumer.cc
intern/GHOST_Context.cc
intern/GHOST_ContextNone.cc
intern/GHOST_DisplayManager.cc
intern/GHOST_EventManager.cc
intern/GHOST_ISystem.cc
intern/GHOST_ISystemPaths.cc
intern/GHOST_ModifierKeys.cc
intern/GHOST_Path-api.cc
intern/GHOST_PathUtils.cc
intern/GHOST_Rect.cc
intern/GHOST_System.cc
intern/GHOST_TimerManager.cc
intern/GHOST_Window.cc
intern/GHOST_WindowManager.cc
GHOST_C-api.h
GHOST_IContext.h
GHOST_IEvent.h
GHOST_IEventConsumer.h
GHOST_ISystem.h
GHOST_ISystemPaths.h
GHOST_ITimerTask.h
GHOST_IWindow.h
GHOST_Path-api.h
GHOST_Rect.h
GHOST_IContext.hh
GHOST_IEvent.hh
GHOST_IEventConsumer.hh
GHOST_ISystem.hh
GHOST_ISystemPaths.hh
GHOST_ITimerTask.hh
GHOST_IWindow.hh
GHOST_Path-api.hh
GHOST_Rect.hh
GHOST_Types.h
intern/GHOST_Buttons.h
intern/GHOST_CallbackEventConsumer.h
intern/GHOST_Context.h
intern/GHOST_ContextNone.h
intern/GHOST_Debug.h
intern/GHOST_DisplayManager.h
intern/GHOST_Event.h
intern/GHOST_EventButton.h
intern/GHOST_EventCursor.h
intern/GHOST_EventDragnDrop.h
intern/GHOST_EventKey.h
intern/GHOST_EventManager.h
intern/GHOST_EventString.h
intern/GHOST_EventTrackpad.h
intern/GHOST_EventWheel.h
intern/GHOST_ModifierKeys.h
intern/GHOST_PathUtils.h
intern/GHOST_System.h
intern/GHOST_SystemPaths.h
intern/GHOST_TimerManager.h
intern/GHOST_TimerTask.h
intern/GHOST_Util.h
intern/GHOST_Window.h
intern/GHOST_WindowManager.h
intern/GHOST_utildefines.h
intern/GHOST_utildefines_variadic.h
intern/GHOST_Buttons.hh
intern/GHOST_CallbackEventConsumer.hh
intern/GHOST_Context.hh
intern/GHOST_ContextNone.hh
intern/GHOST_Debug.hh
intern/GHOST_DisplayManager.hh
intern/GHOST_Event.hh
intern/GHOST_EventButton.hh
intern/GHOST_EventCursor.hh
intern/GHOST_EventDragnDrop.hh
intern/GHOST_EventKey.hh
intern/GHOST_EventManager.hh
intern/GHOST_EventString.hh
intern/GHOST_EventTrackpad.hh
intern/GHOST_EventWheel.hh
intern/GHOST_ModifierKeys.hh
intern/GHOST_PathUtils.hh
intern/GHOST_System.hh
intern/GHOST_SystemPaths.hh
intern/GHOST_TimerManager.hh
intern/GHOST_TimerTask.hh
intern/GHOST_Util.hh
intern/GHOST_Window.hh
intern/GHOST_WindowManager.hh
intern/GHOST_utildefines.hh
intern/GHOST_utildefines_variadic.hh
)
set(LIB
@ -78,9 +78,9 @@ set(LIB
if(WITH_VULKAN_BACKEND)
list(APPEND SRC
intern/GHOST_ContextVK.cpp
intern/GHOST_ContextVK.cc
intern/GHOST_ContextVK.h
intern/GHOST_ContextVK.hh
)
list(APPEND INC_SYS
@ -98,9 +98,9 @@ endif()
if(WITH_GHOST_DEBUG)
list(APPEND SRC
intern/GHOST_EventPrinter.cpp
intern/GHOST_EventPrinter.cc
intern/GHOST_EventPrinter.h
intern/GHOST_EventPrinter.hh
)
add_definitions(-DWITH_GHOST_DEBUG)
endif()
@ -109,10 +109,10 @@ if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManager.cpp
intern/GHOST_NDOFManager.cc
intern/GHOST_EventNDOF.h
intern/GHOST_NDOFManager.h
intern/GHOST_EventNDOF.hh
intern/GHOST_NDOFManager.hh
)
list(APPEND INC_SYS
@ -124,24 +124,24 @@ if(WITH_INPUT_NDOF)
endif()
list(APPEND SRC
intern/GHOST_DisplayManagerNULL.h
intern/GHOST_SystemHeadless.h
intern/GHOST_WindowNULL.h
intern/GHOST_DisplayManagerNULL.hh
intern/GHOST_SystemHeadless.hh
intern/GHOST_WindowNULL.hh
)
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
elseif(WITH_GHOST_SDL)
list(APPEND SRC
intern/GHOST_ContextSDL.cpp
intern/GHOST_DisplayManagerSDL.cpp
intern/GHOST_SystemSDL.cpp
intern/GHOST_WindowSDL.cpp
intern/GHOST_ContextSDL.cc
intern/GHOST_DisplayManagerSDL.cc
intern/GHOST_SystemSDL.cc
intern/GHOST_WindowSDL.cc
intern/GHOST_ContextSDL.h
intern/GHOST_DisplayManagerSDL.h
intern/GHOST_SystemSDL.h
intern/GHOST_WindowSDL.h
intern/GHOST_ContextSDL.hh
intern/GHOST_DisplayManagerSDL.hh
intern/GHOST_SystemSDL.hh
intern/GHOST_WindowSDL.hh
)
add_definitions(-DWITH_GHOST_SDL)
@ -167,23 +167,23 @@ elseif(APPLE AND NOT WITH_GHOST_X11)
intern/GHOST_SystemCocoa.mm
intern/GHOST_WindowCocoa.mm
intern/GHOST_DisplayManagerCocoa.h
intern/GHOST_SystemCocoa.h
intern/GHOST_WindowCocoa.h
intern/GHOST_WindowViewCocoa.h
intern/GHOST_DisplayManagerCocoa.hh
intern/GHOST_SystemCocoa.hh
intern/GHOST_WindowCocoa.hh
intern/GHOST_WindowViewCocoa.hh
)
list(APPEND SRC
intern/GHOST_ContextCGL.mm
intern/GHOST_ContextCGL.h
intern/GHOST_ContextCGL.hh
)
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerCocoa.mm
intern/GHOST_NDOFManagerCocoa.h
intern/GHOST_NDOFManagerCocoa.hh
)
endif()
@ -199,22 +199,22 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
)
list(APPEND SRC
intern/GHOST_DisplayManagerX11.cpp
intern/GHOST_SystemX11.cpp
intern/GHOST_TaskbarX11.cpp
intern/GHOST_WindowX11.cpp
intern/GHOST_DisplayManagerX11.cc
intern/GHOST_SystemX11.cc
intern/GHOST_TaskbarX11.cc
intern/GHOST_WindowX11.cc
intern/GHOST_DisplayManagerX11.h
intern/GHOST_IconX11.h
intern/GHOST_SystemX11.h
intern/GHOST_TaskbarX11.h
intern/GHOST_WindowX11.h
intern/GHOST_DisplayManagerX11.hh
intern/GHOST_IconX11.hh
intern/GHOST_SystemX11.hh
intern/GHOST_TaskbarX11.hh
intern/GHOST_WindowX11.hh
)
list(APPEND SRC
intern/GHOST_ContextGLX.cpp
intern/GHOST_ContextGLX.cc
intern/GHOST_ContextGLX.h
intern/GHOST_ContextGLX.hh
)
if(WITH_GHOST_XDND)
@ -229,9 +229,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
)
list(APPEND SRC
intern/GHOST_DropTargetX11.cpp
intern/GHOST_DropTargetX11.cc
intern/GHOST_DropTargetX11.h
intern/GHOST_DropTargetX11.hh
)
endif()
@ -336,13 +336,13 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
endif()
list(APPEND SRC
intern/GHOST_SystemWayland.cpp
intern/GHOST_WindowWayland.cpp
intern/GHOST_SystemWayland.cc
intern/GHOST_WindowWayland.cc
intern/GHOST_SystemWayland.h
intern/GHOST_WaylandCursorSettings.h
intern/GHOST_WaylandUtils.h
intern/GHOST_WindowWayland.h
intern/GHOST_SystemWayland.hh
intern/GHOST_WaylandCursorSettings.hh
intern/GHOST_WaylandUtils.hh
intern/GHOST_WindowWayland.hh
)
set(INC_DST ${CMAKE_CURRENT_BINARY_DIR}/libwayland)
@ -441,9 +441,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerUnix.cpp
intern/GHOST_NDOFManagerUnix.cc
intern/GHOST_NDOFManagerUnix.h
intern/GHOST_NDOFManagerUnix.hh
)
endif()
@ -463,67 +463,67 @@ elseif(WIN32)
)
list(APPEND SRC
intern/GHOST_ContextD3D.cpp
intern/GHOST_DisplayManagerWin32.cpp
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
intern/GHOST_TrackpadWin32.cpp
intern/GHOST_WindowWin32.cpp
intern/GHOST_Wintab.cpp
intern/GHOST_ContextD3D.cc
intern/GHOST_DisplayManagerWin32.cc
intern/GHOST_DropTargetWin32.cc
intern/GHOST_SystemWin32.cc
intern/GHOST_TrackpadWin32.cc
intern/GHOST_WindowWin32.cc
intern/GHOST_Wintab.cc
intern/GHOST_ContextD3D.h
intern/GHOST_DisplayManagerWin32.h
intern/GHOST_DropTargetWin32.h
intern/GHOST_SystemWin32.h
intern/GHOST_TaskbarWin32.h
intern/GHOST_TrackpadWin32.h
intern/GHOST_WindowWin32.h
intern/GHOST_Wintab.h
intern/GHOST_ContextD3D.hh
intern/GHOST_DisplayManagerWin32.hh
intern/GHOST_DropTargetWin32.hh
intern/GHOST_SystemWin32.hh
intern/GHOST_TaskbarWin32.hh
intern/GHOST_TrackpadWin32.hh
intern/GHOST_WindowWin32.hh
intern/GHOST_Wintab.hh
)
list(APPEND SRC
intern/GHOST_ContextWGL.cpp
intern/GHOST_ContextWGL.cc
intern/GHOST_ContextWGL.h
intern/GHOST_ContextWGL.hh
)
if(WITH_INPUT_IME)
add_definitions(-DWITH_INPUT_IME)
list(APPEND SRC
intern/GHOST_ImeWin32.cpp
intern/GHOST_ImeWin32.cc
intern/GHOST_ImeWin32.h
intern/GHOST_ImeWin32.hh
)
endif()
if(WITH_INPUT_NDOF)
list(APPEND SRC
intern/GHOST_NDOFManagerWin32.cpp
intern/GHOST_NDOFManagerWin32.cc
intern/GHOST_NDOFManagerWin32.h
intern/GHOST_NDOFManagerWin32.hh
)
endif()
endif()
if(UNIX AND NOT APPLE)
list(APPEND SRC
intern/GHOST_ContextEGL.cpp
intern/GHOST_ContextEGL.cc
intern/GHOST_ContextEGL.h
intern/GHOST_ContextEGL.hh
)
endif()
if(APPLE)
list(APPEND SRC
intern/GHOST_SystemPathsCocoa.h
intern/GHOST_SystemPathsCocoa.hh
intern/GHOST_SystemPathsCocoa.mm
)
elseif(UNIX)
list(APPEND SRC
intern/GHOST_SystemPathsUnix.cpp
intern/GHOST_SystemPathsUnix.h
intern/GHOST_SystemPathsUnix.cc
intern/GHOST_SystemPathsUnix.hh
)
if(NOT WITH_INSTALL_PORTABLE)
@ -532,8 +532,8 @@ elseif(UNIX)
elseif(WIN32)
list(APPEND SRC
intern/GHOST_SystemPathsWin32.cpp
intern/GHOST_SystemPathsWin32.h
intern/GHOST_SystemPathsWin32.cc
intern/GHOST_SystemPathsWin32.hh
)
list(APPEND INC
@ -544,25 +544,25 @@ endif()
if(WITH_XR_OPENXR)
list(APPEND SRC
intern/GHOST_Xr.cpp
intern/GHOST_XrAction.cpp
intern/GHOST_XrContext.cpp
intern/GHOST_XrControllerModel.cpp
intern/GHOST_XrEvent.cpp
intern/GHOST_XrGraphicsBinding.cpp
intern/GHOST_XrSession.cpp
intern/GHOST_XrSwapchain.cpp
intern/GHOST_Xr.cc
intern/GHOST_XrAction.cc
intern/GHOST_XrContext.cc
intern/GHOST_XrControllerModel.cc
intern/GHOST_XrEvent.cc
intern/GHOST_XrGraphicsBinding.cc
intern/GHOST_XrSession.cc
intern/GHOST_XrSwapchain.cc
GHOST_IXrContext.h
intern/GHOST_IXrGraphicsBinding.h
intern/GHOST_XrAction.h
intern/GHOST_XrContext.h
intern/GHOST_XrControllerModel.h
intern/GHOST_XrException.h
intern/GHOST_XrSession.h
intern/GHOST_XrSwapchain.h
intern/GHOST_Xr_intern.h
intern/GHOST_Xr_openxr_includes.h
GHOST_IXrContext.hh
intern/GHOST_IXrGraphicsBinding.hh
intern/GHOST_XrAction.hh
intern/GHOST_XrContext.hh
intern/GHOST_XrControllerModel.hh
intern/GHOST_XrException.hh
intern/GHOST_XrSession.hh
intern/GHOST_XrSwapchain.hh
intern/GHOST_Xr_intern.hh
intern/GHOST_Xr_openxr_includes.hh
# Header only library.
../../extern/tinygltf/tiny_gltf.h

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_IEvent.h"
#include "GHOST_IEvent.hh"
/**
* Interface class for objects interested in receiving events.

View File

@ -12,9 +12,9 @@
#include <stdlib.h>
#include "GHOST_IContext.h"
#include "GHOST_ITimerTask.h"
#include "GHOST_IWindow.h"
#include "GHOST_IContext.hh"
#include "GHOST_ITimerTask.hh"
#include "GHOST_IWindow.hh"
#include "GHOST_Types.h"
class GHOST_IEventConsumer;
@ -77,12 +77,12 @@ class GHOST_IEventConsumer;
*
* \subsection cplusplus_api The C++ API consists of the following files:
*
* - GHOST_IEvent.h
* - GHOST_IEventConsumer.h
* - GHOST_ISystem.h
* - GHOST_ITimerTask.h
* - GHOST_IWindow.h
* - GHOST_Rect.h
* - GHOST_IEvent.hh
* - GHOST_IEventConsumer.hh
* - GHOST_ISystem.hh
* - GHOST_ITimerTask.hh
* - GHOST_IWindow.hh
* - GHOST_Rect.hh
* - GHOST_Types.h
*
* For an example of using the C++-API, have a look at the GHOST_C-Test.cpp

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_Rect.h"
#include "GHOST_Rect.hh"
#include "GHOST_Types.h"
#include <stdlib.h>

View File

@ -5,7 +5,7 @@
* \ingroup GHOST
*/
#include "GHOST_Buttons.h"
#include "GHOST_Buttons.hh"
GHOST_Buttons::GHOST_Buttons()
{

View File

@ -11,16 +11,16 @@
#include <cstring>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_ISystem.h"
#include "intern/GHOST_Debug.h"
#include "GHOST_IEvent.hh"
#include "GHOST_IEventConsumer.hh"
#include "GHOST_ISystem.hh"
#include "intern/GHOST_Debug.hh"
#ifdef WITH_XR_OPENXR
# include "GHOST_IXrContext.h"
# include "intern/GHOST_XrSession.h"
# include "GHOST_IXrContext.hh"
# include "intern/GHOST_XrSession.hh"
#endif
#include "intern/GHOST_CallbackEventConsumer.h"
#include "intern/GHOST_XrException.h"
#include "intern/GHOST_CallbackEventConsumer.hh"
#include "intern/GHOST_XrException.hh"
GHOST_SystemHandle GHOST_CreateSystem(void)
{

View File

@ -9,9 +9,9 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
#include "GHOST_CallbackEventConsumer.h"
#include "GHOST_CallbackEventConsumer.hh"
#include "GHOST_C-api.h"
#include "GHOST_Debug.h"
#include "GHOST_Debug.hh"
GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProcPtr eventCallback,
GHOST_TUserDataPtr userData)

View File

@ -9,7 +9,7 @@
#pragma once
#include "GHOST_C-api.h"
#include "GHOST_IEventConsumer.h"
#include "GHOST_IEventConsumer.hh"
/**
* Event consumer that will forward events to a call-back routine.

View File

@ -7,7 +7,7 @@
* Definition of GHOST_Context class.
*/
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#ifdef _WIN32
# include <epoxy/wgl.h>

View File

@ -8,7 +8,7 @@
#pragma once
#include "GHOST_IContext.h"
#include "GHOST_IContext.hh"
#include "GHOST_Types.h"
#include <epoxy/gl.h>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <Cocoa/Cocoa.h>
#include <Metal/Metal.h>

View File

@ -13,7 +13,7 @@
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "GHOST_ContextCGL.h"
#include "GHOST_ContextCGL.hh"
#include <Cocoa/Cocoa.h>
#include <Metal/Metal.h>

View File

@ -12,8 +12,8 @@
#include <epoxy/wgl.h>
#include "GHOST_ContextD3D.h"
#include "GHOST_ContextWGL.h" /* For shared drawing */
#include "GHOST_ContextD3D.hh"
#include "GHOST_ContextWGL.hh" /* For shared drawing */
HMODULE GHOST_ContextD3D::s_d3d_lib = NULL;
PFN_D3D11_CREATE_DEVICE GHOST_ContextD3D::s_D3D11CreateDeviceFn = NULL;

View File

@ -12,7 +12,7 @@
#include <D3D11.h>
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
class GHOST_ContextD3D : public GHOST_Context {
/* XR code needs low level graphics data to send to OpenXR. */

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextEGL class.
*/
#include "GHOST_ContextEGL.h"
#include "GHOST_ContextEGL.hh"
#include <set>
#include <sstream>

View File

@ -7,8 +7,8 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_System.h"
#include "GHOST_Context.hh"
#include "GHOST_System.hh"
#include <epoxy/egl.h>
#include <epoxy/gl.h>

View File

@ -7,8 +7,8 @@
* Definition of GHOST_ContextGLX class.
*/
#include "GHOST_ContextGLX.h"
#include "GHOST_SystemX11.h"
#include "GHOST_ContextGLX.hh"
#include "GHOST_SystemX11.hh"
#include <vector>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <epoxy/glx.h>

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextNone class.
*/
#include "GHOST_ContextNone.h"
#include "GHOST_ContextNone.hh"
GHOST_TSuccess GHOST_ContextNone::swapBuffers()
{

View File

@ -9,7 +9,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
class GHOST_ContextNone : public GHOST_Context {
public:

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextSDL class.
*/
#include "GHOST_ContextSDL.h"
#include "GHOST_ContextSDL.hh"
#include <vector>

View File

@ -7,7 +7,7 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
extern "C" {
#include "SDL.h"

View File

@ -4,7 +4,7 @@
* \ingroup GHOST
*/
#include "GHOST_ContextVK.h"
#include "GHOST_ContextVK.hh"
#ifdef _WIN32
# include <vulkan/vulkan_win32.h>

View File

@ -6,16 +6,16 @@
#pragma once
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#ifdef _WIN32
# include "GHOST_SystemWin32.h"
# include "GHOST_SystemWin32.hh"
#elif defined(__APPLE__)
# include "GHOST_SystemCocoa.h"
# include "GHOST_SystemCocoa.hh"
#else
# include "GHOST_SystemX11.h"
# include "GHOST_SystemX11.hh"
# ifdef WITH_GHOST_WAYLAND
# include "GHOST_SystemWayland.h"
# include "GHOST_SystemWayland.hh"
# else
# define wl_surface void
# define wl_display void

View File

@ -7,7 +7,7 @@
* Definition of GHOST_ContextWGL class.
*/
#include "GHOST_ContextWGL.h"
#include "GHOST_ContextWGL.hh"
#include <tchar.h>

View File

@ -9,7 +9,7 @@
//#define WIN32_COMPOSITING
#include "GHOST_Context.h"
#include "GHOST_Context.hh"
#include <epoxy/wgl.h>

View File

@ -9,8 +9,8 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
#include "GHOST_DisplayManager.h"
#include "GHOST_Debug.h"
#include "GHOST_DisplayManager.hh"
#include "GHOST_Debug.hh"
GHOST_DisplayManager::GHOST_DisplayManager() : m_settingsInitialized(false) {}

Some files were not shown because too many files have changed in this diff Show More