Code refactor: improve attribute handling for optional volume attributes.

A volume shader should be able to request attributes, and still be rendered
as homogeneous if no volume attributes are available for the object.
This commit is contained in:
Brecht Van Lommel 2018-02-18 03:20:39 +01:00
parent 4448ed6c5e
commit a963c7d48d
14 changed files with 126 additions and 41 deletions

View File

@ -925,19 +925,22 @@ enum ShaderDataFlag {
SD_HAS_DISPLACEMENT = (1 << 26),
/* Has constant emission (value stored in __shader_flag) */
SD_HAS_CONSTANT_EMISSION = (1 << 27),
/* Needs to access attributes */
SD_NEED_ATTRIBUTES = (1 << 28),
SD_SHADER_FLAGS = (SD_USE_MIS |
SD_HAS_TRANSPARENT_SHADOW |
SD_HAS_VOLUME |
SD_HAS_ONLY_VOLUME |
SD_HETEROGENEOUS_VOLUME|
SD_HETEROGENEOUS_VOLUME |
SD_HAS_BSSRDF_BUMP |
SD_VOLUME_EQUIANGULAR |
SD_VOLUME_MIS |
SD_VOLUME_CUBIC |
SD_HAS_BUMP |
SD_HAS_DISPLACEMENT |
SD_HAS_CONSTANT_EMISSION)
SD_HAS_CONSTANT_EMISSION |
SD_NEED_ATTRIBUTES)
};
/* Object flags. */
@ -958,6 +961,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6),
/* object is used to catch shadows */
SD_OBJECT_SHADOW_CATCHER = (1 << 7),
/* object has volume attributes */
SD_OBJECT_HAS_VOLUME_ATTRIBUTES = (1 << 8),
SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK |
SD_OBJECT_MOTION |
@ -965,7 +970,8 @@ enum ShaderDataObjectFlag {
SD_OBJECT_NEGATIVE_SCALE_APPLIED |
SD_OBJECT_HAS_VOLUME |
SD_OBJECT_INTERSECTS_VOLUME |
SD_OBJECT_SHADOW_CATCHER)
SD_OBJECT_SHADOW_CATCHER |
SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
};
typedef ccl_addr_space struct ShaderData {

View File

@ -106,8 +106,21 @@ ccl_device bool volume_stack_is_heterogeneous(KernelGlobals *kg, ccl_addr_space
for(int i = 0; stack[i].shader != SHADER_NONE; i++) {
int shader_flag = kernel_tex_fetch(__shader_flag, (stack[i].shader & SHADER_MASK)*SHADER_SIZE);
if(shader_flag & SD_HETEROGENEOUS_VOLUME)
if(shader_flag & SD_HETEROGENEOUS_VOLUME) {
return true;
}
else if(shader_flag & SD_NEED_ATTRIBUTES) {
/* We want to render world or objects without any volume grids
* as homogenous, but can only verify this at runtime since other
* heterogenous volume objects may be using the same shader. */
int object = stack[i].object;
if(object != OBJECT_NONE) {
int object_flag = kernel_tex_fetch(__object_flag, object);
if(object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) {
return true;
}
}
}
}
return false;

View File

@ -298,9 +298,13 @@ const char *Attribute::standard_name(AttributeStandard std)
AttributeStandard Attribute::name_standard(const char *name)
{
for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++)
if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0)
return (AttributeStandard)std;
if(name) {
for(int std = ATTR_STD_NONE; std < ATTR_STD_NUM; std++) {
if(strcmp(name, Attribute::standard_name((AttributeStandard)std)) == 0) {
return (AttributeStandard)std;
}
}
}
return ATTR_STD_NONE;
}
@ -615,9 +619,11 @@ bool AttributeRequestSet::modified(const AttributeRequestSet& other)
void AttributeRequestSet::add(ustring name)
{
foreach(AttributeRequest& req, requests)
if(req.name == name)
foreach(AttributeRequest& req, requests) {
if(req.name == name) {
return;
}
}
requests.push_back(AttributeRequest(name));
}
@ -641,6 +647,22 @@ void AttributeRequestSet::add(AttributeRequestSet& reqs)
}
}
void AttributeRequestSet::add_standard(ustring name)
{
if(!name) {
return;
}
AttributeStandard std = Attribute::name_standard(name.c_str());
if(std) {
add(std);
}
else {
add(name);
}
}
bool AttributeRequestSet::find(ustring name)
{
foreach(AttributeRequest& req, requests)

View File

@ -159,6 +159,7 @@ public:
void add(ustring name);
void add(AttributeStandard std);
void add(AttributeRequestSet& reqs);
void add_standard(ustring name);
bool find(ustring name);
bool find(AttributeStandard std);

View File

@ -156,6 +156,7 @@ public:
virtual bool has_bssrdf_bump() { return false; }
virtual bool has_spatial_varying() { return false; }
virtual bool has_object_dependency() { return false; }
virtual bool has_attribute_dependency() { return false; }
virtual bool has_integrator_dependency() { return false; }
virtual bool has_volume_support() { return false; }
virtual bool has_raytrace() { return false; }

View File

@ -208,7 +208,7 @@ NODE_DEFINE(ImageTextureNode)
TEXTURE_MAPPING_DEFINE(ImageTextureNode);
SOCKET_STRING(filename, "Filename", ustring(""));
SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
@ -419,7 +419,7 @@ NODE_DEFINE(EnvironmentTextureNode)
TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
SOCKET_STRING(filename, "Filename", ustring(""));
SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum color_space_enum;
color_space_enum.insert("none", NODE_COLOR_SPACE_NONE);
@ -1348,7 +1348,7 @@ NODE_DEFINE(PointDensityTextureNode)
{
NodeType* type = NodeType::add("point_density_texture", create, NodeType::SHADER);
SOCKET_STRING(filename, "Filename", ustring(""));
SOCKET_STRING(filename, "Filename", ustring());
static NodeEnum space_enum;
space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
@ -3167,7 +3167,7 @@ NODE_DEFINE(UVMapNode)
{
NodeType* type = NodeType::add("uvmap", create, NodeType::SHADER);
SOCKET_IN_STRING(attribute, "attribute", ustring(""));
SOCKET_STRING(attribute, "attribute", ustring());
SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
SOCKET_OUT_POINT(UV, "UV");
@ -4465,7 +4465,7 @@ NODE_DEFINE(AttributeNode)
{
NodeType* type = NodeType::add("attribute", create, NodeType::SHADER);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_VECTOR(vector, "Vector");
@ -4486,16 +4486,12 @@ void AttributeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
ShaderOutput *fac_out = output("Fac");
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);
attributes->add_standard(attribute);
}
if(shader->has_volume)
if(shader->has_volume) {
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
}
ShaderNode::attributes(shader, attributes);
}
@ -4506,13 +4502,7 @@ void AttributeNode::compile(SVMCompiler& compiler)
ShaderOutput *vector_out = output("Vector");
ShaderOutput *fac_out = output("Fac");
ShaderNodeType 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);
int attr = compiler.attribute_standard(attribute);;
if(bump == SHADER_BUMP_DX)
attr_node = NODE_ATTR_BUMP_DX;
@ -5470,7 +5460,7 @@ NODE_DEFINE(NormalMapNode)
space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_TANGENT_RADIAL);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
@ -5489,7 +5479,7 @@ NormalMapNode::NormalMapNode()
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
}
@ -5512,7 +5502,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
int attr = 0, attr_sign = 0;
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
}
@ -5534,7 +5524,7 @@ void NormalMapNode::compile(SVMCompiler& compiler)
void NormalMapNode::compile(OSLCompiler& compiler)
{
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
}
@ -5565,7 +5555,7 @@ NODE_DEFINE(TangentNode)
axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_NORMAL(normal_osl, "NormalIn", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
SOCKET_OUT_NORMAL(tangent, "Tangent");
@ -5582,7 +5572,7 @@ void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface) {
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
if(attribute.empty())
attributes->add(ATTR_STD_UV_TANGENT);
else
attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
@ -5600,7 +5590,7 @@ void TangentNode::compile(SVMCompiler& compiler)
int attr;
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
if(attribute.empty())
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
else
attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
@ -5618,7 +5608,7 @@ void TangentNode::compile(SVMCompiler& compiler)
void TangentNode::compile(OSLCompiler& compiler)
{
if(direction_type == NODE_TANGENT_UVMAP) {
if(attribute == ustring(""))
if(attribute.empty())
compiler.parameter("attr_name", ustring("geom:tangent"));
else
compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
@ -5731,7 +5721,7 @@ NODE_DEFINE(VectorDisplacementNode)
space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
SOCKET_STRING(attribute, "Attribute", ustring(""));
SOCKET_STRING(attribute, "Attribute", ustring());
SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
@ -5750,7 +5740,7 @@ VectorDisplacementNode::VectorDisplacementNode()
void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if(shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
attributes->add(ATTR_STD_UV_TANGENT);
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
}
@ -5774,7 +5764,7 @@ void VectorDisplacementNode::compile(SVMCompiler& compiler)
int attr = 0, attr_sign = 0;
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
attr = compiler.attribute(ATTR_STD_UV_TANGENT);
attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
}
@ -5797,7 +5787,7 @@ void VectorDisplacementNode::compile(SVMCompiler& compiler)
void VectorDisplacementNode::compile(OSLCompiler& compiler)
{
if(space == NODE_NORMAL_MAP_TANGENT) {
if(attribute == ustring("")) {
if(attribute.empty()) {
compiler.parameter("attr_name", ustring("geom:tangent"));
compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
}

View File

@ -82,6 +82,7 @@ public:
~ImageTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
ImageManager *image_manager;
int is_float;
@ -112,6 +113,7 @@ public:
~EnvironmentTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_2; }
ImageManager *image_manager;
@ -257,6 +259,7 @@ public:
~PointDensityTextureNode();
ShaderNode *clone() const;
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return true; }
@ -361,6 +364,7 @@ public:
ClosureType get_closure_type() { return distribution; }
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
};
class DiffuseBsdfNode : public BsdfNode {
@ -394,6 +398,7 @@ public:
bool has_integrator_dependency();
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
};
class TranslucentBsdfNode : public BsdfNode {
@ -572,6 +577,7 @@ class GeometryNode : public ShaderNode {
public:
SHADER_NODE_CLASS(GeometryNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
float3 normal_osl;
@ -581,6 +587,7 @@ class TextureCoordinateNode : public ShaderNode {
public:
SHADER_NODE_CLASS(TextureCoordinateNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
bool has_object_dependency() { return use_transform; }
@ -594,6 +601,7 @@ class UVMapNode : public ShaderNode {
public:
SHADER_NODE_CLASS(UVMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
@ -627,6 +635,7 @@ class ParticleInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ParticleInfoNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
};
@ -635,6 +644,7 @@ public:
SHADER_NODE_CLASS(HairInfoNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
virtual int get_feature() {
@ -796,6 +806,7 @@ class AttributeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(AttributeNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
ustring attribute;
@ -993,6 +1004,7 @@ class NormalMapNode : public ShaderNode {
public:
SHADER_NODE_CLASS(NormalMapNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
@ -1007,6 +1019,7 @@ class TangentNode : public ShaderNode {
public:
SHADER_NODE_CLASS(TangentNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
bool has_spatial_varying() { return true; }
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
@ -1046,6 +1059,7 @@ class VectorDisplacementNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorDisplacementNode)
void attributes(Shader *shader, AttributeRequestSet *attributes);
bool has_attribute_dependency() { return true; }
virtual int get_feature() {
return NODE_FEATURE_BUMP;
}

View File

@ -604,9 +604,16 @@ void ObjectManager::device_update_flags(Device *,
foreach(Object *object, scene->objects) {
if(object->mesh->has_volume) {
object_flag[object_index] |= SD_OBJECT_HAS_VOLUME;
object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
foreach(Attribute& attr, object->mesh->attributes.attributes) {
if(attr.element == ATTR_ELEMENT_VOXEL) {
object_flag[object_index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES;
}
}
}
else {
object_flag[object_index] &= ~SD_OBJECT_HAS_VOLUME;
object_flag[object_index] &= ~(SD_OBJECT_HAS_VOLUME|SD_OBJECT_HAS_VOLUME_ATTRIBUTES);
}
if(object->is_shadow_catcher) {
object_flag[object_index] |= SD_OBJECT_SHADOW_CATCHER;

View File

@ -744,6 +744,10 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
current_shader->has_object_dependency = true;
}
if(node->has_attribute_dependency()) {
current_shader->has_attribute_dependency = true;
}
if(node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
@ -991,6 +995,14 @@ void OSLCompiler::parameter_color_array(const char *name, const array<float3>& f
ss->Parameter(name, type, table.data());
}
void OSLCompiler::parameter_attribute(const char *name, ustring s)
{
if(Attribute::name_standard(s.c_str()))
parameter(name, (string("geom:") + s.c_str()).c_str());
else
parameter(name, s.c_str());
}
void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
{
ShaderNode *node = (input->link)? input->link->parent: NULL;
@ -1124,6 +1136,7 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
shader->has_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate surface shader */

View File

@ -140,6 +140,8 @@ public:
void parameter_array(const char *name, const float f[], int arraylen);
void parameter_color_array(const char *name, const array<float3>& f);
void parameter_attribute(const char *name, ustring s);
ShaderType output_type() { return current_type; }
bool background;

View File

@ -191,6 +191,7 @@ Shader::Shader()
has_surface_spatial_varying = false;
has_volume_spatial_varying = false;
has_object_dependency = false;
has_attribute_dependency = false;
has_integrator_dependency = false;
has_volume_connected = false;
@ -463,6 +464,8 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_HAS_ONLY_VOLUME;
if(shader->heterogeneous_volume && shader->has_volume_spatial_varying)
flag |= SD_HETEROGENEOUS_VOLUME;
if(shader->has_attribute_dependency)
flag |= SD_NEED_ATTRIBUTES;
if(shader->has_bssrdf_bump)
flag |= SD_HAS_BSSRDF_BUMP;
if(device->info.has_volume_decoupled) {

View File

@ -121,6 +121,7 @@ public:
bool has_surface_spatial_varying;
bool has_volume_spatial_varying;
bool has_object_dependency;
bool has_attribute_dependency;
bool has_integrator_dependency;
/* displacement */

View File

@ -399,6 +399,12 @@ uint SVMCompiler::attribute(AttributeStandard std)
return shader_manager->get_attribute_id(std);
}
uint SVMCompiler::attribute_standard(ustring name)
{
AttributeStandard std = Attribute::name_standard(name.c_str());
return (std)? attribute(std): attribute(name);
}
bool SVMCompiler::node_skip_input(ShaderNode * /*node*/, ShaderInput *input)
{
/* nasty exception .. */
@ -447,6 +453,10 @@ void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done)
current_shader->has_object_dependency = true;
}
if(node->has_attribute_dependency()) {
current_shader->has_attribute_dependency = true;
}
if(node->has_integrator_dependency()) {
current_shader->has_integrator_dependency = true;
}
@ -830,6 +840,7 @@ void SVMCompiler::compile(Scene *scene,
shader->has_surface_spatial_varying = false;
shader->has_volume_spatial_varying = false;
shader->has_object_dependency = false;
shader->has_attribute_dependency = false;
shader->has_integrator_dependency = false;
/* generate bump shader */

View File

@ -117,6 +117,7 @@ public:
void add_node(const float4& f);
uint attribute(ustring name);
uint attribute(AttributeStandard std);
uint attribute_standard(ustring name);
uint encode_uchar4(uint x, uint y = 0, uint z = 0, uint w = 0);
uint closure_mix_weight_offset() { return mix_weight_offset; }