From 27043b8e40f74c8b0917850d1aefbd6315fa46a5 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 29 Mar 2014 13:03:48 +0100 Subject: Cycles code internals: add support for mesh voxel grid attributes. These are internally stored as a 3D image textures, but accessible like e.g. UV coordinates though the attribute node and getattribute(). This is convenient for rendering e.g. smoke objects where data like density is really a property of the mesh, and it avoids having to specify the smoke object in a texture node, instead the material will work with any smoke domain. --- intern/cycles/kernel/CMakeLists.txt | 1 + intern/cycles/kernel/geom/geom.h | 1 + intern/cycles/kernel/geom/geom_attribute.h | 40 +++++------- intern/cycles/kernel/geom/geom_primitive.h | 36 +++++++--- intern/cycles/kernel/geom/geom_volume.h | 75 +++++++++++++++++++++ intern/cycles/kernel/kernel_types.h | 3 +- intern/cycles/kernel/osl/osl_services.cpp | 4 +- intern/cycles/kernel/svm/svm_attribute.h | 4 +- intern/cycles/kernel/svm/svm_tex_coord.h | 45 ++++--------- intern/cycles/render/attribute.cpp | 101 ++++++++++++++++++++--------- intern/cycles/render/attribute.h | 15 ++++- intern/cycles/render/mesh.cpp | 7 +- intern/cycles/render/nodes.cpp | 41 ++++++++---- 13 files changed, 257 insertions(+), 116 deletions(-) create mode 100644 intern/cycles/kernel/geom/geom_volume.h diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index e473b1ab91c..45b4c81610e 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -119,6 +119,7 @@ set(SRC_GEOM_HEADERS geom/geom_object.h geom/geom_primitive.h geom/geom_triangle.h + geom/geom_volume.h ) set(SRC_UTIL_HEADERS diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index a4e9bdb1c57..9495a2541f9 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -38,6 +38,7 @@ #include "geom_motion_triangle.h" #include "geom_motion_curve.h" #include "geom_curve.h" +#include "geom_volume.h" #include "geom_primitive.h" #include "geom_bvh.h" diff --git a/intern/cycles/kernel/geom/geom_attribute.h b/intern/cycles/kernel/geom/geom_attribute.h index cbc1fb4fbf2..63ce31c492f 100644 --- a/intern/cycles/kernel/geom/geom_attribute.h +++ b/intern/cycles/kernel/geom/geom_attribute.h @@ -32,35 +32,29 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, const ShaderData *sd, ui if(sd->object == PRIM_NONE) return (int)ATTR_STD_NOT_FOUND; -#ifdef __OSL__ - if (kg->osl) { - return OSLShader::find_attribute(kg, sd, id, elem); - } - else -#endif - { - /* for SVM, find attribute by unique id */ - uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; + /* for SVM, find attribute by unique id */ + uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; #ifdef __HAIR__ - attr_offset = (sd->type & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; + attr_offset = (sd->type & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; #endif - uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - - while(attr_map.x != id) { - attr_offset += ATTR_PRIM_TYPES; - attr_map = kernel_tex_fetch(__attributes_map, attr_offset); - } + uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + + while(attr_map.x != id) { + attr_offset += ATTR_PRIM_TYPES; + attr_map = kernel_tex_fetch(__attributes_map, attr_offset); + } - *elem = (AttributeElement)attr_map.y; - - if(sd->prim == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH) - return ATTR_STD_NOT_FOUND; + *elem = (AttributeElement)attr_map.y; + + if(sd->prim == PRIM_NONE && (AttributeElement)attr_map.y != ATTR_ELEMENT_MESH) + return ATTR_STD_NOT_FOUND; - /* return result */ - return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; - } + /* return result */ + return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; } +/* Transform matrix attribute on meshes */ + ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, int offset) { Transform tfm; diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index d90cc108492..f821e696a07 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -25,26 +25,46 @@ CCL_NAMESPACE_BEGIN ccl_device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy) { -#ifdef __HAIR__ - if(sd->type & PRIMITIVE_ALL_TRIANGLE) -#endif + if(sd->type & PRIMITIVE_ALL_TRIANGLE) { return triangle_attribute_float(kg, sd, elem, offset, dx, dy); + } #ifdef __HAIR__ - else + else if(sd->type & PRIMITIVE_ALL_CURVE) { return curve_attribute_float(kg, sd, elem, offset, dx, dy); + } #endif +#ifdef __VOLUME__ + else if(sd->object != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) { + return volume_attribute_float(kg, sd, elem, offset, dx, dy); + } +#endif + else { + if(dx) *dx = 0.0f; + if(dy) *dy = 0.0f; + return 0.0f; + } } ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy) { -#ifdef __HAIR__ - if(sd->type & PRIMITIVE_ALL_TRIANGLE) -#endif + if(sd->type & PRIMITIVE_ALL_TRIANGLE) { return triangle_attribute_float3(kg, sd, elem, offset, dx, dy); + } #ifdef __HAIR__ - else + else if(sd->type & PRIMITIVE_ALL_CURVE) { return curve_attribute_float3(kg, sd, elem, offset, dx, dy); + } +#endif +#ifdef __VOLUME__ + else if(sd->object != OBJECT_NONE && elem == ATTR_ELEMENT_VOXEL) { + return volume_attribute_float3(kg, sd, elem, offset, dx, dy); + } #endif + else { + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + return make_float3(0.0f, 0.0f, 0.0f); + } } /* Default UV coordinate */ diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h new file mode 100644 index 00000000000..963d6cbee9c --- /dev/null +++ b/intern/cycles/kernel/geom/geom_volume.h @@ -0,0 +1,75 @@ +/* + * 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 + */ + +/* Volume Primitive + * + * Volumes are just regions inside meshes with the mesh surface as boundaries. + * There isn't as much data to access as for surfaces, there is only a position + * to do lookups in 3D voxel or procedural textures. + * + * 3D voxel textures can be assigned as attributes per mesh, which means the + * same shader can be used for volume objects with different densities, etc. */ + +CCL_NAMESPACE_BEGIN + +#ifdef __VOLUME__ + +/* Return position normalized to 0..1 in mesh bounds */ + +ccl_device float3 volume_normalized_position(KernelGlobals *kg, const ShaderData *sd, float3 P) +{ + /* todo: optimize this so it's just a single matrix multiplication when + * possible (not motion blur), or perhaps even just translation + scale */ + AttributeElement attr_elem; + int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem); + + object_inverse_position_transform(kg, sd, &P); + + if(attr_offset != ATTR_STD_NOT_FOUND) { + Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset); + P = transform_point(&tfm, P); + } + + return P; +} + +ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float *dx, float *dy) +{ + float3 P = volume_normalized_position(kg, sd, sd->P); + float4 r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z); + + if(dx) *dx = 0.0f; + if(dx) *dy = 0.0f; + + /* todo: support float textures to lower memory usage for single floats */ + return average(float4_to_float3(r)); +} + +ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int id, float3 *dx, float3 *dy) +{ + float3 P = volume_normalized_position(kg, sd, sd->P); + float4 r = kernel_tex_image_interp_3d(id, P.x, P.y, P.z); + + if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f); + if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f); + + return float4_to_float3(r); +} + +#endif + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 0be83e5cbc1..f7aebd29bbe 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -459,7 +459,8 @@ typedef enum AttributeElement { ATTR_ELEMENT_CORNER, ATTR_ELEMENT_CURVE, ATTR_ELEMENT_CURVE_KEY, - ATTR_ELEMENT_CURVE_KEY_MOTION + ATTR_ELEMENT_CURVE_KEY_MOTION, + ATTR_ELEMENT_VOXEL } AttributeElement; typedef enum AttributeStandard { diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 65548d65308..d5edd04d8a5 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -768,9 +768,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri if (attr.elem != ATTR_ELEMENT_OBJECT) { /* triangle and vertex attributes */ - if (prim != PRIM_NONE) - return get_mesh_element_attribute(kg, sd, attr, type, derivatives, val); - else + if(!get_mesh_element_attribute(kg, sd, attr, type, derivatives, val)) return get_mesh_attribute(kg, sd, attr, type, derivatives, val); } else { diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h index 2592bbe575f..fd0ea7fef31 100644 --- a/intern/cycles/kernel/svm/svm_attribute.h +++ b/intern/cycles/kernel/svm/svm_attribute.h @@ -22,12 +22,12 @@ ccl_device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd, uint4 node, NodeAttributeType *type, NodeAttributeType *mesh_type, AttributeElement *elem, int *offset, uint *out_offset) { - if(sd->object != OBJECT_NONE && sd->prim != PRIM_NONE) { + if(sd->object != OBJECT_NONE) { /* find attribute by unique id */ uint id = node.y; uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride; #ifdef __HAIR__ - attr_offset = (sd->type & PRIMITIVE_ALL_TRIANGLE)? attr_offset: attr_offset + ATTR_PRIM_CURVE; + attr_offset = (sd->type & PRIMITIVE_ALL_CURVE)? attr_offset + ATTR_PRIM_CURVE: attr_offset; #endif uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset); diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index bddeac0b722..a17e4a25efe 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -70,17 +70,10 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, int path_f case NODE_TEXCO_VOLUME_GENERATED: { data = sd->P; - if(sd->object != OBJECT_NONE) { - AttributeElement attr_elem; - int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem); - - object_inverse_position_transform(kg, sd, &data); - - if(attr_offset != ATTR_STD_NOT_FOUND) { - Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset); - data = transform_point(&tfm, data); - } - } +#ifdef __VOLUME__ + if(sd->object != OBJECT_NONE) + data = volume_normalized_position(kg, sd, data); +#endif break; } } @@ -141,17 +134,10 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, in case NODE_TEXCO_VOLUME_GENERATED: { data = sd->P + sd->dP.dx; - if(sd->object != OBJECT_NONE) { - AttributeElement attr_elem; - int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem); - - object_inverse_position_transform(kg, sd, &data); - - if(attr_offset != ATTR_STD_NOT_FOUND) { - Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset); - data = transform_point(&tfm, data); - } - } +#ifdef __VOLUME__ + if(sd->object != OBJECT_NONE) + data = volume_normalized_position(kg, sd, data); +#endif break; } } @@ -215,17 +201,10 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, in case NODE_TEXCO_VOLUME_GENERATED: { data = sd->P + sd->dP.dy; - if(sd->object != OBJECT_NONE) { - AttributeElement attr_elem; - int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED_TRANSFORM, &attr_elem); - - object_inverse_position_transform(kg, sd, &data); - - if(attr_offset != ATTR_STD_NOT_FOUND) { - Transform tfm = primitive_attribute_matrix(kg, sd, attr_offset); - data = transform_point(&tfm, data); - } - } +#ifdef __VOLUME__ + if(sd->object != OBJECT_NONE) + data = volume_normalized_position(kg, sd, data); +#endif break; } } diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index f524a9fa3bc..cd81c33a28f 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -14,6 +14,7 @@ * limitations under the License */ +#include "image.h" #include "mesh.h" #include "attribute.h" @@ -25,6 +26,17 @@ CCL_NAMESPACE_BEGIN /* Attribute */ +Attribute::~Attribute() +{ + /* for voxel data, we need to remove the image from the image manager */ + if(element == ATTR_ELEMENT_VOXEL) { + VoxelAttribute *voxel_data = data_voxel(); + + if(voxel_data) + voxel_data->manager->remove_image(voxel_data->slot); + } +} + void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) { name = name_; @@ -75,9 +87,20 @@ void Attribute::add(const Transform& f) buffer.push_back(data[i]); } +void Attribute::add(const VoxelAttribute& f) +{ + char *data = (char*)&f; + size_t size = sizeof(f); + + for(size_t i = 0; i < size; i++) + buffer.push_back(data[i]); +} + size_t Attribute::data_sizeof() const { - if(type == TypeDesc::TypeFloat) + if(element == ATTR_ELEMENT_VOXEL) + return sizeof(VoxelAttribute); + else if(type == TypeDesc::TypeFloat) return sizeof(float); else if(type == TypeDesc::TypeMatrix) return sizeof(Transform); @@ -92,6 +115,7 @@ size_t Attribute::element_size(int numverts, int numtris, int numsteps, int numc switch(element) { case ATTR_ELEMENT_OBJECT: case ATTR_ELEMENT_MESH: + case ATTR_ELEMENT_VOXEL: size = 1; break; case ATTR_ELEMENT_VERTEX: @@ -147,40 +171,55 @@ bool Attribute::same_storage(TypeDesc a, TypeDesc b) const char *Attribute::standard_name(AttributeStandard std) { - if(std == ATTR_STD_VERTEX_NORMAL) - return "N"; - else if(std == ATTR_STD_FACE_NORMAL) - return "Ng"; - else if(std == ATTR_STD_UV) - return "uv"; - else if(std == ATTR_STD_GENERATED) - return "generated"; - else if(std == ATTR_STD_UV_TANGENT) - return "tangent"; - else if(std == ATTR_STD_UV_TANGENT_SIGN) - return "tangent_sign"; - else if(std == ATTR_STD_POSITION_UNDEFORMED) - return "undeformed"; - else if(std == ATTR_STD_POSITION_UNDISPLACED) - return "undisplaced"; - else if(std == ATTR_STD_MOTION_VERTEX_POSITION) - return "motion_P"; - else if(std == ATTR_STD_MOTION_VERTEX_NORMAL) - return "motion_N"; - else if(std == ATTR_STD_PARTICLE) - return "particle"; - else if(std == ATTR_STD_CURVE_INTERCEPT) - return "curve_intercept"; - else if(std == ATTR_STD_PTEX_FACE_ID) - return "ptex_face_id"; - else if(std == ATTR_STD_PTEX_UV) - return "ptex_uv"; - else if(std == ATTR_STD_GENERATED_TRANSFORM) - return "generated_transform"; + switch(std) { + case ATTR_STD_VERTEX_NORMAL: + return "N"; + case ATTR_STD_FACE_NORMAL: + return "Ng"; + case ATTR_STD_UV: + return "uv"; + case ATTR_STD_GENERATED: + return "generated"; + case ATTR_STD_GENERATED_TRANSFORM: + return "generated_transform"; + case ATTR_STD_UV_TANGENT: + return "tangent"; + case ATTR_STD_UV_TANGENT_SIGN: + return "tangent_sign"; + case ATTR_STD_POSITION_UNDEFORMED: + return "undeformed"; + case ATTR_STD_POSITION_UNDISPLACED: + return "undisplaced"; + case ATTR_STD_MOTION_VERTEX_POSITION: + return "motion_P"; + case ATTR_STD_MOTION_VERTEX_NORMAL: + return "motion_N"; + case ATTR_STD_PARTICLE: + return "particle"; + case ATTR_STD_CURVE_INTERCEPT: + return "curve_intercept"; + case ATTR_STD_PTEX_FACE_ID: + return "ptex_face_id"; + case ATTR_STD_PTEX_UV: + return "ptex_uv"; + case ATTR_STD_NOT_FOUND: + case ATTR_STD_NONE: + case ATTR_STD_NUM: + return ""; + } return ""; } +AttributeStandard Attribute::name_standard(const char *name) +{ + for(AttributeStandard std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) + if(strcmp(name, Attribute::standard_name(std)) == 0) + return std; + + return ATTR_STD_NONE; +} + /* Attribute Set */ AttributeSet::AttributeSet() diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index 5160224f4e3..3dc7b7f7401 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -27,12 +27,20 @@ CCL_NAMESPACE_BEGIN class Attribute; -class AttributeSet; class AttributeRequest; class AttributeRequestSet; +class AttributeSet; +class ImageManager; class Mesh; struct Transform; +/* Attributes for voxels are images */ + +struct VoxelAttribute { + ImageManager *manager; + int slot; +}; + /* Attribute * * Arbitrary data layers on meshes. @@ -48,6 +56,7 @@ public: AttributeElement element; Attribute() {} + ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); void reserve(int numverts, int numfaces, int numsteps, int numcurves, int numkeys, bool resize); @@ -60,19 +69,23 @@ public: float4 *data_float4() { return (float4*)data(); } float *data_float() { return (float*)data(); } Transform *data_transform() { return (Transform*)data(); } + VoxelAttribute *data_voxel() { return ( VoxelAttribute*)data(); } const char *data() const { return (buffer.size())? &buffer[0]: NULL; } const float3 *data_float3() const { return (const float3*)data(); } const float4 *data_float4() const { return (const float4*)data(); } const float *data_float() const { return (const float*)data(); } const Transform *data_transform() const { return (const Transform*)data(); } + const VoxelAttribute *data_voxel() const { return (const VoxelAttribute*)data(); } void add(const float& f); void add(const float3& f); void add(const Transform& f); + void add(const VoxelAttribute& f); static bool same_storage(TypeDesc a, TypeDesc b); static const char *standard_name(AttributeStandard std); + static AttributeStandard name_standard(const char *name); }; /* Attribute Set diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 52cd946456f..2ae15e09efb 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -756,7 +756,12 @@ static void update_attribute_element_offset(Mesh *mesh, vector& attr_floa mesh->curves.size(), mesh->curve_keys.size()); - if(mattr->type == TypeDesc::TypeFloat) { + if(mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + VoxelAttribute *voxel_data = mattr->data_voxel(); + offset = voxel_data->slot; + } + else if(mattr->type == TypeDesc::TypeFloat) { float *data = mattr->data_float(); offset = attr_float.size(); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index d5e358be161..f10b956a482 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2209,8 +2209,9 @@ void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attr if(shader->has_volume) { if(!from_dupli) { - if(!output("Generated")->links.empty()) + if(!output("Generated")->links.empty()) { attributes->add(ATTR_STD_GENERATED_TRANSFORM); + } } } @@ -2629,7 +2630,7 @@ void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes) if(!intercept_out->links.empty()) attributes->add(ATTR_STD_CURVE_INTERCEPT); } - + ShaderNode::attributes(shader, attributes); } @@ -3143,15 +3144,22 @@ AttributeNode::AttributeNode() void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes) { - if(shader->has_surface) { - ShaderOutput *color_out = output("Color"); - ShaderOutput *vector_out = output("Vector"); - ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *vector_out = output("Vector"); + ShaderOutput *fac_out = output("Fac"); - if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) + if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) { + AttributeStandard std = Attribute::name_standard(attribute.c_str()); + + if(std != ATTR_STD_NONE) + attributes->add(std); + else attributes->add(attribute); } - + + if(shader->has_volume) + attributes->add(ATTR_STD_GENERATED_TRANSFORM); + ShaderNode::attributes(shader, attributes); } @@ -3161,6 +3169,13 @@ void AttributeNode::compile(SVMCompiler& compiler) ShaderOutput *vector_out = output("Vector"); ShaderOutput *fac_out = output("Fac"); NodeType attr_node = NODE_ATTR; + AttributeStandard std = Attribute::name_standard(attribute.c_str()); + int attr; + + if(std != ATTR_STD_NONE) + attr = compiler.attribute(std); + else + attr = compiler.attribute(attribute); if(bump == SHADER_BUMP_DX) attr_node = NODE_ATTR_BUMP_DX; @@ -3168,8 +3183,6 @@ void AttributeNode::compile(SVMCompiler& compiler) attr_node = NODE_ATTR_BUMP_DY; if(!color_out->links.empty() || !vector_out->links.empty()) { - int attr = compiler.attribute(attribute); - if(!color_out->links.empty()) { compiler.stack_assign(color_out); compiler.add_node(attr_node, attr, color_out->stack_offset, NODE_ATTR_FLOAT3); @@ -3181,8 +3194,6 @@ void AttributeNode::compile(SVMCompiler& compiler) } if(!fac_out->links.empty()) { - int attr = compiler.attribute(attribute); - compiler.stack_assign(fac_out); compiler.add_node(attr_node, attr, fac_out->stack_offset, NODE_ATTR_FLOAT); } @@ -3196,8 +3207,12 @@ void AttributeNode::compile(OSLCompiler& compiler) compiler.parameter("bump_offset", "dy"); else compiler.parameter("bump_offset", "center"); + + if(Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE) + compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str()); + else + compiler.parameter("name", attribute.c_str()); - compiler.parameter("name", attribute.c_str()); compiler.add(this, "node_attribute"); } -- cgit v1.2.3