forked from bartvdbraak/blender
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:
parent
35b5888b15
commit
e760972221
@ -223,65 +223,95 @@ def system_info():
|
||||
import _cycles
|
||||
return _cycles.system_info()
|
||||
|
||||
def list_render_passes(srl):
|
||||
# Builtin Blender passes.
|
||||
yield ("Combined", "RGBA", 'COLOR')
|
||||
|
||||
def register_passes(engine, scene, srl):
|
||||
engine.register_pass(scene, srl, "Combined", 4, "RGBA", 'COLOR')
|
||||
|
||||
if srl.use_pass_z: engine.register_pass(scene, srl, "Depth", 1, "Z", 'VALUE')
|
||||
if srl.use_pass_mist: engine.register_pass(scene, srl, "Mist", 1, "Z", 'VALUE')
|
||||
if srl.use_pass_normal: engine.register_pass(scene, srl, "Normal", 3, "XYZ", 'VECTOR')
|
||||
if srl.use_pass_vector: engine.register_pass(scene, srl, "Vector", 4, "XYZW", 'VECTOR')
|
||||
if srl.use_pass_uv: engine.register_pass(scene, srl, "UV", 3, "UVA", 'VECTOR')
|
||||
if srl.use_pass_object_index: engine.register_pass(scene, srl, "IndexOB", 1, "X", 'VALUE')
|
||||
if srl.use_pass_material_index: engine.register_pass(scene, srl, "IndexMA", 1, "X", 'VALUE')
|
||||
if srl.use_pass_shadow: engine.register_pass(scene, srl, "Shadow", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_ambient_occlusion: engine.register_pass(scene, srl, "AO", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_direct: engine.register_pass(scene, srl, "DiffDir", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_indirect: engine.register_pass(scene, srl, "DiffInd", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_color: engine.register_pass(scene, srl, "DiffCol", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_direct: engine.register_pass(scene, srl, "GlossDir", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_indirect: engine.register_pass(scene, srl, "GlossInd", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_color: engine.register_pass(scene, srl, "GlossCol", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_direct: engine.register_pass(scene, srl, "TransDir", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_indirect: engine.register_pass(scene, srl, "TransInd", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_color: engine.register_pass(scene, srl, "TransCol", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_subsurface_direct: engine.register_pass(scene, srl, "SubsurfaceDir", 3, "RGB", 'COLOR')
|
||||
if srl.use_pass_subsurface_indirect: engine.register_pass(scene, srl, "SubsurfaceInd", 3, "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')
|
||||
if srl.use_pass_z: yield ("Depth", "Z", 'VALUE')
|
||||
if srl.use_pass_mist: yield ("Mist", "Z", 'VALUE')
|
||||
if srl.use_pass_normal: yield ("Normal", "XYZ", 'VECTOR')
|
||||
if srl.use_pass_vector: yield ("Vector", "XYZW", 'VECTOR')
|
||||
if srl.use_pass_uv: yield ("UV", "UVA", 'VECTOR')
|
||||
if srl.use_pass_object_index: yield ("IndexOB", "X", 'VALUE')
|
||||
if srl.use_pass_material_index: yield ("IndexMA", "X", 'VALUE')
|
||||
if srl.use_pass_shadow: yield ("Shadow", "RGB", 'COLOR')
|
||||
if srl.use_pass_ambient_occlusion: yield ("AO", "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_direct: yield ("DiffDir", "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_indirect: yield ("DiffInd", "RGB", 'COLOR')
|
||||
if srl.use_pass_diffuse_color: yield ("DiffCol", "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_direct: yield ("GlossDir", "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_indirect: yield ("GlossInd", "RGB", 'COLOR')
|
||||
if srl.use_pass_glossy_color: yield ("GlossCol", "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_direct: yield ("TransDir", "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_indirect: yield ("TransInd", "RGB", 'COLOR')
|
||||
if srl.use_pass_transmission_color: yield ("TransCol", "RGB", 'COLOR')
|
||||
if srl.use_pass_subsurface_direct: yield ("SubsurfaceDir", "RGB", 'COLOR')
|
||||
if srl.use_pass_subsurface_indirect: yield ("SubsurfaceInd", "RGB", 'COLOR')
|
||||
if srl.use_pass_subsurface_color: yield ("SubsurfaceCol", "RGB", 'COLOR')
|
||||
if srl.use_pass_emit: yield ("Emit", "RGB", 'COLOR')
|
||||
if srl.use_pass_environment: yield ("Env", "RGB", 'COLOR')
|
||||
|
||||
# Cycles specific passes.
|
||||
crl = srl.cycles
|
||||
if crl.pass_debug_render_time: engine.register_pass(scene, srl, "Debug Render Time", 1, "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_instances: engine.register_pass(scene, srl, "Debug BVH Traversed Instances", 1, "X", 'VALUE')
|
||||
if crl.pass_debug_bvh_intersections: engine.register_pass(scene, srl, "Debug BVH Intersections", 1, "X", 'VALUE')
|
||||
if crl.pass_debug_ray_bounces: engine.register_pass(scene, srl, "Debug Ray Bounces", 1, "X", 'VALUE')
|
||||
if crl.use_pass_volume_direct: engine.register_pass(scene, srl, "VolumeDir", 3, "RGB", 'COLOR')
|
||||
if crl.use_pass_volume_indirect: engine.register_pass(scene, srl, "VolumeInd", 3, "RGB", 'COLOR')
|
||||
if crl.pass_debug_render_time: yield ("Debug Render Time", "X", 'VALUE')
|
||||
if crl.pass_debug_bvh_traversed_nodes: yield ("Debug BVH Traversed Nodes", "X", 'VALUE')
|
||||
if crl.pass_debug_bvh_traversed_instances: yield ("Debug BVH Traversed Instances", "X", 'VALUE')
|
||||
if crl.pass_debug_bvh_intersections: yield ("Debug BVH Intersections", "X", 'VALUE')
|
||||
if crl.pass_debug_ray_bounces: yield ("Debug Ray Bounces", "X", 'VALUE')
|
||||
if crl.use_pass_volume_direct: yield ("VolumeDir", "RGB", 'COLOR')
|
||||
if crl.use_pass_volume_indirect: yield ("VolumeInd", "RGB", 'COLOR')
|
||||
|
||||
# Cryptomatte passes.
|
||||
if crl.use_pass_crypto_object:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
engine.register_pass(scene, srl, "Noisy Image", 4, "RGBA", 'COLOR')
|
||||
yield ("Noisy Image", "RGBA", 'COLOR')
|
||||
if crl.denoising_store_passes:
|
||||
engine.register_pass(scene, srl, "Denoising Normal", 3, "XYZ", 'VECTOR')
|
||||
engine.register_pass(scene, srl, "Denoising Albedo", 3, "RGB", 'COLOR')
|
||||
engine.register_pass(scene, srl, "Denoising Depth", 1, "Z", 'VALUE')
|
||||
engine.register_pass(scene, srl, "Denoising Shadowing", 1, "X", 'VALUE')
|
||||
engine.register_pass(scene, srl, "Denoising Variance", 3, "RGB", 'COLOR')
|
||||
engine.register_pass(scene, srl, "Denoising Intensity", 1, "X", 'VALUE')
|
||||
yield ("Denoising Normal", "XYZ", 'VECTOR')
|
||||
yield ("Denoising Albedo", "RGB", 'COLOR')
|
||||
yield ("Denoising Depth", "Z", 'VALUE')
|
||||
yield ("Denoising Shadowing", "X", 'VALUE')
|
||||
yield ("Denoising Variance", "RGB", 'COLOR')
|
||||
yield ("Denoising Intensity", "X", 'VALUE')
|
||||
clean_options = ("denoising_diffuse_direct", "denoising_diffuse_indirect",
|
||||
"denoising_glossy_direct", "denoising_glossy_indirect",
|
||||
"denoising_transmission_direct", "denoising_transmission_indirect",
|
||||
"denoising_subsurface_direct", "denoising_subsurface_indirect")
|
||||
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'}
|
||||
|
||||
|
||||
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):
|
||||
"Denoise rendered animation sequence using current scene and view " \
|
||||
"layer settings. Requires denoising data passes and output to " \
|
||||
@ -167,6 +197,8 @@ class CYCLES_OT_merge_images(Operator):
|
||||
|
||||
classes = (
|
||||
CYCLES_OT_use_shading_nodes,
|
||||
CYCLES_OT_add_aov,
|
||||
CYCLES_OT_remove_aov,
|
||||
CYCLES_OT_denoise_animation,
|
||||
CYCLES_OT_merge_images
|
||||
)
|
||||
|
@ -19,6 +19,7 @@
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
CollectionProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
IntProperty,
|
||||
@ -31,6 +32,7 @@ from math import pi
|
||||
# enums
|
||||
|
||||
import _cycles
|
||||
from . import engine
|
||||
|
||||
enum_devices = (
|
||||
('CPU', "CPU", "Use CPU for rendering"),
|
||||
@ -190,6 +192,10 @@ enum_view3d_shading_render_pass= (
|
||||
('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):
|
||||
|
||||
@ -1218,8 +1224,29 @@ class CyclesCurveRenderSettings(bpy.types.PropertyGroup):
|
||||
def update_render_passes(self, context):
|
||||
view_layer = context.view_layer
|
||||
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):
|
||||
|
||||
pass_debug_bvh_traversed_nodes: BoolProperty(
|
||||
@ -1378,6 +1405,15 @@ class CyclesRenderLayerSettings(bpy.types.PropertyGroup):
|
||||
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
|
||||
def register(cls):
|
||||
bpy.types.ViewLayer.cycles = PointerProperty(
|
||||
@ -1552,6 +1588,7 @@ def register():
|
||||
bpy.utils.register_class(CyclesCurveRenderSettings)
|
||||
bpy.utils.register_class(CyclesDeviceSettings)
|
||||
bpy.utils.register_class(CyclesPreferences)
|
||||
bpy.utils.register_class(CyclesAOVPass)
|
||||
bpy.utils.register_class(CyclesRenderLayerSettings)
|
||||
bpy.utils.register_class(CyclesView3DShadingSettings)
|
||||
|
||||
@ -1573,5 +1610,6 @@ def unregister():
|
||||
bpy.utils.unregister_class(CyclesCurveRenderSettings)
|
||||
bpy.utils.unregister_class(CyclesDeviceSettings)
|
||||
bpy.utils.unregister_class(CyclesPreferences)
|
||||
bpy.utils.unregister_class(CyclesAOVPass)
|
||||
bpy.utils.unregister_class(CyclesRenderLayerSettings)
|
||||
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")
|
||||
|
||||
|
||||
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):
|
||||
bl_label = "Denoising"
|
||||
bl_context = "view_layer"
|
||||
@ -2233,6 +2269,8 @@ classes = (
|
||||
CYCLES_RENDER_PT_passes_light,
|
||||
CYCLES_RENDER_PT_passes_crypto,
|
||||
CYCLES_RENDER_PT_passes_debug,
|
||||
CYCLES_RENDER_UL_aov,
|
||||
CYCLES_RENDER_PT_passes_aov,
|
||||
CYCLES_RENDER_PT_filter,
|
||||
CYCLES_RENDER_PT_override,
|
||||
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) {
|
||||
BL::RenderPass b_pass(*b_iter);
|
||||
|
||||
/* find matching pass type */
|
||||
PassType pass_type = BlenderSync::get_pass_type(b_pass);
|
||||
int components = b_pass.channels();
|
||||
|
||||
bool read = false;
|
||||
if (pass_type != PASS_NONE) {
|
||||
/* copy pixels */
|
||||
read = buffers->get_pass_rect(
|
||||
pass_type, exposure, sample, components, &pixels[0], b_pass.name());
|
||||
}
|
||||
else {
|
||||
/* Copy pixels from regular render passes. */
|
||||
bool read = buffers->get_pass_rect(b_pass.name(), exposure, sample, components, &pixels[0]);
|
||||
|
||||
/* If denoising pass, */
|
||||
if (!read) {
|
||||
int denoising_offset = BlenderSync::get_denoising_pass(b_pass);
|
||||
if (denoising_offset >= 0) {
|
||||
read = buffers->get_denoising_pass_rect(
|
||||
@ -822,7 +817,7 @@ void BlenderSession::do_write_update_render_result(BL::RenderLayer &b_rlay,
|
||||
else {
|
||||
/* copy combined pass */
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@ -921,6 +921,12 @@ static ShaderNode *add_node(Scene *scene,
|
||||
disp->attribute = "";
|
||||
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) {
|
||||
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)
|
||||
continue;
|
||||
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");
|
||||
@ -570,32 +570,32 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
|
||||
#ifdef __KERNEL_DEBUG__
|
||||
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());
|
||||
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")) {
|
||||
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")) {
|
||||
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")) {
|
||||
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
|
||||
if (get_boolean(crp, "pass_debug_render_time")) {
|
||||
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")) {
|
||||
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")) {
|
||||
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.
|
||||
@ -635,6 +635,21 @@ vector<Pass> BlenderSync::sync_render_passes(BL::RenderLayer &b_rlay, BL::ViewLa
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,7 @@ set(SRC_HEADERS
|
||||
kernel_types.h
|
||||
kernel_volume.h
|
||||
kernel_work_stealing.h
|
||||
kernel_write_passes.h
|
||||
)
|
||||
|
||||
set(SRC_KERNELS_CPU_HEADERS
|
||||
@ -182,6 +183,7 @@ set(SRC_CLOSURE_HEADERS
|
||||
set(SRC_SVM_HEADERS
|
||||
svm/svm.h
|
||||
svm/svm_ao.h
|
||||
svm/svm_aov.h
|
||||
svm/svm_attribute.h
|
||||
svm/svm_bevel.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);
|
||||
|
||||
/* 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 */
|
||||
shader_bsdf_disable_transparency(kg, sd);
|
||||
@ -209,12 +209,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg,
|
||||
}
|
||||
else {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
shader_eval_surface(kg, sd, state, 0);
|
||||
shader_eval_surface(kg, sd, state, NULL, 0);
|
||||
color = kernel_bake_shader_bsdf(kg, sd, type);
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
|
||||
case SHADER_EVAL_EMISSION: {
|
||||
if (type != SHADER_EVAL_NORMAL || (sd.flag & SD_HAS_BUMP)) {
|
||||
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) {
|
||||
@ -445,7 +445,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg,
|
||||
|
||||
/* evaluate */
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@ -524,7 +524,7 @@ ccl_device void kernel_background_evaluate(KernelGlobals *kg,
|
||||
|
||||
/* evaluate */
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* weak but we'd have to do multiple evaluations otherwise. */
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
ShaderData *emission_sd,
|
||||
ccl_addr_space PathState *state,
|
||||
ccl_global float *buffer,
|
||||
ccl_addr_space Ray *ray)
|
||||
{
|
||||
#ifdef __BACKGROUND__
|
||||
@ -322,7 +323,7 @@ ccl_device_noinline_cpu float3 indirect_background(KernelGlobals *kg,
|
||||
# endif
|
||||
|
||||
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);
|
||||
|
||||
L = shader_background_eval(emission_sd);
|
||||
|
@ -14,85 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined(__SPLIT_KERNEL__) || defined(__KERNEL_CUDA__)
|
||||
# define __ATOMIC_PASS_WRITE__
|
||||
#endif
|
||||
|
||||
#include "kernel/kernel_id_passes.h"
|
||||
|
||||
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 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_global float *buffer,
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "kernel/geom/geom.h"
|
||||
#include "kernel/bvh/bvh.h"
|
||||
|
||||
#include "kernel/kernel_write_passes.h"
|
||||
#include "kernel/kernel_accumulate.h"
|
||||
#include "kernel/kernel_shader.h"
|
||||
#include "kernel/kernel_light.h"
|
||||
@ -116,6 +117,7 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
|
||||
ccl_addr_space Ray *ray,
|
||||
float3 throughput,
|
||||
ShaderData *sd,
|
||||
ccl_global float *buffer,
|
||||
PathRadiance *L)
|
||||
{
|
||||
/* eval background shader if nothing hit */
|
||||
@ -136,7 +138,7 @@ ccl_device_forceinline void kernel_path_background(KernelGlobals *kg,
|
||||
|
||||
#ifdef __BACKGROUND__
|
||||
/* 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);
|
||||
#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);
|
||||
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);
|
||||
}
|
||||
@ -418,7 +420,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
||||
|
||||
/* Shade background. */
|
||||
if (!hit) {
|
||||
kernel_path_background(kg, state, ray, throughput, sd, L);
|
||||
kernel_path_background(kg, state, ray, throughput, sd, NULL, L);
|
||||
break;
|
||||
}
|
||||
else if (path_state_ao_bounce(kg, state)) {
|
||||
@ -434,7 +436,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
||||
# endif
|
||||
|
||||
/* Evaluate shader. */
|
||||
shader_eval_surface(kg, sd, state, state->flag);
|
||||
shader_eval_surface(kg, sd, state, NULL, state->flag);
|
||||
shader_prepare_closures(sd, state);
|
||||
|
||||
/* Apply shadow catcher, holdout, emission. */
|
||||
@ -556,7 +558,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
||||
|
||||
/* Shade background. */
|
||||
if (!hit) {
|
||||
kernel_path_background(kg, state, ray, throughput, &sd, L);
|
||||
kernel_path_background(kg, state, ray, throughput, &sd, buffer, L);
|
||||
break;
|
||||
}
|
||||
else if (path_state_ao_bounce(kg, state)) {
|
||||
@ -572,7 +574,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
||||
# endif
|
||||
|
||||
/* Evaluate shader. */
|
||||
shader_eval_surface(kg, &sd, state, state->flag);
|
||||
shader_eval_surface(kg, &sd, state, buffer, state->flag);
|
||||
shader_prepare_closures(&sd, state);
|
||||
|
||||
/* Apply shadow catcher, holdout, emission. */
|
||||
|
@ -405,7 +405,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
|
||||
/* Shade background. */
|
||||
if (!hit) {
|
||||
kernel_path_background(kg, &state, &ray, throughput, &sd, L);
|
||||
kernel_path_background(kg, &state, &ray, throughput, &sd, buffer, L);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
if (!(sd.flag & SD_HAS_ONLY_VOLUME)) {
|
||||
# endif
|
||||
|
||||
shader_eval_surface(kg, &sd, &state, state.flag);
|
||||
shader_eval_surface(kg, &sd, &state, buffer, state.flag);
|
||||
shader_merge_closures(&sd);
|
||||
|
||||
/* 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,
|
||||
ShaderData *sd,
|
||||
ccl_addr_space PathState *state,
|
||||
ccl_global float *buffer,
|
||||
int path_flag)
|
||||
{
|
||||
PROFILING_INIT(kg, PROFILING_SHADER_EVAL);
|
||||
@ -1107,7 +1108,7 @@ ccl_device void shader_eval_surface(KernelGlobals *kg,
|
||||
#endif
|
||||
{
|
||||
#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
|
||||
if (sd->object == OBJECT_NONE) {
|
||||
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
|
||||
# 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
|
||||
|
||||
@ -1348,7 +1349,7 @@ ccl_device void shader_eval_displacement(KernelGlobals *kg,
|
||||
else
|
||||
# endif
|
||||
{
|
||||
svm_eval_nodes(kg, sd, state, SHADER_TYPE_DISPLACEMENT, 0);
|
||||
svm_eval_nodes(kg, sd, state, NULL, SHADER_TYPE_DISPLACEMENT, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ ccl_device_forceinline bool shadow_handle_transparent_isect(KernelGlobals *kg,
|
||||
/* Attenuation from transparent surface. */
|
||||
if (!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) {
|
||||
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);
|
||||
*throughput *= shader_bsdf_transparency(kg, shadow_sd);
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ ccl_device void subsurface_color_bump_blur(
|
||||
|
||||
if (bump || texture_blur > 0.0f) {
|
||||
/* 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);
|
||||
|
||||
/* 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_SUBSURFACE_COLOR,
|
||||
SHADER_EVAL_EMISSION,
|
||||
SHADER_EVAL_AOV_COLOR,
|
||||
SHADER_EVAL_AOV_VALUE,
|
||||
|
||||
/* light passes */
|
||||
SHADER_EVAL_AO,
|
||||
@ -371,6 +373,8 @@ typedef enum PassType {
|
||||
#endif
|
||||
PASS_RENDER_TIME,
|
||||
PASS_CRYPTOMATTE,
|
||||
PASS_AOV_COLOR,
|
||||
PASS_AOV_VALUE,
|
||||
PASS_CATEGORY_MAIN_END = 31,
|
||||
|
||||
PASS_MIST = 32,
|
||||
@ -1244,6 +1248,11 @@ typedef struct KernelFilm {
|
||||
int pass_denoising_clean;
|
||||
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
|
||||
* ensure consistent padding/alignment across devices. */
|
||||
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_color.h"
|
||||
#include "kernel/kernel_random.h"
|
||||
#include "kernel/kernel_write_passes.h"
|
||||
#include "kernel/kernel_projection.h"
|
||||
#include "kernel/kernel_differential.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];
|
||||
float3 throughput = kernel_split_state.throughput[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);
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,10 @@ ccl_device void kernel_shader_eval(KernelGlobals *kg)
|
||||
ccl_global char *ray_state = kernel_split_state.ray_state;
|
||||
if (IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
|
||||
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__
|
||||
if (kernel_data.integrator.branched) {
|
||||
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_mapping_util.h"
|
||||
|
||||
#include "kernel/svm/svm_aov.h"
|
||||
#include "kernel/svm/svm_attribute.h"
|
||||
#include "kernel/svm/svm_gradient.h"
|
||||
#include "kernel/svm/svm_blackbody.h"
|
||||
@ -218,6 +219,7 @@ CCL_NAMESPACE_BEGIN
|
||||
ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
|
||||
ShaderData *sd,
|
||||
ccl_addr_space PathState *state,
|
||||
ccl_global float *buffer,
|
||||
ShaderType type,
|
||||
int path_flag)
|
||||
{
|
||||
@ -467,6 +469,17 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
|
||||
case NODE_IES:
|
||||
svm_node_ies(kg, sd, stack, node, &offset);
|
||||
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 /* 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_BUMP_DX,
|
||||
NODE_VERTEX_COLOR_BUMP_DY,
|
||||
NODE_AOV_START,
|
||||
NODE_AOV_VALUE,
|
||||
NODE_AOV_COLOR,
|
||||
} ShaderNodeType;
|
||||
|
||||
typedef enum NodeAttributeType {
|
||||
|
@ -234,7 +234,7 @@ bool RenderBuffers::get_denoising_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) {
|
||||
return false;
|
||||
@ -245,18 +245,14 @@ bool RenderBuffers::get_pass_rect(
|
||||
for (size_t j = 0; j < params.passes.size(); 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Tell Cryptomatte passes apart by their name. */
|
||||
if (pass.type == PASS_CRYPTOMATTE) {
|
||||
if (pass.name != name) {
|
||||
pass_offset += pass.components;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PassType type = pass.type;
|
||||
|
||||
float *in = buffer.data() + pass_offset;
|
||||
int pass_stride = params.get_passes_size();
|
||||
|
@ -88,12 +88,8 @@ class RenderBuffers {
|
||||
void zero();
|
||||
|
||||
bool copy_from_device();
|
||||
bool get_pass_rect(PassType type,
|
||||
float exposure,
|
||||
int sample,
|
||||
int components,
|
||||
float *pixels,
|
||||
const string &name);
|
||||
bool get_pass_rect(
|
||||
const string &name, float exposure, int sample, int components, float *pixels);
|
||||
bool get_denoising_pass_rect(
|
||||
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:
|
||||
pass.components = 4;
|
||||
break;
|
||||
case PASS_AOV_COLOR:
|
||||
pass.components = 4;
|
||||
break;
|
||||
case PASS_AOV_VALUE:
|
||||
pass.components = 1;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
@ -327,7 +333,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
kfilm->pass_stride = 0;
|
||||
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++) {
|
||||
Pass &pass = passes[i];
|
||||
@ -464,6 +470,18 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
|
||||
kfilm->pass_stride;
|
||||
have_cryptomatte = true;
|
||||
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:
|
||||
assert(false);
|
||||
break;
|
||||
@ -569,4 +587,27 @@ void Film::tag_update(Scene * /*scene*/)
|
||||
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
|
||||
|
@ -93,6 +93,8 @@ class Film : public Node {
|
||||
bool modified(const Film &film);
|
||||
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes = true);
|
||||
void tag_update(Scene *scene);
|
||||
|
||||
int get_aov_offset(string name, bool &is_color);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@ -55,6 +55,25 @@ bool check_node_inputs_traversed(const ShaderNode *node, const ShaderNodeSet &do
|
||||
|
||||
} /* 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 */
|
||||
|
||||
ShaderNode::ShaderNode(const NodeType *type) : Node(type)
|
||||
@ -285,11 +304,7 @@ void ShaderGraph::disconnect(ShaderOutput *from)
|
||||
assert(!finalized);
|
||||
simplified = false;
|
||||
|
||||
foreach (ShaderInput *sock, from->links) {
|
||||
sock->link = NULL;
|
||||
}
|
||||
|
||||
from->links.clear();
|
||||
from->disconnect();
|
||||
}
|
||||
|
||||
void ShaderGraph::disconnect(ShaderInput *to)
|
||||
@ -298,10 +313,7 @@ void ShaderGraph::disconnect(ShaderInput *to)
|
||||
assert(to->link);
|
||||
simplified = false;
|
||||
|
||||
ShaderOutput *from = to->link;
|
||||
|
||||
to->link = NULL;
|
||||
from->links.erase(remove(from->links.begin(), from->links.end(), to), from->links.end());
|
||||
to->disconnect();
|
||||
}
|
||||
|
||||
void ShaderGraph::relink(ShaderInput *from, ShaderInput *to)
|
||||
@ -782,6 +794,11 @@ void ShaderGraph::clean(Scene *scene)
|
||||
|
||||
/* break cycles */
|
||||
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 */
|
||||
foreach (ShaderNode *node, nodes) {
|
||||
|
@ -67,6 +67,7 @@ enum ShaderNodeSpecialType {
|
||||
SHADER_SPECIAL_TYPE_COMBINE_CLOSURE,
|
||||
SHADER_SPECIAL_TYPE_OUTPUT,
|
||||
SHADER_SPECIAL_TYPE_BUMP,
|
||||
SHADER_SPECIAL_TYPE_OUTPUT_AOV,
|
||||
};
|
||||
|
||||
/* Input
|
||||
@ -104,6 +105,8 @@ class ShaderInput {
|
||||
((Node *)parent)->set(socket_type, f);
|
||||
}
|
||||
|
||||
void disconnect();
|
||||
|
||||
const SocketType &socket_type;
|
||||
ShaderNode *parent;
|
||||
ShaderOutput *link;
|
||||
@ -130,6 +133,8 @@ class ShaderOutput {
|
||||
return socket_type.type;
|
||||
}
|
||||
|
||||
void disconnect();
|
||||
|
||||
const SocketType &socket_type;
|
||||
ShaderNode *parent;
|
||||
vector<ShaderInput *> links;
|
||||
|
@ -5709,6 +5709,58 @@ void ClampNode::compile(OSLCompiler &compiler)
|
||||
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 */
|
||||
|
||||
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 {
|
||||
public:
|
||||
SHADER_NODE_CLASS(GradientTextureNode)
|
||||
|
@ -225,6 +225,13 @@ Shader::~Shader()
|
||||
|
||||
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");
|
||||
|
||||
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,
|
||||
ShaderNode *node,
|
||||
CompilerState *state)
|
||||
@ -703,21 +721,21 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
||||
current_graph = graph;
|
||||
|
||||
/* get input in output node */
|
||||
ShaderNode *node = graph->output();
|
||||
ShaderNode *output = graph->output();
|
||||
ShaderInput *clin = NULL;
|
||||
|
||||
switch (type) {
|
||||
case SHADER_TYPE_SURFACE:
|
||||
clin = node->input("Surface");
|
||||
clin = output->input("Surface");
|
||||
break;
|
||||
case SHADER_TYPE_VOLUME:
|
||||
clin = node->input("Volume");
|
||||
clin = output->input("Volume");
|
||||
break;
|
||||
case SHADER_TYPE_DISPLACEMENT:
|
||||
clin = node->input("Displacement");
|
||||
clin = output->input("Displacement");
|
||||
break;
|
||||
case SHADER_TYPE_BUMP:
|
||||
clin = node->input("Normal");
|
||||
clin = output->input("Normal");
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@ -728,10 +746,10 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
||||
memset((void *)&active_stack, 0, sizeof(active_stack));
|
||||
current_svm_nodes.clear();
|
||||
|
||||
foreach (ShaderNode *node_iter, graph->nodes) {
|
||||
foreach (ShaderInput *input, node_iter->inputs)
|
||||
foreach (ShaderNode *node, graph->nodes) {
|
||||
foreach (ShaderInput *input, node->inputs)
|
||||
input->stack_offset = SVM_STACK_INVALID;
|
||||
foreach (ShaderOutput *output, node_iter->outputs)
|
||||
foreach (ShaderOutput *output, node->outputs)
|
||||
output->stack_offset = SVM_STACK_INVALID;
|
||||
}
|
||||
|
||||
@ -745,6 +763,7 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
||||
}
|
||||
|
||||
if (shader->used) {
|
||||
CompilerState state(graph);
|
||||
if (clin->link) {
|
||||
bool generate = false;
|
||||
|
||||
@ -769,13 +788,36 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
||||
}
|
||||
|
||||
if (generate) {
|
||||
CompilerState state(graph);
|
||||
generate_multi_closure(clin->link->parent, clin->link->parent, &state);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
@ -204,6 +204,7 @@ class SVMCompiler {
|
||||
ShaderInput *input,
|
||||
ShaderNode *skip_node = NULL);
|
||||
void generate_node(ShaderNode *node, ShaderNodeSet &done);
|
||||
void generate_aov_node(ShaderNode *node, CompilerState *state);
|
||||
void generate_closure_node(ShaderNode *node, CompilerState *state);
|
||||
void generated_shared_closure_nodes(ShaderNode *root_node,
|
||||
ShaderNode *node,
|
||||
|
@ -157,6 +157,11 @@ def object_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):
|
||||
return (object_shader_nodes_poll(context) and
|
||||
eevee_shader_nodes_poll(context))
|
||||
@ -197,6 +202,7 @@ shader_node_categories = [
|
||||
ShaderNodeCategory("SH_NEW_OUTPUT", "Output", items=[
|
||||
NodeItem("ShaderNodeOutputMaterial", poll=object_eevee_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("ShaderNodeOutputLineStyle", poll=line_style_shader_nodes_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_VOLUME_INFO 705
|
||||
#define SH_NODE_VERTEX_COLOR 706
|
||||
#define SH_NODE_OUTPUT_AOV 707
|
||||
|
||||
/* custom defines options for Material node */
|
||||
#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_world();
|
||||
register_node_type_sh_output_linestyle();
|
||||
register_node_type_sh_output_aov();
|
||||
|
||||
register_node_type_sh_tex_image();
|
||||
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);
|
||||
}
|
||||
|
||||
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 */
|
||||
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:
|
||||
ntype->draw_buttons = node_shader_buts_white_noise;
|
||||
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];
|
||||
} NodeShaderTexIES;
|
||||
|
||||
typedef struct NodeShaderOutputAOV {
|
||||
char name[64];
|
||||
} NodeShaderOutputAOV;
|
||||
|
||||
typedef struct NodeSunBeams {
|
||||
float source[2];
|
||||
|
||||
|
@ -574,6 +574,7 @@ extern StructRNA RNA_ShaderNodeMath;
|
||||
extern StructRNA RNA_ShaderNodeMixRGB;
|
||||
extern StructRNA RNA_ShaderNodeNormal;
|
||||
extern StructRNA RNA_ShaderNodeOutput;
|
||||
extern StructRNA RNA_ShaderNodeOutputAOV;
|
||||
extern StructRNA RNA_ShaderNodeRGB;
|
||||
extern StructRNA RNA_ShaderNodeRGBCurve;
|
||||
extern StructRNA RNA_ShaderNodeRGBToBW;
|
||||
|
@ -5187,6 +5187,19 @@ static void def_sh_tex_ies(StructRNA *srna)
|
||||
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)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
@ -177,6 +177,7 @@ set(SRC
|
||||
shader/nodes/node_shader_output_linestyle.c
|
||||
shader/nodes/node_shader_output_material.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_rgb.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_world(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_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_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_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_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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user