Cycles: support for custom shader AOVs
Custom render passes are added in the Shader AOVs panel in the view layer settings, with a name and data type. In shader nodes, an AOV Output node is then used to output either a value or color to the pass. Arbitrary names can be used for these passes, as long as they don't conflict with built-in passes that are enabled. The AOV Output node can be used in both material and world shader nodes. Implemented by Lukas, with tweaks by Brecht. Differential Revision: https://developer.blender.org/D4837
This commit is contained in:
@@ -223,65 +223,95 @@ def system_info():
|
|||||||
import _cycles
|
import _cycles
|
||||||
return _cycles.system_info()
|
return _cycles.system_info()
|
||||||
|
|
||||||
|
def list_render_passes(srl):
|
||||||
|
# Builtin Blender passes.
|
||||||
|
yield ("Combined", "RGBA", 'COLOR')
|
||||||
|
|
||||||
def register_passes(engine, scene, srl):
|
if srl.use_pass_z: yield ("Depth", "Z", 'VALUE')
|
||||||
engine.register_pass(scene, srl, "Combined", 4, "RGBA", 'COLOR')
|
if srl.use_pass_mist: yield ("Mist", "Z", 'VALUE')
|
||||||
|
if srl.use_pass_normal: yield ("Normal", "XYZ", 'VECTOR')
|
||||||
if srl.use_pass_z: engine.register_pass(scene, srl, "Depth", 1, "Z", 'VALUE')
|
if srl.use_pass_vector: yield ("Vector", "XYZW", 'VECTOR')
|
||||||
if srl.use_pass_mist: engine.register_pass(scene, srl, "Mist", 1, "Z", 'VALUE')
|
if srl.use_pass_uv: yield ("UV", "UVA", 'VECTOR')
|
||||||
if srl.use_pass_normal: engine.register_pass(scene, srl, "Normal", 3, "XYZ", 'VECTOR')
|
if srl.use_pass_object_index: yield ("IndexOB", "X", 'VALUE')
|
||||||
if srl.use_pass_vector: engine.register_pass(scene, srl, "Vector", 4, "XYZW", 'VECTOR')
|
if srl.use_pass_material_index: yield ("IndexMA", "X", 'VALUE')
|
||||||
if srl.use_pass_uv: engine.register_pass(scene, srl, "UV", 3, "UVA", 'VECTOR')
|
if srl.use_pass_shadow: yield ("Shadow", "RGB", 'COLOR')
|
||||||
if srl.use_pass_object_index: engine.register_pass(scene, srl, "IndexOB", 1, "X", 'VALUE')
|
if srl.use_pass_ambient_occlusion: yield ("AO", "RGB", 'COLOR')
|
||||||
if srl.use_pass_material_index: engine.register_pass(scene, srl, "IndexMA", 1, "X", 'VALUE')
|
if srl.use_pass_diffuse_direct: yield ("DiffDir", "RGB", 'COLOR')
|
||||||
if srl.use_pass_shadow: engine.register_pass(scene, srl, "Shadow", 3, "RGB", 'COLOR')
|
if srl.use_pass_diffuse_indirect: yield ("DiffInd", "RGB", 'COLOR')
|
||||||
if srl.use_pass_ambient_occlusion: engine.register_pass(scene, srl, "AO", 3, "RGB", 'COLOR')
|
if srl.use_pass_diffuse_color: yield ("DiffCol", "RGB", 'COLOR')
|
||||||
if srl.use_pass_diffuse_direct: engine.register_pass(scene, srl, "DiffDir", 3, "RGB", 'COLOR')
|
if srl.use_pass_glossy_direct: yield ("GlossDir", "RGB", 'COLOR')
|
||||||
if srl.use_pass_diffuse_indirect: engine.register_pass(scene, srl, "DiffInd", 3, "RGB", 'COLOR')
|
if srl.use_pass_glossy_indirect: yield ("GlossInd", "RGB", 'COLOR')
|
||||||
if srl.use_pass_diffuse_color: engine.register_pass(scene, srl, "DiffCol", 3, "RGB", 'COLOR')
|
if srl.use_pass_glossy_color: yield ("GlossCol", "RGB", 'COLOR')
|
||||||
if srl.use_pass_glossy_direct: engine.register_pass(scene, srl, "GlossDir", 3, "RGB", 'COLOR')
|
if srl.use_pass_transmission_direct: yield ("TransDir", "RGB", 'COLOR')
|
||||||
if srl.use_pass_glossy_indirect: engine.register_pass(scene, srl, "GlossInd", 3, "RGB", 'COLOR')
|
if srl.use_pass_transmission_indirect: yield ("TransInd", "RGB", 'COLOR')
|
||||||
if srl.use_pass_glossy_color: engine.register_pass(scene, srl, "GlossCol", 3, "RGB", 'COLOR')
|
if srl.use_pass_transmission_color: yield ("TransCol", "RGB", 'COLOR')
|
||||||
if srl.use_pass_transmission_direct: engine.register_pass(scene, srl, "TransDir", 3, "RGB", 'COLOR')
|
if srl.use_pass_subsurface_direct: yield ("SubsurfaceDir", "RGB", 'COLOR')
|
||||||
if srl.use_pass_transmission_indirect: engine.register_pass(scene, srl, "TransInd", 3, "RGB", 'COLOR')
|
if srl.use_pass_subsurface_indirect: yield ("SubsurfaceInd", "RGB", 'COLOR')
|
||||||
if srl.use_pass_transmission_color: engine.register_pass(scene, srl, "TransCol", 3, "RGB", 'COLOR')
|
if srl.use_pass_subsurface_color: yield ("SubsurfaceCol", "RGB", 'COLOR')
|
||||||
if srl.use_pass_subsurface_direct: engine.register_pass(scene, srl, "SubsurfaceDir", 3, "RGB", 'COLOR')
|
if srl.use_pass_emit: yield ("Emit", "RGB", 'COLOR')
|
||||||
if srl.use_pass_subsurface_indirect: engine.register_pass(scene, srl, "SubsurfaceInd", 3, "RGB", 'COLOR')
|
if srl.use_pass_environment: yield ("Env", "RGB", 'COLOR')
|
||||||
if srl.use_pass_subsurface_color: engine.register_pass(scene, srl, "SubsurfaceCol", 3, "RGB", 'COLOR')
|
|
||||||
if srl.use_pass_emit: engine.register_pass(scene, srl, "Emit", 3, "RGB", 'COLOR')
|
|
||||||
if srl.use_pass_environment: engine.register_pass(scene, srl, "Env", 3, "RGB", 'COLOR')
|
|
||||||
|
|
||||||
|
# Cycles specific passes.
|
||||||
crl = srl.cycles
|
crl = srl.cycles
|
||||||
if crl.pass_debug_render_time: engine.register_pass(scene, srl, "Debug Render Time", 1, "X", 'VALUE')
|
if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
|
||||||
if crl.pass_debug_bvh_traversed_nodes: engine.register_pass(scene, srl, "Debug BVH Traversed Nodes", 1, "X", 'VALUE')
|
if crl.pass_debug_bvh_traversed_nodes: yield ("Debug BVH Traversed Nodes", "X", 'VALUE')
|
||||||
if crl.pass_debug_bvh_traversed_instances: engine.register_pass(scene, srl, "Debug BVH Traversed Instances", 1, "X", 'VALUE')
|
if crl.pass_debug_bvh_traversed_instances: yield ("Debug BVH Traversed Instances", "X", 'VALUE')
|
||||||
if crl.pass_debug_bvh_intersections: engine.register_pass(scene, srl, "Debug BVH Intersections", 1, "X", 'VALUE')
|
if crl.pass_debug_bvh_intersections: yield ("Debug BVH Intersections", "X", 'VALUE')
|
||||||
if crl.pass_debug_ray_bounces: engine.register_pass(scene, srl, "Debug Ray Bounces", 1, "X", 'VALUE')
|
if crl.pass_debug_ray_bounces: yield ("Debug Ray Bounces", "X", 'VALUE')
|
||||||
if crl.use_pass_volume_direct: engine.register_pass(scene, srl, "VolumeDir", 3, "RGB", 'COLOR')
|
if crl.use_pass_volume_direct: yield ("VolumeDir", "RGB", 'COLOR')
|
||||||
if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
|
if crl.use_pass_volume_indirect: yield ("VolumeInd", "RGB", 'COLOR')
|
||||||
|
|
||||||
|
# Cryptomatte passes.
|
||||||
if crl.use_pass_crypto_object:
|
if crl.use_pass_crypto_object:
|
||||||
for i in range(0, crl.pass_crypto_depth, 2):
|
for i in range(0, crl.pass_crypto_depth, 2):
|
||||||
engine.register_pass(scene, srl, "CryptoObject" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
|
yield ("CryptoObject" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
|
||||||
if crl.use_pass_crypto_material:
|
if crl.use_pass_crypto_material:
|
||||||
for i in range(0, crl.pass_crypto_depth, 2):
|
for i in range(0, crl.pass_crypto_depth, 2):
|
||||||
engine.register_pass(scene, srl, "CryptoMaterial" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
|
yield ("CryptoMaterial" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
|
||||||
if srl.cycles.use_pass_crypto_asset:
|
if srl.cycles.use_pass_crypto_asset:
|
||||||
for i in range(0, srl.cycles.pass_crypto_depth, 2):
|
for i in range(0, srl.cycles.pass_crypto_depth, 2):
|
||||||
engine.register_pass(scene, srl, "CryptoAsset" + '{:02d}'.format(i//2), 4, "RGBA", 'COLOR')
|
yield ("CryptoAsset" + '{:02d}'.format(i//2), "RGBA", 'COLOR')
|
||||||
|
|
||||||
|
# Denoising passes.
|
||||||
if crl.use_denoising or crl.denoising_store_passes:
|
if crl.use_denoising or crl.denoising_store_passes:
|
||||||
engine.register_pass(scene, srl, "Noisy Image", 4, "RGBA", 'COLOR')
|
yield ("Noisy Image", "RGBA", 'COLOR')
|
||||||
if crl.denoising_store_passes:
|
if crl.denoising_store_passes:
|
||||||
engine.register_pass(scene, srl, "Denoising Normal", 3, "XYZ", 'VECTOR')
|
yield ("Denoising Normal", "XYZ", 'VECTOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Albedo", 3, "RGB", 'COLOR')
|
yield ("Denoising Albedo", "RGB", 'COLOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Depth", 1, "Z", 'VALUE')
|
yield ("Denoising Depth", "Z", 'VALUE')
|
||||||
engine.register_pass(scene, srl, "Denoising Shadowing", 1, "X", 'VALUE')
|
yield ("Denoising Shadowing", "X", 'VALUE')
|
||||||
engine.register_pass(scene, srl, "Denoising Variance", 3, "RGB", 'COLOR')
|
yield ("Denoising Variance", "RGB", 'COLOR')
|
||||||
engine.register_pass(scene, srl, "Denoising Intensity", 1, "X", 'VALUE')
|
yield ("Denoising Intensity", "X", 'VALUE')
|
||||||
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
||||||
"denoising_glossy_direct", "denoising_glossy_indirect",
|
"denoising_glossy_direct", "denoising_glossy_indirect",
|
||||||
"denoising_transmission_direct", "denoising_transmission_indirect",
|
"denoising_transmission_direct", "denoising_transmission_indirect",
|
||||||
"denoising_subsurface_direct", "denoising_subsurface_indirect")
|
"denoising_subsurface_direct", "denoising_subsurface_indirect")
|
||||||
if any(getattr(crl, option) for option in clean_options):
|
if any(getattr(crl, option) for option in clean_options):
|
||||||
engine.register_pass(scene, srl, "Denoising Clean", 3, "RGB", 'COLOR')
|
yield ("Denoising Clean", "RGB", 'COLOR')
|
||||||
|
|
||||||
|
# Custom AOV passes.
|
||||||
|
for aov in crl.aovs:
|
||||||
|
if aov.type == 'VALUE':
|
||||||
|
yield (aov.name, "X", 'VALUE')
|
||||||
|
else:
|
||||||
|
yield (aov.name, "RGBA", 'COLOR')
|
||||||
|
|
||||||
|
def register_passes(engine, scene, view_layer):
|
||||||
|
# Detect duplicate render pass names, first one wins.
|
||||||
|
listed = set()
|
||||||
|
for name, channelids, channeltype in list_render_passes(view_layer):
|
||||||
|
if name not in listed:
|
||||||
|
engine.register_pass(scene, view_layer, name, len(channelids), channelids, channeltype)
|
||||||
|
listed.add(name)
|
||||||
|
|
||||||
|
def detect_conflicting_passes(view_layer):
|
||||||
|
# Detect conflicting render pass names for UI.
|
||||||
|
counter = {}
|
||||||
|
for name, _, _ in list_render_passes(view_layer):
|
||||||
|
counter[name] = counter.get(name, 0) + 1
|
||||||
|
|
||||||
|
for aov in view_layer.cycles.aovs:
|
||||||
|
if counter[aov.name] > 1:
|
||||||
|
aov.conflict = "Conflicts with another render pass with the same name"
|
||||||
|
else:
|
||||||
|
aov.conflict = ""
|
||||||
|
|||||||
@@ -44,6 +44,36 @@ class CYCLES_OT_use_shading_nodes(Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class CYCLES_OT_add_aov(bpy.types.Operator):
|
||||||
|
"""Add an AOV pass"""
|
||||||
|
bl_idname="cycles.add_aov"
|
||||||
|
bl_label="Add AOV"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
view_layer = context.view_layer
|
||||||
|
cycles_view_layer = view_layer.cycles
|
||||||
|
|
||||||
|
cycles_view_layer.aovs.add()
|
||||||
|
|
||||||
|
view_layer.update_render_passes()
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class CYCLES_OT_remove_aov(bpy.types.Operator):
|
||||||
|
"""Remove an AOV pass"""
|
||||||
|
bl_idname="cycles.remove_aov"
|
||||||
|
bl_label="Remove AOV"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
view_layer = context.view_layer
|
||||||
|
cycles_view_layer = view_layer.cycles
|
||||||
|
|
||||||
|
cycles_view_layer.aovs.remove(cycles_view_layer.active_aov)
|
||||||
|
|
||||||
|
view_layer.update_render_passes()
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
class CYCLES_OT_denoise_animation(Operator):
|
class CYCLES_OT_denoise_animation(Operator):
|
||||||
"Denoise rendered animation sequence using current scene and view " \
|
"Denoise rendered animation sequence using current scene and view " \
|
||||||
"layer settings. Requires denoising data passes and output to " \
|
"layer settings. Requires denoising data passes and output to " \
|
||||||
@@ -167,6 +197,8 @@ class CYCLES_OT_merge_images(Operator):
|
|||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
CYCLES_OT_use_shading_nodes,
|
CYCLES_OT_use_shading_nodes,
|
||||||
|
CYCLES_OT_add_aov,
|
||||||
|
CYCLES_OT_remove_aov,
|
||||||
CYCLES_OT_denoise_animation,
|
CYCLES_OT_denoise_animation,
|
||||||
CYCLES_OT_merge_images
|
CYCLES_OT_merge_images
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
BoolProperty,
|
BoolProperty,
|
||||||
|
CollectionProperty,
|
||||||
EnumProperty,
|
EnumProperty,
|
||||||
FloatProperty,
|
FloatProperty,
|
||||||
IntProperty,
|
IntProperty,
|
||||||
@@ -31,6 +32,7 @@ from math import pi
|
|||||||
# enums
|
# enums
|
||||||
|
|
||||||
import _cycles
|
import _cycles
|
||||||
|
from . import engine
|
||||||
|
|
||||||
enum_devices = (
|
enum_devices = (
|
||||||
('CPU', "CPU", "Use CPU for rendering"),
|
('CPU', "CPU", "Use CPU for rendering"),
|
||||||
@@ -190,6 +192,10 @@ enum_view3d_shading_render_pass= (
|
|||||||
('MIST', "Mist", "Show the Mist render pass", 32),
|
('MIST', "Mist", "Show the Mist render pass", 32),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum_aov_types = (
|
||||||
|
('VALUE', "Value", "Write a Value pass", 0),
|
||||||
|
('COLOR', "Color", "Write a Color pass", 1),
|
||||||
|
)
|
||||||
|
|
||||||
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||||
|
|
||||||
@@ -1218,8 +1224,29 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
|
|||||||
def update_render_passes(self, context):
|
def update_render_passes(self, context):
|
||||||
view_layer = context.view_layer
|
view_layer = context.view_layer
|
||||||
view_layer.update_render_passes()
|
view_layer.update_render_passes()
|
||||||
|
engine.detect_conflicting_passes(view_layer)
|
||||||
|
|
||||||
|
|
||||||
|
class CyclesAOVPass(bpy.types.PropertyGroup):
|
||||||
|
name: StringProperty(
|
||||||
|
name="Name",
|
||||||
|
description="Name of the pass, to use in the AOV Output shader node",
|
||||||
|
update=update_render_passes,
|
||||||
|
default="AOV"
|
||||||
|
)
|
||||||
|
type: EnumProperty(
|
||||||
|
name="Type",
|
||||||
|
description="Pass data type",
|
||||||
|
update=update_render_passes,
|
||||||
|
items=enum_aov_types,
|
||||||
|
default='COLOR'
|
||||||
|
)
|
||||||
|
conflict: StringProperty(
|
||||||
|
name="Conflict",
|
||||||
|
description="If there is a conflict with another render passes, message explaining why",
|
||||||
|
default=""
|
||||||
|
)
|
||||||
|
|
||||||
class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
||||||
|
|
||||||
pass_debug_bvh_traversed_nodes: BoolProperty(
|
pass_debug_bvh_traversed_nodes: BoolProperty(
|
||||||
@@ -1378,6 +1405,15 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
|||||||
update=update_render_passes,
|
update=update_render_passes,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
aovs: CollectionProperty(
|
||||||
|
type=CyclesAOVPass,
|
||||||
|
description="Custom render passes that can be output by shader nodes",
|
||||||
|
)
|
||||||
|
active_aov: IntProperty(
|
||||||
|
default=0,
|
||||||
|
min=0
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls):
|
def register(cls):
|
||||||
bpy.types.ViewLayer.cycles = PointerProperty(
|
bpy.types.ViewLayer.cycles = PointerProperty(
|
||||||
@@ -1552,6 +1588,7 @@ def register():
|
|||||||
bpy.utils.register_class(CyclesCurveRenderSettings)
|
bpy.utils.register_class(CyclesCurveRenderSettings)
|
||||||
bpy.utils.register_class(CyclesDeviceSettings)
|
bpy.utils.register_class(CyclesDeviceSettings)
|
||||||
bpy.utils.register_class(CyclesPreferences)
|
bpy.utils.register_class(CyclesPreferences)
|
||||||
|
bpy.utils.register_class(CyclesAOVPass)
|
||||||
bpy.utils.register_class(CyclesRenderLayerSettings)
|
bpy.utils.register_class(CyclesRenderLayerSettings)
|
||||||
bpy.utils.register_class(CyclesView3DShadingSettings)
|
bpy.utils.register_class(CyclesView3DShadingSettings)
|
||||||
|
|
||||||
@@ -1573,5 +1610,6 @@ def unregister():
|
|||||||
bpy.utils.unregister_class(CyclesCurveRenderSettings)
|
bpy.utils.unregister_class(CyclesCurveRenderSettings)
|
||||||
bpy.utils.unregister_class(CyclesDeviceSettings)
|
bpy.utils.unregister_class(CyclesDeviceSettings)
|
||||||
bpy.utils.unregister_class(CyclesPreferences)
|
bpy.utils.unregister_class(CyclesPreferences)
|
||||||
|
bpy.utils.unregister_class(CyclesAOVPass)
|
||||||
bpy.utils.unregister_class(CyclesRenderLayerSettings)
|
bpy.utils.unregister_class(CyclesRenderLayerSettings)
|
||||||
bpy.utils.unregister_class(CyclesView3DShadingSettings)
|
bpy.utils.unregister_class(CyclesView3DShadingSettings)
|
||||||
|
|||||||
@@ -918,6 +918,42 @@ class CYCLES_RENDER_PT_passes_debug(CyclesButtonsPanel, Panel):
|
|||||||
layout.prop(cycles_view_layer, "pass_debug_ray_bounces")
|
layout.prop(cycles_view_layer, "pass_debug_ray_bounces")
|
||||||
|
|
||||||
|
|
||||||
|
class CYCLES_RENDER_UL_aov(bpy.types.UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
|
row = layout.row()
|
||||||
|
split = row.split(factor=0.65)
|
||||||
|
icon = 'ERROR' if item.conflict else 'NONE'
|
||||||
|
split.row().prop(item, "name", text="", icon=icon, emboss=False)
|
||||||
|
split.row().prop(item, "type", text="", emboss=False)
|
||||||
|
|
||||||
|
|
||||||
|
class CYCLES_RENDER_PT_passes_aov(CyclesButtonsPanel, Panel):
|
||||||
|
bl_label = "Shader AOV"
|
||||||
|
bl_context = "view_layer"
|
||||||
|
bl_parent_id = "CYCLES_RENDER_PT_passes"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.use_property_split = True
|
||||||
|
layout.use_property_decorate = False
|
||||||
|
|
||||||
|
cycles_view_layer = context.view_layer.cycles
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
col = row.column()
|
||||||
|
col.template_list("CYCLES_RENDER_UL_aov", "aovs", cycles_view_layer, "aovs", cycles_view_layer, "active_aov", rows=2)
|
||||||
|
|
||||||
|
col = row.column()
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.operator("cycles.add_aov", icon='ADD', text="")
|
||||||
|
sub.operator("cycles.remove_aov", icon='REMOVE', text="")
|
||||||
|
|
||||||
|
if cycles_view_layer.active_aov < len(cycles_view_layer.aovs):
|
||||||
|
active_aov = cycles_view_layer.aovs[cycles_view_layer.active_aov]
|
||||||
|
if active_aov.conflict:
|
||||||
|
layout.label(text=active_aov.conflict, icon='ERROR')
|
||||||
|
|
||||||
|
|
||||||
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
|
class CYCLES_RENDER_PT_denoising(CyclesButtonsPanel, Panel):
|
||||||
bl_label = "Denoising"
|
bl_label = "Denoising"
|
||||||
bl_context = "view_layer"
|
bl_context = "view_layer"
|
||||||
@@ -2233,6 +2269,8 @@ classes = (
|
|||||||
CYCLES_RENDER_PT_passes_light,
|
CYCLES_RENDER_PT_passes_light,
|
||||||
CYCLES_RENDER_PT_passes_crypto,
|
CYCLES_RENDER_PT_passes_crypto,
|
||||||
CYCLES_RENDER_PT_passes_debug,
|
CYCLES_RENDER_PT_passes_debug,
|
||||||
|
CYCLES_RENDER_UL_aov,
|
||||||
|
CYCLES_RENDER_PT_passes_aov,
|
||||||
CYCLES_RENDER_PT_filter,
|
CYCLES_RENDER_PT_filter,
|
||||||
CYCLES_RENDER_PT_override,
|
CYCLES_RENDER_PT_override,
|
||||||
CYCLES_RENDER_PT_denoising,
|
CYCLES_RENDER_PT_denoising,
|
||||||
|
|||||||
@@ -793,18 +793,13 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
|
|||||||
|
|
||||||
for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
for (b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
|
||||||
BL::RenderPass b_pass(*b_iter);
|
BL::RenderPass b_pass(*b_iter);
|
||||||
|
|
||||||
/* find matching pass type */
|
|
||||||
PassType pass_type = BlenderSync::get_pass_type(b_pass);
|
|
||||||
int components = b_pass.channels();
|
int components = b_pass.channels();
|
||||||
|
|
||||||
bool read = false;
|
/* Copy pixels from regular render passes. */
|
||||||
if (pass_type != PASS_NONE) {
|
bool read = buffers->get_pass_rect(b_pass.name(), exposure, sample, components, &pixels[0]);
|
||||||
/* copy pixels */
|
|
||||||
read = buffers->get_pass_rect(
|
/* If denoising pass, */
|
||||||
pass_type, exposure, sample, components, &pixels[0], b_pass.name());
|
if (!read) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
||||||
if (denoising_offset >= 0) {
|
if (denoising_offset >= 0) {
|
||||||
read = buffers->get_denoising_pass_rect(
|
read = buffers->get_denoising_pass_rect(
|
||||||
@@ -822,7 +817,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
|
|||||||
else {
|
else {
|
||||||
/* copy combined pass */
|
/* copy combined pass */
|
||||||
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
|
BL::RenderPass b_combined_pass(b_rlay.passes.find_by_name("Combined", b_rview_name.c_str()));
|
||||||
if (buffers->get_pass_rect(PASS_COMBINED, exposure, sample, 4, &pixels[0], "Combined"))
|
if (buffers->get_pass_rect("Combined", exposure, sample, 4, &pixels[0]))
|
||||||
b_combined_pass.rect(&pixels[0]);
|
b_combined_pass.rect(&pixels[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -921,6 +921,12 @@ static ShaderNode *add_node(Scene *scene,
|
|||||||
disp->attribute = "";
|
disp->attribute = "";
|
||||||
node = disp;
|
node = disp;
|
||||||
}
|
}
|
||||||
|
else if (b_node.is_a(&RNA_ShaderNodeOutputAOV)) {
|
||||||
|
BL::ShaderNodeOutputAOV b_aov_node(b_node);
|
||||||
|
OutputAOVNode *aov = new OutputAOVNode();
|
||||||
|
aov->name = b_aov_node.name();
|
||||||
|
node = aov;
|
||||||
|
}
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
node->name = b_node.name();
|
node->name = b_node.name();
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
|
|||||||
if (pass_type == PASS_MOTION && scene->integrator->motion_blur)
|
if (pass_type == PASS_MOTION && scene->integrator->motion_blur)
|
||||||
continue;
|
continue;
|
||||||
if (pass_type != PASS_NONE)
|
if (pass_type != PASS_NONE)
|
||||||
Pass::add(pass_type, passes);
|
Pass::add(pass_type, passes, b_pass.name().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
PointerRNA crp = RNA_pointer_get(&b_view_layer.ptr, "cycles");
|
||||||
@@ -570,32 +570,32 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
|
|||||||
#ifdef __KERNEL_DEBUG__
|
#ifdef __KERNEL_DEBUG__
|
||||||
if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
|
if (get_boolean(crp, "pass_debug_bvh_traversed_nodes")) {
|
||||||
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug BVH Traversed Nodes", 1, "X", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_BVH_TRAVERSED_NODES, passes);
|
Pass::add(PASS_BVH_TRAVERSED_NODES, passes, "Debug BVH Traversed Nodes");
|
||||||
}
|
}
|
||||||
if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
|
if (get_boolean(crp, "pass_debug_bvh_traversed_instances")) {
|
||||||
b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug BVH Traversed Instances", 1, "X", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes);
|
Pass::add(PASS_BVH_TRAVERSED_INSTANCES, passes, "Debug BVH Traversed Instances");
|
||||||
}
|
}
|
||||||
if (get_boolean(crp, "pass_debug_bvh_intersections")) {
|
if (get_boolean(crp, "pass_debug_bvh_intersections")) {
|
||||||
b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug BVH Intersections", 1, "X", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_BVH_INTERSECTIONS, passes);
|
Pass::add(PASS_BVH_INTERSECTIONS, passes, "Debug BVH Intersections");
|
||||||
}
|
}
|
||||||
if (get_boolean(crp, "pass_debug_ray_bounces")) {
|
if (get_boolean(crp, "pass_debug_ray_bounces")) {
|
||||||
b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug Ray Bounces", 1, "X", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_RAY_BOUNCES, passes);
|
Pass::add(PASS_RAY_BOUNCES, passes, "Debug Ray Bounces");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (get_boolean(crp, "pass_debug_render_time")) {
|
if (get_boolean(crp, "pass_debug_render_time")) {
|
||||||
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
|
b_engine.add_pass("Debug Render Time", 1, "X", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_RENDER_TIME, passes);
|
Pass::add(PASS_RENDER_TIME, passes, "Debug Render Time");
|
||||||
}
|
}
|
||||||
if (get_boolean(crp, "use_pass_volume_direct")) {
|
if (get_boolean(crp, "use_pass_volume_direct")) {
|
||||||
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
|
b_engine.add_pass("VolumeDir", 3, "RGB", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_VOLUME_DIRECT, passes);
|
Pass::add(PASS_VOLUME_DIRECT, passes, "VolumeDir");
|
||||||
}
|
}
|
||||||
if (get_boolean(crp, "use_pass_volume_indirect")) {
|
if (get_boolean(crp, "use_pass_volume_indirect")) {
|
||||||
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
|
b_engine.add_pass("VolumeInd", 3, "RGB", b_view_layer.name().c_str());
|
||||||
Pass::add(PASS_VOLUME_INDIRECT, passes);
|
Pass::add(PASS_VOLUME_INDIRECT, passes, "VolumeInd");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
|
/* Cryptomatte stores two ID/weight pairs per RGBA layer.
|
||||||
@@ -635,6 +635,21 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
|
|||||||
CRYPT_ACCURATE);
|
CRYPT_ACCURATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RNA_BEGIN (&crp, b_aov, "aovs") {
|
||||||
|
bool is_color = (get_enum(b_aov, "type") == 1);
|
||||||
|
string name = get_string(b_aov, "name");
|
||||||
|
|
||||||
|
if (is_color) {
|
||||||
|
b_engine.add_pass(name.c_str(), 4, "RGBA", b_view_layer.name().c_str());
|
||||||
|
Pass::add(PASS_AOV_COLOR, passes, name.c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
b_engine.add_pass(name.c_str(), 1, "X", b_view_layer.name().c_str());
|
||||||
|
Pass::add(PASS_AOV_VALUE, passes, name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RNA_END;
|
||||||
|
|
||||||
return passes;
|
return passes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ set(SRC_HEADERS
|
|||||||
kernel_types.h
|
kernel_types.h
|
||||||
kernel_volume.h
|
kernel_volume.h
|
||||||
kernel_work_stealing.h
|
kernel_work_stealing.h
|
||||||
|
kernel_write_passes.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SRC_KERNELS_CPU_HEADERS
|
set(SRC_KERNELS_CPU_HEADERS
|
||||||
@@ -182,6 +183,7 @@ set(SRC_CLOSURE_HEADERS
|
|||||||
set(SRC_SVM_HEADERS
|
set(SRC_SVM_HEADERS
|
||||||
svm/svm.h
|
svm/svm.h
|
||||||
svm/svm_ao.h
|
svm/svm_ao.h
|
||||||
|
svm/svm_aov.h
|
||||||
svm/svm_attribute.h
|
svm/svm_attribute.h
|
||||||
svm/svm_bevel.h
|
svm/svm_bevel.h
|
||||||
svm/svm_blackbody.h
|
svm/svm_blackbody.h
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ ccl_device_inline void compute_light_pass(
|
|||||||
path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL);
|
path_state_init(kg, &emission_sd, &state, rng_hash, sample, NULL);
|
||||||
|
|
||||||
/* evaluate surface shader */
|
/* evaluate surface shader */
|
||||||
shader_eval_surface(kg, sd, &state, state.flag);
|
shader_eval_surface(kg, sd, &state, NULL, state.flag);
|
||||||
|
|
||||||
/* TODO, disable more closures we don't need besides transparent */
|
/* TODO, disable more closures we don't need besides transparent */
|
||||||
shader_bsdf_disable_transparency(kg, sd);
|
shader_bsdf_disable_transparency(kg, sd);
|
||||||
@@ -209,12 +209,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* surface color of the pass only */
|
/* surface color of the pass only */
|
||||||
shader_eval_surface(kg, sd, state, 0);
|
shader_eval_surface(kg, sd, state, NULL, 0);
|
||||||
return kernel_bake_shader_bsdf(kg, sd, type);
|
return kernel_bake_shader_bsdf(kg, sd, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
shader_eval_surface(kg, sd, state, 0);
|
shader_eval_surface(kg, sd, state, NULL, 0);
|
||||||
color = kernel_bake_shader_bsdf(kg, sd, type);
|
color = kernel_bake_shader_bsdf(kg, sd, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
|
|||||||
case SHADER_EVAL_EMISSION: {
|
case SHADER_EVAL_EMISSION: {
|
||||||
if (type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
|
if (type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
|
||||||
int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0;
|
int path_flag = (type == SHADER_EVAL_EMISSION) ? PATH_RAY_EMISSION : 0;
|
||||||
shader_eval_surface(kg, &sd, &state, path_flag);
|
shader_eval_surface(kg, &sd, &state, NULL, path_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == SHADER_EVAL_NORMAL) {
|
if (type == SHADER_EVAL_NORMAL) {
|
||||||
@@ -445,7 +445,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* evaluate */
|
/* evaluate */
|
||||||
int path_flag = 0; /* we can't know which type of BSDF this is for */
|
int path_flag = 0; /* we can't know which type of BSDF this is for */
|
||||||
shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
|
shader_eval_surface(kg, &sd, &state, NULL, path_flag | PATH_RAY_EMISSION);
|
||||||
out = shader_background_eval(&sd);
|
out = shader_background_eval(&sd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -524,7 +524,7 @@ ccl_device void kernel_background_evaluate(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* evaluate */
|
/* evaluate */
|
||||||
int path_flag = 0; /* we can't know which type of BSDF this is for */
|
int path_flag = 0; /* we can't know which type of BSDF this is for */
|
||||||
shader_eval_surface(kg, &sd, &state, path_flag | PATH_RAY_EMISSION);
|
shader_eval_surface(kg, &sd, &state, NULL, path_flag | PATH_RAY_EMISSION);
|
||||||
float3 color = shader_background_eval(&sd);
|
float3 color = shader_background_eval(&sd);
|
||||||
|
|
||||||
/* write output */
|
/* write output */
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ ccl_device_noinline_cpu float3 direct_emissive_eval(KernelGlobals *kg,
|
|||||||
/* No proper path flag, we're evaluating this for all closures. that's
|
/* No proper path flag, we're evaluating this for all closures. that's
|
||||||
* weak but we'd have to do multiple evaluations otherwise. */
|
* weak but we'd have to do multiple evaluations otherwise. */
|
||||||
path_state_modify_bounce(state, true);
|
path_state_modify_bounce(state, true);
|
||||||
shader_eval_surface(kg, emission_sd, state, PATH_RAY_EMISSION);
|
shader_eval_surface(kg, emission_sd, state, NULL, PATH_RAY_EMISSION);
|
||||||
path_state_modify_bounce(state, false);
|
path_state_modify_bounce(state, false);
|
||||||
|
|
||||||
/* Evaluate closures. */
|
/* Evaluate closures. */
|
||||||
@@ -294,6 +294,7 @@ ccl_device_noinline_cpu bool indirect_lamp_emission(KernelGlobals *kg,
|
|||||||
ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
|
ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
|
||||||
ShaderData *emission_sd,
|
ShaderData *emission_sd,
|
||||||
ccl_addr_space PathState *state,
|
ccl_addr_space PathState *state,
|
||||||
|
ccl_global float *buffer,
|
||||||
ccl_addr_space Ray *ray)
|
ccl_addr_space Ray *ray)
|
||||||
{
|
{
|
||||||
#ifdef __BACKGROUND__
|
#ifdef __BACKGROUND__
|
||||||
@@ -322,7 +323,7 @@ ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
path_state_modify_bounce(state, true);
|
path_state_modify_bounce(state, true);
|
||||||
shader_eval_surface(kg, emission_sd, state, state->flag | PATH_RAY_EMISSION);
|
shader_eval_surface(kg, emission_sd, state, buffer, state->flag | PATH_RAY_EMISSION);
|
||||||
path_state_modify_bounce(state, false);
|
path_state_modify_bounce(state, false);
|
||||||
|
|
||||||
L = shader_background_eval(emission_sd);
|
L = shader_background_eval(emission_sd);
|
||||||
|
|||||||
@@ -14,85 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
|
|
||||||
# define __ATOMIC_PASS_WRITE__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "kernel/kernel_id_passes.h"
|
#include "kernel/kernel_id_passes.h"
|
||||||
|
|
||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
|
|
||||||
{
|
|
||||||
ccl_global float *buf = buffer;
|
|
||||||
#ifdef __ATOMIC_PASS_WRITE__
|
|
||||||
atomic_add_and_fetch_float(buf, value);
|
|
||||||
#else
|
|
||||||
*buf += value;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, float3 value)
|
|
||||||
{
|
|
||||||
#ifdef __ATOMIC_PASS_WRITE__
|
|
||||||
ccl_global float *buf_x = buffer + 0;
|
|
||||||
ccl_global float *buf_y = buffer + 1;
|
|
||||||
ccl_global float *buf_z = buffer + 2;
|
|
||||||
|
|
||||||
atomic_add_and_fetch_float(buf_x, value.x);
|
|
||||||
atomic_add_and_fetch_float(buf_y, value.y);
|
|
||||||
atomic_add_and_fetch_float(buf_z, value.z);
|
|
||||||
#else
|
|
||||||
ccl_global float3 *buf = (ccl_global float3 *)buffer;
|
|
||||||
*buf += value;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, float4 value)
|
|
||||||
{
|
|
||||||
#ifdef __ATOMIC_PASS_WRITE__
|
|
||||||
ccl_global float *buf_x = buffer + 0;
|
|
||||||
ccl_global float *buf_y = buffer + 1;
|
|
||||||
ccl_global float *buf_z = buffer + 2;
|
|
||||||
ccl_global float *buf_w = buffer + 3;
|
|
||||||
|
|
||||||
atomic_add_and_fetch_float(buf_x, value.x);
|
|
||||||
atomic_add_and_fetch_float(buf_y, value.y);
|
|
||||||
atomic_add_and_fetch_float(buf_z, value.z);
|
|
||||||
atomic_add_and_fetch_float(buf_w, value.w);
|
|
||||||
#else
|
|
||||||
ccl_global float4 *buf = (ccl_global float4 *)buffer;
|
|
||||||
*buf += value;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __DENOISING_FEATURES__
|
#ifdef __DENOISING_FEATURES__
|
||||||
ccl_device_inline void kernel_write_pass_float_variance(ccl_global float *buffer, float value)
|
|
||||||
{
|
|
||||||
kernel_write_pass_float(buffer, value);
|
|
||||||
|
|
||||||
/* The online one-pass variance update that's used for the mega-kernel can't easily be
|
|
||||||
* implemented with atomics,
|
|
||||||
* so for the split kernel the E[x^2] - 1/N * (E[x])^2 fallback is used. */
|
|
||||||
kernel_write_pass_float(buffer + 1, value * value);
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef __ATOMIC_PASS_WRITE__
|
|
||||||
# define kernel_write_pass_float3_unaligned kernel_write_pass_float3
|
|
||||||
# else
|
|
||||||
ccl_device_inline void kernel_write_pass_float3_unaligned(ccl_global float *buffer, float3 value)
|
|
||||||
{
|
|
||||||
buffer[0] += value.x;
|
|
||||||
buffer[1] += value.y;
|
|
||||||
buffer[2] += value.z;
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_pass_float3_variance(ccl_global float *buffer, float3 value)
|
|
||||||
{
|
|
||||||
kernel_write_pass_float3_unaligned(buffer, value);
|
|
||||||
kernel_write_pass_float3_unaligned(buffer + 3, value * value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ccl_device_inline void kernel_write_denoising_shadow(KernelGlobals *kg,
|
ccl_device_inline void kernel_write_denoising_shadow(KernelGlobals *kg,
|
||||||
ccl_global float *buffer,
|
ccl_global float *buffer,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "kernel/geom/geom.h"
|
#include "kernel/geom/geom.h"
|
||||||
#include "kernel/bvh/bvh.h"
|
#include "kernel/bvh/bvh.h"
|
||||||
|
|
||||||
|
#include "kernel/kernel_write_passes.h"
|
||||||
#include "kernel/kernel_accumulate.h"
|
#include "kernel/kernel_accumulate.h"
|
||||||
#include "kernel/kernel_shader.h"
|
#include "kernel/kernel_shader.h"
|
||||||
#include "kernel/kernel_light.h"
|
#include "kernel/kernel_light.h"
|
||||||
@@ -116,6 +117,7 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
|
|||||||
ccl_addr_space Ray *ray,
|
ccl_addr_space Ray *ray,
|
||||||
float3 throughput,
|
float3 throughput,
|
||||||
ShaderData *sd,
|
ShaderData *sd,
|
||||||
|
ccl_global float *buffer,
|
||||||
PathRadiance *L)
|
PathRadiance *L)
|
||||||
{
|
{
|
||||||
/* eval background shader if nothing hit */
|
/* eval background shader if nothing hit */
|
||||||
@@ -136,7 +138,7 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
|
|||||||
|
|
||||||
#ifdef __BACKGROUND__
|
#ifdef __BACKGROUND__
|
||||||
/* sample background shader */
|
/* sample background shader */
|
||||||
float3 L_background = indirect_background(kg, sd, state, ray);
|
float3 L_background = indirect_background(kg, sd, state, buffer, ray);
|
||||||
path_radiance_accum_background(L, state, throughput, L_background);
|
path_radiance_accum_background(L, state, throughput, L_background);
|
||||||
#endif /* __BACKGROUND__ */
|
#endif /* __BACKGROUND__ */
|
||||||
}
|
}
|
||||||
@@ -267,7 +269,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
|
|||||||
|
|
||||||
float3 bg = make_float3(0.0f, 0.0f, 0.0f);
|
float3 bg = make_float3(0.0f, 0.0f, 0.0f);
|
||||||
if (!kernel_data.background.transparent) {
|
if (!kernel_data.background.transparent) {
|
||||||
bg = indirect_background(kg, emission_sd, state, ray);
|
bg = indirect_background(kg, emission_sd, state, NULL, ray);
|
||||||
}
|
}
|
||||||
path_radiance_accum_shadowcatcher(L, throughput, bg);
|
path_radiance_accum_shadowcatcher(L, throughput, bg);
|
||||||
}
|
}
|
||||||
@@ -418,7 +420,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* Shade background. */
|
/* Shade background. */
|
||||||
if (!hit) {
|
if (!hit) {
|
||||||
kernel_path_background(kg, state, ray, throughput, sd, L);
|
kernel_path_background(kg, state, ray, throughput, sd, NULL, L);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (path_state_ao_bounce(kg, state)) {
|
else if (path_state_ao_bounce(kg, state)) {
|
||||||
@@ -434,7 +436,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Evaluate shader. */
|
/* Evaluate shader. */
|
||||||
shader_eval_surface(kg, sd, state, state->flag);
|
shader_eval_surface(kg, sd, state, NULL, state->flag);
|
||||||
shader_prepare_closures(sd, state);
|
shader_prepare_closures(sd, state);
|
||||||
|
|
||||||
/* Apply shadow catcher, holdout, emission. */
|
/* Apply shadow catcher, holdout, emission. */
|
||||||
@@ -556,7 +558,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* Shade background. */
|
/* Shade background. */
|
||||||
if (!hit) {
|
if (!hit) {
|
||||||
kernel_path_background(kg, state, ray, throughput, &sd, L);
|
kernel_path_background(kg, state, ray, throughput, &sd, buffer, L);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (path_state_ao_bounce(kg, state)) {
|
else if (path_state_ao_bounce(kg, state)) {
|
||||||
@@ -572,7 +574,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Evaluate shader. */
|
/* Evaluate shader. */
|
||||||
shader_eval_surface(kg, &sd, state, state->flag);
|
shader_eval_surface(kg, &sd, state, buffer, state->flag);
|
||||||
shader_prepare_closures(&sd, state);
|
shader_prepare_closures(&sd, state);
|
||||||
|
|
||||||
/* Apply shadow catcher, holdout, emission. */
|
/* Apply shadow catcher, holdout, emission. */
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
|||||||
|
|
||||||
/* Shade background. */
|
/* Shade background. */
|
||||||
if (!hit) {
|
if (!hit) {
|
||||||
kernel_path_background(kg, &state, &ray, throughput, &sd, L);
|
kernel_path_background(kg, &state, &ray, throughput, &sd, buffer, L);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +417,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
|||||||
if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
|
if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
shader_eval_surface(kg, &sd, &state, state.flag);
|
shader_eval_surface(kg, &sd, &state, buffer, state.flag);
|
||||||
shader_merge_closures(&sd);
|
shader_merge_closures(&sd);
|
||||||
|
|
||||||
/* Apply shadow catcher, holdout, emission. */
|
/* Apply shadow catcher, holdout, emission. */
|
||||||
|
|||||||
@@ -1076,6 +1076,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd)
|
|||||||
ccl_device void shader_eval_surface(KernelGlobals *kg,
|
ccl_device void shader_eval_surface(KernelGlobals *kg,
|
||||||
ShaderData *sd,
|
ShaderData *sd,
|
||||||
ccl_addr_space PathState *state,
|
ccl_addr_space PathState *state,
|
||||||
|
ccl_global float *buffer,
|
||||||
int path_flag)
|
int path_flag)
|
||||||
{
|
{
|
||||||
PROFILING_INIT(kg, PROFILING_SHADER_EVAL);
|
PROFILING_INIT(kg, PROFILING_SHADER_EVAL);
|
||||||
@@ -1107,7 +1108,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg,
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#ifdef __SVM__
|
#ifdef __SVM__
|
||||||
svm_eval_nodes(kg, sd, state, SHADER_TYPE_SURFACE, path_flag);
|
svm_eval_nodes(kg, sd, state, buffer, SHADER_TYPE_SURFACE, path_flag);
|
||||||
#else
|
#else
|
||||||
if (sd->object == OBJECT_NONE) {
|
if (sd->object == OBJECT_NONE) {
|
||||||
sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
|
sd->closure_emission_background = make_float3(0.8f, 0.8f, 0.8f);
|
||||||
@@ -1319,7 +1320,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg,
|
|||||||
else
|
else
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
svm_eval_nodes(kg, sd, state, SHADER_TYPE_VOLUME, path_flag);
|
svm_eval_nodes(kg, sd, state, NULL, SHADER_TYPE_VOLUME, path_flag);
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@@ -1348,7 +1349,7 @@ ccl_device void shader_eval_displacement(KernelGlobals *kg,
|
|||||||
else
|
else
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
svm_eval_nodes(kg, sd, state, SHADER_TYPE_DISPLACEMENT, 0);
|
svm_eval_nodes(kg, sd, state, NULL, SHADER_TYPE_DISPLACEMENT, 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ ccl_device_forceinline bool shadow_handle_transparent_isect(KernelGlobals *kg,
|
|||||||
/* Attenuation from transparent surface. */
|
/* Attenuation from transparent surface. */
|
||||||
if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
|
if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
|
||||||
path_state_modify_bounce(state, true);
|
path_state_modify_bounce(state, true);
|
||||||
shader_eval_surface(kg, shadow_sd, state, PATH_RAY_SHADOW);
|
shader_eval_surface(kg, shadow_sd, state, NULL, PATH_RAY_SHADOW);
|
||||||
path_state_modify_bounce(state, false);
|
path_state_modify_bounce(state, false);
|
||||||
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
|
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ ccl_device void subsurface_color_bump_blur(
|
|||||||
|
|
||||||
if (bump || texture_blur > 0.0f) {
|
if (bump || texture_blur > 0.0f) {
|
||||||
/* average color and normal at incoming point */
|
/* average color and normal at incoming point */
|
||||||
shader_eval_surface(kg, sd, state, state->flag);
|
shader_eval_surface(kg, sd, state, NULL, state->flag);
|
||||||
float3 in_color = shader_bssrdf_sum(sd, (bump) ? N : NULL, NULL);
|
float3 in_color = shader_bssrdf_sum(sd, (bump) ? N : NULL, NULL);
|
||||||
|
|
||||||
/* we simply divide out the average color and multiply with the average
|
/* we simply divide out the average color and multiply with the average
|
||||||
|
|||||||
@@ -222,6 +222,8 @@ typedef enum ShaderEvalType {
|
|||||||
SHADER_EVAL_TRANSMISSION_COLOR,
|
SHADER_EVAL_TRANSMISSION_COLOR,
|
||||||
SHADER_EVAL_SUBSURFACE_COLOR,
|
SHADER_EVAL_SUBSURFACE_COLOR,
|
||||||
SHADER_EVAL_EMISSION,
|
SHADER_EVAL_EMISSION,
|
||||||
|
SHADER_EVAL_AOV_COLOR,
|
||||||
|
SHADER_EVAL_AOV_VALUE,
|
||||||
|
|
||||||
/* light passes */
|
/* light passes */
|
||||||
SHADER_EVAL_AO,
|
SHADER_EVAL_AO,
|
||||||
@@ -371,6 +373,8 @@ typedef enum PassType {
|
|||||||
#endif
|
#endif
|
||||||
PASS_RENDER_TIME,
|
PASS_RENDER_TIME,
|
||||||
PASS_CRYPTOMATTE,
|
PASS_CRYPTOMATTE,
|
||||||
|
PASS_AOV_COLOR,
|
||||||
|
PASS_AOV_VALUE,
|
||||||
PASS_CATEGORY_MAIN_END = 31,
|
PASS_CATEGORY_MAIN_END = 31,
|
||||||
|
|
||||||
PASS_MIST = 32,
|
PASS_MIST = 32,
|
||||||
@@ -1244,6 +1248,11 @@ typedef struct KernelFilm {
|
|||||||
int pass_denoising_clean;
|
int pass_denoising_clean;
|
||||||
int denoising_flags;
|
int denoising_flags;
|
||||||
|
|
||||||
|
int pass_aov_color;
|
||||||
|
int pass_aov_value;
|
||||||
|
int pad1;
|
||||||
|
int pad2;
|
||||||
|
|
||||||
/* XYZ to rendering color space transform. float4 instead of float3 to
|
/* XYZ to rendering color space transform. float4 instead of float3 to
|
||||||
* ensure consistent padding/alignment across devices. */
|
* ensure consistent padding/alignment across devices. */
|
||||||
float4 xyz_to_r;
|
float4 xyz_to_r;
|
||||||
|
|||||||
95
intern/cycles/kernel/kernel_write_passes.h
Normal file
95
intern/cycles/kernel/kernel_write_passes.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
|
||||||
|
# define __ATOMIC_PASS_WRITE__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, float value)
|
||||||
|
{
|
||||||
|
ccl_global float *buf = buffer;
|
||||||
|
#ifdef __ATOMIC_PASS_WRITE__
|
||||||
|
atomic_add_and_fetch_float(buf, value);
|
||||||
|
#else
|
||||||
|
*buf += value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, float3 value)
|
||||||
|
{
|
||||||
|
#ifdef __ATOMIC_PASS_WRITE__
|
||||||
|
ccl_global float *buf_x = buffer + 0;
|
||||||
|
ccl_global float *buf_y = buffer + 1;
|
||||||
|
ccl_global float *buf_z = buffer + 2;
|
||||||
|
|
||||||
|
atomic_add_and_fetch_float(buf_x, value.x);
|
||||||
|
atomic_add_and_fetch_float(buf_y, value.y);
|
||||||
|
atomic_add_and_fetch_float(buf_z, value.z);
|
||||||
|
#else
|
||||||
|
ccl_global float3 *buf = (ccl_global float3 *)buffer;
|
||||||
|
*buf += value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, float4 value)
|
||||||
|
{
|
||||||
|
#ifdef __ATOMIC_PASS_WRITE__
|
||||||
|
ccl_global float *buf_x = buffer + 0;
|
||||||
|
ccl_global float *buf_y = buffer + 1;
|
||||||
|
ccl_global float *buf_z = buffer + 2;
|
||||||
|
ccl_global float *buf_w = buffer + 3;
|
||||||
|
|
||||||
|
atomic_add_and_fetch_float(buf_x, value.x);
|
||||||
|
atomic_add_and_fetch_float(buf_y, value.y);
|
||||||
|
atomic_add_and_fetch_float(buf_z, value.z);
|
||||||
|
atomic_add_and_fetch_float(buf_w, value.w);
|
||||||
|
#else
|
||||||
|
ccl_global float4 *buf = (ccl_global float4 *)buffer;
|
||||||
|
*buf += value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __DENOISING_FEATURES__
|
||||||
|
ccl_device_inline void kernel_write_pass_float_variance(ccl_global float *buffer, float value)
|
||||||
|
{
|
||||||
|
kernel_write_pass_float(buffer, value);
|
||||||
|
|
||||||
|
/* The online one-pass variance update that's used for the megakernel can't easily be implemented
|
||||||
|
* with atomics, so for the split kernel the E[x^2] - 1/N * (E[x])^2 fallback is used. */
|
||||||
|
kernel_write_pass_float(buffer + 1, value * value);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef __ATOMIC_PASS_WRITE__
|
||||||
|
# define kernel_write_pass_float3_unaligned kernel_write_pass_float3
|
||||||
|
# else
|
||||||
|
ccl_device_inline void kernel_write_pass_float3_unaligned(ccl_global float *buffer, float3 value)
|
||||||
|
{
|
||||||
|
buffer[0] += value.x;
|
||||||
|
buffer[1] += value.y;
|
||||||
|
buffer[2] += value.z;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
ccl_device_inline void kernel_write_pass_float3_variance(ccl_global float *buffer, float3 value)
|
||||||
|
{
|
||||||
|
kernel_write_pass_float3_unaligned(buffer, value);
|
||||||
|
kernel_write_pass_float3_unaligned(buffer + 3, value * value);
|
||||||
|
}
|
||||||
|
#endif /* __DENOISING_FEATURES__ */
|
||||||
|
|
||||||
|
CCL_NAMESPACE_END
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "kernel/kernel_globals.h"
|
#include "kernel/kernel_globals.h"
|
||||||
#include "kernel/kernel_color.h"
|
#include "kernel/kernel_color.h"
|
||||||
#include "kernel/kernel_random.h"
|
#include "kernel/kernel_random.h"
|
||||||
|
#include "kernel/kernel_write_passes.h"
|
||||||
#include "kernel/kernel_projection.h"
|
#include "kernel/kernel_projection.h"
|
||||||
#include "kernel/kernel_differential.h"
|
#include "kernel/kernel_differential.h"
|
||||||
#include "kernel/kernel_montecarlo.h"
|
#include "kernel/kernel_montecarlo.h"
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
|
|||||||
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
|
||||||
float3 throughput = kernel_split_state.throughput[ray_index];
|
float3 throughput = kernel_split_state.throughput[ray_index];
|
||||||
ShaderData *sd = kernel_split_sd(sd, ray_index);
|
ShaderData *sd = kernel_split_sd(sd, ray_index);
|
||||||
|
uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
|
||||||
|
ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
|
||||||
|
|
||||||
kernel_path_background(kg, state, ray, throughput, sd, L);
|
kernel_path_background(kg, state, ray, throughput, sd, buffer, L);
|
||||||
kernel_split_path_end(kg, ray_index);
|
kernel_split_path_end(kg, ray_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,10 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg)
|
|||||||
ccl_global char *ray_state = kernel_split_state.ray_state;
|
ccl_global char *ray_state = kernel_split_state.ray_state;
|
||||||
if (IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
if (IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||||
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
|
||||||
|
uint buffer_offset = kernel_split_state.buffer_offset[ray_index];
|
||||||
|
ccl_global float *buffer = kernel_split_params.tile.buffer + buffer_offset;
|
||||||
|
|
||||||
shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, state->flag);
|
shader_eval_surface(kg, kernel_split_sd(sd, ray_index), state, buffer, state->flag);
|
||||||
#ifdef __BRANCHED_PATH__
|
#ifdef __BRANCHED_PATH__
|
||||||
if (kernel_data.integrator.branched) {
|
if (kernel_data.integrator.branched) {
|
||||||
shader_merge_closures(kernel_split_sd(sd, ray_index));
|
shader_merge_closures(kernel_split_sd(sd, ray_index));
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ CCL_NAMESPACE_END
|
|||||||
#include "kernel/svm/svm_math_util.h"
|
#include "kernel/svm/svm_math_util.h"
|
||||||
#include "kernel/svm/svm_mapping_util.h"
|
#include "kernel/svm/svm_mapping_util.h"
|
||||||
|
|
||||||
|
#include "kernel/svm/svm_aov.h"
|
||||||
#include "kernel/svm/svm_attribute.h"
|
#include "kernel/svm/svm_attribute.h"
|
||||||
#include "kernel/svm/svm_gradient.h"
|
#include "kernel/svm/svm_gradient.h"
|
||||||
#include "kernel/svm/svm_blackbody.h"
|
#include "kernel/svm/svm_blackbody.h"
|
||||||
@@ -218,6 +219,7 @@ CCL_NAMESPACE_BEGIN
|
|||||||
ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
|
ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
|
||||||
ShaderData *sd,
|
ShaderData *sd,
|
||||||
ccl_addr_space PathState *state,
|
ccl_addr_space PathState *state,
|
||||||
|
ccl_global float *buffer,
|
||||||
ShaderType type,
|
ShaderType type,
|
||||||
int path_flag)
|
int path_flag)
|
||||||
{
|
{
|
||||||
@@ -467,6 +469,17 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
|
|||||||
case NODE_IES:
|
case NODE_IES:
|
||||||
svm_node_ies(kg, sd, stack, node, &offset);
|
svm_node_ies(kg, sd, stack, node, &offset);
|
||||||
break;
|
break;
|
||||||
|
case NODE_AOV_START:
|
||||||
|
if (!svm_node_aov_check(state, buffer)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NODE_AOV_COLOR:
|
||||||
|
svm_node_aov_color(kg, sd, stack, node, buffer);
|
||||||
|
break;
|
||||||
|
case NODE_AOV_VALUE:
|
||||||
|
svm_node_aov_value(kg, sd, stack, node, buffer);
|
||||||
|
break;
|
||||||
# endif /* __EXTRA_NODES__ */
|
# endif /* __EXTRA_NODES__ */
|
||||||
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */
|
#endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */
|
||||||
|
|
||||||
|
|||||||
49
intern/cycles/kernel/svm/svm_aov.h
Normal file
49
intern/cycles/kernel/svm/svm_aov.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2013 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
ccl_device_inline bool svm_node_aov_check(ccl_addr_space PathState *state,
|
||||||
|
ccl_global float *buffer)
|
||||||
|
{
|
||||||
|
int path_flag = state->flag;
|
||||||
|
|
||||||
|
bool is_primary = (path_flag & PATH_RAY_CAMERA) && (!(path_flag & PATH_RAY_SINGLE_PASS_DONE));
|
||||||
|
|
||||||
|
return ((buffer != NULL) && is_primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device void svm_node_aov_color(
|
||||||
|
KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ccl_global float *buffer)
|
||||||
|
{
|
||||||
|
float3 val = stack_load_float3(stack, node.y);
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
kernel_write_pass_float4(buffer + kernel_data.film.pass_aov_color + 4 * node.z,
|
||||||
|
make_float4(val.x, val.y, val.z, 1.0f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ccl_device void svm_node_aov_value(
|
||||||
|
KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, ccl_global float *buffer)
|
||||||
|
{
|
||||||
|
float val = stack_load_float(stack, node.y);
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
kernel_write_pass_float(buffer + kernel_data.film.pass_aov_value + node.z, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CCL_NAMESPACE_END
|
||||||
@@ -150,6 +150,9 @@ typedef enum ShaderNodeType {
|
|||||||
NODE_VERTEX_COLOR,
|
NODE_VERTEX_COLOR,
|
||||||
NODE_VERTEX_COLOR_BUMP_DX,
|
NODE_VERTEX_COLOR_BUMP_DX,
|
||||||
NODE_VERTEX_COLOR_BUMP_DY,
|
NODE_VERTEX_COLOR_BUMP_DY,
|
||||||
|
NODE_AOV_START,
|
||||||
|
NODE_AOV_VALUE,
|
||||||
|
NODE_AOV_COLOR,
|
||||||
} ShaderNodeType;
|
} ShaderNodeType;
|
||||||
|
|
||||||
typedef enum NodeAttributeType {
|
typedef enum NodeAttributeType {
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ bool RenderBuffers::get_denoising_pass_rect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool RenderBuffers::get_pass_rect(
|
bool RenderBuffers::get_pass_rect(
|
||||||
PassType type, float exposure, int sample, int components, float *pixels, const string &name)
|
const string &name, float exposure, int sample, int components, float *pixels)
|
||||||
{
|
{
|
||||||
if (buffer.data() == NULL) {
|
if (buffer.data() == NULL) {
|
||||||
return false;
|
return false;
|
||||||
@@ -245,18 +245,14 @@ bool RenderBuffers::get_pass_rect(
|
|||||||
for (size_t j = 0; j < params.passes.size(); j++) {
|
for (size_t j = 0; j < params.passes.size(); j++) {
|
||||||
Pass &pass = params.passes[j];
|
Pass &pass = params.passes[j];
|
||||||
|
|
||||||
if (pass.type != type) {
|
/* Pass is identified by both type and name, multiple of the same type
|
||||||
|
* may exist with a different name. */
|
||||||
|
if (pass.name != name) {
|
||||||
pass_offset += pass.components;
|
pass_offset += pass.components;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell Cryptomatte passes apart by their name. */
|
PassType type = pass.type;
|
||||||
if (pass.type == PASS_CRYPTOMATTE) {
|
|
||||||
if (pass.name != name) {
|
|
||||||
pass_offset += pass.components;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float *in = buffer.data() + pass_offset;
|
float *in = buffer.data() + pass_offset;
|
||||||
int pass_stride = params.get_passes_size();
|
int pass_stride = params.get_passes_size();
|
||||||
|
|||||||
@@ -88,12 +88,8 @@ class RenderBuffers {
|
|||||||
void zero();
|
void zero();
|
||||||
|
|
||||||
bool copy_from_device();
|
bool copy_from_device();
|
||||||
bool get_pass_rect(PassType type,
|
bool get_pass_rect(
|
||||||
float exposure,
|
const string &name, float exposure, int sample, int components, float *pixels);
|
||||||
int sample,
|
|
||||||
int components,
|
|
||||||
float *pixels,
|
|
||||||
const string &name);
|
|
||||||
bool get_denoising_pass_rect(
|
bool get_denoising_pass_rect(
|
||||||
int offset, float exposure, int sample, int components, float *pixels);
|
int offset, float exposure, int sample, int components, float *pixels);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -163,6 +163,12 @@ void Pass::add(PassType type, vector<Pass> &passes, const char *name)
|
|||||||
case PASS_CRYPTOMATTE:
|
case PASS_CRYPTOMATTE:
|
||||||
pass.components = 4;
|
pass.components = 4;
|
||||||
break;
|
break;
|
||||||
|
case PASS_AOV_COLOR:
|
||||||
|
pass.components = 4;
|
||||||
|
break;
|
||||||
|
case PASS_AOV_VALUE:
|
||||||
|
pass.components = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
@@ -327,7 +333,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kfilm->pass_stride = 0;
|
kfilm->pass_stride = 0;
|
||||||
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
|
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
|
||||||
|
|
||||||
bool have_cryptomatte = false;
|
bool have_cryptomatte = false, have_aov_color = false, have_aov_value = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < passes.size(); i++) {
|
for (size_t i = 0; i < passes.size(); i++) {
|
||||||
Pass &pass = passes[i];
|
Pass &pass = passes[i];
|
||||||
@@ -464,6 +470,18 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
|||||||
kfilm->pass_stride;
|
kfilm->pass_stride;
|
||||||
have_cryptomatte = true;
|
have_cryptomatte = true;
|
||||||
break;
|
break;
|
||||||
|
case PASS_AOV_COLOR:
|
||||||
|
if (!have_aov_color) {
|
||||||
|
kfilm->pass_aov_color = kfilm->pass_stride;
|
||||||
|
have_aov_color = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PASS_AOV_VALUE:
|
||||||
|
if (!have_aov_value) {
|
||||||
|
kfilm->pass_aov_value = kfilm->pass_stride;
|
||||||
|
have_aov_value = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
@@ -569,4 +587,27 @@ void Film::tag_update(Scene * /*scene*/)
|
|||||||
need_update = true;
|
need_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Film::get_aov_offset(string name, bool &is_color)
|
||||||
|
{
|
||||||
|
int num_color = 0, num_value = 0;
|
||||||
|
foreach (const Pass &pass, passes) {
|
||||||
|
if (pass.type == PASS_AOV_COLOR) {
|
||||||
|
num_color++;
|
||||||
|
}
|
||||||
|
else if (pass.type == PASS_AOV_VALUE) {
|
||||||
|
num_value++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass.name == name) {
|
||||||
|
is_color = (pass.type == PASS_AOV_COLOR);
|
||||||
|
return (is_color ? num_color : num_value) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ class Film : public Node {
|
|||||||
bool modified(const Film &film);
|
bool modified(const Film &film);
|
||||||
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
|
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
|
||||||
void tag_update(Scene *scene);
|
void tag_update(Scene *scene);
|
||||||
|
|
||||||
|
int get_aov_offset(string name, bool &is_color);
|
||||||
};
|
};
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
|||||||
@@ -55,6 +55,25 @@ bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &do
|
|||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
||||||
|
/* Sockets */
|
||||||
|
|
||||||
|
void ShaderInput::disconnect()
|
||||||
|
{
|
||||||
|
if (link) {
|
||||||
|
link->links.erase(remove(link->links.begin(), link->links.end(), this), link->links.end());
|
||||||
|
}
|
||||||
|
link = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderOutput::disconnect()
|
||||||
|
{
|
||||||
|
foreach (ShaderInput *sock, links) {
|
||||||
|
sock->link = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
links.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/* Node */
|
/* Node */
|
||||||
|
|
||||||
ShaderNode::ShaderNode(const NodeType *type) : Node(type)
|
ShaderNode::ShaderNode(const NodeType *type) : Node(type)
|
||||||
@@ -285,11 +304,7 @@ void ShaderGraph::disconnect(ShaderOutput *from)
|
|||||||
assert(!finalized);
|
assert(!finalized);
|
||||||
simplified = false;
|
simplified = false;
|
||||||
|
|
||||||
foreach (ShaderInput *sock, from->links) {
|
from->disconnect();
|
||||||
sock->link = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
from->links.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::disconnect(ShaderInput *to)
|
void ShaderGraph::disconnect(ShaderInput *to)
|
||||||
@@ -298,10 +313,7 @@ void ShaderGraph::disconnect(ShaderInput *to)
|
|||||||
assert(to->link);
|
assert(to->link);
|
||||||
simplified = false;
|
simplified = false;
|
||||||
|
|
||||||
ShaderOutput *from = to->link;
|
to->disconnect();
|
||||||
|
|
||||||
to->link = NULL;
|
|
||||||
from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
|
void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
|
||||||
@@ -782,6 +794,11 @@ void ShaderGraph::clean(Scene *scene)
|
|||||||
|
|
||||||
/* break cycles */
|
/* break cycles */
|
||||||
break_cycles(output(), visited, on_stack);
|
break_cycles(output(), visited, on_stack);
|
||||||
|
foreach (ShaderNode *node, nodes) {
|
||||||
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
|
||||||
|
break_cycles(node, visited, on_stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* disconnect unused nodes */
|
/* disconnect unused nodes */
|
||||||
foreach (ShaderNode *node, nodes) {
|
foreach (ShaderNode *node, nodes) {
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ enum ShaderNodeSpecialType {
|
|||||||
SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
|
SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
|
||||||
SHADER_SPECIAL_TYPE_OUTPUT,
|
SHADER_SPECIAL_TYPE_OUTPUT,
|
||||||
SHADER_SPECIAL_TYPE_BUMP,
|
SHADER_SPECIAL_TYPE_BUMP,
|
||||||
|
SHADER_SPECIAL_TYPE_OUTPUT_AOV,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Input
|
/* Input
|
||||||
@@ -104,6 +105,8 @@ class ShaderInput {
|
|||||||
((Node *)parent)->set(socket_type, f);
|
((Node *)parent)->set(socket_type, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
const SocketType &socket_type;
|
const SocketType &socket_type;
|
||||||
ShaderNode *parent;
|
ShaderNode *parent;
|
||||||
ShaderOutput *link;
|
ShaderOutput *link;
|
||||||
@@ -130,6 +133,8 @@ class ShaderOutput {
|
|||||||
return socket_type.type;
|
return socket_type.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
const SocketType &socket_type;
|
const SocketType &socket_type;
|
||||||
ShaderNode *parent;
|
ShaderNode *parent;
|
||||||
vector<ShaderInput *> links;
|
vector<ShaderInput *> links;
|
||||||
|
|||||||
@@ -5709,6 +5709,58 @@ void ClampNode::compile(OSLCompiler &compiler)
|
|||||||
compiler.add(this, "node_clamp");
|
compiler.add(this, "node_clamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* AOV Output */
|
||||||
|
|
||||||
|
NODE_DEFINE(OutputAOVNode)
|
||||||
|
{
|
||||||
|
NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
|
||||||
|
|
||||||
|
SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
|
||||||
|
SOCKET_IN_FLOAT(value, "Value", 0.0f);
|
||||||
|
|
||||||
|
SOCKET_STRING(name, "AOV Name", ustring(""));
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputAOVNode::OutputAOVNode() : ShaderNode(node_type)
|
||||||
|
{
|
||||||
|
special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
|
||||||
|
slot = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputAOVNode::simplify_settings(Scene *scene)
|
||||||
|
{
|
||||||
|
slot = scene->film->get_aov_offset(name.string(), is_color);
|
||||||
|
if (slot == -1) {
|
||||||
|
slot = scene->film->get_aov_offset(name.string(), is_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot == -1 || is_color) {
|
||||||
|
input("Value")->disconnect();
|
||||||
|
}
|
||||||
|
if (slot == -1 || !is_color) {
|
||||||
|
input("Color")->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputAOVNode::compile(SVMCompiler &compiler)
|
||||||
|
{
|
||||||
|
assert(slot >= 0);
|
||||||
|
|
||||||
|
if (is_color) {
|
||||||
|
compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), slot);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
/* Math */
|
/* Math */
|
||||||
|
|
||||||
NODE_DEFINE(MathNode)
|
NODE_DEFINE(MathNode)
|
||||||
|
|||||||
@@ -189,6 +189,26 @@ class OutputNode : public ShaderNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OutputAOVNode : public ShaderNode {
|
||||||
|
public:
|
||||||
|
SHADER_NODE_CLASS(OutputAOVNode)
|
||||||
|
virtual void simplify_settings(Scene *scene);
|
||||||
|
|
||||||
|
float value;
|
||||||
|
float3 color;
|
||||||
|
|
||||||
|
ustring name;
|
||||||
|
|
||||||
|
/* Don't allow output node de-duplication. */
|
||||||
|
virtual bool equals(const ShaderNode & /*other*/)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slot;
|
||||||
|
bool is_color;
|
||||||
|
};
|
||||||
|
|
||||||
class GradientTextureNode : public TextureNode {
|
class GradientTextureNode : public TextureNode {
|
||||||
public:
|
public:
|
||||||
SHADER_NODE_CLASS(GradientTextureNode)
|
SHADER_NODE_CLASS(GradientTextureNode)
|
||||||
|
|||||||
@@ -225,6 +225,13 @@ Shader::~Shader()
|
|||||||
|
|
||||||
bool Shader::is_constant_emission(float3 *emission)
|
bool Shader::is_constant_emission(float3 *emission)
|
||||||
{
|
{
|
||||||
|
/* If the shader has AOVs, they need to be evaluated, so we can't skip the shader. */
|
||||||
|
foreach (ShaderNode *node, graph->nodes) {
|
||||||
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ShaderInput *surf = graph->output()->input("Surface");
|
ShaderInput *surf = graph->output()->input("Surface");
|
||||||
|
|
||||||
if (surf->link == NULL) {
|
if (surf->link == NULL) {
|
||||||
|
|||||||
@@ -554,6 +554,24 @@ void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SVMCompiler::generate_aov_node(ShaderNode *node, CompilerState *state)
|
||||||
|
{
|
||||||
|
/* execute dependencies for node */
|
||||||
|
foreach (ShaderInput *in, node->inputs) {
|
||||||
|
if (in->link != NULL) {
|
||||||
|
ShaderNodeSet dependencies;
|
||||||
|
find_dependencies(dependencies, state->nodes_done, in);
|
||||||
|
generate_svm_nodes(dependencies, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compile node itself */
|
||||||
|
generate_node(node, state->nodes_done);
|
||||||
|
|
||||||
|
state->nodes_done.insert(node);
|
||||||
|
state->nodes_done_flag[node->id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
|
void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
|
||||||
ShaderNode *node,
|
ShaderNode *node,
|
||||||
CompilerState *state)
|
CompilerState *state)
|
||||||
@@ -703,21 +721,21 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
|||||||
current_graph = graph;
|
current_graph = graph;
|
||||||
|
|
||||||
/* get input in output node */
|
/* get input in output node */
|
||||||
ShaderNode *node = graph->output();
|
ShaderNode *output = graph->output();
|
||||||
ShaderInput *clin = NULL;
|
ShaderInput *clin = NULL;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SHADER_TYPE_SURFACE:
|
case SHADER_TYPE_SURFACE:
|
||||||
clin = node->input("Surface");
|
clin = output->input("Surface");
|
||||||
break;
|
break;
|
||||||
case SHADER_TYPE_VOLUME:
|
case SHADER_TYPE_VOLUME:
|
||||||
clin = node->input("Volume");
|
clin = output->input("Volume");
|
||||||
break;
|
break;
|
||||||
case SHADER_TYPE_DISPLACEMENT:
|
case SHADER_TYPE_DISPLACEMENT:
|
||||||
clin = node->input("Displacement");
|
clin = output->input("Displacement");
|
||||||
break;
|
break;
|
||||||
case SHADER_TYPE_BUMP:
|
case SHADER_TYPE_BUMP:
|
||||||
clin = node->input("Normal");
|
clin = output->input("Normal");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
@@ -728,10 +746,10 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
|||||||
memset((void *)&active_stack, 0, sizeof(active_stack));
|
memset((void *)&active_stack, 0, sizeof(active_stack));
|
||||||
current_svm_nodes.clear();
|
current_svm_nodes.clear();
|
||||||
|
|
||||||
foreach (ShaderNode *node_iter, graph->nodes) {
|
foreach (ShaderNode *node, graph->nodes) {
|
||||||
foreach (ShaderInput *input, node_iter->inputs)
|
foreach (ShaderInput *input, node->inputs)
|
||||||
input->stack_offset = SVM_STACK_INVALID;
|
input->stack_offset = SVM_STACK_INVALID;
|
||||||
foreach (ShaderOutput *output, node_iter->outputs)
|
foreach (ShaderOutput *output, node->outputs)
|
||||||
output->stack_offset = SVM_STACK_INVALID;
|
output->stack_offset = SVM_STACK_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +763,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shader->used) {
|
if (shader->used) {
|
||||||
|
CompilerState state(graph);
|
||||||
if (clin->link) {
|
if (clin->link) {
|
||||||
bool generate = false;
|
bool generate = false;
|
||||||
|
|
||||||
@@ -769,13 +788,36 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (generate) {
|
if (generate) {
|
||||||
CompilerState state(graph);
|
|
||||||
generate_multi_closure(clin->link->parent, clin->link->parent, &state);
|
generate_multi_closure(clin->link->parent, clin->link->parent, &state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compile output node */
|
/* compile output node */
|
||||||
node->compile(*this);
|
output->compile(*this);
|
||||||
|
|
||||||
|
if (type == SHADER_TYPE_SURFACE) {
|
||||||
|
vector<OutputAOVNode *> aov_outputs;
|
||||||
|
foreach (ShaderNode *node, graph->nodes) {
|
||||||
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT_AOV) {
|
||||||
|
OutputAOVNode *aov_node = static_cast<OutputAOVNode *>(node);
|
||||||
|
if (aov_node->slot >= 0) {
|
||||||
|
aov_outputs.push_back(aov_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (aov_outputs.size() > 0) {
|
||||||
|
/* AOV passes are only written if the object is directly visible, so
|
||||||
|
* there is no point in evaluating all the nodes generated only for the
|
||||||
|
* AOV outputs if that's not the case. Therefore, we insert
|
||||||
|
* NODE_AOV_START into the shader before the AOV-only nodes are
|
||||||
|
* generated which tells the kernel that it can stop evaluation
|
||||||
|
* early if AOVs will not be written. */
|
||||||
|
add_node(NODE_AOV_START, 0, 0, 0);
|
||||||
|
foreach (OutputAOVNode *node, aov_outputs) {
|
||||||
|
generate_aov_node(node, &state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add node to restore state after bump shader has finished */
|
/* add node to restore state after bump shader has finished */
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ class SVMCompiler {
|
|||||||
ShaderInput *input,
|
ShaderInput *input,
|
||||||
ShaderNode *skip_node = NULL);
|
ShaderNode *skip_node = NULL);
|
||||||
void generate_node(ShaderNode *node, ShaderNodeSet &done);
|
void generate_node(ShaderNode *node, ShaderNodeSet &done);
|
||||||
|
void generate_aov_node(ShaderNode *node, CompilerState *state);
|
||||||
void generate_closure_node(ShaderNode *node, CompilerState *state);
|
void generate_closure_node(ShaderNode *node, CompilerState *state);
|
||||||
void generated_shared_closure_nodes(ShaderNode *root_node,
|
void generated_shared_closure_nodes(ShaderNode *root_node,
|
||||||
ShaderNode *node,
|
ShaderNode *node,
|
||||||
|
|||||||
@@ -157,6 +157,11 @@ def object_cycles_shader_nodes_poll(context):
|
|||||||
cycles_shader_nodes_poll(context))
|
cycles_shader_nodes_poll(context))
|
||||||
|
|
||||||
|
|
||||||
|
def cycles_aov_node_poll(context):
|
||||||
|
return (object_cycles_shader_nodes_poll(context) or
|
||||||
|
world_shader_nodes_poll(context))
|
||||||
|
|
||||||
|
|
||||||
def object_eevee_shader_nodes_poll(context):
|
def object_eevee_shader_nodes_poll(context):
|
||||||
return (object_shader_nodes_poll(context) and
|
return (object_shader_nodes_poll(context) and
|
||||||
eevee_shader_nodes_poll(context))
|
eevee_shader_nodes_poll(context))
|
||||||
@@ -197,6 +202,7 @@ shader_node_categories = [
|
|||||||
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
|
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
|
||||||
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
|
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_cycles_shader_nodes_poll),
|
||||||
NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll),
|
NodeItem("ShaderNodeOutputLight", poll=object_cycles_shader_nodes_poll),
|
||||||
|
NodeItem("ShaderNodeOutputAOV", poll=cycles_aov_node_poll),
|
||||||
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
|
NodeItem("ShaderNodeOutputWorld", poll=world_shader_nodes_poll),
|
||||||
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
|
NodeItem("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_poll),
|
||||||
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
|
NodeItem("NodeGroupOutput", poll=group_input_output_item_poll),
|
||||||
|
|||||||
@@ -990,6 +990,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
|
|||||||
#define SH_NODE_TEX_WHITE_NOISE 704
|
#define SH_NODE_TEX_WHITE_NOISE 704
|
||||||
#define SH_NODE_VOLUME_INFO 705
|
#define SH_NODE_VOLUME_INFO 705
|
||||||
#define SH_NODE_VERTEX_COLOR 706
|
#define SH_NODE_VERTEX_COLOR 706
|
||||||
|
#define SH_NODE_OUTPUT_AOV 707
|
||||||
|
|
||||||
/* custom defines options for Material node */
|
/* custom defines options for Material node */
|
||||||
#define SH_NODE_MAT_DIFF 1
|
#define SH_NODE_MAT_DIFF 1
|
||||||
|
|||||||
@@ -4007,6 +4007,7 @@ static void registerShaderNodes(void)
|
|||||||
register_node_type_sh_output_material();
|
register_node_type_sh_output_material();
|
||||||
register_node_type_sh_output_world();
|
register_node_type_sh_output_world();
|
||||||
register_node_type_sh_output_linestyle();
|
register_node_type_sh_output_linestyle();
|
||||||
|
register_node_type_sh_output_aov();
|
||||||
|
|
||||||
register_node_type_sh_tex_image();
|
register_node_type_sh_tex_image();
|
||||||
register_node_type_sh_tex_environment();
|
register_node_type_sh_tex_environment();
|
||||||
|
|||||||
@@ -1154,6 +1154,11 @@ static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C),
|
|||||||
uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
|
uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
/* only once called */
|
/* only once called */
|
||||||
static void node_shader_set_butfunc(bNodeType *ntype)
|
static void node_shader_set_butfunc(bNodeType *ntype)
|
||||||
{
|
{
|
||||||
@@ -1310,6 +1315,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
|
|||||||
case SH_NODE_TEX_WHITE_NOISE:
|
case SH_NODE_TEX_WHITE_NOISE:
|
||||||
ntype->draw_buttons = node_shader_buts_white_noise;
|
ntype->draw_buttons = node_shader_buts_white_noise;
|
||||||
break;
|
break;
|
||||||
|
case SH_NODE_OUTPUT_AOV:
|
||||||
|
ntype->draw_buttons = node_shader_buts_output_aov;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1010,6 +1010,10 @@ typedef struct NodeShaderTexIES {
|
|||||||
char filepath[1024];
|
char filepath[1024];
|
||||||
} NodeShaderTexIES;
|
} NodeShaderTexIES;
|
||||||
|
|
||||||
|
typedef struct NodeShaderOutputAOV {
|
||||||
|
char name[64];
|
||||||
|
} NodeShaderOutputAOV;
|
||||||
|
|
||||||
typedef struct NodeSunBeams {
|
typedef struct NodeSunBeams {
|
||||||
float source[2];
|
float source[2];
|
||||||
|
|
||||||
|
|||||||
@@ -574,6 +574,7 @@ extern StructRNA RNA_ShaderNodeMath;
|
|||||||
extern StructRNA RNA_ShaderNodeMixRGB;
|
extern StructRNA RNA_ShaderNodeMixRGB;
|
||||||
extern StructRNA RNA_ShaderNodeNormal;
|
extern StructRNA RNA_ShaderNodeNormal;
|
||||||
extern StructRNA RNA_ShaderNodeOutput;
|
extern StructRNA RNA_ShaderNodeOutput;
|
||||||
|
extern StructRNA RNA_ShaderNodeOutputAOV;
|
||||||
extern StructRNA RNA_ShaderNodeRGB;
|
extern StructRNA RNA_ShaderNodeRGB;
|
||||||
extern StructRNA RNA_ShaderNodeRGBCurve;
|
extern StructRNA RNA_ShaderNodeRGBCurve;
|
||||||
extern StructRNA RNA_ShaderNodeRGBToBW;
|
extern StructRNA RNA_ShaderNodeRGBToBW;
|
||||||
|
|||||||
@@ -5187,6 +5187,19 @@ static void def_sh_tex_ies(StructRNA *srna)
|
|||||||
RNA_def_struct_sdna_from(srna, "bNode", NULL);
|
RNA_def_struct_sdna_from(srna, "bNode", NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void def_sh_output_aov(StructRNA *srna)
|
||||||
|
{
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
|
RNA_def_struct_sdna_from(srna, "NodeShaderOutputAOV", "storage");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||||
|
RNA_def_property_ui_text(prop, "Name", "Name of the AOV that this output writes to");
|
||||||
|
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||||
|
|
||||||
|
RNA_def_struct_sdna_from(srna, "bNode", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void def_sh_script(StructRNA *srna)
|
static void def_sh_script(StructRNA *srna)
|
||||||
{
|
{
|
||||||
PropertyRNA *prop;
|
PropertyRNA *prop;
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ set(SRC
|
|||||||
shader/nodes/node_shader_output_linestyle.c
|
shader/nodes/node_shader_output_linestyle.c
|
||||||
shader/nodes/node_shader_output_material.c
|
shader/nodes/node_shader_output_material.c
|
||||||
shader/nodes/node_shader_output_world.c
|
shader/nodes/node_shader_output_world.c
|
||||||
|
shader/nodes/node_shader_output_aov.c
|
||||||
shader/nodes/node_shader_particle_info.c
|
shader/nodes/node_shader_particle_info.c
|
||||||
shader/nodes/node_shader_rgb.c
|
shader/nodes/node_shader_rgb.c
|
||||||
shader/nodes/node_shader_script.c
|
shader/nodes/node_shader_script.c
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ void register_node_type_sh_output_material(void);
|
|||||||
void register_node_type_sh_output_eevee_material(void);
|
void register_node_type_sh_output_eevee_material(void);
|
||||||
void register_node_type_sh_output_world(void);
|
void register_node_type_sh_output_world(void);
|
||||||
void register_node_type_sh_output_linestyle(void);
|
void register_node_type_sh_output_linestyle(void);
|
||||||
|
void register_node_type_sh_output_aov(void);
|
||||||
|
|
||||||
void register_node_type_sh_tex_image(void);
|
void register_node_type_sh_tex_image(void);
|
||||||
void register_node_type_sh_tex_environment(void);
|
void register_node_type_sh_tex_environment(void);
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DIS
|
|||||||
DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","" )
|
DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","" )
|
||||||
DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" )
|
DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" )
|
||||||
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
|
DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
|
||||||
|
DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" )
|
||||||
|
|
||||||
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
|
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
|
||||||
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
|
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
|
||||||
|
|||||||
51
source/blender/nodes/shader/nodes/node_shader_output_aov.c
Normal file
51
source/blender/nodes/shader/nodes/node_shader_output_aov.c
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2005 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../node_shader_util.h"
|
||||||
|
|
||||||
|
/* **************** OUTPUT ******************** */
|
||||||
|
|
||||||
|
static bNodeSocketTemplate sh_node_output_aov_in[] = {
|
||||||
|
{SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
|
||||||
|
{SOCK_FLOAT, 1, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
|
{-1, 0, ""},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
|
||||||
|
{
|
||||||
|
NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV");
|
||||||
|
node->storage = aov;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* node type definition */
|
||||||
|
void register_node_type_sh_output_aov(void)
|
||||||
|
{
|
||||||
|
static bNodeType ntype;
|
||||||
|
|
||||||
|
sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0);
|
||||||
|
node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL);
|
||||||
|
node_type_init(&ntype, node_shader_init_output_aov);
|
||||||
|
node_type_storage(
|
||||||
|
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
|
||||||
|
|
||||||
|
/* Do not allow muting output node. */
|
||||||
|
node_type_internal_links(&ntype, NULL);
|
||||||
|
|
||||||
|
nodeRegisterType(&ntype);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user