Cycles Volume Render: generated texture coordinates for volume render.

This does not support staying fixed while the surface deforms, but for static
meshes it should match up with the surface texture coordinates. Implemented
as a matrix transform from objects space to mesh texture space.

Making this work for deforming surfaces would be quite complicated, you might
need something like harmonic coordinates as used in the mesh deform modifier,
probably will not be possible anytime soon.
This commit is contained in:
Brecht Van Lommel
2013-12-31 17:33:55 +01:00
parent 6b03f92aa7
commit 9cd2b19999
13 changed files with 200 additions and 45 deletions

View File

@@ -348,9 +348,7 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
}
}
/* create generated coordinates. todo: we should actually get the orco
* coordinates from modifiers, for now we use texspace loc/size which
* is available in the api. */
/* create generated coordinates from undeformed coordinates */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
@@ -363,6 +361,19 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, const vector<
for(b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v)
generated[i++] = get_float3(v->undeformed_co())*size - loc;
}
/* for volume objects, create a matrix to transform from object space to
* mesh texture space. this does not work with deformations but that can
* probably only be done well with a volume grid mapping of coordinates */
if(mesh->need_attribute(scene, ATTR_STD_GENERATED_TRANSFORM)) {
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED_TRANSFORM);
Transform *tfm = attr->data_transform();
float3 loc, size;
mesh_texture_space(b_mesh, loc, size);
*tfm = transform_translate(-loc)*transform_scale(size);
}
}
static void create_subd_mesh(Scene *scene, Mesh *mesh, BL::Mesh b_mesh, PointerRNA *cmesh, const vector<uint>& used_shaders)

View File

@@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem)
{
if(sd->object == ~0 || sd->prim == ~0)
if(sd->object == ~0)
return (int)ATTR_STD_NOT_FOUND;
#ifdef __OSL__
@@ -47,6 +47,9 @@ ccl_device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id,
*elem = (AttributeElement)attr_map.y;
if(sd->prim == ~0 && (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;
}
@@ -76,6 +79,18 @@ ccl_device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData
#endif
}
ccl_device Transform primitive_attribute_matrix(KernelGlobals *kg, const ShaderData *sd, int offset)
{
Transform tfm;
tfm.x = kernel_tex_fetch(__attributes_float3, offset + 0);
tfm.y = kernel_tex_fetch(__attributes_float3, offset + 1);
tfm.z = kernel_tex_fetch(__attributes_float3, offset + 2);
tfm.w = kernel_tex_fetch(__attributes_float3, offset + 3);
return tfm;
}
ccl_device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
{
AttributeElement elem_uv;

View File

@@ -418,7 +418,8 @@ typedef struct Intersection {
typedef enum AttributeElement {
ATTR_ELEMENT_NONE,
ATTR_ELEMENT_VALUE,
ATTR_ELEMENT_OBJECT,
ATTR_ELEMENT_MESH,
ATTR_ELEMENT_FACE,
ATTR_ELEMENT_VERTEX,
ATTR_ELEMENT_CORNER,
@@ -434,6 +435,7 @@ typedef enum AttributeStandard {
ATTR_STD_UV_TANGENT,
ATTR_STD_UV_TANGENT_SIGN,
ATTR_STD_GENERATED,
ATTR_STD_GENERATED_TRANSFORM,
ATTR_STD_POSITION_UNDEFORMED,
ATTR_STD_POSITION_UNDISPLACED,
ATTR_STD_MOTION_PRE,

View File

@@ -510,12 +510,22 @@ static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives,
return false;
}
static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
{
if(type == TypeDesc::TypeMatrix) {
Transform transpose = transform_transpose(tfm);
memcpy(val, &transpose, sizeof(Transform));
return true;
}
return false;
}
static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
const TypeDesc& type, bool derivatives, void *val)
{
if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
{
attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
float3 fval[3];
fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
(derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
@@ -532,6 +542,18 @@ static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OS
}
}
static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
const TypeDesc& type, bool derivatives, void *val)
{
if (attr.type == TypeDesc::TypeMatrix) {
Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
return set_attribute_matrix(tfm, type, val);
}
else {
return false;
}
}
static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
{
size_t datasize = attr.value.datasize();
@@ -745,9 +767,11 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
if (it != attribute_map.end()) {
const OSLGlobals::Attribute& attr = it->second;
if (attr.elem != ATTR_ELEMENT_VALUE) {
if (attr.elem != ATTR_ELEMENT_OBJECT) {
/* triangle and vertex attributes */
if (prim != ~0)
return get_mesh_element_attribute(kg, sd, attr, type, derivatives, val);
else
return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
}
else {

View File

@@ -545,6 +545,10 @@ int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id,
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
*elem = osl_attr.elem;
if(sd->prim == ~0 && (AttributeElement)osl_attr.elem != ATTR_ELEMENT_MESH)
return ATTR_STD_NOT_FOUND;
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
}

View File

@@ -19,6 +19,7 @@
shader node_texture_coordinate(
normal NormalIn = N,
int is_background = 0,
int is_volume = 0,
int from_dupli = 0,
string bump_offset = "center",
@@ -45,6 +46,15 @@ shader node_texture_coordinate(
getattribute("geom:dupli_generated", Generated);
getattribute("geom:dupli_uv", UV);
}
else if(is_volume) {
Generated = transform("object", P);
matrix tfm;
if(getattribute("geom:generated_transform", tfm))
Generated = transform(tfm, Generated);
getattribute("geom:uv", UV);
}
else {
getattribute("geom:generated", Generated);
getattribute("geom:uv", UV);

View File

@@ -24,21 +24,15 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, int path_f
switch(type) {
case NODE_TEXCO_OBJECT: {
if(sd->object != ~0) {
data = sd->P;
if(sd->object != ~0)
object_inverse_position_transform(kg, sd, &data);
}
else
data = sd->P;
break;
}
case NODE_TEXCO_NORMAL: {
if(sd->object != ~0) {
data = sd->N;
if(sd->object != ~0)
object_inverse_normal_transform(kg, sd, &data);
}
else
data = sd->N;
break;
}
case NODE_TEXCO_CAMERA: {
@@ -73,6 +67,22 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, int path_f
data = object_dupli_uv(kg, sd->object);
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
data = sd->P;
if(sd->object != ~0) {
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);
}
}
break;
}
}
stack_store_float3(stack, out_offset, data);
@@ -85,21 +95,15 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, in
switch(type) {
case NODE_TEXCO_OBJECT: {
if(sd->object != ~0) {
data = sd->P + sd->dP.dx;
if(sd->object != ~0)
object_inverse_position_transform(kg, sd, &data);
}
else
data = sd->P + sd->dP.dx;
break;
}
case NODE_TEXCO_NORMAL: {
if(sd->object != ~0) {
data = sd->N;
if(sd->object != ~0)
object_inverse_normal_transform(kg, sd, &data);
}
else
data = sd->N;
break;
}
case NODE_TEXCO_CAMERA: {
@@ -134,6 +138,22 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, in
data = object_dupli_uv(kg, sd->object);
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
data = sd->P + sd->dP.dx;
if(sd->object != ~0) {
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);
}
}
break;
}
}
stack_store_float3(stack, out_offset, data);
@@ -149,21 +169,15 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, in
switch(type) {
case NODE_TEXCO_OBJECT: {
if(sd->object != ~0) {
data = sd->P + sd->dP.dy;
if(sd->object != ~0)
object_inverse_position_transform(kg, sd, &data);
}
else
data = sd->P + sd->dP.dy;
break;
}
case NODE_TEXCO_NORMAL: {
if(sd->object != ~0) {
data = sd->N;
if(sd->object != ~0)
object_inverse_normal_transform(kg, sd, &data);
}
else
data = sd->N;
break;
}
case NODE_TEXCO_CAMERA: {
@@ -198,6 +212,22 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, in
data = object_dupli_uv(kg, sd->object);
break;
}
case NODE_TEXCO_VOLUME_GENERATED: {
data = sd->P + sd->dP.dy;
if(sd->object != ~0) {
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);
}
}
break;
}
}
stack_store_float3(stack, out_offset, data);

View File

@@ -107,7 +107,8 @@ typedef enum NodeType {
typedef enum NodeAttributeType {
NODE_ATTR_FLOAT = 0,
NODE_ATTR_FLOAT3
NODE_ATTR_FLOAT3,
NODE_ATTR_MATRIX
} NodeAttributeType;
typedef enum NodeGeometry {
@@ -173,7 +174,8 @@ typedef enum NodeTexCoord {
NODE_TEXCO_WINDOW,
NODE_TEXCO_REFLECTION,
NODE_TEXCO_DUPLI_GENERATED,
NODE_TEXCO_DUPLI_UV
NODE_TEXCO_DUPLI_UV,
NODE_TEXCO_VOLUME_GENERATED
} NodeTexCoord;
typedef enum NodeMix {

View File

@@ -19,6 +19,7 @@
#include "util_debug.h"
#include "util_foreach.h"
#include "util_transform.h"
CCL_NAMESPACE_BEGIN
@@ -34,7 +35,7 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
type == TypeDesc::TypeNormal);
type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix);
}
void Attribute::reserve(int numverts, int numtris, int numcurves, int numkeys)
@@ -60,10 +61,21 @@ void Attribute::add(const float3& f)
buffer.push_back(data[i]);
}
void Attribute::add(const Transform& 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)
return sizeof(float);
else if(type == TypeDesc::TypeMatrix)
return sizeof(Transform);
else
return sizeof(float3);
}
@@ -73,7 +85,8 @@ size_t Attribute::element_size(int numverts, int numtris, int numcurves, int num
size_t size;
switch(element) {
case ATTR_ELEMENT_VALUE:
case ATTR_ELEMENT_OBJECT:
case ATTR_ELEMENT_MESH:
size = 1;
break;
case ATTR_ELEMENT_VERTEX:
@@ -151,6 +164,8 @@ const char *Attribute::standard_name(AttributeStandard std)
return "ptex_face_id";
else if(std == ATTR_STD_PTEX_UV)
return "ptex_uv";
else if(std == ATTR_STD_GENERATED_TRANSFORM)
return "generated_transform";
return "";
}
@@ -256,6 +271,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_PTEX_UV:
attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_VERTEX);
break;
case ATTR_STD_GENERATED_TRANSFORM:
attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
break;
default:
assert(0);
break;
@@ -274,6 +292,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name)
case ATTR_STD_CURVE_INTERCEPT:
attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY);
break;
case ATTR_STD_GENERATED_TRANSFORM:
attr = add(name, TypeDesc::TypeMatrix, ATTR_ELEMENT_MESH);
break;
default:
assert(0);
break;

View File

@@ -31,6 +31,7 @@ class AttributeSet;
class AttributeRequest;
class AttributeRequestSet;
class Mesh;
struct Transform;
/* Attribute
*
@@ -57,13 +58,16 @@ public:
char *data() { return (buffer.size())? &buffer[0]: NULL; };
float3 *data_float3() { return (float3*)data(); }
float *data_float() { return (float*)data(); }
Transform *data_transform() { return (Transform*)data(); }
const char *data() const { return (buffer.size())? &buffer[0]: NULL; }
const float3 *data_float3() const { return (const float3*)data(); }
const float *data_float() const { return (const float*)data(); }
const Transform *data_transform() const { return (const Transform*)data(); }
void add(const float& f);
void add(const float3& f);
void add(const Transform& f);
static bool same_storage(TypeDesc a, TypeDesc b);
static const char *standard_name(AttributeStandard std);

View File

@@ -120,8 +120,10 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
foreach(ShaderInput *input, inputs) {
if(!input->link) {
if(input->default_value == ShaderInput::TEXTURE_GENERATED)
if(input->default_value == ShaderInput::TEXTURE_GENERATED) {
attributes->add(ATTR_STD_GENERATED);
attributes->add(ATTR_STD_GENERATED_TRANSFORM); // XXX only for volumes!
}
else if(input->default_value == ShaderInput::TEXTURE_UV)
attributes->add(ATTR_STD_UV);
}

View File

@@ -466,7 +466,7 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
OSLGlobals::Attribute osl_attr;
osl_attr.type = attr.type();
osl_attr.elem = ATTR_ELEMENT_VALUE;
osl_attr.elem = ATTR_ELEMENT_OBJECT;
osl_attr.value = attr;
osl_attr.offset = 0;
@@ -493,6 +493,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
if(req.triangle_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else if(req.triangle_type == TypeDesc::TypeMatrix)
osl_attr.type = TypeDesc::TypeMatrix;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -513,6 +515,8 @@ void MeshManager::update_osl_attributes(Device *device, Scene *scene, vector<Att
if(req.curve_type == TypeDesc::TypeFloat)
osl_attr.type = TypeDesc::TypeFloat;
else if(req.curve_type == TypeDesc::TypeMatrix)
osl_attr.type = TypeDesc::TypeMatrix;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -580,6 +584,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
if(req.triangle_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
else if(req.triangle_type == TypeDesc::TypeMatrix)
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
}
@@ -593,6 +599,8 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce
if(req.curve_type == TypeDesc::TypeFloat)
attr_map[index].w = NODE_ATTR_FLOAT;
else if(req.curve_type == TypeDesc::TypeMatrix)
attr_map[index].w = NODE_ATTR_MATRIX;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
}
@@ -645,6 +653,15 @@ static void update_attribute_element_offset(Mesh *mesh, vector<float>& attr_floa
for(size_t k = 0; k < size; k++)
attr_float[offset+k] = data[k];
}
else if(mattr->type == TypeDesc::TypeMatrix) {
Transform *tfm = mattr->data_transform();
offset = attr_float3.size();
attr_float3.resize(attr_float3.size() + size*4);
for(size_t k = 0; k < size*4; k++)
attr_float3[offset+k] = (&tfm->x)[k];
}
else {
float3 *data = mattr->data_float3();
offset = attr_float3.size();

View File

@@ -2193,6 +2193,13 @@ void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attr
}
}
if(shader->has_volume) {
if(!from_dupli) {
if(!output("Generated")->links.empty())
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
}
}
ShaderNode::attributes(shader, attributes);
}
@@ -2225,6 +2232,10 @@ void TextureCoordinateNode::compile(SVMCompiler& compiler)
compiler.stack_assign(out);
compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, out->stack_offset);
}
else if(compiler.output_type() == SHADER_TYPE_VOLUME) {
compiler.stack_assign(out);
compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, out->stack_offset);
}
else {
int attr = compiler.attribute(ATTR_STD_GENERATED);
compiler.stack_assign(out);
@@ -2294,6 +2305,8 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler)
if(compiler.background)
compiler.parameter("is_background", true);
if(compiler.output_type() == SHADER_TYPE_VOLUME)
compiler.parameter("is_volume", true);
compiler.parameter("from_dupli", from_dupli);