Compare commits
139 Commits
temp-noise
...
cycles_tex
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c5b56a525c | ||
![]() |
34e8d79c3e | ||
![]() |
465fb31ed2 | ||
![]() |
0a2c10e4f0 | ||
![]() |
e6599787eb | ||
![]() |
5fa0ec97c6 | ||
![]() |
18ecdde359 | ||
![]() |
3002f66362 | ||
0bbeb24fe6 | |||
ee37819cfb | |||
a650d18821 | |||
0c5d8f4ea5 | |||
81ba70facb | |||
2aebfa8b4b | |||
![]() |
22cfab5a55 | ||
d19176765d | |||
01a0699cdc | |||
82e1420b11 | |||
29d0570ec6 | |||
79f5281d4f | |||
bcbe639396 | |||
de7d37db69 | |||
5cf73f8b4a | |||
4f95a89960 | |||
d74d0bb239 | |||
985d005b93 | |||
8a30944e43 | |||
c949c8dc16 | |||
a353aeb532 | |||
3391e679ac | |||
c038247fcf | |||
ddef5df62a | |||
6ca59bb60c | |||
16750942da | |||
f9bc8c8ac5 | |||
2577e31889 | |||
988fb85960 | |||
8d1c3ceb54 | |||
![]() |
ced72034d5 | ||
04a18ea6de | |||
baa4c054df | |||
![]() |
cd7a1042bf | ||
![]() |
9e4e797491 | ||
4993a0e7ef | |||
65787ca4c9 | |||
![]() |
711f521e42 | ||
![]() |
ad7deefc62 | ||
![]() |
745ad6d311 | ||
![]() |
87040ce007 | ||
![]() |
e8566adf91 | ||
![]() |
6db39d36cb | ||
![]() |
44f99b0357 | ||
![]() |
540de41cc3 | ||
![]() |
ac9326a263 | ||
![]() |
1991012527 | ||
![]() |
c3cc89ebaa | ||
![]() |
3bf94a6d04 | ||
![]() |
84139622a7 | ||
![]() |
4199738997 | ||
![]() |
7111a40b4f | ||
![]() |
0c0868a5da | ||
![]() |
df596132f3 | ||
![]() |
195c664716 | ||
![]() |
12bc88cfdf | ||
![]() |
cef7fbf50f | ||
![]() |
d6e34e4825 | ||
![]() |
49ece61195 | ||
de75be1eaa | |||
![]() |
7ec3dff04d | ||
![]() |
bc99c2bceb | ||
![]() |
267038756b | ||
![]() |
ffa55fbfdd | ||
![]() |
cf6eb9a7f2 | ||
![]() |
6a5dc7124b | ||
![]() |
7be7f1a884 | ||
![]() |
ddb90691fd | ||
![]() |
287adc8eba | ||
![]() |
c9fcc2cdab | ||
![]() |
5e0eed8958 | ||
![]() |
36f9a9694d | ||
![]() |
8600c7f9ef | ||
![]() |
6568074b94 | ||
![]() |
80bcd2cffb | ||
![]() |
b178cc0a9e | ||
![]() |
98a1c684cd | ||
![]() |
e9ad3f4356 | ||
![]() |
e3067641c3 | ||
![]() |
53700beb09 | ||
![]() |
bfa29bb704 | ||
![]() |
0c7aaf9545 | ||
![]() |
c367153c6c | ||
![]() |
2fd6efed5e | ||
![]() |
c00925cac5 | ||
![]() |
b56be6e73c | ||
![]() |
c174ad09f9 | ||
![]() |
60da3f4ca6 | ||
![]() |
295944b49e | ||
![]() |
e17430d00d | ||
![]() |
66e571dfad | ||
![]() |
c987f6e6e1 | ||
![]() |
20825728f2 | ||
![]() |
d85c76e7b9 | ||
![]() |
697600e784 | ||
![]() |
92bf11548d | ||
![]() |
ecdc2f7108 | ||
![]() |
f363d080ca | ||
![]() |
3d11353856 | ||
![]() |
baf66bfa48 | ||
![]() |
a8e32a86e5 | ||
![]() |
15e5f06f38 | ||
![]() |
6d47a91220 | ||
![]() |
6450e35a2f | ||
![]() |
443b91aebe | ||
![]() |
1bcad0d920 | ||
![]() |
34e28c29b6 | ||
![]() |
2925298d96 | ||
![]() |
693667b85e | ||
![]() |
7c61f79e4d | ||
![]() |
9341dac223 | ||
![]() |
9d1417d210 | ||
![]() |
cf1ecb86a9 | ||
![]() |
e437bab5d8 | ||
![]() |
101b248174 | ||
![]() |
9525996321 | ||
![]() |
c553041b81 | ||
![]() |
280fc52ba2 | ||
![]() |
183a706239 | ||
![]() |
ef65e1c823 | ||
![]() |
4d0f9d07eb | ||
![]() |
8b54b957f7 | ||
![]() |
d04b16bb84 | ||
![]() |
5faa6893e3 | ||
![]() |
c5bce9ce8e | ||
![]() |
0c49eaaf3b | ||
![]() |
0820ee4a04 | ||
![]() |
2052b3d5c2 | ||
![]() |
0f61e96161 | ||
![]() |
8946dc52ed | ||
![]() |
db34c9eceb |
@@ -1598,7 +1598,8 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
ADD_CHECK_C_COMPILER_FLAG(C_WARNINGS C_WARN_UNUSED_PARAMETER -Wunused-parameter)
|
||||
|
||||
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_ALL -Wall)
|
||||
# Using C++20 features while having C++17 as the project language isn't allowed by MSVC.
|
||||
# Designated initializer is a C++20 feature & breaks MSVC build. Dropping MSVC 2019 or
|
||||
# updating to C++20 allows removing this.
|
||||
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_CXX20_DESIGNATOR -Wc++20-designator)
|
||||
|
||||
ADD_CHECK_CXX_COMPILER_FLAG(CXX_WARNINGS CXX_WARN_NO_AUTOLOGICAL_COMPARE -Wno-tautological-compare)
|
||||
|
@@ -151,8 +151,8 @@ if(MSVC_CLANG) # Clangs version of cl doesn't support all flags
|
||||
string(APPEND CMAKE_CXX_FLAGS " ${CXX_WARN_FLAGS} /nologo /J /Gd /EHsc -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference ")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd -Wno-unused-command-line-argument -Wno-microsoft-enum-forward-reference")
|
||||
else()
|
||||
string(APPEND CMAKE_CXX_FLAGS " /nologo /J /Gd /MP /EHsc /bigobj /Zc:inline")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP /bigobj /Zc:inline")
|
||||
string(APPEND CMAKE_CXX_FLAGS " /nologo /J /Gd /MP /EHsc /bigobj")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP /bigobj")
|
||||
endif()
|
||||
|
||||
# X64 ASAN is available and usable on MSVC 16.9 preview 4 and up)
|
||||
@@ -259,7 +259,7 @@ if(NOT DEFINED LIBDIR)
|
||||
else()
|
||||
message(FATAL_ERROR "32 bit compiler detected, blender no longer provides pre-build libraries for 32 bit windows, please set the LIBDIR cmake variable to your own library folder")
|
||||
endif()
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.30.30423)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.29.30130)
|
||||
message(STATUS "Visual Studio 2022 detected.")
|
||||
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
|
||||
elseif(MSVC_VERSION GREATER 1919)
|
||||
|
@@ -51,9 +51,9 @@ buildbot:
|
||||
gcc:
|
||||
version: '9.0.0'
|
||||
cuda10:
|
||||
version: '10.1.243'
|
||||
version: '10.1.0'
|
||||
cuda11:
|
||||
version: '11.4.1'
|
||||
version: '11.4.0'
|
||||
optix:
|
||||
version: '7.1.0'
|
||||
cmake:
|
||||
|
@@ -31,7 +31,6 @@ def parse_arguments():
|
||||
parser.add_argument("--no-submodules", action="store_true")
|
||||
parser.add_argument("--use-tests", action="store_true")
|
||||
parser.add_argument("--svn-command", default="svn")
|
||||
parser.add_argument("--svn-branch", default=None)
|
||||
parser.add_argument("--git-command", default="git")
|
||||
parser.add_argument("--use-centos-libraries", action="store_true")
|
||||
return parser.parse_args()
|
||||
@@ -47,7 +46,7 @@ def svn_update(args, release_version):
|
||||
svn_non_interactive = [args.svn_command, '--non-interactive']
|
||||
|
||||
lib_dirpath = os.path.join(get_blender_git_root(), '..', 'lib')
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version, args.svn_branch)
|
||||
svn_url = make_utils.svn_libraries_base_url(release_version)
|
||||
|
||||
# Checkout precompiled libraries
|
||||
if sys.platform == 'darwin':
|
||||
@@ -171,28 +170,26 @@ def submodules_update(args, release_version, branch):
|
||||
sys.stderr.write("git not found, can't update code\n")
|
||||
sys.exit(1)
|
||||
|
||||
# Update submodules to appropriate given branch,
|
||||
# falling back to master if none is given and/or found in a sub-repository.
|
||||
branch_fallback = "master"
|
||||
if not branch:
|
||||
branch = branch_fallback
|
||||
# Update submodules to latest master or appropriate release branch.
|
||||
if not release_version:
|
||||
branch = "master"
|
||||
|
||||
submodules = [
|
||||
("release/scripts/addons", branch, branch_fallback),
|
||||
("release/scripts/addons_contrib", branch, branch_fallback),
|
||||
("release/datafiles/locale", branch, branch_fallback),
|
||||
("source/tools", branch, branch_fallback),
|
||||
("release/scripts/addons", branch),
|
||||
("release/scripts/addons_contrib", branch),
|
||||
("release/datafiles/locale", branch),
|
||||
("source/tools", branch),
|
||||
]
|
||||
|
||||
# Initialize submodules only if needed.
|
||||
for submodule_path, submodule_branch, submodule_branch_fallback in submodules:
|
||||
for submodule_path, submodule_branch in submodules:
|
||||
if not os.path.exists(os.path.join(submodule_path, ".git")):
|
||||
call([args.git_command, "submodule", "update", "--init", "--recursive"])
|
||||
break
|
||||
|
||||
# Checkout appropriate branch and pull changes.
|
||||
skip_msg = ""
|
||||
for submodule_path, submodule_branch, submodule_branch_fallback in submodules:
|
||||
for submodule_path, submodule_branch in submodules:
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
os.chdir(submodule_path)
|
||||
@@ -204,11 +201,6 @@ def submodules_update(args, release_version, branch):
|
||||
call([args.git_command, "fetch", "origin"])
|
||||
call([args.git_command, "checkout", submodule_branch])
|
||||
call([args.git_command, "pull", "--rebase", "origin", submodule_branch])
|
||||
# If we cannot find the specified branch for this submodule, fallback to default one (aka master).
|
||||
if make_utils.git_branch(args.git_command) != submodule_branch:
|
||||
call([args.git_command, "fetch", "origin"])
|
||||
call([args.git_command, "checkout", submodule_branch_fallback])
|
||||
call([args.git_command, "pull", "--rebase", "origin", submodule_branch_fallback])
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
||||
|
@@ -70,11 +70,9 @@ def git_branch_release_version(branch, tag):
|
||||
return release_version
|
||||
|
||||
|
||||
def svn_libraries_base_url(release_version, branch):
|
||||
def svn_libraries_base_url(release_version):
|
||||
if release_version:
|
||||
svn_branch = "tags/blender-" + release_version + "-release"
|
||||
elif branch:
|
||||
svn_branch = "branches/" + branch
|
||||
else:
|
||||
svn_branch = "trunk"
|
||||
return "https://svn.blender.org/svnroot/bf-blender/" + svn_branch + "/lib/"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
if EXIST "%PYTHON%" (
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
|
@@ -1039,17 +1039,13 @@ context_type_map = {
|
||||
# context_member: (RNA type, is_collection)
|
||||
"active_annotation_layer": ("GPencilLayer", False),
|
||||
"active_bone": ("EditBone", False),
|
||||
"active_file": ("FileSelectEntry", False),
|
||||
"active_gpencil_frame": ("GreasePencilLayer", True),
|
||||
"active_gpencil_layer": ("GPencilLayer", True),
|
||||
"active_node": ("Node", False),
|
||||
"active_object": ("Object", False),
|
||||
"active_operator": ("Operator", False),
|
||||
"active_pose_bone": ("PoseBone", False),
|
||||
"active_sequence_strip": ("Sequence", False),
|
||||
"active_editable_fcurve": ("FCurve", False),
|
||||
"active_nla_strip": ("NlaStrip", False),
|
||||
"active_nla_track": ("NlaTrack", False),
|
||||
"annotation_data": ("GreasePencil", False),
|
||||
"annotation_data_owner": ("ID", False),
|
||||
"armature": ("Armature", False),
|
||||
@@ -1078,7 +1074,6 @@ context_type_map = {
|
||||
"gpencil_data": ("GreasePencil", False),
|
||||
"gpencil_data_owner": ("ID", False),
|
||||
"hair": ("Hair", False),
|
||||
"id": ("ID", False),
|
||||
"image_paint_object": ("Object", False),
|
||||
"lattice": ("Lattice", False),
|
||||
"light": ("Light", False),
|
||||
@@ -1107,7 +1102,6 @@ context_type_map = {
|
||||
"selected_editable_keyframes": ("Keyframe", True),
|
||||
"selected_editable_objects": ("Object", True),
|
||||
"selected_editable_sequences": ("Sequence", True),
|
||||
"selected_files": ("FileSelectEntry", True),
|
||||
"selected_nla_strips": ("NlaStrip", True),
|
||||
"selected_nodes": ("Node", True),
|
||||
"selected_objects": ("Object", True),
|
||||
@@ -1204,7 +1198,6 @@ def pycontext2sphinx(basepath):
|
||||
"text_context_dir",
|
||||
"clip_context_dir",
|
||||
"sequencer_context_dir",
|
||||
"file_context_dir",
|
||||
)
|
||||
|
||||
unique = set()
|
||||
@@ -2002,7 +1995,7 @@ def write_rst_importable_modules(basepath):
|
||||
"blf": "Font Drawing",
|
||||
"imbuf": "Image Buffer",
|
||||
"imbuf.types": "Image Buffer Types",
|
||||
"gpu": "GPU Module",
|
||||
"gpu": "GPU Shader Module",
|
||||
"gpu.types": "GPU Types",
|
||||
"gpu.matrix": "GPU Matrix Utilities",
|
||||
"gpu.select": "GPU Select Utilities",
|
||||
|
2
extern/mantaflow/UPDATE.sh
vendored
2
extern/mantaflow/UPDATE.sh
vendored
@@ -8,7 +8,7 @@
|
||||
|
||||
# YOUR INSTALLATION PATHS GO HERE:
|
||||
MANTA_INSTALLATION=/Users/sebbas/Developer/Mantaflow/mantaflowDevelop
|
||||
BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender
|
||||
BLENDER_INSTALLATION=/Users/sebbas/Developer/Blender/fluid-mantaflow
|
||||
|
||||
# Try to check out Mantaflow repository before building?
|
||||
CLEAN_REPOSITORY=0
|
||||
|
@@ -28,13 +28,11 @@ extern PyTypeObject PbVec3Type;
|
||||
extern PyTypeObject PbVec4Type;
|
||||
|
||||
struct PbVec3 {
|
||||
PyObject_HEAD
|
||||
float data[3];
|
||||
PyObject_HEAD float data[3];
|
||||
};
|
||||
|
||||
struct PbVec4 {
|
||||
PyObject_HEAD
|
||||
float data[4];
|
||||
PyObject_HEAD float data[4];
|
||||
};
|
||||
|
||||
PyObject *getPyNone()
|
||||
|
6
extern/mantaflow/helper/pwrapper/pvec3.cpp
vendored
6
extern/mantaflow/helper/pwrapper/pvec3.cpp
vendored
@@ -25,8 +25,7 @@ namespace Manta {
|
||||
extern PyTypeObject PbVec3Type;
|
||||
|
||||
struct PbVec3 {
|
||||
PyObject_HEAD
|
||||
float data[3];
|
||||
PyObject_HEAD float data[3];
|
||||
};
|
||||
|
||||
static void PbVec3Dealloc(PbVec3 *self)
|
||||
@@ -294,8 +293,7 @@ inline PyObject *castPy(PyTypeObject *p)
|
||||
extern PyTypeObject PbVec4Type;
|
||||
|
||||
struct PbVec4 {
|
||||
PyObject_HEAD
|
||||
float data[4];
|
||||
PyObject_HEAD float data[4];
|
||||
};
|
||||
|
||||
static PyMethodDef PbVec4Methods[] = {
|
||||
|
@@ -76,8 +76,7 @@ struct ClassData {
|
||||
};
|
||||
|
||||
struct PbObject {
|
||||
PyObject_HEAD
|
||||
Manta::PbClass *instance;
|
||||
PyObject_HEAD Manta::PbClass *instance;
|
||||
ClassData *classdef;
|
||||
};
|
||||
|
||||
|
202
extern/mantaflow/preprocessed/fastmarch.cpp
vendored
202
extern/mantaflow/preprocessed/fastmarch.cpp
vendored
@@ -874,136 +874,6 @@ static const Vec3i nb[6] = {Vec3i(1, 0, 0),
|
||||
Vec3i(0, 0, 1),
|
||||
Vec3i(0, 0, -1)};
|
||||
|
||||
struct knMarkSkipCells : public KernelBase {
|
||||
knMarkSkipCells(Grid<Real> &phi, Grid<int> &tmp, bool inside)
|
||||
: KernelBase(&phi, 1), phi(phi), tmp(tmp), inside(inside)
|
||||
{
|
||||
runMessage();
|
||||
run();
|
||||
}
|
||||
inline void op(int i, int j, int k, Grid<Real> &phi, Grid<int> &tmp, bool inside) const
|
||||
{
|
||||
if (!inside && phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
if (inside && phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
inline Grid<Real> &getArg0()
|
||||
{
|
||||
return phi;
|
||||
}
|
||||
typedef Grid<Real> type0;
|
||||
inline Grid<int> &getArg1()
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
typedef Grid<int> type1;
|
||||
inline bool &getArg2()
|
||||
{
|
||||
return inside;
|
||||
}
|
||||
typedef bool type2;
|
||||
void runMessage()
|
||||
{
|
||||
debMsg("Executing kernel knMarkSkipCells ", 3);
|
||||
debMsg("Kernel range"
|
||||
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||||
4);
|
||||
};
|
||||
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||||
{
|
||||
const int _maxX = maxX;
|
||||
const int _maxY = maxY;
|
||||
if (maxZ > 1) {
|
||||
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||||
for (int j = 1; j < _maxY; j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, phi, tmp, inside);
|
||||
}
|
||||
else {
|
||||
const int k = 0;
|
||||
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, phi, tmp, inside);
|
||||
}
|
||||
}
|
||||
void run()
|
||||
{
|
||||
if (maxZ > 1)
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||||
else
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
|
||||
}
|
||||
Grid<Real> φ
|
||||
Grid<int> &tmp;
|
||||
bool inside;
|
||||
};
|
||||
|
||||
struct knSetFirstLayer : public KernelBase {
|
||||
knSetFirstLayer(Grid<int> &tmp, int dim) : KernelBase(&tmp, 1), tmp(tmp), dim(dim)
|
||||
{
|
||||
runMessage();
|
||||
run();
|
||||
}
|
||||
inline void op(int i, int j, int k, Grid<int> &tmp, int dim) const
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
return;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline Grid<int> &getArg0()
|
||||
{
|
||||
return tmp;
|
||||
}
|
||||
typedef Grid<int> type0;
|
||||
inline int &getArg1()
|
||||
{
|
||||
return dim;
|
||||
}
|
||||
typedef int type1;
|
||||
void runMessage()
|
||||
{
|
||||
debMsg("Executing kernel knSetFirstLayer ", 3);
|
||||
debMsg("Kernel range"
|
||||
<< " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
|
||||
4);
|
||||
};
|
||||
void operator()(const tbb::blocked_range<IndexInt> &__r) const
|
||||
{
|
||||
const int _maxX = maxX;
|
||||
const int _maxY = maxY;
|
||||
if (maxZ > 1) {
|
||||
for (int k = __r.begin(); k != (int)__r.end(); k++)
|
||||
for (int j = 1; j < _maxY; j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, tmp, dim);
|
||||
}
|
||||
else {
|
||||
const int k = 0;
|
||||
for (int j = __r.begin(); j != (int)__r.end(); j++)
|
||||
for (int i = 1; i < _maxX; i++)
|
||||
op(i, j, k, tmp, dim);
|
||||
}
|
||||
}
|
||||
void run()
|
||||
{
|
||||
if (maxZ > 1)
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
|
||||
else
|
||||
tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
|
||||
}
|
||||
Grid<int> &tmp;
|
||||
int dim;
|
||||
};
|
||||
|
||||
template<class S> struct knExtrapolateLsSimple : public KernelBase {
|
||||
knExtrapolateLsSimple(Grid<S> &val, int distance, Grid<int> &tmp, const int d, S direction)
|
||||
: KernelBase(&val, 1), val(val), distance(distance), tmp(tmp), d(d), direction(direction)
|
||||
@@ -1173,12 +1043,39 @@ void extrapolateLsSimple(Grid<Real> &phi, int distance = 4, bool inside = false)
|
||||
tmp.clear();
|
||||
const int dim = (phi.is3D() ? 3 : 2);
|
||||
|
||||
// by default, march outside (ie mark all inside to be skipped)
|
||||
Real direction = (inside) ? -1. : 1.;
|
||||
knMarkSkipCells(phi, tmp, inside);
|
||||
|
||||
// by default, march outside
|
||||
Real direction = 1.;
|
||||
if (!inside) {
|
||||
// mark all inside
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
direction = -1.;
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// + first layer around
|
||||
knSetFirstLayer(tmp, dim);
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
continue;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
n = 2 * dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// extrapolate for distance
|
||||
for (int d = 2; d < 1 + distance; ++d) {
|
||||
@@ -1229,12 +1126,37 @@ void extrapolateVec3Simple(Grid<Vec3> &vel, Grid<Real> &phi, int distance = 4, b
|
||||
tmp.clear();
|
||||
const int dim = (vel.is3D() ? 3 : 2);
|
||||
|
||||
// mark initial cells, by default, march outside (ie mark all inside to be skipped)
|
||||
Real direction = (inside) ? -1. : 1.;
|
||||
knMarkSkipCells(phi, tmp, inside);
|
||||
|
||||
// mark initial cells, by default, march outside
|
||||
if (!inside) {
|
||||
// mark all inside
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) < 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
FOR_IJK_BND(phi, 1)
|
||||
{
|
||||
if (phi(i, j, k) > 0.) {
|
||||
tmp(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// + first layer next to initial cells
|
||||
knSetFirstLayer(tmp, dim);
|
||||
FOR_IJK_BND(vel, 1)
|
||||
{
|
||||
Vec3i p(i, j, k);
|
||||
if (tmp(p))
|
||||
continue;
|
||||
for (int n = 0; n < 2 * dim; ++n) {
|
||||
if (tmp(p + nb[n]) == 1) {
|
||||
tmp(i, j, k) = 2;
|
||||
n = 2 * dim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int d = 2; d < 1 + distance; ++d) {
|
||||
knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.));
|
||||
|
2
extern/mantaflow/preprocessed/gitinfo.h
vendored
2
extern/mantaflow/preprocessed/gitinfo.h
vendored
@@ -1,3 +1,3 @@
|
||||
|
||||
|
||||
#define MANTA_GIT_VERSION "commit d5d9a6c28daa8f21426d7a285f48639c0d8fd13f"
|
||||
#define MANTA_GIT_VERSION "commit 8fbebe02459b7f72575872c20961f7cb757db408"
|
||||
|
@@ -60,108 +60,9 @@
|
||||
# define JE_FORCE_SYNC_COMPARE_AND_SWAP_8
|
||||
#endif
|
||||
|
||||
/* Define the `ATOMIC_FORCE_USE_FALLBACK` to force lock-based fallback implementation to be used
|
||||
* (even on platforms where there is native implementation available via compiler.
|
||||
* Useful for development purposes. */
|
||||
#undef ATOMIC_FORCE_USE_FALLBACK
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Spin-lock implementation
|
||||
*
|
||||
* Used to implement atomics on unsupported platforms.
|
||||
* The spin implementation is shared for all platforms to make sure it compiles and tested.
|
||||
* \{ */
|
||||
|
||||
typedef struct AtomicSpinLock {
|
||||
volatile int lock;
|
||||
|
||||
/* Pad the structure size to a cache-line, to avoid unwanted sharing with other data. */
|
||||
int pad[32 - sizeof(int)];
|
||||
} __attribute__((aligned(32))) AtomicSpinLock;
|
||||
|
||||
ATOMIC_INLINE void atomic_spin_lock(volatile AtomicSpinLock *lock)
|
||||
{
|
||||
while (__sync_lock_test_and_set(&lock->lock, 1)) {
|
||||
while (lock->lock) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ATOMIC_INLINE void atomic_spin_unlock(volatile AtomicSpinLock *lock)
|
||||
{
|
||||
__sync_lock_release(&lock->lock);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Common part of locking fallback implementation
|
||||
* \{ */
|
||||
|
||||
/* Global lock, shared by all atomic operations implementations.
|
||||
*
|
||||
* Could be split into per-size locks, although added complexity and being more error-proone does
|
||||
* not seem to worth it for a fall-back implementation. */
|
||||
static _ATOMIC_MAYBE_UNUSED AtomicSpinLock _atomic_global_lock = {0};
|
||||
|
||||
#define ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, _op_name, _op) \
|
||||
ATOMIC_INLINE _type##_t atomic_##_op_name##_and_fetch_##_type(_type##_t *p, _type##_t x) \
|
||||
{ \
|
||||
atomic_spin_lock(&_atomic_global_lock); \
|
||||
const _type##_t original_value = *(p); \
|
||||
const _type##_t new_value = original_value _op(x); \
|
||||
*(p) = new_value; \
|
||||
atomic_spin_unlock(&_atomic_global_lock); \
|
||||
return new_value; \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, _op_name, _op) \
|
||||
ATOMIC_INLINE _type##_t atomic_fetch_and_##_op_name##_##_type(_type##_t *p, _type##_t x) \
|
||||
{ \
|
||||
atomic_spin_lock(&_atomic_global_lock); \
|
||||
const _type##_t original_value = *(p); \
|
||||
*(p) = original_value _op(x); \
|
||||
atomic_spin_unlock(&_atomic_global_lock); \
|
||||
return original_value; \
|
||||
}
|
||||
|
||||
#define ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(_type) \
|
||||
ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, add, +)
|
||||
|
||||
#define ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(_type) \
|
||||
ATOMIC_LOCKING_OP_AND_FETCH_DEFINE(_type, sub, -)
|
||||
|
||||
#define ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(_type) \
|
||||
ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, add, +)
|
||||
|
||||
#define ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(_type) \
|
||||
ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, sub, -)
|
||||
|
||||
#define ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(_type) ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, or, |)
|
||||
|
||||
#define ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(_type) \
|
||||
ATOMIC_LOCKING_FETCH_AND_OP_DEFINE(_type, and, &)
|
||||
|
||||
#define ATOMIC_LOCKING_CAS_DEFINE(_type) \
|
||||
ATOMIC_INLINE _type##_t atomic_cas_##_type(_type##_t *v, _type##_t old, _type##_t _new) \
|
||||
{ \
|
||||
atomic_spin_lock(&_atomic_global_lock); \
|
||||
const _type##_t original_value = *v; \
|
||||
if (*v == old) { \
|
||||
*v = _new; \
|
||||
} \
|
||||
atomic_spin_unlock(&_atomic_global_lock); \
|
||||
return original_value; \
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name 64-bit operations
|
||||
* \{ */
|
||||
|
||||
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
|
||||
/******************************************************************************/
|
||||
/* 64-bit operations. */
|
||||
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
@@ -214,7 +115,7 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
|
||||
return __sync_val_compare_and_swap(v, old, _new);
|
||||
}
|
||||
|
||||
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && (defined(__amd64__) || defined(__x86_64__))
|
||||
#elif (defined(__amd64__) || defined(__x86_64__))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
|
||||
{
|
||||
@@ -289,36 +190,12 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
|
||||
/* Unsigned */
|
||||
|
||||
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(uint64)
|
||||
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint64)
|
||||
|
||||
ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(uint64)
|
||||
ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(uint64)
|
||||
|
||||
ATOMIC_LOCKING_CAS_DEFINE(uint64)
|
||||
|
||||
/* Signed */
|
||||
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int64)
|
||||
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int64)
|
||||
|
||||
ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(int64)
|
||||
ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(int64)
|
||||
|
||||
ATOMIC_LOCKING_CAS_DEFINE(int64)
|
||||
|
||||
# error "Missing implementation for 64-bit atomic operations"
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name 32-bit operations
|
||||
* \{ */
|
||||
|
||||
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
|
||||
/******************************************************************************/
|
||||
/* 32-bit operations. */
|
||||
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
@@ -351,8 +228,7 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
|
||||
return __sync_val_compare_and_swap(v, old, _new);
|
||||
}
|
||||
|
||||
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
|
||||
#elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
@@ -410,25 +286,10 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Unsigned */
|
||||
|
||||
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(uint32)
|
||||
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint32)
|
||||
|
||||
ATOMIC_LOCKING_CAS_DEFINE(uint32)
|
||||
|
||||
/* Signed */
|
||||
|
||||
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int32)
|
||||
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int32)
|
||||
|
||||
ATOMIC_LOCKING_CAS_DEFINE(int32)
|
||||
|
||||
# error "Missing implementation for 32-bit atomic operations"
|
||||
#endif
|
||||
|
||||
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
|
||||
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
|
||||
{
|
||||
@@ -462,27 +323,12 @@ ATOMIC_INLINE int32_t atomic_fetch_and_and_int32(int32_t *p, int32_t x)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Unsigned */
|
||||
ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(uint32)
|
||||
ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(uint32)
|
||||
ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(uint32)
|
||||
|
||||
/* Signed */
|
||||
ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE(int32)
|
||||
ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int32)
|
||||
ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int32)
|
||||
|
||||
# error "Missing implementation for 32-bit atomic operations"
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name 16-bit operations
|
||||
* \{ */
|
||||
|
||||
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_2))
|
||||
/******************************************************************************/
|
||||
/* 16-bit operations. */
|
||||
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_2))
|
||||
|
||||
/* Signed */
|
||||
ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t b)
|
||||
@@ -495,21 +341,12 @@ ATOMIC_INLINE int16_t atomic_fetch_and_or_int16(int16_t *p, int16_t b)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int16)
|
||||
ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int16)
|
||||
|
||||
# error "Missing implementation for 16-bit atomic operations"
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name 8-bit operations
|
||||
* \{ */
|
||||
|
||||
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
|
||||
(defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1))
|
||||
|
||||
/******************************************************************************/
|
||||
/* 8-bit operations. */
|
||||
#if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_1))
|
||||
/* Unsigned */
|
||||
ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b)
|
||||
{
|
||||
@@ -531,27 +368,7 @@ ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Unsigned */
|
||||
ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(uint8)
|
||||
ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(uint8)
|
||||
|
||||
/* Signed */
|
||||
ATOMIC_LOCKING_FETCH_AND_AND_DEFINE(int8)
|
||||
ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
|
||||
|
||||
# error "Missing implementation for 8-bit atomic operations"
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
#undef ATOMIC_LOCKING_OP_AND_FETCH_DEFINE
|
||||
#undef ATOMIC_LOCKING_FETCH_AND_OP_DEFINE
|
||||
#undef ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE
|
||||
#undef ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE
|
||||
#undef ATOMIC_LOCKING_FETCH_AND_ADD_DEFINE
|
||||
#undef ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE
|
||||
#undef ATOMIC_LOCKING_FETCH_AND_OR_DEFINE
|
||||
#undef ATOMIC_LOCKING_FETCH_AND_AND_DEFINE
|
||||
#undef ATOMIC_LOCKING_CAS_DEFINE
|
||||
|
||||
#endif /* __ATOMIC_OPS_UNIX_H__ */
|
||||
|
@@ -64,11 +64,9 @@
|
||||
#ifdef __GNUC__
|
||||
# define _ATOMIC_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define _ATOMIC_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define _ATOMIC_MAYBE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
# define _ATOMIC_LIKELY(x) (x)
|
||||
# define _ATOMIC_UNLIKELY(x) (x)
|
||||
# define _ATOMIC_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(__SIZEOF_POINTER__)
|
||||
|
@@ -808,6 +808,82 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
items=enum_texture_limit
|
||||
)
|
||||
|
||||
use_texture_cache: BoolProperty(
|
||||
name="Use Texture Cache",
|
||||
default=False,
|
||||
description="Enables out-of-core texturing to conserve RAM"
|
||||
)
|
||||
|
||||
texture_cache_size: IntProperty(
|
||||
name="Texture Cache Size (MB)",
|
||||
default=1024,
|
||||
description="The size of the OpenImageIO texture cache in MB",
|
||||
min=0
|
||||
)
|
||||
|
||||
texture_auto_convert: BoolProperty(
|
||||
name="Auto Convert Textures",
|
||||
default=True,
|
||||
description="Automatically convert textures to .tx files for optimal texture cache performance"
|
||||
)
|
||||
|
||||
texture_accept_unmipped: BoolProperty(
|
||||
name="Accept Unmipped",
|
||||
default=True,
|
||||
description="Texture cached rendering without mip mapping is very expensive. Uncheck to prevent Cycles from using textures that are not mip mapped"
|
||||
)
|
||||
|
||||
texture_accept_untiled: BoolProperty(
|
||||
name="Accept Untiled",
|
||||
default=True,
|
||||
description="Texture cached rendering without tiled textures is very expensive. Uncheck to prevent Cycles from using textures that are not tiled"
|
||||
)
|
||||
|
||||
texture_auto_tile: BoolProperty(
|
||||
name="Auto Tile",
|
||||
default=True,
|
||||
description="On the fly creation of tiled versions of textures that are not tiled. This can increase render time but helps reduce memory usage"
|
||||
)
|
||||
|
||||
texture_auto_mip: BoolProperty(
|
||||
name="Auto Mip",
|
||||
default=True,
|
||||
description="On the fly creation of mip maps of textures that are not mip mapped. This can increase render time but helps reduce memory usage"
|
||||
)
|
||||
|
||||
texture_tile_size: IntProperty(
|
||||
name="Tile Size",
|
||||
default=64,
|
||||
description="The size of tiles that Cycles uses for auto tiling"
|
||||
)
|
||||
|
||||
texture_blur_diffuse: FloatProperty(
|
||||
name="Diffuse Blur",
|
||||
default=0.0156,
|
||||
description="The amount of texture blur applied to diffuse bounces",
|
||||
min = 0.0, max = 1.0
|
||||
)
|
||||
|
||||
texture_blur_glossy: FloatProperty(
|
||||
name="Glossy Blur",
|
||||
default=0.0,
|
||||
description="The amount of texture blur applied to glossy bounces",
|
||||
min = 0.0, max = 1.0
|
||||
)
|
||||
|
||||
use_custom_cache_path: BoolProperty(
|
||||
name="Use Custom Cache Path",
|
||||
default=False,
|
||||
description="Use a custom path for the texture cache, as oppoosed to placing cache files next to the original file"
|
||||
)
|
||||
|
||||
custom_cache_path: StringProperty(
|
||||
name="Custom Cache Path",
|
||||
default="",
|
||||
subtype="DIR_PATH",
|
||||
description="Custom path for the texture cache"
|
||||
)
|
||||
|
||||
use_fast_gi: BoolProperty(
|
||||
name="Fast GI Approximation",
|
||||
description="Approximate diffuse indirect light with background tinted ambient occlusion. This provides fast alternative to full global illumination, for interactive viewport rendering or final renders with reduced quality",
|
||||
|
@@ -781,6 +781,40 @@ class CYCLES_RENDER_PT_performance_final_render(CyclesButtonsPanel, Panel):
|
||||
col.prop(rd, "use_save_buffers")
|
||||
col.prop(rd, "use_persistent_data", text="Persistent Data")
|
||||
|
||||
class CYCLES_RENDER_PT_texture_cache(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Texture Cache"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
cscene = context.scene.cycles
|
||||
|
||||
self.layout.prop(cscene, "use_texture_cache", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
cscene = scene.cycles
|
||||
rd = scene.render
|
||||
layout.active = cscene.use_texture_cache
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
col.prop(cscene, "texture_auto_convert")
|
||||
col.prop(cscene, "texture_accept_unmipped")
|
||||
col.prop(cscene, "texture_accept_untiled")
|
||||
col.prop(cscene, "texture_auto_mip")
|
||||
col.prop(cscene, "texture_auto_tile")
|
||||
col = split.column()
|
||||
col.prop(cscene, "texture_cache_size")
|
||||
col.prop(cscene, "texture_tile_size")
|
||||
col.prop(cscene, "texture_blur_diffuse")
|
||||
col.prop(cscene, "texture_blur_glossy")
|
||||
row = layout.row()
|
||||
row.prop(cscene, "use_custom_cache_path")
|
||||
row = layout.row()
|
||||
row.active = cscene.use_custom_cache_path
|
||||
row.prop(cscene, "custom_cache_path")
|
||||
|
||||
class CYCLES_RENDER_PT_performance_viewport(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Viewport"
|
||||
@@ -2307,6 +2341,7 @@ classes = (
|
||||
CYCLES_RENDER_PT_performance_acceleration_structure,
|
||||
CYCLES_RENDER_PT_performance_final_render,
|
||||
CYCLES_RENDER_PT_performance_viewport,
|
||||
CYCLES_RENDER_PT_texture_cache,
|
||||
CYCLES_RENDER_PT_passes,
|
||||
CYCLES_RENDER_PT_passes_data,
|
||||
CYCLES_RENDER_PT_passes_light,
|
||||
|
@@ -526,13 +526,8 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
|
||||
|
||||
/* Old particle hair. */
|
||||
void BlenderSync::sync_particle_hair(
|
||||
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step)
|
||||
{
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
BL::Object b_ob = b_ob_info.real_object;
|
||||
|
||||
/* obtain general settings */
|
||||
if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
|
||||
return;
|
||||
@@ -793,10 +788,10 @@ static void export_hair_curves_motion(Hair *hair, BL::Hair b_hair, int motion_st
|
||||
}
|
||||
|
||||
/* Hair object. */
|
||||
void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
|
||||
{
|
||||
/* Convert Blender hair to Cycles curves. */
|
||||
BL::Hair b_hair(b_ob_info.object_data);
|
||||
BL::Hair b_hair(b_ob.data());
|
||||
if (motion) {
|
||||
export_hair_curves_motion(hair, b_hair, motion_step);
|
||||
}
|
||||
@@ -805,16 +800,16 @@ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int
|
||||
}
|
||||
}
|
||||
#else
|
||||
void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
|
||||
void BlenderSync::sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step)
|
||||
{
|
||||
(void)hair;
|
||||
(void)b_ob_info;
|
||||
(void)b_ob;
|
||||
(void)motion;
|
||||
(void)motion_step;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
|
||||
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair)
|
||||
{
|
||||
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
|
||||
* attributes */
|
||||
@@ -824,19 +819,19 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, H
|
||||
new_hair.set_used_shaders(used_shaders);
|
||||
|
||||
if (view_layer.use_hair) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR) {
|
||||
/* Hair object. */
|
||||
sync_hair(&new_hair, b_ob_info, false);
|
||||
sync_hair(&new_hair, b_ob, false);
|
||||
}
|
||||
else {
|
||||
/* Particle hair. */
|
||||
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob_info, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
|
||||
b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE);
|
||||
|
||||
if (b_mesh) {
|
||||
sync_particle_hair(&new_hair, b_mesh, b_ob_info, false);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
sync_particle_hair(&new_hair, b_mesh, b_ob, false);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -864,7 +859,7 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, H
|
||||
}
|
||||
|
||||
void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object b_ob,
|
||||
Hair *hair,
|
||||
int motion_step)
|
||||
{
|
||||
@@ -874,19 +869,18 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
|
||||
/* Export deformed coordinates. */
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair)) {
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR) {
|
||||
/* Hair object. */
|
||||
sync_hair(hair, b_ob_info, true, motion_step);
|
||||
sync_hair(hair, b_ob, true, motion_step);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* Particle hair. */
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
if (b_mesh) {
|
||||
sync_particle_hair(hair, b_mesh, b_ob_info, true, motion_step);
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
sync_particle_hair(hair, b_mesh, b_ob, true, motion_step);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -29,15 +29,13 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
|
||||
static Geometry::Type determine_geom_type(BL::Object &b_ob, bool use_particle_hair)
|
||||
{
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
return Geometry::HAIR;
|
||||
}
|
||||
|
||||
if (b_ob_info.object_data.is_a(&RNA_Volume) ||
|
||||
(b_ob_info.object_data == b_ob_info.real_object.data() &&
|
||||
object_fluid_gas_domain_find(b_ob_info.real_object))) {
|
||||
if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
return Geometry::VOLUME;
|
||||
}
|
||||
|
||||
@@ -73,17 +71,20 @@ array<Node *> BlenderSync::find_used_shaders(BL::Object &b_ob)
|
||||
}
|
||||
|
||||
Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool)
|
||||
{
|
||||
/* Test if we can instance or if the object is modified. */
|
||||
Geometry::Type geom_type = determine_geom_type(b_ob_info, use_particle_hair);
|
||||
GeometryKey key(b_ob_info.object_data, geom_type);
|
||||
BL::ID b_ob_data = b_ob.data();
|
||||
BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data;
|
||||
Geometry::Type geom_type = determine_geom_type(b_ob, use_particle_hair);
|
||||
GeometryKey key(b_key_id.ptr.data, geom_type);
|
||||
|
||||
/* Find shader indices. */
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob_info.iter_object);
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob);
|
||||
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = geometry_map.find(key);
|
||||
@@ -110,7 +111,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
else {
|
||||
/* Test if we need to update existing geometry. */
|
||||
sync = geometry_map.update(geom, b_ob_info.object_data);
|
||||
sync = geometry_map.update(geom, b_key_id);
|
||||
}
|
||||
|
||||
if (!sync) {
|
||||
@@ -143,7 +144,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
geometry_synced.insert(geom);
|
||||
|
||||
geom->name = ustring(b_ob_info.object_data.name().c_str());
|
||||
geom->name = ustring(b_ob_data.name().c_str());
|
||||
|
||||
/* Store the shaders immediately for the object attribute code. */
|
||||
geom->set_used_shaders(used_shaders);
|
||||
@@ -152,19 +153,19 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
progress.set_sync_status("Synchronizing object", b_ob_info.real_object.name());
|
||||
progress.set_sync_status("Synchronizing object", b_ob.name());
|
||||
|
||||
if (geom_type == Geometry::HAIR) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair(b_depsgraph, b_ob_info, hair);
|
||||
sync_hair(b_depsgraph, b_ob, hair);
|
||||
}
|
||||
else if (geom_type == Geometry::VOLUME) {
|
||||
Volume *volume = static_cast<Volume *>(geom);
|
||||
sync_volume(b_ob_info, volume);
|
||||
sync_volume(b_ob, volume);
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh(b_depsgraph, b_ob_info, mesh);
|
||||
sync_mesh(b_depsgraph, b_ob, mesh);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -180,7 +181,7 @@ Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
|
||||
void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair,
|
||||
@@ -189,10 +190,8 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
/* Ensure we only sync instanced geometry once. */
|
||||
Geometry *geom = object->get_geometry();
|
||||
|
||||
if (geometry_motion_synced.find(geom) != geometry_motion_synced.end() ||
|
||||
geometry_motion_attribute_synced.find(geom) != geometry_motion_attribute_synced.end()) {
|
||||
if (geometry_motion_synced.find(geom) != geometry_motion_synced.end())
|
||||
return;
|
||||
}
|
||||
|
||||
geometry_motion_synced.insert(geom);
|
||||
|
||||
@@ -211,17 +210,16 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
if (b_ob_info.object_data.is_a(&RNA_Hair) || use_particle_hair) {
|
||||
if (b_ob.type() == BL::Object::type_HAIR || use_particle_hair) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
|
||||
sync_hair_motion(b_depsgraph, b_ob, hair, motion_step);
|
||||
}
|
||||
else if (b_ob_info.object_data.is_a(&RNA_Volume) ||
|
||||
object_fluid_gas_domain_find(b_ob_info.real_object)) {
|
||||
else if (b_ob.type() == BL::Object::type_VOLUME || object_fluid_gas_domain_find(b_ob)) {
|
||||
/* No volume motion blur support yet. */
|
||||
}
|
||||
else {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
sync_mesh_motion(b_depsgraph, b_ob_info, mesh, motion_step);
|
||||
sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -27,14 +27,15 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
int random_id,
|
||||
Transform &tfm,
|
||||
bool *use_portal)
|
||||
{
|
||||
/* test if we need to sync */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, false);
|
||||
BL::Light b_light(b_ob_info.object_data);
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_instance, false);
|
||||
BL::Light b_light(b_ob.data());
|
||||
|
||||
Light *light = light_map.find(key);
|
||||
|
||||
@@ -43,7 +44,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
const bool tfm_updated = (light && light->get_tfm() != tfm);
|
||||
|
||||
/* Update if either object or light data changed. */
|
||||
if (!light_map.add_or_update(&light, b_ob_info.real_object, b_parent, key) && !tfm_updated) {
|
||||
if (!light_map.add_or_update(&light, b_ob, b_parent, key) && !tfm_updated) {
|
||||
Shader *shader;
|
||||
if (!shader_map.add_or_update(&shader, b_light)) {
|
||||
if (light->get_is_portal())
|
||||
@@ -138,11 +139,11 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
|
||||
light->set_max_bounces(get_int(clight, "max_bounces"));
|
||||
|
||||
if (b_ob_info.real_object != b_ob_info.iter_object) {
|
||||
if (b_ob != b_ob_instance) {
|
||||
light->set_random_id(random_id);
|
||||
}
|
||||
else {
|
||||
light->set_random_id(hash_uint2(hash_string(b_ob_info.real_object.name().c_str()), 0));
|
||||
light->set_random_id(hash_uint2(hash_string(b_ob.name().c_str()), 0));
|
||||
}
|
||||
|
||||
if (light->get_light_type() == LIGHT_AREA)
|
||||
@@ -154,7 +155,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
*use_portal = true;
|
||||
|
||||
/* visibility */
|
||||
uint visibility = object_ray_visibility(b_ob_info.real_object);
|
||||
uint visibility = object_ray_visibility(b_ob);
|
||||
light->set_use_diffuse((visibility & PATH_RAY_DIFFUSE) != 0);
|
||||
light->set_use_glossy((visibility & PATH_RAY_GLOSSY) != 0);
|
||||
light->set_use_transmission((visibility & PATH_RAY_TRANSMIT) != 0);
|
||||
|
@@ -347,57 +347,16 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
|
||||
}
|
||||
}
|
||||
|
||||
static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale)
|
||||
{
|
||||
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
|
||||
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
|
||||
const int numverts = mesh->get_verts().size();
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
const float relative_time = motion_times[step] * 0.5f * motion_scale;
|
||||
float3 *mP = attr_mP->data_float3() + step * numverts;
|
||||
|
||||
for (int i = 0; i < numverts; i++) {
|
||||
mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void attr_create_generic(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh &b_mesh,
|
||||
const bool subdivision,
|
||||
const bool need_motion,
|
||||
const float motion_scale)
|
||||
static void attr_create_generic(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
|
||||
{
|
||||
if (subdivision) {
|
||||
/* TODO: Handle subdivision correctly. */
|
||||
return;
|
||||
}
|
||||
AttributeSet &attributes = mesh->attributes;
|
||||
static const ustring u_velocity("velocity");
|
||||
|
||||
for (BL::Attribute &b_attribute : b_mesh.attributes) {
|
||||
const ustring name{b_attribute.name().c_str()};
|
||||
|
||||
if (need_motion && name == u_velocity) {
|
||||
attr_create_motion(mesh, b_attribute, motion_scale);
|
||||
}
|
||||
|
||||
if (!mesh->need_attribute(scene, name)) {
|
||||
continue;
|
||||
}
|
||||
@@ -900,10 +859,8 @@ static void create_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh &b_mesh,
|
||||
const array<Node *> &used_shaders,
|
||||
const bool need_motion,
|
||||
const float motion_scale,
|
||||
const bool subdivision = false,
|
||||
const bool subdivide_uvs = true)
|
||||
bool subdivision = false,
|
||||
bool subdivide_uvs = true)
|
||||
{
|
||||
/* count vertices and faces */
|
||||
int numverts = b_mesh.vertices.length();
|
||||
@@ -1017,7 +974,7 @@ static void create_mesh(Scene *scene,
|
||||
attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
|
||||
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
|
||||
attr_create_generic(scene, mesh, b_mesh, subdivision);
|
||||
|
||||
if (subdivision) {
|
||||
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs);
|
||||
@@ -1042,20 +999,16 @@ static void create_mesh(Scene *scene,
|
||||
|
||||
static void create_subd_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
BL::Mesh &b_mesh,
|
||||
const array<Node *> &used_shaders,
|
||||
const bool need_motion,
|
||||
const float motion_scale,
|
||||
float dicing_rate,
|
||||
int max_subdivisions)
|
||||
{
|
||||
BL::Object b_ob = b_ob_info.real_object;
|
||||
|
||||
BL::SubsurfModifier subsurf_mod(b_ob.modifiers[b_ob.modifiers.length() - 1]);
|
||||
bool subdivide_uvs = subsurf_mod.uv_smooth() != BL::SubsurfModifier::uv_smooth_NONE;
|
||||
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, true, subdivide_uvs);
|
||||
|
||||
/* export creases */
|
||||
size_t num_creases = 0;
|
||||
@@ -1090,7 +1043,7 @@ static void create_subd_mesh(Scene *scene,
|
||||
*
|
||||
* NOTE: This code is run prior to object motion blur initialization. so can not access properties
|
||||
* set by `sync_object_motion_init()`. */
|
||||
static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
static bool mesh_need_motion_attribute(BL::Object &b_ob, Scene *scene)
|
||||
{
|
||||
const Scene::MotionType need_motion = scene->need_motion();
|
||||
if (need_motion == Scene::MOTION_NONE) {
|
||||
@@ -1107,7 +1060,7 @@ static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
* - Motion attribute expects non-zero time steps.
|
||||
*
|
||||
* Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
const bool use_motion = get_boolean(cobject, "use_motion_blur");
|
||||
if (!use_motion) {
|
||||
return false;
|
||||
@@ -1119,7 +1072,92 @@ static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
|
||||
static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *mesh)
|
||||
{
|
||||
if (!mesh_need_motion_attribute(b_ob, scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
|
||||
|
||||
if (!b_mesh_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MeshSequenceCacheModifier_read_velocity_get(&b_mesh_cache.ptr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t numverts = mesh->get_verts().size();
|
||||
|
||||
if (b_mesh_cache.vertex_velocities.length() != numverts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
const float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
|
||||
float3 *mP = attr_mP->data_float3() + step * numverts;
|
||||
|
||||
BL::MeshSequenceCacheModifier::vertex_velocities_iterator vvi;
|
||||
int i = 0;
|
||||
|
||||
for (b_mesh_cache.vertex_velocities.begin(vvi); vvi != b_mesh_cache.vertex_velocities.end();
|
||||
++vvi, ++i) {
|
||||
mP[i] = P[i] + get_float3(vvi->velocity()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sync_mesh_fluid_motion(BL::Object &b_ob, Scene *scene, Mesh *mesh)
|
||||
{
|
||||
if (!mesh_need_motion_attribute(b_ob, scene)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
|
||||
|
||||
if (!b_fluid_domain)
|
||||
return;
|
||||
|
||||
/* If the mesh has modifiers following the fluid domain we can't export motion. */
|
||||
if (b_fluid_domain.mesh_vertices.length() != mesh->get_verts().size())
|
||||
return;
|
||||
|
||||
/* Find or add attribute */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
|
||||
if (!attr_mP) {
|
||||
attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
}
|
||||
|
||||
/* Only export previous and next frame, we don't have any in between data. */
|
||||
float motion_times[2] = {-1.0f, 1.0f};
|
||||
for (int step = 0; step < 2; step++) {
|
||||
float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f;
|
||||
float3 *mP = attr_mP->data_float3() + step * mesh->get_verts().size();
|
||||
|
||||
BL::FluidDomainSettings::mesh_vertices_iterator svi;
|
||||
int i = 0;
|
||||
|
||||
for (b_fluid_domain.mesh_vertices.begin(svi); svi != b_fluid_domain.mesh_vertices.end();
|
||||
++svi, ++i) {
|
||||
mP[i] = P[i] + get_float3(svi->velocity()) * relative_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh)
|
||||
{
|
||||
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
|
||||
* attributes */
|
||||
@@ -1132,47 +1170,37 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
|
||||
/* Adaptive subdivision setup. Not for baking since that requires
|
||||
* exact mapping to the Blender mesh. */
|
||||
if (!scene->bake_manager->get_baking()) {
|
||||
new_mesh.set_subdivision_type(
|
||||
object_subdivision_type(b_ob_info.real_object, preview, experimental));
|
||||
new_mesh.set_subdivision_type(object_subdivision_type(b_ob, preview, experimental));
|
||||
}
|
||||
|
||||
/* For some reason, meshes do not need this... */
|
||||
bool need_undeformed = new_mesh.need_attribute(scene, ATTR_STD_GENERATED);
|
||||
BL::Mesh b_mesh = object_to_mesh(
|
||||
b_data, b_ob_info, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
|
||||
b_data, b_ob, b_depsgraph, need_undeformed, new_mesh.get_subdivision_type());
|
||||
|
||||
if (b_mesh) {
|
||||
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
|
||||
const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
|
||||
const float motion_scale = (need_motion) ?
|
||||
scene->motion_shutter_time() /
|
||||
(b_scene.render().fps() / b_scene.render().fps_base()) :
|
||||
0.0f;
|
||||
|
||||
/* Sync mesh itself. */
|
||||
if (new_mesh.get_subdivision_type() != Mesh::SUBDIVISION_NONE)
|
||||
create_subd_mesh(scene,
|
||||
&new_mesh,
|
||||
b_ob_info,
|
||||
b_ob,
|
||||
b_mesh,
|
||||
new_mesh.get_used_shaders(),
|
||||
need_motion,
|
||||
motion_scale,
|
||||
dicing_rate,
|
||||
max_subdivisions);
|
||||
else
|
||||
create_mesh(scene,
|
||||
&new_mesh,
|
||||
b_mesh,
|
||||
new_mesh.get_used_shaders(),
|
||||
need_motion,
|
||||
motion_scale,
|
||||
false);
|
||||
create_mesh(scene, &new_mesh, b_mesh, new_mesh.get_used_shaders(), false);
|
||||
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
/* cached velocities (e.g. from alembic archive) */
|
||||
sync_mesh_cached_velocities(b_ob, scene, &new_mesh);
|
||||
|
||||
/* mesh fluid motion mantaflow */
|
||||
sync_mesh_fluid_motion(b_ob, scene, &new_mesh);
|
||||
|
||||
/* update original sockets */
|
||||
|
||||
mesh->clear_non_sockets();
|
||||
@@ -1202,10 +1230,22 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
|
||||
}
|
||||
|
||||
void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object b_ob,
|
||||
Mesh *mesh,
|
||||
int motion_step)
|
||||
{
|
||||
/* Fluid motion blur already exported. */
|
||||
BL::FluidDomainSettings b_fluid_domain = object_fluid_liquid_domain_find(b_ob);
|
||||
if (b_fluid_domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cached motion blur already exported. */
|
||||
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true, nullptr);
|
||||
if (mesh_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip if no vertices were exported. */
|
||||
size_t numverts = mesh->get_verts().size();
|
||||
if (numverts == 0) {
|
||||
@@ -1215,13 +1255,11 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
/* Skip objects without deforming modifiers. this is not totally reliable,
|
||||
* would need a more extensive check to see which objects are animated. */
|
||||
BL::Mesh b_mesh(PointerRNA_NULL);
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
|
||||
if (ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) {
|
||||
/* get derived mesh */
|
||||
b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
|
||||
}
|
||||
|
||||
const std::string ob_name = b_ob_info.real_object.name();
|
||||
|
||||
/* TODO(sergey): Perform preliminary check for number of vertices. */
|
||||
if (b_mesh) {
|
||||
/* Export deformed coordinates. */
|
||||
@@ -1257,17 +1295,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
|
||||
/* no motion, remove attributes again */
|
||||
if (b_mesh.vertices.length() != numverts) {
|
||||
VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
|
||||
VLOG(1) << "Topology differs, disabling motion blur for object " << b_ob.name();
|
||||
}
|
||||
else {
|
||||
VLOG(1) << "No actual deformation motion for object " << ob_name;
|
||||
VLOG(1) << "No actual deformation motion for object " << b_ob.name();
|
||||
}
|
||||
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
|
||||
if (attr_mN)
|
||||
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
|
||||
}
|
||||
else if (motion_step > 0) {
|
||||
VLOG(1) << "Filling deformation motion for object " << ob_name;
|
||||
VLOG(1) << "Filling deformation motion for object " << b_ob.name();
|
||||
/* motion, fill up previous steps that we might have skipped because
|
||||
* they had no motion, but we need them anyway now */
|
||||
float3 *P = &mesh->get_verts()[0];
|
||||
@@ -1281,8 +1319,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
else {
|
||||
if (b_mesh.vertices.length() != numverts) {
|
||||
VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
|
||||
<< motion_step;
|
||||
VLOG(1) << "Topology differs, discarding motion blur for object " << b_ob.name()
|
||||
<< " at time " << motion_step;
|
||||
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
|
||||
if (mN != NULL) {
|
||||
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
|
||||
@@ -1290,7 +1328,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
}
|
||||
|
||||
free_object_to_mesh(b_data, b_ob_info, b_mesh);
|
||||
free_object_to_mesh(b_data, b_ob, b_mesh);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -154,7 +154,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
const bool is_instance = b_instance.is_instance();
|
||||
BL::Object b_ob = b_instance.object();
|
||||
BL::Object b_parent = is_instance ? b_instance.parent() : b_instance.object();
|
||||
BObjectInfo b_ob_info{b_ob, is_instance ? b_instance.instance_object() : b_ob, b_ob.data()};
|
||||
BL::Object b_ob_instance = is_instance ? b_instance.instance_object() : b_ob;
|
||||
const bool motion = motion_time != 0.0f;
|
||||
/*const*/ Transform tfm = get_transform(b_ob.matrix_world());
|
||||
int *persistent_id = NULL;
|
||||
@@ -178,7 +178,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
{
|
||||
sync_light(b_parent,
|
||||
persistent_id,
|
||||
b_ob_info,
|
||||
b_ob,
|
||||
b_ob_instance,
|
||||
is_instance ? b_instance.random_id() : 0,
|
||||
tfm,
|
||||
use_portal);
|
||||
@@ -230,7 +231,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
TaskPool *object_geom_task_pool = (is_instance) ? NULL : geom_task_pool;
|
||||
|
||||
/* key to lookup object */
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_info.real_object, use_particle_hair);
|
||||
ObjectKey key(b_parent, persistent_id, b_ob_instance, use_particle_hair);
|
||||
Object *object;
|
||||
|
||||
/* motion vector case */
|
||||
@@ -248,8 +249,12 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
/* mesh deformation */
|
||||
if (object->get_geometry())
|
||||
sync_geometry_motion(
|
||||
b_depsgraph, b_ob_info, object, motion_time, use_particle_hair, object_geom_task_pool);
|
||||
sync_geometry_motion(b_depsgraph,
|
||||
b_ob_instance,
|
||||
object,
|
||||
motion_time,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
}
|
||||
|
||||
return object;
|
||||
@@ -260,8 +265,15 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
(tfm != object->get_tfm());
|
||||
|
||||
/* mesh sync */
|
||||
Geometry *geometry = sync_geometry(
|
||||
b_depsgraph, b_ob_info, object_updated, use_particle_hair, object_geom_task_pool);
|
||||
/* b_ob is owned by the iterator and will go out of scope at the end of the block.
|
||||
* b_ob_instance is the original object and will remain valid for deferred geometry
|
||||
* sync. */
|
||||
Geometry *geometry = sync_geometry(b_depsgraph,
|
||||
b_ob_instance,
|
||||
b_ob_instance,
|
||||
object_updated,
|
||||
use_particle_hair,
|
||||
object_geom_task_pool);
|
||||
object->set_geometry(geometry);
|
||||
|
||||
/* special case not tracked by object update flags */
|
||||
@@ -364,7 +376,7 @@ static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value)
|
||||
if (type == PROP_FLOAT)
|
||||
value = RNA_property_float_get(&ptr, prop);
|
||||
else if (type == PROP_INT)
|
||||
value = static_cast<float>(RNA_property_int_get(&ptr, prop));
|
||||
value = RNA_property_int_get(&ptr, prop);
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -492,14 +504,14 @@ void BlenderSync::sync_procedural(BL::Object &b_ob,
|
||||
procedural_map.used(procedural);
|
||||
}
|
||||
|
||||
float current_frame = static_cast<float>(b_scene.frame_current());
|
||||
float current_frame = b_scene.frame_current();
|
||||
if (cache_file.override_frame()) {
|
||||
current_frame = cache_file.frame();
|
||||
}
|
||||
|
||||
if (!cache_file.override_frame()) {
|
||||
procedural->set_start_frame(static_cast<float>(b_scene.frame_start()));
|
||||
procedural->set_end_frame(static_cast<float>(b_scene.frame_end()));
|
||||
procedural->set_start_frame(b_scene.frame_start());
|
||||
procedural->set_end_frame(b_scene.frame_end());
|
||||
}
|
||||
|
||||
procedural->set_frame(current_frame);
|
||||
@@ -535,7 +547,6 @@ void BlenderSync::sync_procedural(BL::Object &b_ob,
|
||||
#else
|
||||
(void)b_ob;
|
||||
(void)b_mesh_cache;
|
||||
(void)has_subdivision_modifier;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -604,7 +615,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
* only available in preview renders since currently do not have a good cache policy, the
|
||||
* data being loaded at once for all the frames. */
|
||||
if (experimental && b_v3d) {
|
||||
b_mesh_cache = object_mesh_cache_find(b_ob, &has_subdivision_modifier);
|
||||
b_mesh_cache = object_mesh_cache_find(b_ob, false, &has_subdivision_modifier);
|
||||
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
|
||||
}
|
||||
|
||||
@@ -719,14 +730,6 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check which geometry already has motion blur so it can be skipped. */
|
||||
geometry_motion_attribute_synced.clear();
|
||||
for (Geometry *geom : scene->geometry) {
|
||||
if (geom->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
|
||||
geometry_motion_attribute_synced.insert(geom);
|
||||
}
|
||||
}
|
||||
|
||||
/* note iteration over motion_times set happens in sorted order */
|
||||
foreach (float relative_time, motion_times) {
|
||||
/* center time is already handled. */
|
||||
@@ -757,8 +760,6 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
|
||||
sync_objects(b_depsgraph, b_v3d, relative_time);
|
||||
}
|
||||
|
||||
geometry_motion_attribute_synced.clear();
|
||||
|
||||
/* we need to set the python thread state again because this
|
||||
* function assumes it is being executed from python and will
|
||||
* try to save the thread state */
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "blender/blender_util.h"
|
||||
|
||||
#include "render/denoising.h"
|
||||
#include "render/image_oiio.h"
|
||||
#include "render/merge.h"
|
||||
|
||||
#include "util/util_debug.h"
|
||||
@@ -691,6 +692,22 @@ static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *oiio_make_tx(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
const char *inputfile = NULL, *outputfile = NULL, *colorspace = NULL;
|
||||
int extension = EXTENSION_CLIP;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sssi", &inputfile, &outputfile, &colorspace, &extension))
|
||||
return NULL;
|
||||
|
||||
/* return */
|
||||
if (!OIIOImageLoader::make_tx(
|
||||
inputfile, outputfile, ustring(colorspace), (ExtensionType)extension))
|
||||
Py_RETURN_FALSE;
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
|
||||
{
|
||||
string system_info = Device::device_capabilities();
|
||||
@@ -1080,6 +1097,7 @@ static PyMethodDef methods[] = {
|
||||
{"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
|
||||
{"osl_compile", osl_compile_func, METH_VARARGS, ""},
|
||||
#endif
|
||||
{"oiio_make_tx", oiio_make_tx, METH_VARARGS, ""},
|
||||
{"available_devices", available_devices_func, METH_VARARGS, ""},
|
||||
{"system_info", system_info_func, METH_NOARGS, ""},
|
||||
#ifdef WITH_OPENCL
|
||||
|
@@ -802,6 +802,27 @@ SceneParams BlenderSync::get_scene_params(BL::Scene &b_scene, bool background)
|
||||
|
||||
params.bvh_layout = DebugFlags().cpu.bvh_layout;
|
||||
|
||||
params.texture.use_cache = RNA_boolean_get(&cscene, "use_texture_cache");
|
||||
params.texture.cache_size = RNA_int_get(&cscene, "texture_cache_size");
|
||||
params.texture.auto_convert = RNA_boolean_get(&cscene, "texture_auto_convert");
|
||||
params.texture.accept_unmipped = RNA_boolean_get(&cscene, "texture_accept_unmipped");
|
||||
params.texture.accept_untiled = RNA_boolean_get(&cscene, "texture_accept_untiled");
|
||||
params.texture.tile_size = RNA_int_get(&cscene, "texture_tile_size");
|
||||
params.texture.auto_mip = RNA_boolean_get(&cscene, "texture_auto_mip");
|
||||
params.texture.auto_tile = RNA_boolean_get(&cscene, "texture_auto_tile");
|
||||
params.texture.diffuse_blur = RNA_float_get(&cscene, "texture_blur_diffuse");
|
||||
params.texture.glossy_blur = RNA_float_get(&cscene, "texture_blur_glossy");
|
||||
params.texture.use_custom_cache_path = RNA_boolean_get(&cscene, "use_custom_cache_path");
|
||||
if (params.texture.use_custom_cache_path) {
|
||||
char *path = RNA_string_get_alloc(&cscene, "custom_cache_path", NULL, 0);
|
||||
if (path) {
|
||||
params.texture.custom_cache_path = path;
|
||||
MEM_freeN(path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
params.texture.custom_cache_path.clear();
|
||||
}
|
||||
params.background = background;
|
||||
|
||||
return params;
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "blender/blender_id_map.h"
|
||||
#include "blender/blender_util.h"
|
||||
#include "blender/blender_viewport.h"
|
||||
|
||||
#include "render/scene.h"
|
||||
@@ -159,24 +158,18 @@ class BlenderSync {
|
||||
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
|
||||
|
||||
/* Volume */
|
||||
void sync_volume(BObjectInfo &b_ob_info, Volume *volume);
|
||||
void sync_volume(BL::Object &b_ob, Volume *volume);
|
||||
|
||||
/* Mesh */
|
||||
void sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh);
|
||||
void sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
Mesh *mesh,
|
||||
int motion_step);
|
||||
void sync_mesh(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh);
|
||||
void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step);
|
||||
|
||||
/* Hair */
|
||||
void sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair);
|
||||
void sync_hair_motion(BL::Depsgraph b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
Hair *hair,
|
||||
int motion_step);
|
||||
void sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
|
||||
void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair);
|
||||
void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Hair *hair, int motion_step);
|
||||
void sync_hair(Hair *hair, BL::Object &b_ob, bool motion, int motion_step = 0);
|
||||
void sync_particle_hair(
|
||||
Hair *hair, BL::Mesh &b_mesh, BObjectInfo &b_ob_info, bool motion, int motion_step = 0);
|
||||
Hair *hair, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0);
|
||||
bool object_has_particle_hair(BL::Object b_ob);
|
||||
|
||||
/* Camera */
|
||||
@@ -185,13 +178,14 @@ class BlenderSync {
|
||||
|
||||
/* Geometry */
|
||||
Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
bool object_updated,
|
||||
bool use_particle_hair,
|
||||
TaskPool *task_pool);
|
||||
|
||||
void sync_geometry_motion(BL::Depsgraph &b_depsgraph,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
Object *object,
|
||||
float motion_time,
|
||||
bool use_particle_hair,
|
||||
@@ -200,7 +194,8 @@ class BlenderSync {
|
||||
/* Light */
|
||||
void sync_light(BL::Object &b_parent,
|
||||
int persistent_id[OBJECT_PERSISTENT_ID_SIZE],
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
BL::Object &b_ob_instance,
|
||||
int random_id,
|
||||
Transform &tfm,
|
||||
bool *use_portal);
|
||||
@@ -236,7 +231,6 @@ class BlenderSync {
|
||||
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
||||
set<Geometry *> geometry_synced;
|
||||
set<Geometry *> geometry_motion_synced;
|
||||
set<Geometry *> geometry_motion_attribute_synced;
|
||||
set<float> motion_times;
|
||||
void *world_map;
|
||||
bool world_recalc;
|
||||
|
@@ -40,28 +40,6 @@ float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct BObjectInfo {
|
||||
/* Object directly provided by the depsgraph iterator. This object is only valid during one
|
||||
* iteration and must not be accessed afterwards. Transforms and visibility should be checked on
|
||||
* this object. */
|
||||
BL::Object iter_object;
|
||||
|
||||
/* This object remains alive even after the object iterator is done. It corresponds to one
|
||||
* original object. It is the object that owns the object data below. */
|
||||
BL::Object real_object;
|
||||
|
||||
/* The object-data referenced by the iter object. This is still valid after the depsgraph
|
||||
* iterator is done. It might have a different type compared to real_object.data(). */
|
||||
BL::ID object_data;
|
||||
|
||||
/* True when the current geometry is the data of the referenced object. False when it is a
|
||||
* geometry instance that does not have a 1-to-1 relationship with an object. */
|
||||
bool is_real_object_data() const
|
||||
{
|
||||
return const_cast<BL::Object &>(real_object).data() == object_data;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BL::ShaderNodeAttribute::attribute_type_enum BlenderAttributeType;
|
||||
BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_real_name);
|
||||
|
||||
@@ -69,7 +47,7 @@ void python_thread_state_save(void **python_thread_state);
|
||||
void python_thread_state_restore(void **python_thread_state);
|
||||
|
||||
static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &object,
|
||||
BL::Depsgraph & /*depsgraph*/,
|
||||
bool /*calc_undeformed*/,
|
||||
Mesh::SubdivisionType subdivision_type)
|
||||
@@ -91,9 +69,9 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
#endif
|
||||
|
||||
BL::Mesh mesh(PointerRNA_NULL);
|
||||
if (b_ob_info.object_data.is_a(&RNA_Mesh)) {
|
||||
if (object.type() == BL::Object::type_MESH) {
|
||||
/* TODO: calc_undeformed is not used. */
|
||||
mesh = BL::Mesh(b_ob_info.object_data);
|
||||
mesh = BL::Mesh(object.data());
|
||||
|
||||
/* Make a copy to split faces if we use autosmooth, otherwise not needed.
|
||||
* Also in edit mode do we need to make a copy, to ensure data layers like
|
||||
@@ -101,15 +79,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
if (mesh.is_editmode() ||
|
||||
(mesh.use_auto_smooth() && subdivision_type == Mesh::SUBDIVISION_NONE)) {
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
assert(b_ob_info.is_real_object_data());
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
mesh = object.to_mesh(false, depsgraph);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BL::Depsgraph depsgraph(PointerRNA_NULL);
|
||||
if (b_ob_info.is_real_object_data()) {
|
||||
mesh = b_ob_info.real_object.to_mesh(false, depsgraph);
|
||||
}
|
||||
mesh = object.to_mesh(false, depsgraph);
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -133,14 +108,10 @@ static inline BL::Mesh object_to_mesh(BL::BlendData & /*data*/,
|
||||
}
|
||||
|
||||
static inline void free_object_to_mesh(BL::BlendData & /*data*/,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &object,
|
||||
BL::Mesh &mesh)
|
||||
{
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
/* Free mesh if we didn't just use the existing one. */
|
||||
BL::Object object = b_ob_info.real_object;
|
||||
if (object.data().ptr.data != mesh.ptr.data) {
|
||||
object.to_mesh_clear();
|
||||
}
|
||||
@@ -248,13 +219,9 @@ static inline bool BKE_object_is_modified(BL::Object &self, BL::Scene &scene, bo
|
||||
return self.is_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
|
||||
}
|
||||
|
||||
static inline bool BKE_object_is_deform_modified(BObjectInfo &self, BL::Scene &scene, bool preview)
|
||||
static inline bool BKE_object_is_deform_modified(BL::Object &self, BL::Scene &scene, bool preview)
|
||||
{
|
||||
if (!self.is_real_object_data()) {
|
||||
return false;
|
||||
}
|
||||
return self.real_object.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true :
|
||||
false;
|
||||
return self.is_deform_modified(scene, (preview) ? (1 << 0) : (1 << 1)) ? true : false;
|
||||
}
|
||||
|
||||
static inline int render_resolution_x(BL::RenderSettings &b_render)
|
||||
@@ -457,7 +424,7 @@ static inline void set_enum(PointerRNA &ptr, const char *name, const string &ide
|
||||
static inline string get_string(PointerRNA &ptr, const char *name)
|
||||
{
|
||||
char cstrbuf[1024];
|
||||
char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf), NULL);
|
||||
char *cstr = RNA_string_get_alloc(&ptr, name, cstrbuf, sizeof(cstrbuf));
|
||||
string str(cstr);
|
||||
if (cstr != cstrbuf)
|
||||
MEM_freeN(cstr);
|
||||
@@ -573,6 +540,22 @@ static inline bool object_use_deform_motion(BL::Object &b_parent, BL::Object &b_
|
||||
return use_deform_motion;
|
||||
}
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_liquid_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
for (BL::Modifier &b_mod : b_ob.modifiers) {
|
||||
if (b_mod.is_a(&RNA_FluidModifier)) {
|
||||
BL::FluidModifier b_mmd(b_mod);
|
||||
|
||||
if (b_mmd.fluid_type() == BL::FluidModifier::fluid_type_DOMAIN &&
|
||||
b_mmd.domain_settings().domain_type() == BL::FluidDomainSettings::domain_type_LIQUID) {
|
||||
return b_mmd.domain_settings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BL::FluidDomainSettings(PointerRNA_NULL);
|
||||
}
|
||||
|
||||
static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b_ob)
|
||||
{
|
||||
for (BL::Modifier &b_mod : b_ob.modifiers) {
|
||||
@@ -590,6 +573,7 @@ static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b
|
||||
}
|
||||
|
||||
static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
|
||||
bool check_velocity,
|
||||
bool *has_subdivision_modifier)
|
||||
{
|
||||
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
|
||||
@@ -597,6 +581,13 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
|
||||
|
||||
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
|
||||
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
|
||||
|
||||
if (check_velocity) {
|
||||
if (!MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
|
||||
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return mesh_cache;
|
||||
}
|
||||
|
||||
@@ -605,7 +596,9 @@ static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b_mod.type() == BL::Modifier::type_SUBSURF) {
|
||||
/* Only skip the subsurf modifier if we are not checking for the mesh sequence cache modifier
|
||||
* for motion blur. */
|
||||
if (b_mod.type() == BL::Modifier::type_SUBSURF && !check_velocity) {
|
||||
if (has_subdivision_modifier) {
|
||||
*has_subdivision_modifier = true;
|
||||
}
|
||||
|
@@ -181,12 +181,9 @@ class BlenderSmokeLoader : public ImageLoader {
|
||||
AttributeStandard attribute;
|
||||
};
|
||||
|
||||
static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volume, float frame)
|
||||
static void sync_smoke_volume(Scene *scene, BL::Object &b_ob, Volume *volume, float frame)
|
||||
{
|
||||
if (!b_ob_info.is_real_object_data()) {
|
||||
return;
|
||||
}
|
||||
BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob_info.real_object);
|
||||
BL::FluidDomainSettings b_domain = object_fluid_gas_domain_find(b_ob);
|
||||
if (!b_domain) {
|
||||
return;
|
||||
}
|
||||
@@ -209,7 +206,7 @@ static void sync_smoke_volume(Scene *scene, BObjectInfo &b_ob_info, Volume *volu
|
||||
|
||||
Attribute *attr = volume->attributes.add(std);
|
||||
|
||||
ImageLoader *loader = new BlenderSmokeLoader(b_ob_info.real_object, std);
|
||||
ImageLoader *loader = new BlenderSmokeLoader(b_ob, std);
|
||||
ImageParams params;
|
||||
params.frame = frame;
|
||||
|
||||
@@ -247,11 +244,11 @@ class BlenderVolumeLoader : public VDBImageLoader {
|
||||
};
|
||||
|
||||
static void sync_volume_object(BL::BlendData &b_data,
|
||||
BObjectInfo &b_ob_info,
|
||||
BL::Object &b_ob,
|
||||
Scene *scene,
|
||||
Volume *volume)
|
||||
{
|
||||
BL::Volume b_volume(b_ob_info.object_data);
|
||||
BL::Volume b_volume(b_ob.data());
|
||||
b_volume.grids.load(b_data.ptr.data);
|
||||
|
||||
BL::VolumeRender b_render(b_volume.render());
|
||||
@@ -299,19 +296,19 @@ static void sync_volume_object(BL::BlendData &b_data,
|
||||
}
|
||||
}
|
||||
|
||||
void BlenderSync::sync_volume(BObjectInfo &b_ob_info, Volume *volume)
|
||||
void BlenderSync::sync_volume(BL::Object &b_ob, Volume *volume)
|
||||
{
|
||||
volume->clear(true);
|
||||
|
||||
if (view_layer.use_volumes) {
|
||||
if (b_ob_info.object_data.is_a(&RNA_Volume)) {
|
||||
if (b_ob.type() == BL::Object::type_VOLUME) {
|
||||
/* Volume object. Create only attributes, bounding mesh will then
|
||||
* be automatically generated later. */
|
||||
sync_volume_object(b_data, b_ob_info, scene, volume);
|
||||
sync_volume_object(b_data, b_ob, scene, volume);
|
||||
}
|
||||
else {
|
||||
/* Smoke domain. */
|
||||
sync_smoke_volume(scene, b_ob_info, volume, b_scene.frame_current());
|
||||
sync_smoke_volume(scene, b_ob, volume, b_scene.frame_current());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -376,6 +376,12 @@ class Device {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open image io, only for CPU device */
|
||||
virtual void *oiio_memory()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* load/compile kernels, must be called before adding tasks */
|
||||
virtual bool load_kernels(const DeviceRequestedFeatures & /*requested_features*/)
|
||||
{
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include "kernel/kernel_types.h"
|
||||
#include "kernel/split/kernel_split_data.h"
|
||||
#include "kernel/kernel_globals.h"
|
||||
#include "kernel/kernel_oiio_globals.h"
|
||||
#include "kernel/kernel_adaptive_sampling.h"
|
||||
|
||||
#include "kernel/filter/filter.h"
|
||||
@@ -184,6 +185,9 @@ class CPUDevice : public Device {
|
||||
#ifdef WITH_OSL
|
||||
OSLGlobals osl_globals;
|
||||
#endif
|
||||
|
||||
OIIOGlobals oiio_globals;
|
||||
|
||||
#ifdef WITH_OPENIMAGEDENOISE
|
||||
oidn::DeviceRef oidn_device;
|
||||
oidn::FilterRef oidn_filter;
|
||||
@@ -312,6 +316,9 @@ class CPUDevice : public Device {
|
||||
#ifdef WITH_OSL
|
||||
kernel_globals.osl = &osl_globals;
|
||||
#endif
|
||||
oiio_globals.tex_sys = NULL;
|
||||
kernel_globals.oiio = &oiio_globals;
|
||||
|
||||
#ifdef WITH_EMBREE
|
||||
embree_device = rtcNewDevice("verbose=0");
|
||||
#endif
|
||||
@@ -357,6 +364,12 @@ class CPUDevice : public Device {
|
||||
#endif
|
||||
task_pool.cancel();
|
||||
texture_info.free();
|
||||
if (oiio_globals.tex_sys) {
|
||||
VLOG(1) << oiio_globals.tex_sys->getstats();
|
||||
oiio_globals.tex_sys->reset_stats();
|
||||
TextureSystem::destroy(oiio_globals.tex_sys);
|
||||
}
|
||||
kernel_globals.oiio = NULL;
|
||||
}
|
||||
|
||||
virtual bool show_samples() const override
|
||||
@@ -548,6 +561,11 @@ class CPUDevice : public Device {
|
||||
#endif
|
||||
}
|
||||
|
||||
void *oiio_memory() override
|
||||
{
|
||||
return &oiio_globals;
|
||||
}
|
||||
|
||||
void build_bvh(BVH *bvh, Progress &progress, bool refit) override
|
||||
{
|
||||
#ifdef WITH_EMBREE
|
||||
@@ -1486,6 +1504,10 @@ class CPUDevice : public Device {
|
||||
#ifdef WITH_OSL
|
||||
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
|
||||
#endif
|
||||
if (kg.oiio && kg.oiio->tex_sys) {
|
||||
kg.oiio_tdata = kg.oiio->tex_sys->get_perthread_info();
|
||||
}
|
||||
|
||||
return kg;
|
||||
}
|
||||
|
||||
|
@@ -231,6 +231,12 @@ device_texture::device_texture(Device *device,
|
||||
data_type = TYPE_UINT16;
|
||||
data_elements = 1;
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_OIIO:
|
||||
/* Assumes 64 bit pointers to be stored as uint. */
|
||||
static_assert(sizeof(void*) == sizeof(uint64_t));
|
||||
data_type = TYPE_UINT64;
|
||||
data_elements = 1;
|
||||
break;
|
||||
case IMAGE_DATA_NUM_TYPES:
|
||||
assert(0);
|
||||
return;
|
||||
|
@@ -79,7 +79,10 @@ struct SocketType {
|
||||
LINK_NORMAL = (1 << 8),
|
||||
LINK_POSITION = (1 << 9),
|
||||
LINK_TANGENT = (1 << 10),
|
||||
DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)
|
||||
LINK_TEXTURE_DX = (1 << 11),
|
||||
LINK_TEXTURE_DY = (1 << 12),
|
||||
DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) |
|
||||
(1 << 10) | (1 << 11) | (1 << 12)
|
||||
};
|
||||
|
||||
ustring name;
|
||||
|
@@ -211,7 +211,8 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
omega_in,
|
||||
&domega_in->dx,
|
||||
&domega_in->dy,
|
||||
pdf);
|
||||
pdf,
|
||||
sd);
|
||||
break;
|
||||
case CLOSURE_BSDF_REFRACTION_ID:
|
||||
label = bsdf_refraction_sample(sc,
|
||||
@@ -225,7 +226,8 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
omega_in,
|
||||
&domega_in->dx,
|
||||
&domega_in->dy,
|
||||
pdf);
|
||||
pdf,
|
||||
sd);
|
||||
break;
|
||||
case CLOSURE_BSDF_TRANSPARENT_ID:
|
||||
label = bsdf_transparent_sample(sc,
|
||||
@@ -257,7 +259,8 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
omega_in,
|
||||
&domega_in->dx,
|
||||
&domega_in->dy,
|
||||
pdf);
|
||||
pdf,
|
||||
sd);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID:
|
||||
@@ -291,7 +294,8 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
&domega_in->dx,
|
||||
&domega_in->dy,
|
||||
pdf,
|
||||
&sd->lcg_state);
|
||||
&sd->lcg_state,
|
||||
sd);
|
||||
break;
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
|
||||
case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
|
||||
@@ -307,7 +311,8 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg,
|
||||
omega_in,
|
||||
&domega_in->dx,
|
||||
&domega_in->dy,
|
||||
pdf);
|
||||
pdf,
|
||||
sd);
|
||||
break;
|
||||
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID:
|
||||
label = bsdf_ashikhmin_shirley_sample(sc,
|
||||
|
@@ -161,8 +161,10 @@ ccl_device int bsdf_ashikhmin_velvet_sample(const ShaderClosure *sc,
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
// TODO: find a better approximation for the retroreflective bounce
|
||||
*domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@@ -101,8 +101,10 @@ ccl_device int bsdf_diffuse_sample(const ShaderClosure *sc,
|
||||
*eval = make_float3(*pdf, *pdf, *pdf);
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
*domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -163,8 +165,10 @@ ccl_device int bsdf_translucent_sample(const ShaderClosure *sc,
|
||||
*eval = make_float3(*pdf, *pdf, *pdf);
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
*domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx);
|
||||
*domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy);
|
||||
*domega_in_dx = -((2.0f * dot(N, dIdx)) * N - dIdx);
|
||||
*domega_in_dy = -((2.0f * dot(N, dIdy)) * N - dIdy);
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@@ -112,8 +112,10 @@ ccl_device int bsdf_diffuse_ramp_sample(const ShaderClosure *sc,
|
||||
if (dot(Ng, *omega_in) > 0.0f) {
|
||||
*eval = bsdf_diffuse_ramp_get_color(bsdf->colors, *pdf * M_PI_F) * M_1_PI_F;
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2 * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
# endif
|
||||
}
|
||||
else
|
||||
|
@@ -228,8 +228,10 @@ ccl_device int bsdf_hair_reflection_sample(const ShaderClosure *sc,
|
||||
|
||||
// differentials - TODO: find a better approximation for the reflective bounce
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = 2 * dot(locy, dIdx) * locy - dIdx;
|
||||
*domega_in_dy = 2 * dot(locy, dIdy) * locy - dIdy;
|
||||
*domega_in_dx = 2.0f * dot(locy, dIdx) * locy - dIdx;
|
||||
*domega_in_dy = 2.0f * dot(locy, dIdy) * locy - dIdy;
|
||||
*domega_in_dx *= 10.0f;
|
||||
*domega_in_dy *= 10.0f;
|
||||
#endif
|
||||
|
||||
*pdf = fabsf(phi_pdf * theta_pdf);
|
||||
|
@@ -570,7 +570,8 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg,
|
||||
float3 *omega_in,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy,
|
||||
float *pdf)
|
||||
float *pdf,
|
||||
const ShaderData *sd)
|
||||
{
|
||||
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
|
||||
float alpha_x = bsdf->alpha_x;
|
||||
@@ -699,8 +700,20 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg,
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx;
|
||||
*domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy;
|
||||
# ifdef __DNDU__
|
||||
float3 dwodx = -dIdx;
|
||||
float3 dwody = -dIdy;
|
||||
float dDNdx = dot(dwodx, N) + dot(I, sd->dNdx);
|
||||
float dDNdy = dot(dwody, N) + dot(I, sd->dNdy);
|
||||
*domega_in_dx = dwodx + 2.0f * (dot(I, N) * sd->dNdx + dDNdx * N);
|
||||
*domega_in_dy = dwody + 2.0f * (dot(I, N) * sd->dNdy + dDNdy * N);
|
||||
# else
|
||||
*domega_in_dx = (2.0f * dot(m, dIdx)) * m - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(m, dIdy)) * m - dIdy;
|
||||
# endif
|
||||
const float softness = min(alpha_x, alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -723,6 +736,10 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg,
|
||||
&R,
|
||||
&T,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx,
|
||||
sd->dNdy,
|
||||
# endif
|
||||
dIdx,
|
||||
dIdy,
|
||||
&dRdx,
|
||||
@@ -738,6 +755,9 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = dTdx;
|
||||
*domega_in_dy = dTdy;
|
||||
const float softness = min(alpha_x, alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
|
||||
if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) {
|
||||
@@ -998,7 +1018,8 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg,
|
||||
float3 *omega_in,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy,
|
||||
float *pdf)
|
||||
float *pdf,
|
||||
const ShaderData *sd)
|
||||
{
|
||||
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
|
||||
float alpha_x = bsdf->alpha_x;
|
||||
@@ -1050,7 +1071,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg,
|
||||
float D, G1i;
|
||||
|
||||
if (alpha_x == alpha_y) {
|
||||
/* Isotropic distribution. */
|
||||
/* istropic distribution */
|
||||
float cosThetaM2 = cosThetaM * cosThetaM;
|
||||
float cosThetaM4 = cosThetaM2 * cosThetaM2;
|
||||
float tanThetaM2 = 1 / (cosThetaM2)-1;
|
||||
@@ -1090,8 +1111,20 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg,
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(m, dIdx)) * m - dIdx;
|
||||
*domega_in_dy = (2 * dot(m, dIdy)) * m - dIdy;
|
||||
# ifdef __DNDU__
|
||||
float3 dwodx = -dIdx;
|
||||
float3 dwody = -dIdy;
|
||||
float dDNdx = dot(dwodx, N) + dot(I, sd->dNdx);
|
||||
float dDNdy = dot(dwody, N) + dot(I, sd->dNdy);
|
||||
*domega_in_dx = dwodx + 2.f * (dot(I, N) * sd->dNdx + dDNdx * N);
|
||||
*domega_in_dy = dwody + 2.f * (dot(I, N) * sd->dNdy + dDNdy * N);
|
||||
# else
|
||||
*domega_in_dx = (2.0f * dot(m, dIdx)) * m - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(m, dIdy)) * m - dIdy;
|
||||
# endif
|
||||
const float softness = min(alpha_x, alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1114,6 +1147,10 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg,
|
||||
&R,
|
||||
&T,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx,
|
||||
sd->dNdy,
|
||||
# endif
|
||||
dIdx,
|
||||
dIdy,
|
||||
&dRdx,
|
||||
@@ -1129,6 +1166,9 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = dTdx;
|
||||
*domega_in_dy = dTdy;
|
||||
const float softness = min(alpha_x, alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
|
||||
if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) {
|
||||
|
@@ -526,8 +526,11 @@ ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg,
|
||||
*omega_in = X * localO.x + Y * localO.y + Z * localO.z;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
|
||||
*domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(Z, dIdx)) * Z - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(Z, dIdy)) * Z - dIdy;
|
||||
const float softness = min(bsdf->alpha_x, bsdf->alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
return LABEL_REFLECT | LABEL_GLOSSY;
|
||||
}
|
||||
@@ -641,7 +644,8 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy,
|
||||
float *pdf,
|
||||
ccl_addr_space uint *lcg_state)
|
||||
ccl_addr_space uint *lcg_state,
|
||||
const ShaderData *sd)
|
||||
{
|
||||
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
|
||||
|
||||
@@ -660,6 +664,10 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg,
|
||||
&R,
|
||||
&T,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx,
|
||||
sd->dNdy,
|
||||
# endif
|
||||
dIdx,
|
||||
dIdy,
|
||||
&dRdx,
|
||||
@@ -713,6 +721,9 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(Z, dIdx)) * Z - dIdx;
|
||||
*domega_in_dy = (2 * dot(Z, dIdy)) * Z - dIdy;
|
||||
const float softness = min(bsdf->alpha_x, bsdf->alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
return LABEL_REFLECT | LABEL_GLOSSY;
|
||||
}
|
||||
@@ -724,6 +735,9 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg,
|
||||
((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdx, Z)) * Z;
|
||||
*domega_in_dy = -(bsdf->ior * dIdy) +
|
||||
((bsdf->ior - bsdf->ior * bsdf->ior * cosI / dnp) * dot(dIdy, Z)) * Z;
|
||||
const float softness = min(bsdf->alpha_x, bsdf->alpha_y) * 10.0f;
|
||||
*domega_in_dx *= (1.0f + softness);
|
||||
*domega_in_dy *= (1.0f + softness);
|
||||
#endif
|
||||
|
||||
return LABEL_TRANSMIT | LABEL_GLOSSY;
|
||||
|
@@ -116,6 +116,8 @@ ccl_device int bsdf_oren_nayar_sample(const ShaderClosure *sc,
|
||||
// TODO: find a better approximation for the bounce
|
||||
*domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@@ -123,8 +123,10 @@ ccl_device int bsdf_phong_ramp_sample(const ShaderClosure *sc,
|
||||
float3 R = (2 * cosNO) * bsdf->N - I;
|
||||
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx *= 10.0f;
|
||||
*domega_in_dy *= 10.0f;
|
||||
# endif
|
||||
|
||||
float3 T, B;
|
||||
|
@@ -36,10 +36,10 @@ static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledDiffuseBsdf),
|
||||
ccl_device float3 calculate_principled_diffuse_brdf(
|
||||
const PrincipledDiffuseBsdf *bsdf, float3 N, float3 V, float3 L, float3 H, float *pdf)
|
||||
{
|
||||
float NdotL = dot(N, L);
|
||||
float NdotV = dot(N, V);
|
||||
float NdotL = max(dot(N, L), 0.0f);
|
||||
float NdotV = max(dot(N, V), 0.0f);
|
||||
|
||||
if (NdotL <= 0 || NdotV <= 0) {
|
||||
if (NdotL < 0 || NdotV < 0) {
|
||||
*pdf = 0.0f;
|
||||
return make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
@@ -125,8 +125,10 @@ ccl_device int bsdf_principled_diffuse_sample(const ShaderClosure *sc,
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
*domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx);
|
||||
*domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy);
|
||||
*domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@@ -126,8 +126,10 @@ ccl_device int bsdf_principled_sheen_sample(const ShaderClosure *sc,
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
// TODO: find a better approximation for the diffuse bounce
|
||||
*domega_in_dx = -((2 * dot(N, dIdx)) * N - dIdx);
|
||||
*domega_in_dy = -((2 * dot(N, dIdy)) * N - dIdy);
|
||||
*domega_in_dx = (2.0f * dot(N, dIdx)) * N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(N, dIdy)) * N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@@ -70,7 +70,8 @@ ccl_device int bsdf_reflection_sample(const ShaderClosure *sc,
|
||||
float3 *omega_in,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy,
|
||||
float *pdf)
|
||||
float *pdf,
|
||||
const ShaderData *sd)
|
||||
{
|
||||
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
|
||||
float3 N = bsdf->N;
|
||||
@@ -81,8 +82,18 @@ ccl_device int bsdf_reflection_sample(const ShaderClosure *sc,
|
||||
*omega_in = (2 * cosNO) * N - I;
|
||||
if (dot(Ng, *omega_in) > 0) {
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = 2 * dot(N, dIdx) * N - dIdx;
|
||||
*domega_in_dy = 2 * dot(N, dIdy) * N - dIdy;
|
||||
# ifdef __DNDU__
|
||||
/* as described in pbrt */
|
||||
float3 dwodx = -dIdx;
|
||||
float3 dwody = -dIdy;
|
||||
float dDNdx = dot(dwodx, N) + dot(I, sd->dNdx);
|
||||
float dDNdy = dot(dwody, N) + dot(I, sd->dNdy);
|
||||
*domega_in_dx = dwodx + 2.f * (dot(I, N) * sd->dNdx + dDNdx * N);
|
||||
*domega_in_dy = dwody + 2.f * (dot(I, N) * sd->dNdy + dDNdy * N);
|
||||
# else
|
||||
*domega_in_dx = 2.0f * dot(N, dIdx) * N - dIdx;
|
||||
*domega_in_dy = 2.0f * dot(N, dIdy) * N - dIdy;
|
||||
# endif
|
||||
#endif
|
||||
/* Some high number for MIS. */
|
||||
*pdf = 1e6f;
|
||||
|
@@ -70,7 +70,8 @@ ccl_device int bsdf_refraction_sample(const ShaderClosure *sc,
|
||||
float3 *omega_in,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy,
|
||||
float *pdf)
|
||||
float *pdf,
|
||||
ShaderData *sd)
|
||||
{
|
||||
const MicrofacetBsdf *bsdf = (const MicrofacetBsdf *)sc;
|
||||
float m_eta = bsdf->ior;
|
||||
@@ -88,6 +89,10 @@ ccl_device int bsdf_refraction_sample(const ShaderClosure *sc,
|
||||
&R,
|
||||
&T,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx,
|
||||
sd->dNdy,
|
||||
# endif
|
||||
dIdx,
|
||||
dIdy,
|
||||
&dRdx,
|
||||
|
@@ -142,6 +142,8 @@ ccl_device int bsdf_diffuse_toon_sample(const ShaderClosure *sc,
|
||||
// TODO: find a better approximation for the bounce
|
||||
*domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx *= 125.0f;
|
||||
*domega_in_dy *= 125.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -233,8 +235,10 @@ ccl_device int bsdf_glossy_toon_sample(const ShaderClosure *sc,
|
||||
*eval = *pdf * bsdf_toon_get_intensity(max_angle, smooth, angle);
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*domega_in_dx = (2 * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2 * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx = (2.0f * dot(bsdf->N, dIdx)) * bsdf->N - dIdx;
|
||||
*domega_in_dy = (2.0f * dot(bsdf->N, dIdy)) * bsdf->N - dIdy;
|
||||
*domega_in_dx *= 10.0f;
|
||||
*domega_in_dy *= 10.0f;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@@ -41,6 +41,10 @@ ccl_device float fresnel_dielectric(float eta,
|
||||
float3 *R,
|
||||
float3 *T,
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
# ifdef __DNDU__
|
||||
const float3 dNdx,
|
||||
const float3 dNdy,
|
||||
# endif
|
||||
const float3 dIdx,
|
||||
const float3 dIdy,
|
||||
float3 *dRdx,
|
||||
@@ -69,14 +73,14 @@ ccl_device float fresnel_dielectric(float eta,
|
||||
}
|
||||
|
||||
// compute reflection
|
||||
*R = (2 * cos) * Nn - I;
|
||||
*R = (2.0f * cos) * Nn - I;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*dRdx = (2 * dot(Nn, dIdx)) * Nn - dIdx;
|
||||
*dRdy = (2 * dot(Nn, dIdy)) * Nn - dIdy;
|
||||
*dRdx = (2.0f * dot(Nn, dIdx)) * Nn - dIdx;
|
||||
*dRdy = (2.0f * dot(Nn, dIdy)) * Nn - dIdy;
|
||||
#endif
|
||||
|
||||
float arg = 1 - (neta * neta * (1 - (cos * cos)));
|
||||
if (arg < 0) {
|
||||
if (arg < 0.0f) {
|
||||
*T = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*dTdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
@@ -89,8 +93,16 @@ ccl_device float fresnel_dielectric(float eta,
|
||||
float nK = (neta * cos) - dnp;
|
||||
*T = -(neta * I) + (nK * Nn);
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
*dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn;
|
||||
*dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn;
|
||||
# ifndef __DNDU__
|
||||
# define dNdx make_float3(0.0f, 0.0f, 0.0f)
|
||||
# define dNdy make_float3(0.0f, 0.0f, 0.0f)
|
||||
# endif
|
||||
float dDNdx = dot(dIdx, Nn) - dot(I, dNdx);
|
||||
float dDNdy = dot(dIdy, Nn) - dot(I, dNdy);
|
||||
float dmudx = (neta - neta * neta * cos / dnp) * dDNdx;
|
||||
float dmudy = (neta - neta * neta * cos / dnp) * dDNdy;
|
||||
*dTdx = -(neta * dIdx) + (nK * dNdx + dmudx * Nn);
|
||||
*dTdy = -(neta * dIdy) + (nK * dNdy + dmudy * Nn);
|
||||
#endif
|
||||
// compute Fresnel terms
|
||||
float cosTheta1 = cos; // N.R
|
||||
|
@@ -90,8 +90,15 @@ ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc,
|
||||
return make_float3(*pdf, *pdf, *pdf);
|
||||
}
|
||||
|
||||
ccl_device float3
|
||||
henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pdf)
|
||||
ccl_device float3 henyey_greenstrein_sample(float3 D,
|
||||
float g,
|
||||
float randu,
|
||||
float randv,
|
||||
float *pdf,
|
||||
float3 dIdx,
|
||||
float3 dIdy,
|
||||
float3 *domega_in_dx,
|
||||
float3 *domega_in_dy)
|
||||
{
|
||||
/* match pdf for small g */
|
||||
float cos_theta;
|
||||
@@ -113,12 +120,33 @@ henyey_greenstrein_sample(float3 D, float g, float randu, float randv, float *pd
|
||||
|
||||
float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
|
||||
float phi = M_2PI_F * randv;
|
||||
float3 dir = make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cos_theta);
|
||||
float cos_phi = cosf(phi);
|
||||
float sin_phi = sinf(phi);
|
||||
float3 dir = make_float3(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta);
|
||||
|
||||
float3 T, B;
|
||||
make_orthonormals(D, &T, &B);
|
||||
dir = dir.x * T + dir.y * B + dir.z * D;
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
if (domega_in_dx && domega_in_dy) {
|
||||
if (pdf && *pdf < 1.0f) {
|
||||
float spread = 0.125f / sqrtf(*pdf);
|
||||
make_orthonormals(dir, &T, &B);
|
||||
*domega_in_dx = spread * T;
|
||||
*domega_in_dy = spread * B;
|
||||
}
|
||||
else {
|
||||
make_orthonormals(D - dIdx, &T, &B);
|
||||
*domega_in_dx = sin_theta * cos_phi * T + sin_theta * sin_phi * B + cos_theta * (D - dIdx) -
|
||||
dir;
|
||||
make_orthonormals(D - dIdy, &T, &B);
|
||||
*domega_in_dy = sin_theta * cos_phi * T + sin_theta * sin_phi * B + cos_theta * (D - dIdy) -
|
||||
dir;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -138,15 +166,10 @@ ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc,
|
||||
float g = volume->g;
|
||||
|
||||
/* note that I points towards the viewer and so is used negated */
|
||||
*omega_in = henyey_greenstrein_sample(-I, g, randu, randv, pdf);
|
||||
*omega_in = henyey_greenstrein_sample(
|
||||
-I, g, randu, randv, pdf, dIdx, dIdy, domega_in_dx, domega_in_dy);
|
||||
*eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* todo: implement ray differential estimation */
|
||||
*domega_in_dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
*domega_in_dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
return LABEL_VOLUME_SCATTER;
|
||||
}
|
||||
|
||||
|
@@ -778,6 +778,10 @@ ccl_device_inline void curve_shader_setup(KernelGlobals *kg,
|
||||
sd->dPdu = dPdu;
|
||||
sd->dPdv = cross(dPdu, sd->Ng);
|
||||
# endif
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
# endif
|
||||
|
||||
if (isect->object != OBJECT_NONE) {
|
||||
# ifdef __OBJECT_MOTION__
|
||||
|
@@ -85,6 +85,7 @@ ccl_device_noinline void motion_triangle_shader_setup(
|
||||
sd->dPdu = (verts[0] - verts[2]);
|
||||
sd->dPdv = (verts[1] - verts[2]);
|
||||
#endif
|
||||
|
||||
/* Compute smooth normal. */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
/* Find attribute. */
|
||||
|
@@ -107,8 +107,8 @@ triangle_smooth_normal(KernelGlobals *kg, float3 Ng, int prim, float u, float v)
|
||||
return is_zero(N) ? Ng : N;
|
||||
}
|
||||
|
||||
ccl_device_inline float3 triangle_smooth_normal_unnormalized(
|
||||
KernelGlobals *kg, ShaderData *sd, float3 Ng, int prim, float u, float v)
|
||||
ccl_device_inline float3
|
||||
triangle_smooth_normal_unnormalized(KernelGlobals *kg, float3 Ng, int prim, float u, float v)
|
||||
{
|
||||
/* load triangle vertices */
|
||||
const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
@@ -116,13 +116,6 @@ ccl_device_inline float3 triangle_smooth_normal_unnormalized(
|
||||
float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
|
||||
float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
|
||||
|
||||
/* ensure that the normals are in object space */
|
||||
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
|
||||
object_inverse_normal_transform(kg, sd, &n0);
|
||||
object_inverse_normal_transform(kg, sd, &n1);
|
||||
object_inverse_normal_transform(kg, sd, &n2);
|
||||
}
|
||||
|
||||
float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1;
|
||||
|
||||
return is_zero(N) ? Ng : N;
|
||||
@@ -146,6 +139,22 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals *kg,
|
||||
*dPdv = (p1 - p2);
|
||||
}
|
||||
|
||||
ccl_device_inline void triangle_dNdudv(KernelGlobals *kg,
|
||||
int prim,
|
||||
ccl_addr_space float3 *dNdu,
|
||||
ccl_addr_space float3 *dNdv)
|
||||
{
|
||||
/* load triangle vertices */
|
||||
const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
|
||||
float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
|
||||
float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
|
||||
|
||||
/* compute derivatives of N w.r.t. uv */
|
||||
*dNdu = (n0 - n2);
|
||||
*dNdv = (n1 - n2);
|
||||
}
|
||||
|
||||
/* Reading attributes on various triangle elements */
|
||||
|
||||
ccl_device float triangle_attribute_float(
|
||||
|
@@ -283,6 +283,7 @@ ccl_device void kernel_bake_evaluate(
|
||||
P,
|
||||
Ng,
|
||||
Ng,
|
||||
NULL,
|
||||
shader,
|
||||
object,
|
||||
prim,
|
||||
|
@@ -36,6 +36,23 @@ ccl_device void differential_transfer(ccl_addr_space differential3 *dP_,
|
||||
dP_->dy = tmpy - dot(tmpy, Ng) * tmp;
|
||||
}
|
||||
|
||||
ccl_device void differential_reflect(differential3 *dD_,
|
||||
float3 D,
|
||||
const ccl_addr_space differential3 *dD,
|
||||
float3 N,
|
||||
const differential3 *dN)
|
||||
{
|
||||
/* ray differential transfer through homogeneous medium, to
|
||||
* compute dPdx/dy at a shading point from the incoming ray */
|
||||
|
||||
const float dotDN = dot(D, N);
|
||||
const float3 tmpx = N * (dot(dD->dx, N) + dot(D, dN->dx));
|
||||
const float3 tmpy = N * (dot(dD->dy, N) + dot(D, dN->dy));
|
||||
|
||||
dD_->dx = dD->dx - 2.0f * (dotDN * dN->dx + tmpx);
|
||||
dD_->dy = dD->dy - 2.0f * (dotDN * dN->dy + tmpy);
|
||||
}
|
||||
|
||||
ccl_device void differential_incoming(ccl_addr_space differential3 *dI, const differential3 dD)
|
||||
{
|
||||
/* compute dIdx/dy at a shading point, we just need to negate the
|
||||
|
@@ -57,6 +57,7 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
|
||||
ls->P,
|
||||
ls->Ng,
|
||||
I,
|
||||
&dI,
|
||||
ls->shader,
|
||||
ls->object,
|
||||
ls->prim,
|
||||
@@ -111,10 +112,21 @@ ccl_device_noinline_cpu bool direct_emission(KernelGlobals *kg,
|
||||
if (ls->pdf == 0.0f)
|
||||
return false;
|
||||
|
||||
/* todo: implement */
|
||||
differential3 dD = differential3_zero();
|
||||
differential3 dD;
|
||||
differential3 dN;
|
||||
#ifdef __DNDU__
|
||||
dN.dx = sd->dNdx;
|
||||
dN.dy = sd->dNdy;
|
||||
#else
|
||||
dN = differential3_zero();
|
||||
#endif
|
||||
/* This is how differentials are calculated for a perfect specular reflection.
|
||||
* This is not the exact value that we should be getting here,
|
||||
* but it's still better than using zero differentials. */
|
||||
differential_reflect(&dD, sd->I, &sd->dI, sd->N, &dN);
|
||||
|
||||
/* evaluate closure */
|
||||
emission_sd->dP = sd->dP;
|
||||
|
||||
float3 light_eval = direct_emissive_eval(
|
||||
kg, emission_sd, ls, state, -ls->D, dD, ls->t, sd->time);
|
||||
|
@@ -44,6 +44,9 @@ struct OSLGlobals;
|
||||
struct OSLThreadData;
|
||||
struct OSLShadingSystem;
|
||||
# endif
|
||||
# ifdef __OIIO__
|
||||
struct OIIOGlobals;
|
||||
# endif
|
||||
|
||||
typedef unordered_map<float, float> CoverageMap;
|
||||
|
||||
@@ -64,6 +67,11 @@ typedef struct KernelGlobals {
|
||||
OSLThreadData *osl_tdata;
|
||||
# endif
|
||||
|
||||
# ifdef __OIIO__
|
||||
OIIOGlobals *oiio;
|
||||
void *oiio_tdata;
|
||||
# endif
|
||||
|
||||
/* **** Run-time data **** */
|
||||
|
||||
/* Heap-allocated storage for transparent shadows intersections. */
|
||||
|
@@ -333,6 +333,33 @@ ccl_device bool lamp_light_eval(
|
||||
return true;
|
||||
}
|
||||
|
||||
ccl_device void lamp_light_dPdudv(KernelGlobals *kg,
|
||||
int lamp,
|
||||
float u,
|
||||
float v,
|
||||
ccl_addr_space float3 *dPdu,
|
||||
ccl_addr_space float3 *dPdv)
|
||||
{
|
||||
const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
|
||||
LightType type = (LightType)klight->type;
|
||||
|
||||
switch (type) {
|
||||
case LIGHT_AREA: {
|
||||
*dPdu = make_float3(klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
|
||||
*dPdv = make_float3(klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]);
|
||||
break;
|
||||
}
|
||||
case LIGHT_POINT:
|
||||
case LIGHT_DISTANT:
|
||||
case LIGHT_SPOT:
|
||||
default:
|
||||
// TODO (Stefan)
|
||||
*dPdu = make_float3(0.0f, 0.0f, 0.0f);
|
||||
*dPdv = make_float3(0.0f, 0.0f, 0.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Triangle Light */
|
||||
|
||||
/* returns true if the triangle is has motion blur or an instancing transform applied */
|
||||
|
41
intern/cycles/kernel/kernel_oiio_globals.h
Normal file
41
intern/cycles/kernel/kernel_oiio_globals.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2011-2017 Blender Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __KERNEL_OIIO_GLOBALS_H__
|
||||
#define __KERNEL_OIIO_GLOBALS_H__
|
||||
|
||||
#include "util/util_thread.h"
|
||||
#include "util/util_vector.h"
|
||||
#include <OpenImageIO/texture.h>
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
struct OIIOTexture {
|
||||
OIIO::TextureSystem::TextureHandle *handle;
|
||||
OIIO::TextureOpt::InterpMode interpolation;
|
||||
OIIO::TextureOpt::Wrap extension;
|
||||
bool is_linear;
|
||||
};
|
||||
|
||||
struct OIIOGlobals {
|
||||
OIIO::TextureSystem *tex_sys;
|
||||
float diffuse_blur;
|
||||
float glossy_blur;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
@@ -30,8 +30,8 @@
|
||||
|
||||
#include "kernel/kernel_write_passes.h"
|
||||
#include "kernel/kernel_accumulate.h"
|
||||
#include "kernel/kernel_shader.h"
|
||||
#include "kernel/kernel_light.h"
|
||||
#include "kernel/kernel_shader.h"
|
||||
#include "kernel/kernel_adaptive_sampling.h"
|
||||
#include "kernel/kernel_passes.h"
|
||||
|
||||
@@ -354,8 +354,14 @@ ccl_device_noinline
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
light_ray.time = sd->time;
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
light_ray.dP = sd->dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
/* This is how pbrt v3 implements differentials for diffuse bounces */
|
||||
float3 a, b;
|
||||
make_orthonormals(ao_D, &a, &b);
|
||||
light_ray.dD.dx = normalize(ao_D + 0.1f * a);
|
||||
light_ray.dD.dy = normalize(ao_D + 0.1f * b);
|
||||
#endif /* __RAY_DIFFERENTIALS__ */
|
||||
|
||||
if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) {
|
||||
path_radiance_accum_ao(kg, L, state, throughput, ao_alpha, ao_bsdf, ao_shadow);
|
||||
|
@@ -50,8 +50,14 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
|
||||
light_ray.D = ao_D;
|
||||
light_ray.t = kernel_data.background.ao_distance;
|
||||
light_ray.time = sd->time;
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
light_ray.dP = sd->dP;
|
||||
light_ray.dD = differential3_zero();
|
||||
/* This is how pbrt v3 implements differentials for diffuse bounces */
|
||||
float3 a, b;
|
||||
make_orthonormals(ao_D, &a, &b);
|
||||
light_ray.dD.dx = normalize(ao_D + 0.1f * a);
|
||||
light_ray.dD.dy = normalize(ao_D + 0.1f * b);
|
||||
# endif /* __RAY_DIFFERENTIALS__ */
|
||||
|
||||
if (!shadow_blocked(kg, sd, emission_sd, state, &light_ray, &ao_shadow)) {
|
||||
path_radiance_accum_ao(
|
||||
|
@@ -146,6 +146,34 @@ ccl_device_noinline
|
||||
differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t);
|
||||
differential_incoming(&sd->dI, ray->dD);
|
||||
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
|
||||
# ifdef __DNDU__
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL && sd->type & PRIMITIVE_TRIANGLE) {
|
||||
// TODO stefan curves
|
||||
/* dNdu/dNdv */
|
||||
float3 dNdu, dNdv;
|
||||
triangle_dNdudv(kg, sd->prim, &dNdu, &dNdv);
|
||||
sd->dNdx = dNdu * sd->du.dx + dNdv * sd->dv.dx;
|
||||
sd->dNdy = dNdu * sd->du.dy + dNdv * sd->dv.dy;
|
||||
|
||||
/* backfacing test */
|
||||
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
|
||||
if (backfacing) {
|
||||
sd->dNdx = -sd->dNdx;
|
||||
sd->dNdy = -sd->dNdy;
|
||||
}
|
||||
# ifdef __INSTANCING__
|
||||
if (isect->object != OBJECT_NONE) {
|
||||
/* instance transform */
|
||||
object_dir_transform_auto(kg, sd, &sd->dNdx);
|
||||
object_dir_transform_auto(kg, sd, &sd->dNdy);
|
||||
}
|
||||
# endif /* __INSTANCING__ */
|
||||
}
|
||||
else {
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
# endif /* __DNDU__ */
|
||||
#endif
|
||||
|
||||
PROFILING_SHADER(sd->shader);
|
||||
@@ -179,6 +207,11 @@ ccl_device_inline
|
||||
sd->u = isect->u;
|
||||
sd->v = isect->v;
|
||||
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
# endif
|
||||
|
||||
/* fetch triangle data */
|
||||
if (sd->type == PRIMITIVE_TRIANGLE) {
|
||||
float3 Ng = triangle_normal(kg, sd);
|
||||
@@ -195,6 +228,15 @@ ccl_device_inline
|
||||
# ifdef __DPDU__
|
||||
/* dPdu/dPdv */
|
||||
triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
|
||||
# endif
|
||||
# ifdef __DNDU__
|
||||
/* dNdu/dNdv */
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL && sd->type & PRIMITIVE_TRIANGLE) {
|
||||
float3 dNdu, dNdv;
|
||||
triangle_dNdudv(kg, sd->prim, &dNdu, &dNdv);
|
||||
sd->dNdx = dNdu * sd->du.dx + dNdv * sd->dv.dx;
|
||||
sd->dNdy = dNdu * sd->du.dy + dNdv * sd->dv.dy;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
else {
|
||||
@@ -211,6 +253,10 @@ ccl_device_inline
|
||||
# ifdef __DPDU__
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
# endif
|
||||
# ifdef __DNDU__
|
||||
object_dir_transform(kg, sd, &sd->dNdx);
|
||||
object_dir_transform(kg, sd, &sd->dNdy);
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -222,6 +268,10 @@ ccl_device_inline
|
||||
# ifdef __DPDU__
|
||||
sd->dPdu = -sd->dPdu;
|
||||
sd->dPdv = -sd->dPdv;
|
||||
# endif
|
||||
# ifdef __DNDU__
|
||||
sd->dNdx = -sd->dNdx;
|
||||
sd->dNdy = -sd->dNdy;
|
||||
# endif
|
||||
}
|
||||
|
||||
@@ -246,6 +296,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
|
||||
const float3 P,
|
||||
const float3 Ng,
|
||||
const float3 I,
|
||||
const differential3 *dI,
|
||||
int shader,
|
||||
int object,
|
||||
int prim,
|
||||
@@ -326,12 +377,39 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdu);
|
||||
object_dir_transform_auto(kg, sd, &sd->dPdv);
|
||||
}
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
|
||||
float3 dNdu, dNdv;
|
||||
triangle_dNdudv(kg, sd->prim, &dNdu, &dNdv);
|
||||
sd->dNdx = dNdu * sd->du.dx + dNdv * sd->dv.dx;
|
||||
sd->dNdy = dNdu * sd->du.dy + dNdv * sd->dv.dy;
|
||||
|
||||
# ifdef __INSTANCING__
|
||||
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
||||
object_normal_transform_auto(kg, sd, &sd->dNdx);
|
||||
object_normal_transform_auto(kg, sd, &sd->dNdy);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
else if (sd->type & PRIMITIVE_LAMP) {
|
||||
#ifdef __DPDU__
|
||||
lamp_light_dPdudv(kg, lamp, sd->u, sd->v, &sd->dPdu, &sd->dPdv);
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = zero_float3();
|
||||
sd->dPdv = zero_float3();
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -346,16 +424,27 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
|
||||
#ifdef __DPDU__
|
||||
sd->dPdu = -sd->dPdu;
|
||||
sd->dPdv = -sd->dPdv;
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
sd->dNdx = -sd->dNdx;
|
||||
sd->dNdx = -sd->dNdx;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* no ray differentials here yet */
|
||||
sd->dP = differential3_zero();
|
||||
sd->dI = differential3_zero();
|
||||
sd->du = differential_zero();
|
||||
sd->dv = differential_zero();
|
||||
if (dI) {
|
||||
sd->dI = *dI;
|
||||
differential_transfer(&sd->dP, sd->dP, I, *dI, Ng, t);
|
||||
differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
|
||||
}
|
||||
else {
|
||||
sd->dP = differential3_zero();
|
||||
sd->dI = differential3_zero();
|
||||
sd->du = differential_zero();
|
||||
sd->dv = differential_zero();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PROFILING_SHADER(sd->shader);
|
||||
@@ -371,25 +460,32 @@ ccl_device void shader_setup_from_displace(
|
||||
int shader;
|
||||
|
||||
triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
|
||||
triangle_dPdudv(kg, prim, &sd->dP.dx, &sd->dP.dy);
|
||||
|
||||
/* force smooth shading for displacement */
|
||||
shader |= SHADER_SMOOTH_NORMAL;
|
||||
|
||||
#if 0
|
||||
/* TODO Stefan - need differentials here that don't break the unfiltered case */
|
||||
I = -Ng;
|
||||
differential3 dI = differential3_zero();
|
||||
|
||||
shader_setup_from_sample(kg, sd,
|
||||
P, Ng, I, &dI,
|
||||
#else
|
||||
|
||||
shader_setup_from_sample(
|
||||
kg,
|
||||
sd,
|
||||
P,
|
||||
Ng,
|
||||
I,
|
||||
shader,
|
||||
object,
|
||||
prim,
|
||||
u,
|
||||
v,
|
||||
0.0f,
|
||||
0.5f,
|
||||
!(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
|
||||
LAMP_NONE);
|
||||
NULL,
|
||||
#endif
|
||||
shader, object, prim,
|
||||
u, v, 0.0f, 0.5f,
|
||||
!(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
|
||||
LAMP_NONE);
|
||||
}
|
||||
|
||||
/* ShaderData setup from ray into background */
|
||||
@@ -422,6 +518,10 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg,
|
||||
sd->dPdu = zero_float3();
|
||||
sd->dPdv = zero_float3();
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
#ifdef __RAY_DIFFERENTIALS__
|
||||
/* differentials */
|
||||
@@ -469,11 +569,17 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
|
||||
sd->dPdu = zero_float3();
|
||||
sd->dPdv = zero_float3();
|
||||
# endif
|
||||
# ifdef __DNDU__
|
||||
/* dNdu/dNdv */
|
||||
sd->dNdx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
sd->dNdy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
# endif
|
||||
|
||||
# ifdef __RAY_DIFFERENTIALS__
|
||||
/* differentials */
|
||||
sd->dP = ray->dD;
|
||||
differential_incoming(&sd->dI, sd->dP);
|
||||
sd->dP.dx = ray->dP.dx + ray->t * ray->dD.dx;
|
||||
sd->dP.dy = ray->dP.dy + ray->t * ray->dD.dy;
|
||||
differential_incoming(&sd->dI, ray->dD);
|
||||
sd->du = differential_zero();
|
||||
sd->dv = differential_zero();
|
||||
# endif
|
||||
|
@@ -558,6 +558,7 @@ ccl_device_noinline
|
||||
/* Sample scattering direction. */
|
||||
float scatter_u, scatter_v;
|
||||
path_state_rng_2D(kg, state, PRNG_BSDF_U, &scatter_u, &scatter_v);
|
||||
|
||||
float cos_theta;
|
||||
if (guided) {
|
||||
cos_theta = sample_phase_dwivedi(diffusion_length, phase_log, scatter_u);
|
||||
|
@@ -124,6 +124,8 @@ CCL_NAMESPACE_BEGIN
|
||||
# endif
|
||||
# define __VOLUME_DECOUPLED__
|
||||
# define __VOLUME_RECORD_ALL__
|
||||
# define __DNDU__
|
||||
# define __OIIO__
|
||||
#endif /* __KERNEL_CPU__ */
|
||||
|
||||
#ifdef __KERNEL_CUDA__
|
||||
@@ -953,6 +955,11 @@ typedef ccl_addr_space struct ccl_align(16) ShaderData
|
||||
float3 dPdu;
|
||||
float3 dPdv;
|
||||
#endif
|
||||
#ifdef __DNDU__
|
||||
/* differential of N w.r.t. x and y. */
|
||||
float3 dNdx;
|
||||
float3 dNdy;
|
||||
#endif
|
||||
|
||||
#ifdef __OBJECT_MOTION__
|
||||
/* object <-> world space transformations, cached to avoid
|
||||
|
@@ -34,6 +34,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/filter/filter.h"
|
||||
#define KERNEL_ARCH cpu_avx
|
||||
#include "kernel/kernels/cpu/filter_cpu_impl.h"
|
||||
|
@@ -35,6 +35,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/filter/filter.h"
|
||||
#define KERNEL_ARCH cpu_avx2
|
||||
#include "kernel/kernels/cpu/filter_cpu_impl.h"
|
||||
|
@@ -34,6 +34,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#define KERNEL_ARCH cpu_avx
|
||||
#include "kernel/kernels/cpu/kernel_cpu_impl.h"
|
||||
|
@@ -35,6 +35,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#define KERNEL_ARCH cpu_avx2
|
||||
#include "kernel/kernels/cpu/kernel_cpu_impl.h"
|
||||
|
@@ -23,6 +23,14 @@
|
||||
# include <nanovdb/util/SampleFromVoxels.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OIIO__
|
||||
# include "kernel/kernel_oiio_globals.h"
|
||||
# define NEAREST_LOOKUP_PATHS \
|
||||
(PATH_RAY_DIFFUSE | PATH_RAY_SHADOW | PATH_RAY_DIFFUSE_ANCESTOR | PATH_RAY_VOLUME_SCATTER | \
|
||||
PATH_RAY_GLOSSY | PATH_RAY_EMISSION)
|
||||
# define DIFFUSE_BLUR_PATHS (PATH_RAY_DIFFUSE | PATH_RAY_DIFFUSE_ANCESTOR)
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Make template functions private so symbols don't conflict between kernels with different
|
||||
@@ -584,32 +592,126 @@ template<typename T> struct NanoVDBInterpolator {
|
||||
|
||||
#undef SET_CUBIC_SPLINE_WEIGHTS
|
||||
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y, differential ds, differential dt, uint path_flag)
|
||||
{
|
||||
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
|
||||
float4 r = make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
|
||||
switch (info.data_type) {
|
||||
case IMAGE_DATA_TYPE_HALF:
|
||||
return TextureInterpolator<half>::interp(info, x, y);
|
||||
r = TextureInterpolator<half>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_BYTE:
|
||||
return TextureInterpolator<uchar>::interp(info, x, y);
|
||||
r = TextureInterpolator<uchar>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_USHORT:
|
||||
return TextureInterpolator<uint16_t>::interp(info, x, y);
|
||||
r = TextureInterpolator<uint16_t>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_FLOAT:
|
||||
return TextureInterpolator<float>::interp(info, x, y);
|
||||
r = TextureInterpolator<float>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_HALF4:
|
||||
return TextureInterpolator<half4>::interp(info, x, y);
|
||||
r = TextureInterpolator<half4>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_BYTE4:
|
||||
return TextureInterpolator<uchar4>::interp(info, x, y);
|
||||
r = TextureInterpolator<uchar4>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_USHORT4:
|
||||
return TextureInterpolator<ushort4>::interp(info, x, y);
|
||||
r = TextureInterpolator<ushort4>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_FLOAT4:
|
||||
return TextureInterpolator<float4>::interp(info, x, y);
|
||||
r = TextureInterpolator<float4>::interp(info, x, y);
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_OIIO:
|
||||
{
|
||||
#ifdef __OIIO__
|
||||
/* Make sure we have all necessary data in place, if not, bail. */
|
||||
kernel_assert(kg->oiio);
|
||||
kernel_assert(kg->oiio->tex_sys);
|
||||
kernel_assert(info.data);
|
||||
if (!kg->oiio || !kg->oiio->tex_sys || !info.data) {
|
||||
return r;
|
||||
}
|
||||
/* Options: Anisotropic is a quality/speed tradeoff.
|
||||
* Interpolation and extensions are supported in OIIO under different constants.
|
||||
* */
|
||||
OIIO::TextureOpt options;
|
||||
options.anisotropic = 8;
|
||||
float missingcolor[4] = {
|
||||
TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A};
|
||||
options.missingcolor = missingcolor;
|
||||
options.mipmode = OIIO::TextureOpt::MipModeAniso;
|
||||
options.sblur = options.tblur = 0.0f;
|
||||
switch (info.interpolation) {
|
||||
case INTERPOLATION_SMART:
|
||||
options.interpmode = OIIO::TextureOpt::InterpSmartBicubic;
|
||||
break;
|
||||
case INTERPOLATION_CUBIC:
|
||||
options.interpmode = OIIO::TextureOpt::InterpBicubic;
|
||||
break;
|
||||
case INTERPOLATION_LINEAR:
|
||||
options.interpmode = OIIO::TextureOpt::InterpBilinear;
|
||||
break;
|
||||
//case INTERPOLATION_NONE:
|
||||
case INTERPOLATION_CLOSEST:
|
||||
default:
|
||||
options.interpmode = OIIO::TextureOpt::InterpClosest;
|
||||
break;
|
||||
}
|
||||
switch (info.extension) {
|
||||
case EXTENSION_CLIP:
|
||||
options.swrap = options.twrap = OIIO::TextureOpt::WrapBlack;
|
||||
break;
|
||||
case EXTENSION_EXTEND:
|
||||
options.swrap = options.twrap = OIIO::TextureOpt::WrapClamp;
|
||||
break;
|
||||
case EXTENSION_REPEAT:
|
||||
default:
|
||||
options.swrap = options.twrap = OIIO::TextureOpt::WrapPeriodic;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Texture lookup simplifications on less important paths. */
|
||||
if (path_flag & NEAREST_LOOKUP_PATHS && !(path_flag & PATH_RAY_SINGULAR)) {
|
||||
options.interpmode = OIIO::TextureOpt::InterpClosest;
|
||||
options.mipmode = OIIO::TextureOpt::MipModeOneLevel;
|
||||
}
|
||||
else {
|
||||
options.mipmode = OIIO::TextureOpt::MipModeAniso;
|
||||
}
|
||||
if (path_flag & DIFFUSE_BLUR_PATHS) {
|
||||
options.sblur = options.tblur = kg->oiio->diffuse_blur;
|
||||
}
|
||||
else if (path_flag & PATH_RAY_GLOSSY) {
|
||||
options.sblur = options.tblur = kg->oiio->glossy_blur;
|
||||
}
|
||||
else {
|
||||
options.sblur = options.tblur = 0.0f;
|
||||
}
|
||||
|
||||
OIIO::TextureSystem::TextureHandle *handle = *((OIIO::TextureSystem::TextureHandle**)info.data);
|
||||
kernel_assert(handle && kg->oiio->tex_sys->good(handle));
|
||||
if(handle && !kg->oiio->tex_sys->good(handle)) {
|
||||
return r;
|
||||
}
|
||||
kg->oiio->tex_sys->texture(handle,
|
||||
(OIIO::TextureSystem::Perthread *)kg->oiio_tdata,
|
||||
options,
|
||||
x,
|
||||
y,
|
||||
ds.dx,
|
||||
ds.dy,
|
||||
dt.dx,
|
||||
dt.dy,
|
||||
4,
|
||||
(float *)&r);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
return make_float4(
|
||||
TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
}
|
||||
return info.compress_as_srgb ? color_srgb_to_linear_v4(r) : r;
|
||||
}
|
||||
|
||||
ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg,
|
||||
@@ -646,6 +748,8 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg,
|
||||
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
|
||||
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, P.x, P.y, P.z, interp);
|
||||
#endif
|
||||
case IMAGE_DATA_TYPE_OIIO:
|
||||
return make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
default:
|
||||
assert(0);
|
||||
return make_float4(
|
||||
|
@@ -36,6 +36,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#define KERNEL_ARCH cpu_avx
|
||||
#include "kernel/kernels/cpu/kernel_cpu_impl.h"
|
||||
|
@@ -37,6 +37,8 @@
|
||||
# endif
|
||||
#endif /* WITH_CYCLES_OPTIMIZED_KERNEL_AVX2 */
|
||||
|
||||
#define OIIO_NO_AVX 1
|
||||
|
||||
#include "kernel/kernel.h"
|
||||
#define KERNEL_ARCH cpu_avx2
|
||||
#include "kernel/kernels/cpu/kernel_cpu_impl.h"
|
||||
|
@@ -178,7 +178,7 @@ ccl_device_inline T kernel_tex_image_interp_nanovdb(
|
||||
}
|
||||
#endif
|
||||
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y, differential, differential, uint)
|
||||
{
|
||||
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
|
||||
|
||||
|
@@ -123,6 +123,10 @@ ccl_device_inline float4 svm_image_texture_read(
|
||||
return make_float4(r.x, r.y, r.z, r.w);
|
||||
}
|
||||
#endif
|
||||
/* Unsupported. */
|
||||
else if (texture_type == IMAGE_DATA_TYPE_OIIO) {
|
||||
return make_float4(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
}
|
||||
/* Byte */
|
||||
else {
|
||||
uchar r = tex_fetch(uchar, info, data_offset);
|
||||
@@ -199,7 +203,7 @@ ccl_device_inline float svm_image_texture_frac(float x, int *ix)
|
||||
} \
|
||||
(void)0
|
||||
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y)
|
||||
ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y, differential, differential, uint)
|
||||
{
|
||||
const ccl_global TextureInfo *info = kernel_tex_info(kg, id);
|
||||
|
||||
|
@@ -56,6 +56,7 @@
|
||||
|
||||
#include "kernel/kernel_projection.h"
|
||||
#include "kernel/kernel_accumulate.h"
|
||||
#include "kernel/kernel_light.h"
|
||||
#include "kernel/kernel_shader.h"
|
||||
// clang-format on
|
||||
|
||||
@@ -1248,7 +1249,12 @@ bool OSLRenderServices::texture(ustring filename,
|
||||
}
|
||||
case OSLTextureHandle::SVM: {
|
||||
/* Packed texture. */
|
||||
float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
|
||||
differential ds, dt;
|
||||
ds.dx = dsdx;
|
||||
ds.dy = dsdy;
|
||||
dt.dx = dtdx;
|
||||
dt.dy = dtdy;
|
||||
float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t, ds, dt, sg->raytype);
|
||||
|
||||
result[0] = rgba[0];
|
||||
if (nchannels > 1)
|
||||
@@ -1280,7 +1286,7 @@ bool OSLRenderServices::texture(ustring filename,
|
||||
texture_thread_info,
|
||||
options,
|
||||
s,
|
||||
t,
|
||||
1.0f - t,
|
||||
dsdx,
|
||||
dtdx,
|
||||
dsdy,
|
||||
@@ -1294,7 +1300,7 @@ bool OSLRenderServices::texture(ustring filename,
|
||||
status = ts->texture(filename,
|
||||
options,
|
||||
s,
|
||||
t,
|
||||
1.0f - t,
|
||||
dsdx,
|
||||
dtdx,
|
||||
dsdy,
|
||||
|
@@ -47,7 +47,6 @@ shader node_environment_texture(
|
||||
string filename = "",
|
||||
string projection = "equirectangular",
|
||||
string interpolation = "linear",
|
||||
int compress_as_srgb = 0,
|
||||
int ignore_alpha = 0,
|
||||
int unassociate_alpha = 0,
|
||||
int is_float = 1,
|
||||
@@ -79,7 +78,4 @@ shader node_environment_texture(
|
||||
if (!is_float)
|
||||
Color = min(Color, 1.0);
|
||||
}
|
||||
|
||||
if (compress_as_srgb)
|
||||
Color = color_srgb_to_scene_linear(Color);
|
||||
}
|
||||
|
@@ -59,7 +59,6 @@ color image_texture_lookup(string filename,
|
||||
float u,
|
||||
float v,
|
||||
output float Alpha,
|
||||
int compress_as_srgb,
|
||||
int ignore_alpha,
|
||||
int unassociate_alpha,
|
||||
int is_float,
|
||||
@@ -89,10 +88,6 @@ color image_texture_lookup(string filename,
|
||||
rgb = min(rgb, 1.0);
|
||||
}
|
||||
|
||||
if (compress_as_srgb) {
|
||||
rgb = color_srgb_to_scene_linear(rgb);
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
@@ -104,7 +99,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
string interpolation = "smartcubic",
|
||||
string extension = "periodic",
|
||||
float projection_blend = 0.0,
|
||||
int compress_as_srgb = 0,
|
||||
int ignore_alpha = 0,
|
||||
int unassociate_alpha = 0,
|
||||
int is_tiled = 0,
|
||||
@@ -122,7 +116,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
p[0],
|
||||
p[1],
|
||||
Alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
@@ -201,7 +194,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
p[1],
|
||||
p[2],
|
||||
tmp_alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
@@ -215,7 +207,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
p[0],
|
||||
p[2],
|
||||
tmp_alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
@@ -229,7 +220,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
p[1],
|
||||
p[0],
|
||||
tmp_alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
@@ -245,7 +235,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
projected[0],
|
||||
projected[1],
|
||||
Alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
@@ -259,7 +248,6 @@ shader node_image_texture(int use_mapping = 0,
|
||||
projected[0],
|
||||
projected[1],
|
||||
Alpha,
|
||||
compress_as_srgb,
|
||||
ignore_alpha,
|
||||
unassociate_alpha,
|
||||
is_float,
|
||||
|
@@ -327,10 +327,10 @@ ccl_device_noinline void svm_eval_nodes(
|
||||
break;
|
||||
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
|
||||
case NODE_TEX_IMAGE:
|
||||
svm_node_tex_image(kg, sd, stack, node, &offset);
|
||||
svm_node_tex_image(kg, sd, path_flag, stack, node, &offset);
|
||||
break;
|
||||
case NODE_TEX_IMAGE_BOX:
|
||||
svm_node_tex_image_box(kg, sd, stack, node);
|
||||
svm_node_tex_image_box(kg, sd, path_flag, stack, node);
|
||||
break;
|
||||
case NODE_TEX_NOISE:
|
||||
svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, &offset);
|
||||
@@ -437,7 +437,7 @@ ccl_device_noinline void svm_eval_nodes(
|
||||
svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
|
||||
break;
|
||||
case NODE_TEX_ENVIRONMENT:
|
||||
svm_node_tex_environment(kg, sd, stack, node);
|
||||
svm_node_tex_environment(kg, sd, path_flag, stack, node);
|
||||
break;
|
||||
case NODE_TEX_SKY:
|
||||
svm_node_tex_sky(kg, sd, stack, node, &offset);
|
||||
|
@@ -16,14 +16,21 @@
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint flags)
|
||||
ccl_device float4 svm_image_texture(KernelGlobals *kg,
|
||||
int id,
|
||||
float x,
|
||||
float y,
|
||||
differential ds,
|
||||
differential dt,
|
||||
uint flags,
|
||||
int path_flag)
|
||||
{
|
||||
if (id == -1) {
|
||||
return make_float4(
|
||||
TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
|
||||
}
|
||||
|
||||
float4 r = kernel_tex_image_interp(kg, id, x, y);
|
||||
float4 r = kernel_tex_image_interp(kg, id, x, y, ds, dt, path_flag);
|
||||
const float alpha = r.w;
|
||||
|
||||
if ((flags & NODE_IMAGE_ALPHA_UNASSOCIATE) && alpha != 1.0f && alpha != 0.0f) {
|
||||
@@ -31,10 +38,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
|
||||
r.w = alpha;
|
||||
}
|
||||
|
||||
if (flags & NODE_IMAGE_COMPRESS_AS_SRGB) {
|
||||
r = color_srgb_to_linear_v4(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -45,19 +48,21 @@ ccl_device_inline float3 texco_remap_square(float3 co)
|
||||
}
|
||||
|
||||
ccl_device void svm_node_tex_image(
|
||||
KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
|
||||
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node, int *offset)
|
||||
{
|
||||
uint co_offset, out_offset, alpha_offset, flags;
|
||||
uint projection, dx_offset, dy_offset, unused;
|
||||
|
||||
svm_unpack_node_uchar4(node.z, &co_offset, &out_offset, &alpha_offset, &flags);
|
||||
svm_unpack_node_uchar4(node.w, &projection, &dx_offset, &dy_offset, &unused);
|
||||
|
||||
float3 co = stack_load_float3(stack, co_offset);
|
||||
float2 tex_co;
|
||||
if (node.w == NODE_IMAGE_PROJ_SPHERE) {
|
||||
if (projection == NODE_IMAGE_PROJ_SPHERE) {
|
||||
co = texco_remap_square(co);
|
||||
tex_co = map_to_sphere(co);
|
||||
}
|
||||
else if (node.w == NODE_IMAGE_PROJ_TUBE) {
|
||||
else if (projection == NODE_IMAGE_PROJ_TUBE) {
|
||||
co = texco_remap_square(co);
|
||||
tex_co = map_to_tube(co);
|
||||
}
|
||||
@@ -65,6 +70,40 @@ ccl_device void svm_node_tex_image(
|
||||
tex_co = make_float2(co.x, co.y);
|
||||
}
|
||||
|
||||
differential ds, dt;
|
||||
#ifdef __KERNEL_CPU__
|
||||
if (stack_valid(dx_offset) && stack_valid(dy_offset)) {
|
||||
float3 dx = stack_load_float3(stack, dx_offset);
|
||||
float3 dy = stack_load_float3(stack, dy_offset);
|
||||
float2 tex_co_dx, tex_co_dy;
|
||||
if (projection == NODE_IMAGE_PROJ_SPHERE) {
|
||||
dx = texco_remap_square(dx);
|
||||
tex_co_dx = map_to_sphere(dx);
|
||||
dy = texco_remap_square(dy);
|
||||
tex_co_dy = map_to_sphere(dy);
|
||||
}
|
||||
else if (projection == NODE_IMAGE_PROJ_TUBE) {
|
||||
dx = texco_remap_square(dx);
|
||||
tex_co_dx = map_to_tube(dx);
|
||||
dy = texco_remap_square(dy);
|
||||
tex_co_dy = map_to_tube(dy);
|
||||
}
|
||||
else {
|
||||
tex_co_dx = make_float2(dx.x, dx.y);
|
||||
tex_co_dy = make_float2(dy.x, dy.y);
|
||||
}
|
||||
ds.dx = tex_co_dx.x - tex_co.x;
|
||||
ds.dy = tex_co_dy.x - tex_co.x;
|
||||
dt.dx = tex_co_dx.y - tex_co.y;
|
||||
dt.dy = tex_co_dy.y - tex_co.y;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ds = differential_zero();
|
||||
dt = differential_zero();
|
||||
}
|
||||
|
||||
/* TODO(lukas): Consider moving tile information out of the SVM node.
|
||||
* TextureInfo seems a reasonable candidate. */
|
||||
int id = -1;
|
||||
@@ -108,7 +147,7 @@ ccl_device void svm_node_tex_image(
|
||||
id = -num_nodes;
|
||||
}
|
||||
|
||||
float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, flags);
|
||||
float4 f = svm_image_texture(kg, id, tex_co.x, tex_co.y, ds, dt, flags, path_flag);
|
||||
|
||||
if (stack_valid(out_offset))
|
||||
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||
@@ -116,7 +155,8 @@ ccl_device void svm_node_tex_image(
|
||||
stack_store_float(stack, alpha_offset, f.w);
|
||||
}
|
||||
|
||||
ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
|
||||
ccl_device void svm_node_tex_image_box(
|
||||
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node)
|
||||
{
|
||||
/* get object space normal */
|
||||
float3 N = sd->N;
|
||||
@@ -144,7 +184,9 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float
|
||||
* 7 zones, with an if() test for each zone */
|
||||
|
||||
float3 weight = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float blend = __int_as_float(node.w);
|
||||
uint blend_hi, blend_lo, dx_offset, dy_offset;
|
||||
svm_unpack_node_uchar4(node.w, &blend_hi, &blend_lo, &dx_offset, &dy_offset);
|
||||
float blend = ((blend_hi << 8) + blend_lo) / 65536.0f;
|
||||
float limit = 0.5f * (1.0f + blend);
|
||||
|
||||
/* first test for corners with single texture */
|
||||
@@ -195,30 +237,49 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float
|
||||
|
||||
float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
float3 co_dx = make_float3(0.0f, 0.0f, 0.0f);
|
||||
float3 co_dy = make_float3(0.0f, 0.0f, 0.0f);
|
||||
differential ds, dt;
|
||||
#ifdef __KERNEL_CPU__
|
||||
if (stack_valid(dx_offset) && stack_valid(dy_offset)) {
|
||||
co_dx = co - stack_load_float3(stack, dx_offset);
|
||||
co_dy = co - stack_load_float3(stack, dy_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Map so that no textures are flipped, rotation is somewhat arbitrary. */
|
||||
if (weight.x > 0.0f) {
|
||||
float2 uv = make_float2((signed_N.x < 0.0f) ? 1.0f - co.y : co.y, co.z);
|
||||
f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, flags);
|
||||
ds.dx = co_dx.y;
|
||||
ds.dy = co_dy.y;
|
||||
dt.dx = co_dx.z;
|
||||
dt.dy = co_dy.z;
|
||||
f += weight.x * svm_image_texture(kg, id, uv.x, uv.y, ds, dt, flags, path_flag);
|
||||
}
|
||||
if (weight.y > 0.0f) {
|
||||
float2 uv = make_float2((signed_N.y > 0.0f) ? 1.0f - co.x : co.x, co.z);
|
||||
f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, flags);
|
||||
float2 uv = make_float2((signed_N.y < 0.0f) ? 1.0f - co.x : co.x, co.z);
|
||||
ds.dx = co_dx.x;
|
||||
ds.dy = co_dy.x;
|
||||
dt.dx = co_dx.z;
|
||||
dt.dy = co_dy.z;
|
||||
f += weight.y * svm_image_texture(kg, id, uv.x, uv.y, ds, dt, flags, path_flag);
|
||||
}
|
||||
if (weight.z > 0.0f) {
|
||||
float2 uv = make_float2((signed_N.z > 0.0f) ? 1.0f - co.y : co.y, co.x);
|
||||
f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, flags);
|
||||
float2 uv = make_float2((signed_N.z < 0.0f) ? 1.0f - co.y : co.y, co.x);
|
||||
ds.dx = co_dx.y;
|
||||
ds.dy = co_dy.y;
|
||||
dt.dx = co_dx.x;
|
||||
dt.dy = co_dy.x;
|
||||
f += weight.z * svm_image_texture(kg, id, uv.x, uv.y, ds, dt, flags, path_flag);
|
||||
}
|
||||
|
||||
if (stack_valid(out_offset))
|
||||
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||
if (stack_valid(alpha_offset))
|
||||
stack_store_float(stack, alpha_offset, f.w);
|
||||
}
|
||||
|
||||
ccl_device void svm_node_tex_environment(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
float *stack,
|
||||
uint4 node)
|
||||
ccl_device void svm_node_tex_environment(
|
||||
KernelGlobals *kg, ShaderData *sd, int path_flag, float *stack, uint4 node)
|
||||
{
|
||||
uint id = node.y;
|
||||
uint co_offset, out_offset, alpha_offset, flags;
|
||||
@@ -236,7 +297,8 @@ ccl_device void svm_node_tex_environment(KernelGlobals *kg,
|
||||
else
|
||||
uv = direction_to_mirrorball(co);
|
||||
|
||||
float4 f = svm_image_texture(kg, id, uv.x, uv.y, flags);
|
||||
float4 f = svm_image_texture(
|
||||
kg, id, uv.x, uv.y, differential_zero(), differential_zero(), flags, path_flag);
|
||||
|
||||
if (stack_valid(out_offset))
|
||||
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
|
||||
|
@@ -141,6 +141,8 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
|
||||
float3 xyz;
|
||||
/* convert dir to spherical coordinates */
|
||||
float2 direction = direction_to_spherical(dir);
|
||||
differential ds, dt;
|
||||
ds.dx = ds.dy = dt.dx = dt.dy = 0.0f;
|
||||
|
||||
/* render above the horizon */
|
||||
if (dir.z >= 0.0f) {
|
||||
@@ -184,7 +186,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
|
||||
if (x > 1.0f) {
|
||||
x -= 1.0f;
|
||||
}
|
||||
xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, y));
|
||||
xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, y, ds, dt, 0));
|
||||
}
|
||||
}
|
||||
/* ground */
|
||||
@@ -201,7 +203,7 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals *kg,
|
||||
if (x > 1.0f) {
|
||||
x -= 1.0f;
|
||||
}
|
||||
xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, -0.5)) * fade;
|
||||
xyz = float4_to_float3(kernel_tex_image_interp(kg, texture_id, x, -0.5f, ds, dt, 0)) * fade;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -121,6 +121,9 @@ ccl_device void svm_node_tex_coord_bump_dx(
|
||||
}
|
||||
case NODE_TEXCO_NORMAL: {
|
||||
data = sd->N;
|
||||
# ifdef __DNDU__
|
||||
data = sd->N + sd->dNdx;
|
||||
# endif
|
||||
object_inverse_normal_transform(kg, sd, &data);
|
||||
break;
|
||||
}
|
||||
@@ -201,6 +204,9 @@ ccl_device void svm_node_tex_coord_bump_dy(
|
||||
}
|
||||
case NODE_TEXCO_NORMAL: {
|
||||
data = sd->N;
|
||||
# ifdef __DNDU__
|
||||
data = sd->N + sd->dNdy;
|
||||
# endif
|
||||
object_inverse_normal_transform(kg, sd, &data);
|
||||
break;
|
||||
}
|
||||
@@ -289,7 +295,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
float3 normal;
|
||||
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
normal = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
normal = triangle_smooth_normal_unnormalized(kg, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
}
|
||||
else {
|
||||
normal = sd->Ng;
|
||||
|
@@ -1739,7 +1739,7 @@ void GeometryManager::device_update_displacement_images(Device *device,
|
||||
|
||||
ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node);
|
||||
for (int i = 0; i < image_node->handle.num_tiles(); i++) {
|
||||
const int slot = image_node->handle.svm_slot(i);
|
||||
const int slot = image_node->handle.svm_slot(scene->shader_manager->use_osl(), i);
|
||||
if (slot != -1) {
|
||||
bump_images.insert(slot);
|
||||
}
|
||||
@@ -1748,10 +1748,12 @@ void GeometryManager::device_update_displacement_images(Device *device,
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
foreach (int slot, bump_images) {
|
||||
pool.push(function_bind(
|
||||
&ImageManager::device_update_slot, image_manager, device, scene, slot, &progress));
|
||||
}
|
||||
}*/
|
||||
image_manager->device_update(device, scene, progress);
|
||||
pool.wait_work();
|
||||
}
|
||||
|
||||
|
@@ -383,6 +383,10 @@ void ShaderGraph::finalize(Scene *scene, bool do_bump, bool do_simplify, bool bu
|
||||
if (do_bump)
|
||||
bump_from_displacement(bump_in_object_space);
|
||||
|
||||
/* This must be after all bump nodes are created,
|
||||
* so that bump map lookups can be mip mapped too. */
|
||||
add_differentials();
|
||||
|
||||
ShaderInput *surface_in = output()->input("Surface");
|
||||
ShaderInput *volume_in = output()->input("Volume");
|
||||
|
||||
@@ -954,6 +958,91 @@ void ShaderGraph::refine_bump_nodes()
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGraph::add_differentials()
|
||||
{
|
||||
/* we transverse the node graph looking for texture nodes, when we find them,
|
||||
* we copy the sub-graph defined from "Vector"
|
||||
* input to the inputs "Vector_dx" and "Vector_dy" */
|
||||
|
||||
foreach (ShaderNode *node, nodes) {
|
||||
if (node->special_type == SHADER_SPECIAL_TYPE_IMAGE_SLOT && node->input("Vector")->link &&
|
||||
node->input("Vector_dx") && node->input("Vector_dy")) {
|
||||
ShaderInput *vector_input = node->input("Vector");
|
||||
ShaderNodeSet nodes_vector;
|
||||
|
||||
/* make 2 extra copies of the subgraph defined in Vector input */
|
||||
ShaderNodeMap nodes_dx;
|
||||
ShaderNodeMap nodes_dy;
|
||||
|
||||
/* find dependencies for the given input */
|
||||
find_dependencies(nodes_vector, vector_input);
|
||||
|
||||
copy_nodes(nodes_vector, nodes_dx);
|
||||
copy_nodes(nodes_vector, nodes_dy);
|
||||
|
||||
/* First: Nodes that have no bump are set to center, others are left untouched. */
|
||||
foreach (ShaderNode *node, nodes_vector)
|
||||
node->bump = node->bump == SHADER_BUMP_NONE ? SHADER_BUMP_CENTER : node->bump;
|
||||
|
||||
/* Second: Nodes that have no bump are set DX, others are shifted by one. */
|
||||
foreach (NodePair &pair, nodes_dx) {
|
||||
switch (pair.second->bump) {
|
||||
case SHADER_BUMP_DX:
|
||||
pair.second->bump = SHADER_BUMP_DY;
|
||||
break;
|
||||
case SHADER_BUMP_DY:
|
||||
pair.second->bump = SHADER_BUMP_CENTER;
|
||||
break;
|
||||
default:
|
||||
pair.second->bump = SHADER_BUMP_DX;
|
||||
}
|
||||
}
|
||||
|
||||
/* Second: Nodes that have no bump are set DY, others are shifted by two. */
|
||||
foreach (NodePair &pair, nodes_dy) {
|
||||
switch (pair.second->bump) {
|
||||
case SHADER_BUMP_DX:
|
||||
pair.second->bump = SHADER_BUMP_CENTER;
|
||||
break;
|
||||
case SHADER_BUMP_DY:
|
||||
pair.second->bump = SHADER_BUMP_DX;
|
||||
break;
|
||||
default:
|
||||
pair.second->bump = SHADER_BUMP_DY;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderOutput *out = vector_input->link;
|
||||
ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name());
|
||||
ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name());
|
||||
|
||||
/* Insert mapping nodes that are duplicates of what's inside the image node.
|
||||
* This is somewhat wasteful, it would be better to have a MappingNode
|
||||
* that does three transforms at a time. */
|
||||
MappingNode *mapping1 = create_node<MappingNode>();
|
||||
MappingNode *mapping2 = create_node<MappingNode>();
|
||||
mapping1->set_location(((ImageTextureNode *)node)->tex_mapping.translation);
|
||||
mapping1->set_rotation(((ImageTextureNode *)node)->tex_mapping.rotation);
|
||||
mapping1->set_scale(((ImageTextureNode *)node)->tex_mapping.scale);
|
||||
mapping2->set_location(((ImageTextureNode *)node)->tex_mapping.translation);
|
||||
mapping2->set_rotation(((ImageTextureNode *)node)->tex_mapping.rotation);
|
||||
mapping2->set_scale(((ImageTextureNode *)node)->tex_mapping.scale);
|
||||
add(mapping1);
|
||||
add(mapping2);
|
||||
connect(out_dx, mapping1->input("Vector"));
|
||||
connect(out_dy, mapping2->input("Vector"));
|
||||
connect(mapping1->output("Vector"), node->input("Vector_dx"));
|
||||
connect(mapping2->output("Vector"), node->input("Vector_dy"));
|
||||
|
||||
/* add generated nodes */
|
||||
foreach (NodePair &pair, nodes_dx)
|
||||
add(pair.second);
|
||||
foreach (NodePair &pair, nodes_dy)
|
||||
add(pair.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderGraph::bump_from_displacement(bool use_object_space)
|
||||
{
|
||||
/* generate bump mapping automatically from displacement. bump mapping is
|
||||
|
@@ -381,6 +381,7 @@ class ShaderGraph : public NodeOwner {
|
||||
void break_cycles(ShaderNode *node, vector<bool> &visited, vector<bool> &on_stack);
|
||||
void bump_from_displacement(bool use_object_space);
|
||||
void refine_bump_nodes();
|
||||
void add_differentials();
|
||||
void expand();
|
||||
void default_inputs(bool do_osl);
|
||||
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);
|
||||
|
@@ -89,10 +89,10 @@ class Hair : public Geometry {
|
||||
float4 r_keys[4]) const;
|
||||
};
|
||||
|
||||
NODE_SOCKET_API_ARRAY(array<float3>, curve_keys)
|
||||
NODE_SOCKET_API_ARRAY(array<float>, curve_radius)
|
||||
NODE_SOCKET_API_ARRAY(array<int>, curve_first_key)
|
||||
NODE_SOCKET_API_ARRAY(array<int>, curve_shader)
|
||||
NODE_SOCKET_API(array<float3>, curve_keys)
|
||||
NODE_SOCKET_API(array<float>, curve_radius)
|
||||
NODE_SOCKET_API(array<int>, curve_first_key)
|
||||
NODE_SOCKET_API(array<int>, curve_shader)
|
||||
|
||||
/* BVH */
|
||||
size_t curvekey_offset;
|
||||
|
@@ -36,6 +36,8 @@
|
||||
# include <OSL/oslexec.h>
|
||||
#endif
|
||||
|
||||
#include "kernel/kernel_oiio_globals.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
@@ -77,6 +79,8 @@ const char *name_from_type(ImageDataType type)
|
||||
return "nanovdb_float";
|
||||
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
|
||||
return "nanovdb_float3";
|
||||
case IMAGE_DATA_TYPE_OIIO:
|
||||
return "openimageio";
|
||||
case IMAGE_DATA_NUM_TYPES:
|
||||
assert(!"System enumerator type, should never be used");
|
||||
return "";
|
||||
@@ -151,13 +155,13 @@ ImageMetaData ImageHandle::metadata()
|
||||
return img->metadata;
|
||||
}
|
||||
|
||||
int ImageHandle::svm_slot(const int tile_index) const
|
||||
int ImageHandle::svm_slot(bool osl, const int tile_index) const
|
||||
{
|
||||
if (tile_index >= tile_slots.size()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (manager->osl_texture_system) {
|
||||
if (osl) {
|
||||
ImageManager::Image *img = manager->images[tile_slots[tile_index]];
|
||||
if (!img->loader->osl_filepath().empty()) {
|
||||
return -1;
|
||||
@@ -239,6 +243,11 @@ bool ImageMetaData::is_float() const
|
||||
|
||||
void ImageMetaData::detect_colorspace()
|
||||
{
|
||||
if (type == IMAGE_DATA_TYPE_OIIO) {
|
||||
compress_as_srgb = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert used specified color spaces to one we know how to handle. */
|
||||
colorspace = ColorSpaceManager::detect_known_colorspace(
|
||||
colorspace, colorspace_file_format, is_float());
|
||||
@@ -299,12 +308,13 @@ bool ImageLoader::is_vdb_loader() const
|
||||
ImageManager::ImageManager(const DeviceInfo &info)
|
||||
{
|
||||
need_update_ = true;
|
||||
osl_texture_system = NULL;
|
||||
oiio_texture_system = NULL;
|
||||
animation_frame = 0;
|
||||
|
||||
/* Set image limits */
|
||||
features.has_half_float = info.has_half_images;
|
||||
features.has_nanovdb = info.has_nanovdb;
|
||||
features.has_texture_cache = false;
|
||||
}
|
||||
|
||||
ImageManager::~ImageManager()
|
||||
@@ -313,9 +323,10 @@ ImageManager::~ImageManager()
|
||||
assert(!images[slot]);
|
||||
}
|
||||
|
||||
void ImageManager::set_osl_texture_system(void *texture_system)
|
||||
void ImageManager::set_oiio_texture_system(void *texture_system)
|
||||
{
|
||||
osl_texture_system = texture_system;
|
||||
oiio_texture_system = texture_system;
|
||||
features.has_texture_cache = texture_system != NULL;
|
||||
}
|
||||
|
||||
bool ImageManager::set_animation_frame_update(int frame)
|
||||
@@ -394,6 +405,28 @@ ImageHandle ImageManager::add_image(const string &filename,
|
||||
return handle;
|
||||
}
|
||||
|
||||
const string ImageManager::get_mip_map_path(const string &filename)
|
||||
{
|
||||
if (!path_exists(filename)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
string::size_type idx = filename.rfind('.');
|
||||
if (idx != string::npos) {
|
||||
std::string extension = filename.substr(idx + 1);
|
||||
if (extension == "tx") {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
string tx_name = filename.substr(0, idx) + ".tx";
|
||||
if (path_exists(tx_name)) {
|
||||
return tx_name;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
ImageHandle ImageManager::add_image(ImageLoader *loader,
|
||||
const ImageParams ¶ms,
|
||||
const bool builtin)
|
||||
@@ -440,7 +473,7 @@ int ImageManager::add_image_slot(ImageLoader *loader,
|
||||
img->params = params;
|
||||
img->loader = loader;
|
||||
img->need_metadata = true;
|
||||
img->need_load = !(osl_texture_system && !img->loader->osl_filepath().empty());
|
||||
img->need_load = !(oiio_texture_system && !img->loader->osl_filepath().empty());
|
||||
img->builtin = builtin;
|
||||
img->users = 1;
|
||||
img->mem = NULL;
|
||||
@@ -650,6 +683,23 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
|
||||
|
||||
Image *img = images[slot];
|
||||
|
||||
if (features.has_texture_cache && !img->builtin) {
|
||||
/* Get or generate a mip mapped tile image file.
|
||||
* If we have a mip map, assume it's linear, not sRGB. */
|
||||
const char *cache_path = scene->params.texture.use_custom_cache_path ?
|
||||
scene->params.texture.custom_cache_path.c_str() :
|
||||
NULL;
|
||||
bool have_mip = ((OIIOImageLoader *)img->loader)
|
||||
->get_tx(img->metadata.colorspace,
|
||||
img->params.extension,
|
||||
progress,
|
||||
scene->params.texture.auto_convert,
|
||||
cache_path);
|
||||
if (have_mip) {
|
||||
img->need_metadata = true;
|
||||
}
|
||||
}
|
||||
|
||||
progress->set_status("Updating Images", "Loading " + img->loader->name());
|
||||
|
||||
const int texture_limit = scene->params.texture_limit;
|
||||
@@ -671,6 +721,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
|
||||
device, img->mem_name.c_str(), slot, type, img->params.interpolation, img->params.extension);
|
||||
img->mem->info.use_transform_3d = img->metadata.use_transform_3d;
|
||||
img->mem->info.transform_3d = img->metadata.transform_3d;
|
||||
img->mem->info.compress_as_srgb = img->metadata.compress_as_srgb;
|
||||
|
||||
/* Create new texture. */
|
||||
if (type == IMAGE_DATA_TYPE_FLOAT4) {
|
||||
@@ -767,7 +818,17 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (type == IMAGE_DATA_TYPE_OIIO) {
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
void *pixels = img->mem->alloc(1, 1);
|
||||
|
||||
if (pixels != NULL) {
|
||||
OIIO::TextureSystem *tex_sys = (OIIO::TextureSystem *)oiio_texture_system;
|
||||
OIIO::TextureSystem::TextureHandle *handle = tex_sys->get_texture_handle(
|
||||
OIIO::ustring(img->loader->osl_filepath()));
|
||||
*((OIIO::TextureSystem::TextureHandle **)pixels) = tex_sys->good(handle) ? handle : NULL;
|
||||
}
|
||||
}
|
||||
{
|
||||
thread_scoped_lock device_lock(device_mutex);
|
||||
img->mem->copy_to_device();
|
||||
@@ -785,11 +846,11 @@ void ImageManager::device_free_image(Device *, int slot)
|
||||
return;
|
||||
}
|
||||
|
||||
if (osl_texture_system) {
|
||||
if (oiio_texture_system) {
|
||||
#ifdef WITH_OSL
|
||||
ustring filepath = img->loader->osl_filepath();
|
||||
if (!filepath.empty()) {
|
||||
((OSL::TextureSystem *)osl_texture_system)->invalidate(filepath);
|
||||
((OIIO::TextureSystem *)oiio_texture_system)->invalidate(filepath);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@@ -102,6 +102,7 @@ class ImageDeviceFeatures {
|
||||
public:
|
||||
bool has_half_float;
|
||||
bool has_nanovdb;
|
||||
bool has_texture_cache;
|
||||
};
|
||||
|
||||
/* Image loader base class, that can be subclassed to load image data
|
||||
@@ -157,7 +158,7 @@ class ImageHandle {
|
||||
int num_tiles();
|
||||
|
||||
ImageMetaData metadata();
|
||||
int svm_slot(const int tile_index = 0) const;
|
||||
int svm_slot(bool osl = false, const int tile_index = 0) const;
|
||||
device_texture *image_memory(const int tile_index = 0) const;
|
||||
|
||||
VDBImageLoader *vdb_loader(const int tile_index = 0) const;
|
||||
@@ -191,7 +192,9 @@ class ImageManager {
|
||||
void device_load_builtin(Device *device, Scene *scene, Progress &progress);
|
||||
void device_free_builtin(Device *device);
|
||||
|
||||
void set_osl_texture_system(void *texture_system);
|
||||
void set_oiio_texture_system(void *texture_system);
|
||||
const string get_mip_map_path(const string &filename);
|
||||
void set_pack_images(bool pack_images_);
|
||||
bool set_animation_frame_update(int frame);
|
||||
|
||||
void collect_statistics(RenderStats *stats);
|
||||
@@ -227,7 +230,7 @@ class ImageManager {
|
||||
int animation_frame;
|
||||
|
||||
vector<Image *> images;
|
||||
void *osl_texture_system;
|
||||
void *oiio_texture_system;
|
||||
|
||||
int add_image_slot(ImageLoader *loader, const ImageParams ¶ms, const bool builtin);
|
||||
void add_image_user(int slot);
|
||||
|
@@ -19,6 +19,9 @@
|
||||
#include "util/util_image.h"
|
||||
#include "util/util_logging.h"
|
||||
#include "util/util_path.h"
|
||||
#include "util/util_progress.h"
|
||||
|
||||
#include <OpenImageIO/imagebufalgo.h>
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
@@ -62,7 +65,8 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMe
|
||||
size_t channel_size = spec.format.basesize();
|
||||
|
||||
bool is_float = false;
|
||||
bool is_half = false;
|
||||
bool is_half = spec.format == TypeDesc::HALF && features.has_half_float;
|
||||
bool is_tiled = spec.tile_pixels() != 0;
|
||||
|
||||
if (spec.format.is_floating_point()) {
|
||||
is_float = true;
|
||||
@@ -75,15 +79,13 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMe
|
||||
}
|
||||
}
|
||||
|
||||
/* check if it's half float */
|
||||
if (spec.format == TypeDesc::HALF && features.has_half_float) {
|
||||
is_half = true;
|
||||
}
|
||||
|
||||
/* set type and channels */
|
||||
metadata.channels = spec.nchannels;
|
||||
|
||||
if (is_half) {
|
||||
if (is_tiled && features.has_texture_cache) {
|
||||
metadata.type = IMAGE_DATA_TYPE_OIIO;
|
||||
}
|
||||
else if (is_half) {
|
||||
metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF;
|
||||
}
|
||||
else if (is_float) {
|
||||
@@ -211,6 +213,7 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
|
||||
break;
|
||||
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
|
||||
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
|
||||
case IMAGE_DATA_TYPE_OIIO:
|
||||
case IMAGE_DATA_NUM_TYPES:
|
||||
break;
|
||||
}
|
||||
@@ -235,4 +238,85 @@ bool OIIOImageLoader::equals(const ImageLoader &other) const
|
||||
return filepath == other_loader.filepath;
|
||||
}
|
||||
|
||||
bool OIIOImageLoader::make_tx(const string &filename,
|
||||
const string &outputfilename,
|
||||
const ustring &colorspace,
|
||||
ExtensionType extension)
|
||||
{
|
||||
ImageSpec config;
|
||||
config.attribute("maketx:filtername", "lanczos3");
|
||||
config.attribute("maketx:opaque_detect", 1);
|
||||
config.attribute("maketx:highlightcomp", 1);
|
||||
config.attribute("maketx:oiio_options", 1);
|
||||
config.attribute("maketx:updatemode", 1);
|
||||
|
||||
switch (extension) {
|
||||
case EXTENSION_CLIP:
|
||||
config.attribute("maketx:wrap", "black");
|
||||
break;
|
||||
case EXTENSION_REPEAT:
|
||||
config.attribute("maketx:wrap", "periodic");
|
||||
break;
|
||||
case EXTENSION_EXTEND:
|
||||
config.attribute("maketx:wrap", "clamp");
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert textures to linear color space before mip mapping. */
|
||||
if (colorspace != u_colorspace_raw) {
|
||||
if (colorspace == u_colorspace_srgb || colorspace.empty()) {
|
||||
config.attribute("maketx:incolorspace", "sRGB");
|
||||
}
|
||||
else {
|
||||
config.attribute("maketx:incolorspace", colorspace.c_str());
|
||||
}
|
||||
config.attribute("maketx:outcolorspace", "linear");
|
||||
}
|
||||
|
||||
return ImageBufAlgo::make_texture(ImageBufAlgo::MakeTxTexture, filename, outputfilename, config);
|
||||
}
|
||||
|
||||
bool OIIOImageLoader::get_tx(const ustring &colorspace,
|
||||
const ExtensionType &extension,
|
||||
Progress *progress,
|
||||
bool auto_convert,
|
||||
const char *cache_path)
|
||||
{
|
||||
if (!path_exists(osl_filepath().c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string::size_type idx = osl_filepath().rfind('.');
|
||||
if (idx != string::npos) {
|
||||
string extension = osl_filepath().substr(idx + 1).c_str();
|
||||
if (extension == "tx") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
string tx_name = string(osl_filepath().substr(0, idx).c_str()) + ".tx";
|
||||
if (cache_path) {
|
||||
string filename = path_filename(tx_name);
|
||||
tx_name = path_join(string(cache_path), filename);
|
||||
}
|
||||
if (path_exists(tx_name)) {
|
||||
filepath = tx_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto_convert && progress) {
|
||||
progress->set_status("Updating Images", string("Converting ") + osl_filepath().c_str());
|
||||
|
||||
bool ok = make_tx(osl_filepath().c_str(), tx_name, colorspace, extension);
|
||||
if (ok) {
|
||||
filepath = tx_name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -39,6 +39,17 @@ class OIIOImageLoader : public ImageLoader {
|
||||
|
||||
bool equals(const ImageLoader &other) const override;
|
||||
|
||||
bool get_tx(const ustring &colorspace,
|
||||
const ExtensionType &extension,
|
||||
Progress *progress,
|
||||
bool auto_convert,
|
||||
const char *cache_path);
|
||||
|
||||
static bool make_tx(const string &filename,
|
||||
const string &outputfilename,
|
||||
const ustring &colorspace,
|
||||
ExtensionType extension);
|
||||
|
||||
protected:
|
||||
ustring filepath;
|
||||
};
|
||||
|
@@ -410,39 +410,38 @@ void LightManager::device_update_distribution(Device *,
|
||||
}
|
||||
|
||||
float trianglearea = totarea;
|
||||
|
||||
/* point lights */
|
||||
float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
|
||||
bool use_lamp_mis = false;
|
||||
|
||||
int light_index = 0;
|
||||
foreach (Light *light, scene->lights) {
|
||||
if (!light->is_enabled)
|
||||
continue;
|
||||
|
||||
if (num_lights > 0) {
|
||||
float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
|
||||
foreach (Light *light, scene->lights) {
|
||||
if (!light->is_enabled)
|
||||
continue;
|
||||
distribution[offset].totarea = totarea;
|
||||
distribution[offset].prim = ~light_index;
|
||||
distribution[offset].lamp.pad = 1.0f;
|
||||
distribution[offset].lamp.size = light->size;
|
||||
totarea += lightarea;
|
||||
|
||||
distribution[offset].totarea = totarea;
|
||||
distribution[offset].prim = ~light_index;
|
||||
distribution[offset].lamp.pad = 1.0f;
|
||||
distribution[offset].lamp.size = light->size;
|
||||
totarea += lightarea;
|
||||
|
||||
if (light->light_type == LIGHT_DISTANT) {
|
||||
use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
|
||||
}
|
||||
else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
|
||||
use_lamp_mis |= (light->size > 0.0f && light->use_mis);
|
||||
}
|
||||
else if (light->light_type == LIGHT_AREA) {
|
||||
use_lamp_mis |= light->use_mis;
|
||||
}
|
||||
else if (light->light_type == LIGHT_BACKGROUND) {
|
||||
num_background_lights++;
|
||||
background_mis |= light->use_mis;
|
||||
}
|
||||
|
||||
light_index++;
|
||||
offset++;
|
||||
if (light->light_type == LIGHT_DISTANT) {
|
||||
use_lamp_mis |= (light->angle > 0.0f && light->use_mis);
|
||||
}
|
||||
else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
|
||||
use_lamp_mis |= (light->size > 0.0f && light->use_mis);
|
||||
}
|
||||
else if (light->light_type == LIGHT_AREA) {
|
||||
use_lamp_mis |= light->use_mis;
|
||||
}
|
||||
else if (light->light_type == LIGHT_BACKGROUND) {
|
||||
num_background_lights++;
|
||||
background_mis |= light->use_mis;
|
||||
}
|
||||
|
||||
light_index++;
|
||||
offset++;
|
||||
}
|
||||
|
||||
/* normalize cumulative distribution functions */
|
||||
|
@@ -250,7 +250,10 @@ NODE_DEFINE(ImageTextureNode)
|
||||
SOCKET_INT_ARRAY(tiles, "Tiles", array<int>());
|
||||
SOCKET_BOOLEAN(animated, "Animated", false);
|
||||
|
||||
|
||||
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_UV);
|
||||
SOCKET_IN_POINT(vector_dx, "Vector_dx", zero_float3());
|
||||
SOCKET_IN_POINT(vector_dy, "Vector_dy", zero_float3());
|
||||
|
||||
SOCKET_OUT_COLOR(color, "Color");
|
||||
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
||||
@@ -365,6 +368,8 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
|
||||
ShaderInput *vector_in = input("Vector");
|
||||
ShaderOutput *color_out = output("Color");
|
||||
ShaderOutput *alpha_out = output("Alpha");
|
||||
ShaderInput *vector_dx = input("Vector_dx");
|
||||
ShaderInput *vector_dy = input("Vector_dy");
|
||||
|
||||
if (handle.empty()) {
|
||||
cull_tiles(compiler.scene, compiler.current_graph);
|
||||
@@ -403,22 +408,24 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
|
||||
num_nodes = divide_up(handle.num_tiles(), 2);
|
||||
}
|
||||
|
||||
compiler.add_node(NODE_TEX_IMAGE,
|
||||
num_nodes,
|
||||
compiler.encode_uchar4(vector_offset,
|
||||
compiler.stack_assign_if_linked(color_out),
|
||||
compiler.stack_assign_if_linked(alpha_out),
|
||||
flags),
|
||||
projection);
|
||||
compiler.add_node(
|
||||
NODE_TEX_IMAGE,
|
||||
num_nodes,
|
||||
compiler.encode_uchar4(vector_offset,
|
||||
compiler.stack_assign_if_linked(color_out),
|
||||
compiler.stack_assign_if_linked(alpha_out),
|
||||
flags),
|
||||
compiler.encode_uchar4(
|
||||
projection, compiler.stack_assign(vector_dx), compiler.stack_assign(vector_dy), 0));
|
||||
|
||||
if (num_nodes > 0) {
|
||||
for (int i = 0; i < num_nodes; i++) {
|
||||
int4 node;
|
||||
node.x = tiles[2 * i];
|
||||
node.y = handle.svm_slot(2 * i);
|
||||
node.y = handle.svm_slot(false, 2 * i);
|
||||
if (2 * i + 1 < tiles.size()) {
|
||||
node.z = tiles[2 * i + 1];
|
||||
node.w = handle.svm_slot(2 * i + 1);
|
||||
node.w = handle.svm_slot(false, 2 * i + 1);
|
||||
}
|
||||
else {
|
||||
node.z = -1;
|
||||
@@ -430,13 +437,19 @@ void ImageTextureNode::compile(SVMCompiler &compiler)
|
||||
}
|
||||
else {
|
||||
assert(handle.num_tiles() == 1);
|
||||
/* Blend is a float between 0 and 1. Convert to 16 bit unsigned int to make room for vector_dx
|
||||
* and vector_dy. */
|
||||
uint blend = clamp((uint)(projection_blend * 65535.0f), 0, 0xffff);
|
||||
compiler.add_node(NODE_TEX_IMAGE_BOX,
|
||||
handle.svm_slot(),
|
||||
compiler.encode_uchar4(vector_offset,
|
||||
compiler.stack_assign_if_linked(color_out),
|
||||
compiler.stack_assign_if_linked(alpha_out),
|
||||
flags),
|
||||
__float_as_int(projection_blend));
|
||||
compiler.encode_uchar4(blend >> 8,
|
||||
blend & 0xff,
|
||||
compiler.stack_assign(vector_dx),
|
||||
compiler.stack_assign(vector_dy)));
|
||||
}
|
||||
|
||||
tex_mapping.compile_end(compiler, vector_in, vector_offset);
|
||||
@@ -458,12 +471,13 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
|
||||
const bool compress_as_srgb = metadata.compress_as_srgb;
|
||||
const ustring known_colorspace = metadata.colorspace;
|
||||
|
||||
if (handle.svm_slot() == -1) {
|
||||
if (handle.svm_slot(true) == -1) {
|
||||
filename = compiler.scene->image_manager->get_mip_map_path(filename.string());
|
||||
compiler.parameter_texture(
|
||||
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
||||
}
|
||||
else {
|
||||
compiler.parameter_texture("filename", handle.svm_slot());
|
||||
compiler.parameter_texture("filename", handle.svm_slot(true));
|
||||
}
|
||||
|
||||
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
|
||||
@@ -473,7 +487,6 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
|
||||
|
||||
compiler.parameter(this, "projection");
|
||||
compiler.parameter(this, "projection_blend");
|
||||
compiler.parameter("compress_as_srgb", compress_as_srgb);
|
||||
compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
|
||||
compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
|
||||
compiler.parameter("is_float", is_float);
|
||||
@@ -518,6 +531,8 @@ NODE_DEFINE(EnvironmentTextureNode)
|
||||
SOCKET_BOOLEAN(animated, "Animated", false);
|
||||
|
||||
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_POSITION);
|
||||
SOCKET_IN_POINT(vector_dx, "Vector_dx", zero_float3());
|
||||
SOCKET_IN_POINT(vector_dy, "Vector_dy", zero_float3());
|
||||
|
||||
SOCKET_OUT_COLOR(color, "Color");
|
||||
SOCKET_OUT_FLOAT(alpha, "Alpha");
|
||||
@@ -567,6 +582,8 @@ void EnvironmentTextureNode::compile(SVMCompiler &compiler)
|
||||
ShaderInput *vector_in = input("Vector");
|
||||
ShaderOutput *color_out = output("Color");
|
||||
ShaderOutput *alpha_out = output("Alpha");
|
||||
ShaderInput *vector_dx = input("Vector_dx");
|
||||
ShaderInput *vector_dy = input("Vector_dy");
|
||||
|
||||
if (handle.empty()) {
|
||||
ImageManager *image_manager = compiler.scene->image_manager;
|
||||
@@ -609,17 +626,16 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
|
||||
const bool compress_as_srgb = metadata.compress_as_srgb;
|
||||
const ustring known_colorspace = metadata.colorspace;
|
||||
|
||||
if (handle.svm_slot() == -1) {
|
||||
if (handle.svm_slot(true) == -1) {
|
||||
compiler.parameter_texture(
|
||||
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
|
||||
}
|
||||
else {
|
||||
compiler.parameter_texture("filename", handle.svm_slot());
|
||||
compiler.parameter_texture("filename", handle.svm_slot(true));
|
||||
}
|
||||
|
||||
compiler.parameter(this, "projection");
|
||||
compiler.parameter(this, "interpolation");
|
||||
compiler.parameter("compress_as_srgb", compress_as_srgb);
|
||||
compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
|
||||
compiler.parameter("is_float", is_float);
|
||||
compiler.add(this, "node_environment_texture");
|
||||
@@ -969,7 +985,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
|
||||
compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
|
||||
/* nishita texture */
|
||||
if (sky_type == NODE_SKY_NISHITA) {
|
||||
compiler.parameter_texture("filename", handle.svm_slot());
|
||||
compiler.parameter_texture("filename", handle.svm_slot(true));
|
||||
}
|
||||
compiler.add(this, "node_sky_texture");
|
||||
}
|
||||
@@ -1861,7 +1877,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
|
||||
handle = image_manager->add_image(filename.string(), image_params());
|
||||
}
|
||||
|
||||
compiler.parameter_texture("filename", handle.svm_slot());
|
||||
compiler.parameter_texture("filename", handle.svm_slot(true));
|
||||
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
|
||||
compiler.parameter("mapping", tfm);
|
||||
compiler.parameter("use_mapping", 1);
|
||||
|
@@ -128,7 +128,9 @@ class ImageTextureNode : public ImageSlotTextureNode {
|
||||
NODE_SOCKET_API(float, projection_blend)
|
||||
NODE_SOCKET_API(bool, animated)
|
||||
NODE_SOCKET_API(float3, vector)
|
||||
NODE_SOCKET_API_ARRAY(array<int>, tiles)
|
||||
NODE_SOCKET_API(float3, vector_dx)
|
||||
NODE_SOCKET_API(float3, vector_dy)
|
||||
NODE_SOCKET_API(array<int>, tiles)
|
||||
|
||||
protected:
|
||||
void cull_tiles(Scene *scene, ShaderGraph *graph);
|
||||
@@ -164,6 +166,8 @@ class EnvironmentTextureNode : public ImageSlotTextureNode {
|
||||
NODE_SOCKET_API(InterpolationType, interpolation)
|
||||
NODE_SOCKET_API(bool, animated)
|
||||
NODE_SOCKET_API(float3, vector)
|
||||
NODE_SOCKET_API(float3, vector_dx)
|
||||
NODE_SOCKET_API(float3, vector_dy)
|
||||
};
|
||||
|
||||
class SkyTextureNode : public TextureNode {
|
||||
@@ -1554,7 +1558,7 @@ class CurvesNode : public ShaderNode {
|
||||
return NODE_GROUP_LEVEL_3;
|
||||
}
|
||||
|
||||
NODE_SOCKET_API_ARRAY(array<float3>, curves)
|
||||
NODE_SOCKET_API(array<float3>, curves)
|
||||
NODE_SOCKET_API(float, min_x)
|
||||
NODE_SOCKET_API(float, max_x)
|
||||
NODE_SOCKET_API(float, fac)
|
||||
@@ -1588,8 +1592,8 @@ class RGBRampNode : public ShaderNode {
|
||||
return NODE_GROUP_LEVEL_1;
|
||||
}
|
||||
|
||||
NODE_SOCKET_API_ARRAY(array<float3>, ramp)
|
||||
NODE_SOCKET_API_ARRAY(array<float>, ramp_alpha)
|
||||
NODE_SOCKET_API(array<float3>, ramp)
|
||||
NODE_SOCKET_API(array<float>, ramp_alpha)
|
||||
NODE_SOCKET_API(float, fac)
|
||||
NODE_SOCKET_API(bool, interpolate)
|
||||
};
|
||||
|
@@ -46,11 +46,7 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OSL
|
||||
|
||||
/* Shared Texture and Shading System */
|
||||
|
||||
OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
|
||||
int OSLShaderManager::ts_shared_users = 0;
|
||||
thread_mutex OSLShaderManager::ts_shared_mutex;
|
||||
/* Shared Shading System */
|
||||
|
||||
OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
|
||||
OSLRenderServices *OSLShaderManager::services_shared = NULL;
|
||||
@@ -110,7 +106,7 @@ void OSLShaderManager::device_update_specific(Device *device,
|
||||
device_free(device, dscene, scene);
|
||||
|
||||
/* set texture system */
|
||||
scene->image_manager->set_osl_texture_system((void *)ts);
|
||||
scene->image_manager->set_oiio_texture_system((void *)ts);
|
||||
|
||||
/* create shaders */
|
||||
OSLGlobals *og = (OSLGlobals *)device->osl_memory();
|
||||
@@ -190,41 +186,6 @@ void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *s
|
||||
og->background_state.reset();
|
||||
}
|
||||
|
||||
void OSLShaderManager::texture_system_init()
|
||||
{
|
||||
/* create texture system, shared between different renders to reduce memory usage */
|
||||
thread_scoped_lock lock(ts_shared_mutex);
|
||||
|
||||
if (ts_shared_users == 0) {
|
||||
ts_shared = TextureSystem::create(true);
|
||||
|
||||
ts_shared->attribute("automip", 1);
|
||||
ts_shared->attribute("autotile", 64);
|
||||
ts_shared->attribute("gray_to_rgb", 1);
|
||||
|
||||
/* effectively unlimited for now, until we support proper mipmap lookups */
|
||||
ts_shared->attribute("max_memory_MB", 16384);
|
||||
}
|
||||
|
||||
ts = ts_shared;
|
||||
ts_shared_users++;
|
||||
}
|
||||
|
||||
void OSLShaderManager::texture_system_free()
|
||||
{
|
||||
/* shared texture system decrease users and destroy if no longer used */
|
||||
thread_scoped_lock lock(ts_shared_mutex);
|
||||
ts_shared_users--;
|
||||
|
||||
if (ts_shared_users == 0) {
|
||||
ts_shared->invalidate_all(true);
|
||||
OSL::TextureSystem::destroy(ts_shared);
|
||||
ts_shared = NULL;
|
||||
}
|
||||
|
||||
ts = NULL;
|
||||
}
|
||||
|
||||
void OSLShaderManager::shading_system_init()
|
||||
{
|
||||
/* create shading system, shared between different renders to reduce memory usage */
|
||||
@@ -232,7 +193,7 @@ void OSLShaderManager::shading_system_init()
|
||||
|
||||
if (ss_shared_users == 0) {
|
||||
/* Must use aligned new due to concurrent hash map. */
|
||||
services_shared = util_aligned_new<OSLRenderServices>(ts_shared);
|
||||
services_shared = util_aligned_new<OSLRenderServices>(ts);
|
||||
|
||||
string shader_path = path_get("shader");
|
||||
# ifdef _WIN32
|
||||
@@ -247,7 +208,7 @@ void OSLShaderManager::shading_system_init()
|
||||
shader_path = string_to_ansi(shader_path);
|
||||
# endif
|
||||
|
||||
ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
|
||||
ss_shared = new OSL::ShadingSystem(services_shared, ts, &errhandler);
|
||||
ss_shared->attribute("lockgeom", 1);
|
||||
ss_shared->attribute("commonspace", "world");
|
||||
ss_shared->attribute("searchpath:shader", shader_path);
|
||||
|
@@ -103,22 +103,14 @@ class OSLShaderManager : public ShaderManager {
|
||||
const std::string &bytecode = "");
|
||||
|
||||
protected:
|
||||
void texture_system_init();
|
||||
void texture_system_free();
|
||||
|
||||
void shading_system_init();
|
||||
void shading_system_free();
|
||||
|
||||
OSL::ShadingSystem *ss;
|
||||
OSL::TextureSystem *ts;
|
||||
OSLRenderServices *services;
|
||||
OSL::ErrorHandler errhandler;
|
||||
map<string, OSLShaderInfo> loaded_shaders;
|
||||
|
||||
static OSL::TextureSystem *ts_shared;
|
||||
static thread_mutex ts_shared_mutex;
|
||||
static int ts_shared_users;
|
||||
|
||||
static OSL::ShadingSystem *ss_shared;
|
||||
static OSLRenderServices *services_shared;
|
||||
static thread_mutex ss_shared_mutex;
|
||||
|
@@ -138,6 +138,50 @@ class DeviceScene {
|
||||
DeviceScene(Device *device);
|
||||
};
|
||||
|
||||
/* Texture Cache Params */
|
||||
class TextureCacheParams {
|
||||
public:
|
||||
TextureCacheParams()
|
||||
: use_cache(false),
|
||||
cache_size(1024),
|
||||
tile_size(64),
|
||||
diffuse_blur(1.0f / 64.f),
|
||||
glossy_blur(0.0f),
|
||||
auto_convert(true),
|
||||
accept_unmipped(true),
|
||||
accept_untiled(true),
|
||||
auto_tile(true),
|
||||
auto_mip(true),
|
||||
use_custom_cache_path(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool modified(const TextureCacheParams ¶ms)
|
||||
{
|
||||
return !(use_cache == params.use_cache && cache_size == params.cache_size &&
|
||||
tile_size == params.tile_size && diffuse_blur == params.diffuse_blur &&
|
||||
glossy_blur == params.glossy_blur && auto_convert == params.auto_convert &&
|
||||
accept_unmipped == params.accept_unmipped &&
|
||||
accept_untiled == params.accept_untiled && auto_tile == params.auto_tile &&
|
||||
auto_mip == params.auto_mip &&
|
||||
use_custom_cache_path == params.use_custom_cache_path &&
|
||||
custom_cache_path == params.custom_cache_path);
|
||||
}
|
||||
|
||||
bool use_cache;
|
||||
int cache_size;
|
||||
int tile_size;
|
||||
float diffuse_blur;
|
||||
float glossy_blur;
|
||||
bool auto_convert;
|
||||
bool accept_unmipped;
|
||||
bool accept_untiled;
|
||||
bool auto_tile;
|
||||
bool auto_mip;
|
||||
bool use_custom_cache_path;
|
||||
string custom_cache_path;
|
||||
};
|
||||
|
||||
/* Scene Parameters */
|
||||
|
||||
class SceneParams {
|
||||
@@ -179,6 +223,7 @@ class SceneParams {
|
||||
int hair_subdivisions;
|
||||
CurveShapeType hair_shape;
|
||||
int texture_limit;
|
||||
TextureCacheParams texture;
|
||||
|
||||
bool background;
|
||||
|
||||
@@ -204,7 +249,7 @@ class SceneParams {
|
||||
use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes &&
|
||||
num_bvh_time_steps == params.num_bvh_time_steps &&
|
||||
hair_subdivisions == params.hair_subdivisions && hair_shape == params.hair_shape &&
|
||||
texture_limit == params.texture_limit);
|
||||
texture_limit == params.texture_limit) || texture.modified(params.texture);
|
||||
}
|
||||
|
||||
int curve_subdivisions()
|
||||
|
@@ -33,10 +33,13 @@
|
||||
#include "render/tables.h"
|
||||
|
||||
#include "util/util_foreach.h"
|
||||
#include "util/util_logging.h"
|
||||
#include "util/util_murmurhash.h"
|
||||
#include "util/util_task.h"
|
||||
#include "util/util_transform.h"
|
||||
|
||||
#include "kernel/kernel_oiio_globals.h"
|
||||
#include <OpenImageIO/texture.h>
|
||||
#ifdef WITH_OCIO
|
||||
# include <OpenColorIO/OpenColorIO.h>
|
||||
namespace OCIO = OCIO_NAMESPACE;
|
||||
@@ -45,6 +48,7 @@ namespace OCIO = OCIO_NAMESPACE;
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
thread_mutex ShaderManager::lookup_table_mutex;
|
||||
|
||||
vector<float> ShaderManager::beckmann_table;
|
||||
bool ShaderManager::beckmann_table_ready = false;
|
||||
|
||||
@@ -491,10 +495,37 @@ void ShaderManager::device_update_common(Device *device,
|
||||
Progress & /*progress*/)
|
||||
{
|
||||
dscene->shaders.free();
|
||||
|
||||
if (scene->shaders.size() == 0)
|
||||
return;
|
||||
|
||||
if (device->info.type == DEVICE_CPU &&
|
||||
(scene->params.shadingsystem == SHADINGSYSTEM_OSL || scene->params.texture.use_cache)) {
|
||||
/* set texture system */
|
||||
scene->image_manager->set_oiio_texture_system((void *)ts);
|
||||
OIIOGlobals *oiio_globals = (OIIOGlobals *)device->oiio_memory();
|
||||
if (oiio_globals) {
|
||||
/* update attributes from scene parms */
|
||||
ts->attribute("autotile",
|
||||
scene->params.texture.auto_tile ? scene->params.texture.tile_size : 0);
|
||||
ts->attribute("automip", scene->params.texture.auto_mip ? 1 : 0);
|
||||
ts->attribute("accept_unmipped", scene->params.texture.accept_unmipped ? 1 : 0);
|
||||
ts->attribute("accept_untiled", scene->params.texture.accept_untiled ? 1 : 0);
|
||||
ts->attribute("max_memory_MB",
|
||||
scene->params.texture.cache_size > 0 ?
|
||||
(float)scene->params.texture.cache_size :
|
||||
16384.0f);
|
||||
ts->attribute("latlong_up", "z");
|
||||
ts->attribute("flip_t", 1);
|
||||
ts->attribute("max_tile_channels", 1);
|
||||
if (scene->params.texture_limit > 0) {
|
||||
ts->attribute("max_mip_res", scene->params.texture_limit);
|
||||
}
|
||||
oiio_globals->tex_sys = ts;
|
||||
oiio_globals->diffuse_blur = scene->params.texture.diffuse_blur;
|
||||
oiio_globals->glossy_blur = scene->params.texture.glossy_blur;
|
||||
}
|
||||
}
|
||||
|
||||
KernelShader *kshader = dscene->shaders.alloc(scene->shaders.size());
|
||||
bool has_volumes = false;
|
||||
bool has_transparent_shadow = false;
|
||||
@@ -750,6 +781,22 @@ void ShaderManager::free_memory()
|
||||
ColorSpaceManager::free_memory();
|
||||
}
|
||||
|
||||
void ShaderManager::texture_system_init()
|
||||
{
|
||||
ts = TextureSystem::create(true);
|
||||
ts->attribute("gray_to_rgb", 1);
|
||||
ts->attribute("forcefloat", 1);
|
||||
}
|
||||
|
||||
void ShaderManager::texture_system_free()
|
||||
{
|
||||
VLOG(1) << ts->getstats(2);
|
||||
ts->reset_stats();
|
||||
ts->invalidate_all(true);
|
||||
TextureSystem::destroy(ts);
|
||||
ts = NULL;
|
||||
}
|
||||
|
||||
float ShaderManager::linear_rgb_to_gray(float3 c)
|
||||
{
|
||||
return dot(c, rgb_to_y);
|
||||
|
@@ -23,11 +23,14 @@
|
||||
# include <OSL/oslexec.h>
|
||||
#endif
|
||||
|
||||
#include <OpenImageIO/texture.h>
|
||||
|
||||
#include "kernel/kernel_types.h"
|
||||
#include "render/attribute.h"
|
||||
|
||||
#include "graph/node.h"
|
||||
|
||||
#include "kernel/kernel_oiio_globals.h"
|
||||
#include "util/util_map.h"
|
||||
#include "util/util_param.h"
|
||||
#include "util/util_string.h"
|
||||
@@ -249,6 +252,11 @@ class ShaderManager {
|
||||
|
||||
thread_spin_lock attribute_lock_;
|
||||
|
||||
void texture_system_init();
|
||||
void texture_system_free();
|
||||
|
||||
OIIO::TextureSystem *ts;
|
||||
|
||||
float3 xyz_to_r;
|
||||
float3 xyz_to_g;
|
||||
float3 xyz_to_b;
|
||||
|
@@ -37,10 +37,12 @@ CCL_NAMESPACE_BEGIN
|
||||
|
||||
SVMShaderManager::SVMShaderManager()
|
||||
{
|
||||
texture_system_init();
|
||||
}
|
||||
|
||||
SVMShaderManager::~SVMShaderManager()
|
||||
{
|
||||
texture_system_free();
|
||||
}
|
||||
|
||||
void SVMShaderManager::reset(Scene * /*scene*/)
|
||||
|
@@ -50,6 +50,7 @@ typedef enum ImageDataType {
|
||||
IMAGE_DATA_TYPE_USHORT = 7,
|
||||
IMAGE_DATA_TYPE_NANOVDB_FLOAT = 8,
|
||||
IMAGE_DATA_TYPE_NANOVDB_FLOAT3 = 9,
|
||||
IMAGE_DATA_TYPE_OIIO = 10,
|
||||
|
||||
IMAGE_DATA_NUM_TYPES
|
||||
} ImageDataType;
|
||||
@@ -94,6 +95,7 @@ typedef struct TextureInfo {
|
||||
/* Transform for 3D textures. */
|
||||
uint use_transform_3d;
|
||||
Transform transform_3d;
|
||||
uint compress_as_srgb;
|
||||
} TextureInfo;
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -652,11 +652,6 @@ typedef struct {
|
||||
enum {
|
||||
GHOST_kXrContextDebug = (1 << 0),
|
||||
GHOST_kXrContextDebugTime = (1 << 1),
|
||||
# ifdef WIN32
|
||||
/* Needed to avoid issues with the SteamVR OpenGL graphics binding (use DirectX fallback
|
||||
instead). */
|
||||
GHOST_kXrContextGpuNVIDIA = (1 << 2),
|
||||
# endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@@ -424,7 +424,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
|
||||
{
|
||||
/* TODO: implement graceful termination through Cocoa mechanism
|
||||
* to avoid session log off to be canceled. */
|
||||
/* Note that Cmd+Q is already handled by key-handler. */
|
||||
/* Note that Cmd+Q is already handled by keyhandler. */
|
||||
systemCocoa->handleQuitRequest();
|
||||
return NSTerminateCancel;
|
||||
}
|
||||
|
@@ -1922,7 +1922,7 @@ static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCo
|
||||
|
||||
#undef MAKE_ID
|
||||
|
||||
/* From `xclip.c` #xcout() v0.11. */
|
||||
/* from xclip.c xcout() v0.11 */
|
||||
|
||||
#define XCLIB_XCOUT_NONE 0 /* no context */
|
||||
#define XCLIB_XCOUT_SENTCONVSEL 1 /* sent a request */
|
||||
|
@@ -20,7 +20,6 @@
|
||||
* Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -99,7 +98,7 @@ void GHOST_XrContext::initialize(const GHOST_XrContextCreateInfo *create_info)
|
||||
storeInstanceProperties();
|
||||
|
||||
/* Multiple bindings may be enabled. Now that we know the runtime in use, settle for one. */
|
||||
m_gpu_binding_type = determineGraphicsBindingTypeToUse(graphics_binding_types, create_info);
|
||||
m_gpu_binding_type = determineGraphicsBindingTypeToUse(graphics_binding_types);
|
||||
|
||||
printInstanceInfo();
|
||||
if (isDebugMode()) {
|
||||
@@ -136,8 +135,7 @@ void GHOST_XrContext::storeInstanceProperties()
|
||||
{"Monado(XRT) by Collabora et al", OPENXR_RUNTIME_MONADO},
|
||||
{"Oculus", OPENXR_RUNTIME_OCULUS},
|
||||
{"SteamVR/OpenXR", OPENXR_RUNTIME_STEAMVR},
|
||||
{"Windows Mixed Reality Runtime", OPENXR_RUNTIME_WMR},
|
||||
{"Varjo OpenXR Runtime", OPENXR_RUNTIME_VARJO}};
|
||||
{"Windows Mixed Reality Runtime", OPENXR_RUNTIME_WMR}};
|
||||
decltype(runtime_map)::const_iterator runtime_map_iter;
|
||||
|
||||
m_oxr->instance_properties.type = XR_TYPE_INSTANCE_PROPERTIES;
|
||||
@@ -412,17 +410,6 @@ void GHOST_XrContext::getExtensionsToEnable(
|
||||
try_ext.push_back(XR_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
/* Try enabling interaction profile extensions. */
|
||||
try_ext.push_back(XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
|
||||
try_ext.push_back(XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
try_ext.push_back(XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
|
||||
|
||||
/* Varjo quad view extension. */
|
||||
try_ext.push_back(XR_VARJO_QUAD_VIEWS_EXTENSION_NAME);
|
||||
|
||||
/* Varjo foveated extension. */
|
||||
try_ext.push_back(XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME);
|
||||
|
||||
r_ext_names.reserve(try_ext.size() + graphics_binding_types.size());
|
||||
|
||||
/* Add graphics binding extensions (may be multiple ones, we'll settle for one to use later, once
|
||||
@@ -473,20 +460,16 @@ std::vector<GHOST_TXrGraphicsBinding> GHOST_XrContext::determineGraphicsBindingT
|
||||
}
|
||||
|
||||
GHOST_TXrGraphicsBinding GHOST_XrContext::determineGraphicsBindingTypeToUse(
|
||||
const std::vector<GHOST_TXrGraphicsBinding> &enabled_types,
|
||||
const GHOST_XrContextCreateInfo *create_info)
|
||||
const std::vector<GHOST_TXrGraphicsBinding> &enabled_types)
|
||||
{
|
||||
/* Return the first working type. */
|
||||
for (GHOST_TXrGraphicsBinding type : enabled_types) {
|
||||
#ifdef WIN32
|
||||
/* The SteamVR OpenGL backend currently fails for NVIDIA GPU's. Disable it and allow falling
|
||||
* back to the DirectX one. */
|
||||
if ((m_runtime_id == OPENXR_RUNTIME_STEAMVR) && (type == GHOST_kXrGraphicsOpenGL) &&
|
||||
((create_info->context_flag & GHOST_kXrContextGpuNVIDIA) != 0)) {
|
||||
/* The SteamVR OpenGL backend fails currently. Disable it and allow falling back to the DirectX
|
||||
* one. */
|
||||
if ((m_runtime_id == OPENXR_RUNTIME_STEAMVR) && (type == GHOST_kXrGraphicsOpenGL)) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
((void)create_info);
|
||||
#endif
|
||||
|
||||
assert(type != GHOST_kXrGraphicsUnknown);
|
||||
@@ -625,11 +608,4 @@ bool GHOST_XrContext::isDebugTimeMode() const
|
||||
return m_debug_time;
|
||||
}
|
||||
|
||||
bool GHOST_XrContext::isExtensionEnabled(const char *ext) const
|
||||
{
|
||||
bool contains = std::find(m_enabled_extensions.begin(), m_enabled_extensions.end(), ext) !=
|
||||
m_enabled_extensions.end();
|
||||
return contains;
|
||||
}
|
||||
|
||||
/** \} */ /* Ghost Internal Accessors and Mutators */
|
||||
|
@@ -51,7 +51,6 @@ enum GHOST_TXrOpenXRRuntimeID {
|
||||
OPENXR_RUNTIME_OCULUS,
|
||||
OPENXR_RUNTIME_STEAMVR,
|
||||
OPENXR_RUNTIME_WMR, /* Windows Mixed Reality */
|
||||
OPENXR_RUNTIME_VARJO,
|
||||
|
||||
OPENXR_RUNTIME_UNKNOWN
|
||||
};
|
||||
@@ -95,8 +94,6 @@ class GHOST_XrContext : public GHOST_IXrContext {
|
||||
bool isDebugMode() const;
|
||||
bool isDebugTimeMode() const;
|
||||
|
||||
bool isExtensionEnabled(const char *ext) const;
|
||||
|
||||
private:
|
||||
static GHOST_XrErrorHandlerFn s_error_handler;
|
||||
static void *s_error_handler_customdata;
|
||||
@@ -139,6 +136,5 @@ class GHOST_XrContext : public GHOST_IXrContext {
|
||||
std::vector<GHOST_TXrGraphicsBinding> determineGraphicsBindingTypesToEnable(
|
||||
const GHOST_XrContextCreateInfo *create_info);
|
||||
GHOST_TXrGraphicsBinding determineGraphicsBindingTypeToUse(
|
||||
const std::vector<GHOST_TXrGraphicsBinding> &enabled_types,
|
||||
const GHOST_XrContextCreateInfo *create_info);
|
||||
const std::vector<GHOST_TXrGraphicsBinding> &enabled_types);
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user