1
1

Compare commits

...

139 Commits

Author SHA1 Message Date
Stefan Werner
c5b56a525c Merge branch 'master' into cycles_texture_cache 2021-08-21 22:03:31 +02:00
Stefan Werner
34e8d79c3e Merge branch 'master' into cycles_texture_cache 2021-08-02 09:28:54 +02:00
Stefan Werner
465fb31ed2 Merge branch 'master' into cycles_texture_cache 2021-07-15 12:26:05 +02:00
Stefan Werner
0a2c10e4f0 Cycles: Making sure render is updated when texture options change. 2021-05-21 15:48:21 +02:00
Stefan Werner
e6599787eb Merge branch 'master' into cycles_texture_cache 2021-05-19 07:24:19 +02:00
Stefan Werner
5fa0ec97c6 Cycles: Writing texture cache stats through VLOG not std::cout. 2021-05-18 22:31:20 +02:00
Stefan Werner
18ecdde359 Merge branch 'master' into cycles_texture_cache 2021-05-14 23:04:10 +02:00
Stefan Werner
3002f66362 Cycles: Fixed differentials for UDIM textures. 2021-05-11 14:18:07 +02:00
0bbeb24fe6 Geometry Nodes: refactor instances component
The main goal of this refactor is to not store Object/Collection
pointers for every individual instance. Instead instances now
store a handle for the referenced data. The actual Object/Collection
pointers are stored in a new `InstanceReference` class.

This refactor also allows for some better optimizations further down
the line, because one does not have to search through all instances
anymore to find what data is instanced.

Furthermore, this refactor makes it easier to support instancing
`GeometrySet` or any other data that has to be owned by the
`InstancesComponent`.

Differential Revision: https://developer.blender.org/D11125
2021-05-06 11:25:24 +02:00
ee37819cfb Fix (unreported): 'CoInitializeEx' being called without 'CoUninitialize'
Problem introduced in {rB1f223b9a}.

This was possibly causing random crashes in Blender file browser when
compiled with ASAN.

Microsoft documents indicate that any call to `CoInitializeEx` must be
balanced by a corresponding call to `CoUninitialize`.

https://docs.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex#remarks
2021-05-06 11:25:24 +02:00
a650d18821 Fix errors in Cycles comments 2021-05-06 11:25:24 +02:00
0c5d8f4ea5 Fix T85287: Cycles deadlock loading Blender images in some cases 2021-05-06 11:25:24 +02:00
81ba70facb Fix T88001: persistent data render wrong when changing camera border 2021-05-06 11:25:24 +02:00
2aebfa8b4b Fix T87982: crash switching render slots while render is in progress 2021-05-06 11:25:24 +02:00
Stefan Werner
22cfab5a55 Cycles standalone: Fixed macOS dependencies.
Added IOKit and Accerelate as linked frameworks where necessary.
2021-05-06 11:25:24 +02:00
d19176765d Geometry Nodes: Initial basic curve data support
This patch adds initial curve support to geometry nodes. Currently
there is only one node available, the "Curve to Mesh" node, T87428.

However, the aim of the changes here is larger than just supporting
curve data in nodes-- it also uses the opportunity to add better spline
data structures, intended to replace the existing curve evaluation code.
The curve code in Blender is quite old, and it's generally regarded as
some of the messiest, hardest-to-understand code as well. The classes
in `BKE_spline.hh` aim to be faster, more extensible, and much more
easily understandable. Further explanation can be found in comments in
that file.

Initial builtin spline attributes are supported-- reading and writing
from the `cyclic` and `resolution` attributes works with any of the
attribute nodes. Also, only Z-up normal calculation is implemented
at the moment, and tilts do not apply yet.

**Limitations**
 - For now, you must bring curves into the node tree with an "Object
   Info" node. Changes to the curve modifier stack will come later.
 - Converting to a mesh is necessary to visualize the curve data.

Further progress can be tracked in: T87245
Higher level design document: https://wiki.blender.org/wiki/Modules/Physics_Nodes/Projects/EverythingNodes/CurveNodes

Differential Revision: https://developer.blender.org/D11091
2021-05-06 11:25:24 +02:00
01a0699cdc Fix T88005: GPencil inverse fill leaves unwanted line at viewport edge.
There was a function to set 2 pixels wide for inverse filling, but this must not be done in the borders of the image.

Now, the borders are checked before set 2 pixels.
2021-05-06 11:25:24 +02:00
82e1420b11 Fix T87926: Transform menu has operators guaranteed to not pass poll in certain modes
Reported for ops.transform.vertex_warp and ops.transform.vertex_random.
Polling will check with ED_transverts_check_obedit, if we know it will
fail e.g. for pose mode, we can do the same check in the UI already.

Maniphest Tasks: T87926

Differential Revision: https://developer.blender.org/D11128
2021-05-06 11:25:24 +02:00
29d0570ec6 Cleanup: spelling 2021-05-06 11:25:24 +02:00
79f5281d4f WM: disable idle event handling timer when simulating events 2021-05-06 11:25:24 +02:00
bcbe639396 Movieclip: Use first clip frame for size detection
Using scene frame 1 is not reliable in cases when there is a
frame offset is involved. Using frame 1 seems more reliable,
although might still fail under certain circumstances.

More reliable fix would require a deeper change in the data
structure and the logic about frame loading and size detection.
2021-05-06 11:25:24 +02:00
de7d37db69 Fix wrong tracking curves after changing clip offset
The issue was caused by frame start/offset change triggering clip
reload, which was happening with a hardcoded scene frame index of 1,
which could be outside of the actual clip frames.

Solved by removing source change tag from the frame start/offset
update. The source doesn't really change: the resolution will stay
the same, as well as media type, its duration. So the tag was not
needed.
2021-05-06 11:25:24 +02:00
5cf73f8b4a Alembic Procedural: precompute vertex normals
This precomputes vertex normals in the procedural and caches them in case none
are found in the archive. This only applies to polygon meshes, as subdivision
meshes are yet to be subdivided, so it is useless to do this computation.

The goal here is to speed up data updates between frames, as computing normals
shows up in profiles even for large objects. This saves around 16% of update time
for a production file.
2021-05-06 11:25:24 +02:00
4f95a89960 Alembic Procedural: refactor data reading
This splits the data reading logic from the AlembicObject class and moves it to
separate files to better enforce a separation of concern. The goal was to simplify
and improve the logic to read data from an Alembic archive.

Since the procedural loads data for the entire animation, this requires looping
over the frame range and looking up data for each frame. Previously those loops
would be duplicated over the entire code causing divergences in how we might
skip or deduplicate data across frames (if only some data change over time and
not other on the same object, e.g. vertices and triangles might not have the
same animation times), and therefore, bugs.

Now, we only use a single function with callback to loop over the geometry data
for each requested frame, and another one to loop over attributes. Given how
attributes are accessed it is a bit tricky to simplify further and only use a
ingle function, however, this is left as a further improvement as it is not
impossible.

To read the data, we now use a set of structures to hold which data to read.
Those structures might seem redundant with the Alembic schemas as they are
somewhat a copy of the schemas' structures, however they will allow us in the
long run to treat the data of one object type as the data of another object
type (e.g. to ignore subdivision, or only loading the vertices as point clouds).

For attributes, this new system allows us to read arbitrary attributes, although
with some limitations still:
* only subdivision and polygon meshes are supported due to lack of examples for
  curve data;
* some data types might be missing: we support float, float2, float3, booleans,
  normals, uvs, rgb, and rbga at the moment, other types can be trivially added
* some attribute scopes (or domains) are not handled, again, due to lack of example
  files
* color types are always interpreted as vertex colors
2021-05-06 11:25:23 +02:00
d74d0bb239 Cleanup: use boolean for has_event variable & return value 2021-05-06 11:25:23 +02:00
985d005b93 Fix T87969: crash accesing FaceMaps / PaintMask data in editmode
Workaround for crash when accessing FaceMaps / PaintMask data in
editmode, just disallow access in editmode as is done with UVs.

Same fix as in {rB3e2619b3e72a}.

Maniphest Tasks: T87969

Differential Revision: https://developer.blender.org/D11146
2021-05-06 11:25:23 +02:00
8a30944e43 Fix compilation error after recent compositor fix
Apparently, there is no emplace semantic available in the Vector in
the stable branch.
2021-05-06 11:25:23 +02:00
c949c8dc16 Fix T87989: Crash using OpenCL in compositor
Initial report was mentioning the Classroom demo scene, but this is
probably because the scene was pre-configured to be used with OpenCL.
Would expect any OpenCL compositing to be failing prior to this fix.

The reason why crash was happening is due to OpenCL queue being
released from OpenCLDevice destructor. Is not that obvious, but
when Vector (including std::vector) is holding elements by value
a destructor will be called on "old" memory when vector capacitance
changes.

Solved by making forbidding copy semantic for compositor devices and
forcing move semantic to be used.

Also use emplace semantic in the devices vector initialization.
2021-05-06 11:25:23 +02:00
a353aeb532 Geometry Nodes: Parallelize attribute nodes
This commit significantly speeds up many of the attribute nodes when
multiple threads are available in linear situations when parallelism
cannot be achieved elsewhere.

See the differential for a table of timing comparisons tested on a
Ryzen 3700x. For an attribute with 4 million elements, the nodes were
about 3 to 9 times faster.

The changes are not exhaustive, other nodes could still be parallelized
in the future. Also, it would be possible to further optimize the grain
size in `parallel_for`, but I'd rather make sure it isn't too small.
I tested some different values, but also relied on intuition--
increasing grain size for less complex operations and vice versa.

Differential Revision: https://developer.blender.org/D11139
2021-05-06 11:25:23 +02:00
3391e679ac LibOverride: temporarily fix the material driver workaround with a hack.
Currently overriding properties within material node trees is not
supported. However there is a workaround that allows feeding values
through drivers via an intermediate custom property, as described
in T82404. The workaround relies on the behavior of the ID copying
code that always patches datablock self-references even without any
overrides.

Unfortunately, this broke during development of 2.93. This happened
because a call RNA_struct_override_matches added in rB2281db72b0157
detects that no override exists, and 'restores' the self-reference
to point to the original datablock.

To avoid this, mark the Material.node_tree property with the
PROPOVERRIDE_IGNORE flag to stop RNA_struct_override_matches
from recursing into the currently unsupported node tree sub-block.
This flag should be removed when this is properly supported.

This was confirmed to fix the workaround and discussed with @mont29.
2021-05-06 11:25:23 +02:00
c038247fcf Minor updates to i18n spellcheck tool. 2021-05-06 11:25:23 +02:00
ddef5df62a Cleanup: clang-tidy 2021-05-06 11:25:23 +02:00
6ca59bb60c Cleanup: clang-tidy 2021-05-06 11:25:23 +02:00
16750942da Cleanup: format 2021-05-06 11:25:23 +02:00
f9bc8c8ac5 Cycles: use reference count to detect used shaders
Shaders are only compiled if they are used by some other Node (Geometry, Light, etc.).
This usage detection is done before updating the Scene, however it fails at detecting
Shaders used by Procedurals not known to Cycles (e.g. ones defined by third party
applications), as Procedurals are only updated after the shaders are compiled.

To remedy this, we now use the Node reference counting mechanism to detect whether a
Shader is used and therefore should be compiled.

This removes `ShaderManager::update_shaders_used` as it is not needed anymore, however,
since it would also update the Shader ids, this is now performed in
`ShaderManager::device_update`, and a new virtual `device_update_specific` method was
added to handle device updates for SVM and OSL.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D10965
2021-05-06 11:25:23 +02:00
2577e31889 Cycles: add reference counting to Nodes
This adds a reference count to Nodes which is incremented or decremented
whenever they are added to or removed from a socket, which will help us
track used Nodes throughout the scene graph generically without having to
add an explicit count or flag on specific Node types. This is especially
useful to track Nodes defined through Procedurals out of Cycles' control.

This also modifies the order in which nodes are deleted to ensure that
upon deletion, a Node does not attempt to decrement the reference
count of another Node which was already freed or deleted.

This is not currently used, but will be in the next commit.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D10965
2021-05-06 11:25:23 +02:00
988fb85960 Fix T87554 Exact Boolean performance bug.
There was a quadratic algorithm extracting triangles from a coplanar
cluster. This is now linear.
Also found and fixed a bug in the same area related to the triangulator
added recently: it didn't get the right correspondence between new
edges and original edges.
2021-05-06 11:25:23 +02:00
8d1c3ceb54 GPencil: Fix unreported problem when save file in Curve Edit mode
This is related to T87905
2021-05-06 11:25:23 +02:00
Robert Guetzkow
ced72034d5 Fix T82824: Draw sensor size with correct alpha
Previously the option in the camera's //Object Data Properties > Viewport Display
 > Sensor// would not display the sensor in camera view. This seemed to be caused
by the theme color `TH_VIEW_OVERLAY` having zero set for the alpha channel and
alpha blending being active, resulting in no visible output. Hence
`immUniformThemeColorShade(TH_VIEW_OVERLAY, 100);` is replaced with
`immUniformThemeColorShadeAlpha(TH_VIEW_OVERLAY, 100, 255);`.

Reviewed By: mano-wii

Differential Revision: https://developer.blender.org/D11075
2021-05-06 11:25:23 +02:00
04a18ea6de UI: Object Thumbnails Orientation Change
Object orientation for thumbnail creation changed to be slightly
oblique (tilted to one side and from above) to better show shape,
especially when axis-aligned. Camera lens changed to 85 to avoid
distortion of close objects like human heads.

see D9940 for details and examples.

Differential Revision: https://developer.blender.org/D9940

Reviewed by Julian Eisel
2021-05-06 11:25:23 +02:00
baa4c054df Fix T87905: GPencil modifiers not applied if saved with multiframe
When saving a file in Edit mode with Multiframe enabled, the render did not include the modifiers.

Now the multiframe is not enabled if it's doing a render.
2021-05-06 11:25:23 +02:00
Germano Cavalcante
cd7a1042bf Python GPU: Replace a few calls of the bgl module with gpu
Concludes these files:
[x]bpy_types.py
[x]operator_modal_draw.py

Reviewed By: fclem

Differential Revision: https://developer.blender.org/D11129
2021-05-06 11:25:23 +02:00
Tomasz Kaye
9e4e797491 GPencil: Auto lock layers, tooltip grammar fix
Reviewed By: #grease_pencil, antoniov

Differential Revision: https://developer.blender.org/D11136
2021-05-06 11:25:23 +02:00
4993a0e7ef Fix T86450: Random dark UI elements when redrawing
Resolves occasional glitch/flicker drawing dark buttons in the UI.

Regression in 405a5d3bd7
which removed shader unbinding when the batch is drawn.

GPU_shader_bind could run with the sRGB uniform in an unexpected state.

Reviewed By: fclem

Ref D11124
2021-05-06 11:25:23 +02:00
65787ca4c9 Docs: PyAPI: Fix css selector failing on some pages 2021-05-06 11:25:23 +02:00
Stefan Werner
711f521e42 Cycles: Texture cache capability is now a device property. 2021-05-03 20:22:28 +02:00
Stefan Werner
ad7deefc62 Cycles: Reintroduced path_flags for textures.
Texture lookups can now use wider or cheaper filters
for less important paths.
2021-05-03 12:45:13 +02:00
Stefan Werner
745ad6d311 Merge branch 'master' into cycles_texture_cache 2021-04-30 21:01:26 +02:00
Stefan Werner
87040ce007 Refactor of texture cache, now texture handles are being stored in device tex memory. 2021-04-30 20:59:39 +02:00
Stefan Werner
e8566adf91 Merge branch 'master' into cycles_texture_cache 2021-04-20 12:02:36 +02:00
Stefan Werner
6db39d36cb Merge branch 'master' into cycles_texture_cache 2021-04-20 12:02:04 +02:00
Stefan Werner
44f99b0357 Merge branch 'master' into cycles_texture_cache 2021-04-05 10:03:02 +02:00
Stefan Werner
540de41cc3 Merge branch 'master' into cycles_texture_cache 2021-04-02 00:52:15 +02:00
Stefan Werner
ac9326a263 Merge branch 'master' into cycles_texture_cache 2021-03-30 12:07:03 +02:00
Stefan Werner
1991012527 Merge branch 'master' into cycles_texture_cache 2021-03-11 10:32:48 +01:00
Stefan Werner
c3cc89ebaa Merge branch 'master' into cycles_texture_cache 2021-03-10 13:34:26 +01:00
Stefan Werner
3bf94a6d04 Cycles: Updated texture cache for new API. 2021-01-04 14:04:35 +01:00
Stefan Werner
84139622a7 Merge branch 'master' into cycles_texture_cache 2021-01-04 13:23:00 +01:00
Stefan Werner
4199738997 Merge branch 'master' into cycles_texture_cache 2020-12-21 09:09:27 +01:00
Stefan Werner
7111a40b4f Merge branch 'master' into cycles_texture_cache 2020-07-22 08:11:07 +02:00
Stefan Werner
0c0868a5da Merge branch 'master' into cycles_texture_cache 2020-06-15 11:40:21 +02:00
Stefan Werner
df596132f3 Merge branch 'master' into cycles_texture_cache 2020-06-12 13:46:42 +02:00
Stefan Werner
195c664716 Merge branch 'master' into cycles_texture_cache 2020-06-08 22:45:40 +02:00
Stefan Werner
12bc88cfdf Merge branch 'master' into cycles_texture_cache 2020-06-05 07:43:26 +02:00
Stefan Werner
cef7fbf50f Merge branch 'master' into cycles_texture_cache 2020-06-03 22:14:09 +02:00
Stefan Werner
d6e34e4825 Merge branch 'master' into cycles_texture_cache 2020-05-18 10:59:34 +02:00
Stefan Werner
49ece61195 Merge branch 'master' into cycles_texture_cache 2020-03-26 12:17:19 +01:00
de75be1eaa Merge branch 'master' into cycles_texture_cache 2020-01-16 15:20:53 +01:00
Stefan Werner
7ec3dff04d Cycles: Fixed OSL crashes from texture caching changes. 2019-11-08 13:54:45 +01:00
Stefan Werner
bc99c2bceb Merge branch 'master' into cycles_texture_cache 2019-11-08 13:00:17 +01:00
Stefan Werner
267038756b Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2019-05-08 14:36:43 +02:00
Stefan Werner
ffa55fbfdd Merge 'master' into 'cycles_texture_cache' 2019-04-18 14:14:44 +02:00
Stefan Werner
cf6eb9a7f2 Merge 'master' into 'cycles_texture_cache' 2019-04-18 14:14:44 +02:00
Stefan Werner
6a5dc7124b Merge 'master' into 'cycles_texture_cache' 2019-04-18 14:14:23 +02:00
Stefan Werner
7be7f1a884 Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2019-03-13 14:08:28 +01:00
Stefan Werner
ddb90691fd Cycles: Disabled anisotropic texture cache lookups for emission shaders.
Leaving it enabled lead to excessive render times in certain scenes.
2019-01-11 13:44:34 +01:00
Stefan Werner
287adc8eba Cycles: Mip map creation now respects texture extension settings 2019-01-11 13:43:38 +01:00
Stefan Werner
c9fcc2cdab Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2018-12-21 14:41:34 +01:00
Stefan Werner
5e0eed8958 Merge remote-tracking branch 'origin/master' into cycles_texture_cache 2018-12-05 15:15:49 +01:00
Stefan Werner
36f9a9694d Merge branch 'master' into cycles_texture_cache 2018-11-08 13:15:48 +01:00
Stefan Werner
8600c7f9ef Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2018-10-29 14:23:46 -04:00
Stefan Werner
6568074b94 Cycles: Added option for custom texture cache path. 2018-10-19 14:49:37 +02:00
Stefan Werner
80bcd2cffb Cycles: Texture Cache toggle is now properly updated. 2018-10-16 12:55:16 +02:00
Stefan Werner
b178cc0a9e Cycles: Fixed OpenCL kernel build on Windows. 2018-10-15 13:30:08 +02:00
Stefan Werner
98a1c684cd Cycles: Fixed build on Linux and OpenCL. 2018-10-15 11:16:32 +02:00
Stefan Werner
e9ad3f4356 Cycles: Fixed texture caching when using the new displacement nodes. 2018-10-05 12:25:41 +02:00
Stefan Werner
e3067641c3 Merge branch 'cycles_texture_cache' of git.blender.org:blender into cycles_texture_cache 2018-10-02 12:02:59 +02:00
Stefan Werner
53700beb09 Cycles: Implmemented texture filtering for box mapping. 2018-09-28 09:22:04 +02:00
Stefan Werner
bfa29bb704 Cycles: Improved ray differentials for volume scattering. 2018-09-27 10:21:33 +02:00
Stefan Werner
0c7aaf9545 Cycles: Fixes for OSL with texture caching: Textures are now right side up again and textures read from the cache are assumed to be linear. 2018-09-26 13:39:40 +02:00
Stefan Werner
c367153c6c Cycles: Set proper defaults for texture caching. 2018-09-26 09:45:39 +02:00
Stefan Werner
2fd6efed5e Cycles: Setting dNdx/dNdy to zero for flat shaded surfaces. 2018-09-24 22:25:03 +02:00
Stefan Werner
c00925cac5 Cycles: Fixed uninitialised variable. 2018-09-24 14:59:03 +02:00
Stefan Werner
b56be6e73c Cycles: Fixed swapped parameters in fresnel_dielectric(). 2018-09-21 16:23:46 +02:00
Stefan Werner
c174ad09f9 Cycles: Moved Texture caching options to their own subsection in the UI. 2018-09-19 14:50:51 +02:00
Stefan Werner
60da3f4ca6 Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2018-09-17 12:39:25 +02:00
Stefan Werner
295944b49e Merge branch 'master' of git.blender.org:blender into cycles_texture_cache
# Conflicts:
#	intern/cycles/render/image.cpp
#	intern/cycles/render/nodes.cpp
#	intern/cycles/render/osl.cpp
2018-08-03 06:02:30 +02:00
Stefan Werner
e17430d00d Cycles: Fixed broken displacement 2018-06-27 13:29:36 +02:00
Stefan Werner
66e571dfad Cycles: Fixed broken bump mapping 2018-06-27 13:29:27 +02:00
Stefan Werner
c987f6e6e1 Cycles: improved texture differentials for bump maps, added texture differntials to displacement maps 2018-06-27 13:29:13 +02:00
Stefan Werner
20825728f2 Cycles: added ray differentials to henyey-greenstein phase function 2018-06-27 13:15:13 +02:00
Stefan Werner
d85c76e7b9 Cycles: Moved texture coordinate differential creation to after all bump maps are created. This should improve texture caching in scenes with bump/displacement maps. 2018-06-27 13:15:01 +02:00
Stefan Werner
697600e784 Cycles: Fixes for texture caching, behavior with auto convert off was broken, color space was misinterpreted sometimes.
Note: Texturing with OSL is currently broken.
2018-06-27 13:12:22 +02:00
Stefan Werner
92bf11548d Cycles: Smaller fixes for differentials, taking dNdu inot account when getting N from a bump shader 2018-06-27 13:08:26 +02:00
Stefan Werner
ecdc2f7108 Ccyles: texture differentials now respect the hidden mapping node inside the image texture node. 2018-06-27 13:08:15 +02:00
Stefan Werner
f363d080ca Cycles: fix for mip map paths 2018-06-27 13:08:05 +02:00
Stefan Werner
3d11353856 Cycles: Changed Mip Map names to replace, not add to suffix
Added oiio_make_tx() call to Cycles' Python API
2018-06-27 13:07:54 +02:00
Stefan Werner
baf66bfa48 Cycles: improved ray differentials for specular/glossy closures with DNDU/V enabled 2018-06-27 13:07:40 +02:00
Stefan Werner
a8e32a86e5 Cycles: more accurate differential approximation for glossy bounces 2018-06-27 13:01:48 +02:00
Stefan Werner
15e5f06f38 Cycles: Don’t apply glossy blur texture filtering on singular paths 2018-06-27 13:01:38 +02:00
Stefan Werner
6d47a91220 Cycles: fixed normal differentials, ShaderData now contains dNdx/y instead of dNdu/v 2018-06-27 13:01:02 +02:00
Stefan Werner
6450e35a2f Cycles: added diffuse_blur and glossy_blur parameters to texture cache 2018-06-27 12:27:37 +02:00
Stefan Werner
443b91aebe Cycles: Smaller updates to texture cache, setting a few more options and letting textureSys do the flipping instead of doing it manually 2018-06-27 12:18:11 +02:00
Stefan Werner
1bcad0d920 Cycles: fixed include statements for image cache to work on case-sensitive file systems 2018-06-27 12:17:55 +02:00
Stefan Werner
34e28c29b6 Cycles: added blurrier texture lookups for indirect diffuse paths 2018-06-27 12:01:23 +02:00
Stefan Werner
2925298d96 Cycles: Added dPdu/dPdv to area ligths so we can use filtered textures on them 2018-06-27 11:49:49 +02:00
Stefan Werner
693667b85e Cycles: Cached textures are now assumed to be linear and converted from sRGB during texture filtering where necessary 2018-06-27 11:31:05 +02:00
Stefan Werner
7c61f79e4d Cycles: Crash fix 2018-06-27 10:52:13 +02:00
Stefan Werner
9341dac223 Cycles: More improvements to texture filtering of light sources 2018-06-27 10:49:18 +02:00
Stefan Werner
9d1417d210 Cycles: Cached textures now support extension and interpolation modes 2018-06-27 10:48:56 +02:00
Stefan Werner
cf1ecb86a9 Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2018-06-19 13:34:50 +02:00
Stefan Werner
e437bab5d8 Cycles: Added NULL pointer check 2018-03-06 14:49:56 +01:00
Stefan Werner
101b248174 Merge branch 'master' of git.blender.org:blender into cycles_texture_cache 2018-03-06 14:49:05 +01:00
Stefan Werner
9525996321 making things build on Linux 2017-11-27 20:39:33 +01:00
Stefan Werner
c553041b81 Cycles: Added texture differentials to mesh light sampling. Currently based on purely specular reflection, can probably be wider than that. 2017-11-27 20:39:23 +01:00
Stefan Werner
280fc52ba2 Cycles: wider ray differential calculation for diffuse components of principled BSDF 2017-11-27 20:39:13 +01:00
Stefan Werner
183a706239 Cycles: Added ray differential calculation for AO 2017-11-27 20:38:48 +01:00
Stefan Werner
ef65e1c823 Cycles: Let OIIO do the sharing of the texture cache, add wider differentials for velvet BSDF 2017-11-27 20:38:37 +01:00
Stefan Werner
4d0f9d07eb Cycles: Added dNdu to kernel globals on CPU, using it for more accurate ray differentials in specular and glossy reflection 2017-11-27 20:38:29 +01:00
Stefan Werner
8b54b957f7 Cycles: ImageTexture node now has dx/dy inputs for offset texture coordinates, being filled out with a hacky shader node duplication a la bump_dx/bump_dy 2017-11-27 20:38:09 +01:00
Stefan Werner
d04b16bb84 Cycles: Widened differentials for diffuse and glossy BSDFs for better texture cache performance 2017-11-27 20:37:54 +01:00
Stefan Werner
5faa6893e3 Cycles: Fixed texture cache build in Visual Studio - need to tell OIIO to disable AVX 2017-11-27 20:37:44 +01:00
Stefan Werner
c5bce9ce8e Cycles: removed “.” at the end of texture cache help text 2017-11-27 20:37:09 +01:00
Stefan Werner
0c49eaaf3b Cycles: Better quality filtering for .tx mip maps 2017-11-27 20:36:54 +01:00
Stefan Werner
0820ee4a04 Cycles: Use texture cache only for CPU devices 2017-11-27 20:36:45 +01:00
Stefan Werner
2052b3d5c2 Cycles: resetting texture cache stats after use 2017-11-27 20:36:33 +01:00
Stefan Werner
0f61e96161 Cycles: made OSL shading use .tx files where available, added a mutex to the kernel texture name array 2017-11-27 20:36:22 +01:00
Stefan Werner
8946dc52ed Cycles: a handful of fixes for texture caching 2017-11-27 20:36:09 +01:00
Stefan Werner
db34c9eceb Cycles: first additions for OIIO texture caching
* TextureSystem options are exposed in the UI
* Automatic generation of .tx files is optional
* Texture lookups do not use differentials or mip maps yet, so performance is pretty bad
2017-11-27 20:35:45 +01:00
70 changed files with 1305 additions and 225 deletions

View File

@@ -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",

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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*/)
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
@@ -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) {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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. */

View File

@@ -139,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(

View File

@@ -283,6 +283,7 @@ ccl_device void kernel_bake_evaluate(
P,
Ng,
Ng,
NULL,
shader,
object,
prim,

View File

@@ -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

View File

@@ -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);

View File

@@ -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. */

View File

@@ -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 */

View 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

View File

@@ -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);

View File

@@ -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(

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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(

View File

@@ -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"

View File

@@ -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"

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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);

View File

@@ -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));

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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 &params,
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
}

View File

@@ -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 &params, const bool builtin);
void add_image_user(int slot);

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -128,6 +128,8 @@ class ImageTextureNode : public ImageSlotTextureNode {
NODE_SOCKET_API(float, projection_blend)
NODE_SOCKET_API(bool, animated)
NODE_SOCKET_API(float3, vector)
NODE_SOCKET_API(float3, vector_dx)
NODE_SOCKET_API(float3, vector_dy)
NODE_SOCKET_API(array<int>, tiles)
protected:
@@ -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 {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 &params)
{
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()

View File

@@ -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);

View File

@@ -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;

View File

@@ -37,10 +37,12 @@ CCL_NAMESPACE_BEGIN
SVMShaderManager::SVMShaderManager()
{
texture_system_init();
}
SVMShaderManager::~SVMShaderManager()
{
texture_system_free();
}
void SVMShaderManager::reset(Scene * /*scene*/)

View File

@@ -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