Fix cycles issue with mapping node rotation and scale order. When using both

scale and rotation in mapping node, there would be shearing, and the only way
to avoid that was to add 2 mapping nodes. This is because to transform the
texture, the inverse transform needs to be done on the texture coordinate

Now the mapping node has Texture/Point/Vector/Normal types to transform the
vector for a particular purpose. Point is the existing behavior, Texture is
the new default that behaves more like you might expect.
This commit is contained in:
Brecht Van Lommel 2013-09-25 20:28:49 +00:00
parent e9859bb0e5
commit c3d3d8be36
25 changed files with 173 additions and 40 deletions

@ -1085,6 +1085,8 @@ class CyclesTexture_PT_mapping(CyclesButtonsPanel, Panel):
mapping = node.texture_mapping
layout.prop(mapping, "type", expand=True)
row = layout.row()
row.column().prop(mapping, "translation")

@ -147,6 +147,7 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping b_mapping)
mapping->translation = get_float3(b_mapping.translation());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
mapping->type = (TextureMapping::Type)b_mapping.type();
mapping->x_mapping = (TextureMapping::Mapping)b_mapping.mapping_x();
mapping->y_mapping = (TextureMapping::Mapping)b_mapping.mapping_y();
@ -161,6 +162,7 @@ static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping b_map
mapping->translation = get_float3(b_mapping.translation());
mapping->rotation = get_float3(b_mapping.rotation());
mapping->scale = get_float3(b_mapping.scale());
mapping->type = (TextureMapping::Type)b_mapping.type();
mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max();

@ -42,6 +42,8 @@ TextureMapping::TextureMapping()
y_mapping = Y;
z_mapping = Z;
type = TEXTURE;
projection = FLAT;
}
@ -55,12 +57,52 @@ Transform TextureMapping::compute_transform()
mmat[1][y_mapping-1] = 1.0f;
if(z_mapping != NONE)
mmat[2][z_mapping-1] = 1.0f;
float3 scale_clamped = scale;
Transform smat = transform_scale(scale);
if(type == TEXTURE || type == NORMAL) {
/* keep matrix invertible */
if(fabsf(scale.x) < 1e-5f)
scale_clamped.x = signf(scale.x)*1e-5f;
if(fabsf(scale.y) < 1e-5f)
scale_clamped.y = signf(scale.y)*1e-5f;
if(fabsf(scale.z) < 1e-5f)
scale_clamped.z = signf(scale.z)*1e-5f;
}
Transform smat = transform_scale(scale_clamped);
Transform rmat = transform_euler(rotation);
Transform tmat = transform_translate(translation);
return tmat*rmat*smat*mmat;
Transform mat;
switch(type) {
case TEXTURE:
/* inverse transform on texture coordinate gives
* forward transform on texture */
mat = tmat*rmat*smat;
mat = transform_inverse(mat);
break;
case POINT:
/* full transform */
mat = tmat*rmat*smat;
break;
case VECTOR:
/* no translation for vectors */
mat = rmat*smat;
break;
case NORMAL:
/* no translation for normals, and inverse transpose */
mat = rmat*smat;
mat = transform_inverse(mat);
mat = transform_transpose(mat);
break;
}
/* projection last */
mat = mat*mmat;
return mat;
}
bool TextureMapping::skip()
@ -98,6 +140,11 @@ void TextureMapping::compile(SVMCompiler& compiler, int offset_in, int offset_ou
compiler.add_node(float3_to_float4(min));
compiler.add_node(float3_to_float4(max));
}
if(type == NORMAL) {
compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out);
compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out);
}
}
void TextureMapping::compile(OSLCompiler &compiler)

@ -43,6 +43,9 @@ public:
float3 min, max;
bool use_minmax;
enum Type { POINT = 0, TEXTURE = 1, VECTOR = 2, NORMAL = 3 };
Type type;
enum Mapping { NONE = 0, X = 1, Y = 2, Z = 3 };
Mapping x_mapping, y_mapping, z_mapping;

@ -101,8 +101,8 @@ void set_current_particle_texture(struct ParticleSettings *part, struct Tex *tex
int has_current_material_texture(struct Material *ma);
struct TexMapping *add_tex_mapping(void);
void default_tex_mapping(struct TexMapping *texmap);
struct TexMapping *add_tex_mapping(int type);
void default_tex_mapping(struct TexMapping *texmap, int type);
void init_tex_mapping(struct TexMapping *texmap);
struct ColorMapping *add_color_mapping(void);

@ -71,16 +71,16 @@
/* ****************** Mapping ******************* */
TexMapping *add_tex_mapping(void)
TexMapping *add_tex_mapping(int type)
{
TexMapping *texmap = MEM_callocN(sizeof(TexMapping), "TexMapping");
default_tex_mapping(texmap);
default_tex_mapping(texmap, type);
return texmap;
}
void default_tex_mapping(TexMapping *texmap)
void default_tex_mapping(TexMapping *texmap, int type)
{
memset(texmap, 0, sizeof(TexMapping));
@ -92,11 +92,12 @@ void default_tex_mapping(TexMapping *texmap)
texmap->projy = PROJ_Y;
texmap->projz = PROJ_Z;
texmap->mapping = MTEX_FLAT;
texmap->type = type;
}
void init_tex_mapping(TexMapping *texmap)
{
float smat[3][3], rmat[3][3], mat[3][3], proj[3][3];
float smat[4][4], rmat[4][4], tmat[4][4], proj[4][4], size[3];
if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z &&
is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size))
@ -107,7 +108,8 @@ void init_tex_mapping(TexMapping *texmap)
}
else {
/* axis projection */
zero_m3(proj);
zero_m4(proj);
proj[3][3] = 1.0f;
if (texmap->projx != PROJ_N)
proj[texmap->projx - 1][0] = 1.0f;
@ -117,19 +119,50 @@ void init_tex_mapping(TexMapping *texmap)
proj[texmap->projz - 1][2] = 1.0f;
/* scale */
size_to_mat3(smat, texmap->size);
copy_v3_v3(size, texmap->size);
if (ELEM(texmap->type, TEXMAP_TYPE_TEXTURE, TEXMAP_TYPE_NORMAL)) {
/* keep matrix invertible */
if(fabsf(size[0]) < 1e-5f)
size[0] = signf(size[0])*1e-5f;
if(fabsf(size[1]) < 1e-5f)
size[1] = signf(size[1])*1e-5f;
if(fabsf(size[2]) < 1e-5f)
size[2] = signf(size[2])*1e-5f;
}
size_to_mat4(smat, texmap->size);
/* rotation */
/* TexMapping rotation are now in radians. */
eul_to_mat3(rmat, texmap->rot);
/* compose it all */
mul_m3_m3m3(mat, rmat, smat);
mul_m3_m3m3(mat, proj, mat);
eul_to_mat4(rmat, texmap->rot);
/* translation */
copy_m4_m3(texmap->mat, mat);
copy_v3_v3(texmap->mat[3], texmap->loc);
unit_m4(tmat);
copy_v3_v3(tmat[3], texmap->loc);
if (texmap->type == TEXMAP_TYPE_TEXTURE) {
/* to transform a texture, the inverse transform needs
* to be applied to the texture coordinate */
mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
invert_m4(texmap->mat);
}
else if (texmap->type == TEXMAP_TYPE_POINT) {
/* forward transform */
mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
}
else if (texmap->type == TEXMAP_TYPE_VECTOR) {
/* no translation for vectors */
mul_m4_m4m4(texmap->mat, rmat, smat);
}
else if (texmap->type == TEXMAP_TYPE_NORMAL) {
/* no translation for normals, and inverse transpose */
mul_m4_m4m4(texmap->mat, rmat, smat);
invert_m4(texmap->mat);
transpose_m4(texmap->mat);
}
/* projection last */
mul_m4_m4m4(texmap->mat, texmap->mat, proj);
texmap->flag &= ~TEXMAP_UNIT_MATRIX;
}

@ -709,6 +709,8 @@ static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), Poin
{
uiLayout *row;
uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemL(layout, IFACE_("Location:"), ICON_NONE);
row = uiLayoutRow(layout, TRUE);
uiItemR(row, ptr, "translation", 0, "", ICON_NONE);

@ -975,7 +975,7 @@ typedef struct NodeShaderNormalMap {
#define SHD_NORMAL_MAP_BLENDER_OBJECT 3
#define SHD_NORMAL_MAP_BLENDER_WORLD 4
/* tangent */
/* subsurface */
#define SHD_SUBSURFACE_COMPATIBLE 0
#define SHD_SUBSURFACE_CUBIC 1
#define SHD_SUBSURFACE_GAUSSIAN 2

@ -263,7 +263,7 @@ typedef struct TexMapping {
float loc[3], rot[3], size[3];
int flag;
char projx, projy, projz, mapping;
int pad;
int type;
float mat[4][4];
float min[3], max[3];
@ -287,6 +287,12 @@ typedef struct ColorMapping {
#define TEXMAP_CLIP_MAX 2
#define TEXMAP_UNIT_MATRIX 4
/* texmap->type */
#define TEXMAP_TYPE_POINT 0
#define TEXMAP_TYPE_TEXTURE 1
#define TEXMAP_TYPE_VECTOR 2
#define TEXMAP_TYPE_NORMAL 3
/* colormap->flag */
#define COLORMAP_USE_RAMP 1

@ -3135,10 +3135,24 @@ static void def_sh_material(StructRNA *srna)
static void def_sh_mapping(StructRNA *srna)
{
static EnumPropertyItem prop_vect_type_items[] = {
{TEXMAP_TYPE_TEXTURE, "TEXTURE", 0, "Texture", "Transforms a texture by inverse mapping the texture coordinate"},
{TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transforms a point"},
{TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transforms a direction vector"},
{TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transforms a normal vector with unit length"},
{0, NULL, 0, NULL, NULL}
};
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_vect_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "");
@ -3522,9 +3536,9 @@ static void def_sh_tex_coord(StructRNA *srna)
static void def_sh_vect_transform(StructRNA *srna)
{
static EnumPropertyItem prop_vect_type_items[] = {
{SHD_VECT_TRANSFORM_TYPE_VECTOR, "VECTOR", 0, "Vector", ""},
{SHD_VECT_TRANSFORM_TYPE_POINT, "POINT", 0, "Point", ""},
{SHD_VECT_TRANSFORM_TYPE_NORMAL, "NORMAL", 0, "Normal", ""},
{SHD_VECT_TRANSFORM_TYPE_POINT, "POINT", 0, "Point", "Transforms a point"},
{SHD_VECT_TRANSFORM_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transforms a direction vector"},
{SHD_VECT_TRANSFORM_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transforms a normal vector with unit length"},
{0, NULL, 0, NULL, NULL}
};

@ -495,6 +495,14 @@ static void rna_def_texmapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem prop_vect_type_items[] = {
{TEXMAP_TYPE_TEXTURE, "TEXTURE", 0, "Texture", "Transforms a texture by inverse mapping the texture coordinate"},
{TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transforms a point"},
{TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transforms a direction vector"},
{TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transforms a normal vector with unit length"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem prop_xyz_mapping_items[] = {
{0, "NONE", 0, "None", ""},
{1, "X", 0, "X", ""},
@ -509,6 +517,12 @@ static void rna_def_texmapping(BlenderRNA *brna)
srna = RNA_def_struct(brna, "TexMapping", NULL);
RNA_def_struct_ui_text(srna, "Texture Mapping", "Texture coordinate mapping settings");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_vect_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");
prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "");

@ -44,7 +44,7 @@ static bNodeSocketTemplate cmp_node_map_value_out[] = {
static void node_composit_init_map_value(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = add_tex_mapping();
node->storage = add_tex_mapping(TEXMAP_TYPE_POINT);
}
void register_node_type_cmp_map_value(void)

@ -271,6 +271,9 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat, bNode *node, GPUNodeStack *in
GPUNodeLink *tdomax = GPU_uniform(&domax);
GPU_link(mat, "mapping", in[0].link, tmat, tmin, tmax, tdomin, tdomax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
}
}

@ -29,7 +29,6 @@
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** MAPPING ******************** */
@ -53,7 +52,7 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo
/* stack order output: vector */
nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
mul_m4_v3(texmap->mat, vec);
if (texmap->flag & TEXMAP_CLIP_MIN) {
if (vec[0] < texmap->min[0]) vec[0] = texmap->min[0];
if (vec[1] < texmap->min[1]) vec[1] = texmap->min[1];
@ -64,12 +63,15 @@ static void node_shader_exec_mapping(void *UNUSED(data), int UNUSED(thread), bNo
if (vec[1] > texmap->max[1]) vec[1] = texmap->max[1];
if (vec[2] > texmap->max[2]) vec[2] = texmap->max[2];
}
if (texmap->type == TEXMAP_TYPE_NORMAL)
normalize_v3(vec);
}
static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
{
node->storage = add_tex_mapping();
node->storage = add_tex_mapping(TEXMAP_TYPE_TEXTURE);
}
static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@ -83,7 +85,12 @@ static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS
GPUNodeLink *tdomin = GPU_uniform(&domin);
GPUNodeLink *tdomax = GPU_uniform(&domax);
return GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
int result = GPU_stack_link(mat, "mapping", in, out, tmat, tmin, tmax, tdomin, tdomax);
if (result && texmap->type == TEXMAP_TYPE_NORMAL)
GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
return result;
}
void register_node_type_sh_mapping(void)

@ -51,7 +51,7 @@ static bNodeSocketTemplate sh_node_tex_brick_out[] = {
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexBrick *tex = MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->offset = 0.5f;

@ -46,7 +46,7 @@ static bNodeSocketTemplate sh_node_tex_checker_out[] = {
static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexChecker *tex = MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
node->storage = tex;

@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = {
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->projection = SHD_PROJ_EQUIRECTANGULAR;

@ -43,7 +43,7 @@ static bNodeSocketTemplate sh_node_tex_gradient_out[] = {
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexGradient *tex = MEM_callocN(sizeof(NodeTexGradient), "NodeTexGradient");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;

@ -45,7 +45,7 @@ static bNodeSocketTemplate sh_node_tex_image_out[] = {
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->color_space = SHD_COLORSPACE_COLOR;
tex->iuser.frames = 1;

@ -45,7 +45,7 @@ static bNodeSocketTemplate sh_node_tex_magic_out[] = {
static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMagic *tex = MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->depth = 2;

@ -49,7 +49,7 @@ static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexMusgrave *tex = MEM_callocN(sizeof(NodeTexMusgrave), "NodeTexMusgrave");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;

@ -46,7 +46,7 @@ static bNodeSocketTemplate sh_node_tex_noise_out[] = {
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
node->storage = tex;

@ -42,7 +42,7 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = {
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
tex->sun_direction[1] = 0.0f;

@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->coloring = SHD_VORONOI_INTENSITY;

@ -47,7 +47,7 @@ static bNodeSocketTemplate sh_node_tex_wave_out[] = {
static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexWave *tex = MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
default_tex_mapping(&tex->base.tex_mapping);
default_tex_mapping(&tex->base.tex_mapping, TEXMAP_TYPE_TEXTURE);
default_color_mapping(&tex->base.color_mapping);
tex->wave_type = SHD_WAVE_BANDS;