2.5: Bump Mapping

Patch by Alfredo de Greef. Considerably improves the quality of bump
mapping, and texture filtering for displacement and warp too. Mainly
this is achieved by getting the texture derivatives just right in
various cases, many thanks to Alfredo for figuring this one out, works
great.


This is enabled by default now, but disabled still for existing
textures to preserve backwards compatibility. Can be enabled with
the "New Bump" option in the material texture slot in the outliner.

Also, I made the range for the normal factor a bit smaller since this
gives stronger effects, but note that you can still type in larger
values than the slider allows.
This commit is contained in:
Brecht Van Lommel 2009-07-21 13:46:49 +00:00
parent d19bb6ffcf
commit 0b49dc77de
10 changed files with 367 additions and 122 deletions

@ -49,6 +49,14 @@ class DATA_PT_normals(DataButtonsPanel):
sub.itemR(mesh, "vertex_normal_flip")
sub.itemR(mesh, "double_sided")
row = layout.row(align=True)
if context.edit_object:
row.itemO("MESH_OT_faces_shade_smooth")
row.itemO("MESH_OT_faces_shade_flat")
else:
row.itemO("OBJECT_OT_shade_smooth")
row.itemO("OBJECT_OT_shade_flat")
class DATA_PT_vertex_groups(DataButtonsPanel):
__idname__ = "DATA_PT_vertex_groups"
__label__ = "Vertex Groups"

@ -671,6 +671,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
ma->mapto |= mtex->mapto;
if(r_mode & R_OSA) {
if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA;
else if(mtex->texflag & MTEX_NEW_BUMP) ma->texco |= TEXCO_OSA; // NEWBUMP: need texture derivatives for procedurals as well
}
if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1;

@ -534,7 +534,7 @@ void default_mtex(MTex *mtex)
mtex->size[1]= 1.0;
mtex->size[2]= 1.0;
mtex->tex= 0;
mtex->texflag= 0;
mtex->texflag= MTEX_NEW_BUMP;
mtex->colormodel= 0;
mtex->r= 1.0;
mtex->g= 0.0;
@ -543,7 +543,7 @@ void default_mtex(MTex *mtex)
mtex->def_var= 1.0;
mtex->blendtype= MTEX_BLEND;
mtex->colfac= 1.0;
mtex->norfac= 0.5;
mtex->norfac= 1.0;
mtex->varfac= 1.0;
mtex->dispfac=0.2;
mtex->normapspace= MTEX_NSPACE_TANGENT;

@ -2197,25 +2197,23 @@ void VecNegf(float *v1)
void VecOrthoBasisf(float *v, float *v1, float *v2)
{
float f = (float)sqrt(v[0]*v[0] + v[1]*v[1]);
const float f = (float)sqrt(v[0]*v[0] + v[1]*v[1]);
if (f < 1e-35f) {
// degenerate case
v1[0] = 0.0f; v1[1] = 1.0f; v1[2] = 0.0f;
if (v[2] > 0.0f) {
v2[0] = 1.0f; v2[1] = v2[2] = 0.0f;
}
else {
v2[0] = -1.0f; v2[1] = v2[2] = 0.0f;
}
v1[0] = (v[2] < 0.0f) ? -1.0f : 1.0f;
v1[1] = v1[2] = v2[0] = v2[2] = 0.0f;
v2[1] = 1.0f;
}
else {
f = 1.0f/f;
v1[0] = v[1]*f;
v1[1] = -v[0]*f;
v1[2] = 0.0f;
const float d= 1.0f/f;
Crossf(v2, v, v1);
v1[0] = v[1]*d;
v1[1] = -v[0]*d;
v1[2] = 0.0f;
v2[0] = -v[2]*v1[1];
v2[1] = v[2]*v1[0];
v2[2] = v[0]*v1[1] - v[1]*v1[0];
}
}

@ -9276,7 +9276,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
Tex *tex;
Scene *sce;
ToolSettings *ts;
int i;
int i, a;
for(ob = main->object.first; ob; ob = ob->id.next) {
@ -9351,15 +9351,26 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
/* texture filter */
for(tex = main->tex.first; tex; tex = tex->id.next)
for(tex = main->tex.first; tex; tex = tex->id.next) {
if(tex->afmax == 0)
tex->afmax= 8;
}
for(ma = main->mat.first; ma; ma = ma->id.next) {
if(ma->mode & MA_HALO) {
ma->material_type= MA_TYPE_HALO;
ma->mode &= ~MA_HALO;
}
/* set new bump for unused slots */
for(a=0; a<MAX_MTEX; a++) {
if(ma->mtex[a]) {
if(!ma->mtex[a]->tex)
ma->mtex[a]->texflag |= MTEX_NEW_BUMP;
else if(((Tex*)newlibadr(fd, ma->id.lib, ma->mtex[a]->tex))->type == 0)
ma->mtex[a]->texflag |= MTEX_NEW_BUMP;
}
}
}
for(sce = main->scene.first; sce; sce = sce->id.next) {

@ -373,6 +373,7 @@ typedef struct TexMapping {
#define MTEX_VIEWSPACE 16
#define MTEX_DUPLI_MAPTO 32
#define MTEX_OB_DUPLI_ORIG 64
#define MTEX_NEW_BUMP 128
/* blendtype */
#define MTEX_BLEND 0

@ -231,99 +231,122 @@ static void rna_def_material_mtex(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "texco");
RNA_def_property_enum_items(prop, prop_texture_coordinates_items);
RNA_def_property_ui_text(prop, "Texture Coordinates", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "object");
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "Object to use for mapping with Object texture coordinates.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "uvname");
RNA_def_property_ui_text(prop, "UV Layer", "UV layer to use for mapping with UV texture coordinates.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_DUPLI_MAPTO);
RNA_def_property_ui_text(prop, "From Dupli", "Dupli's instanced from verts, faces or particles, inherit texture coordinate from their parent.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "from_original", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_OB_DUPLI_ORIG);
RNA_def_property_ui_text(prop, "From Original", "Dupli's derive their object coordinates from the original objects transformation.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_colordiff", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COL);
RNA_def_property_ui_text(prop, "Diffuse Color", "Causes the texture to affect basic color of the material");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_normal", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_NORM);
RNA_def_property_ui_text(prop, "Normal", "Causes the texture to affect the rendered normal");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_colorspec", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COLSPEC);
RNA_def_property_ui_text(prop, "Specular Color", "Causes the texture to affect the specularity color");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_mirror", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COLMIR);
RNA_def_property_ui_text(prop, "Mirror", "Causes the texture to affect the mirror color");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_diffuse", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_REF);
RNA_def_property_ui_text(prop, "Diffuse", "Causes the texture to affect the value of the materials diffuse reflectivity");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_specular", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_SPEC);
RNA_def_property_ui_text(prop, "Specular", "Causes the texture to affect the value of specular reflectivity");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_ambient", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_AMB);
RNA_def_property_ui_text(prop, "Ambient", "Causes the texture to affect the value of ambient");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_hardness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_HAR);
RNA_def_property_ui_text(prop, "Hardness", "Causes the texture to affect the hardness value");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_raymir", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_RAYMIRR);
RNA_def_property_ui_text(prop, "Ray-Mirror", "Causes the texture to affect the ray-mirror value");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_alpha", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_ALPHA);
RNA_def_property_ui_text(prop, "Alpha", "Causes the texture to affect the alpha value");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_emit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_EMIT);
RNA_def_property_ui_text(prop, "Emit", "Causes the texture to affect the emit value");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_translucency", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_TRANSLU);
RNA_def_property_ui_text(prop, "Translucency", "Causes the texture to affect the translucency value");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_displacement", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_DISPLACE);
RNA_def_property_ui_text(prop, "Displacement", "Let the texture displace the surface");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "map_warp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_WARP);
RNA_def_property_ui_text(prop, "Warp", "Let the texture warp texture coordinates of next channels");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "x_mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "projx");
RNA_def_property_enum_items(prop, prop_x_mapping_items);
RNA_def_property_ui_text(prop, "X Mapping", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "y_mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "projy");
RNA_def_property_enum_items(prop, prop_y_mapping_items);
RNA_def_property_ui_text(prop, "Y Mapping", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "z_mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "projz");
RNA_def_property_enum_items(prop, prop_z_mapping_items);
RNA_def_property_ui_text(prop, "Z Mapping", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_mapping_items);
RNA_def_property_ui_text(prop, "Mapping", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
/* XXX: pmapto, pmaptoneg */
@ -331,6 +354,7 @@ static void rna_def_material_mtex(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "normapspace");
RNA_def_property_enum_items(prop, prop_normal_map_space_items);
RNA_def_property_ui_text(prop, "Normal Map Space", "");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
/* XXX: MTex.which_output */
@ -340,11 +364,13 @@ static void rna_def_material_mtex(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "dispfac");
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
RNA_def_property_ui_text(prop, "Displacement Factor", "Amount texture displaces the surface.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "warp_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "warpfac");
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
RNA_def_property_ui_text(prop, "Warp Factor", "Amount texture affects texture coordinates of next channels.");
RNA_def_property_update(prop, NC_TEXTURE, NULL);
prop= RNA_def_property(srna, "colorspec_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "colfac");
@ -417,10 +443,10 @@ static void rna_def_material_mtex(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Enabled", "Enable this material texture slot.");
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
/*prop= RNA_def_property(srna, "new_bump", PROP_BOOLEAN, PROP_NONE);
prop= RNA_def_property(srna, "new_bump", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_NEW_BUMP);
RNA_def_property_ui_text(prop, "New Bump", "Use new, corrected bump mapping code (backwards compatibility option).");
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);*/
RNA_def_property_update(prop, NC_MATERIAL|ND_SHADING, NULL);
}
static void rna_def_material_colors(StructRNA *srna)

@ -2243,6 +2243,7 @@ static void displace_render_face(Render *re, ObjectRen *obr, VlakRen *vlr, float
/* memset above means we dont need this */
/*shi.osatex= 0;*/ /* signal not to use dx[] and dy[] texture AA vectors */
shi.obr= obr;
shi.vlr= vlr; /* current render face */
shi.mat= vlr->mat; /* current input material */
shi.thread= 0;

@ -210,7 +210,6 @@ void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
/* add mist and premul color */
if(shr->alpha!=1.0f || alpha!=1.0f) {
float fac= alpha*(shr->alpha);
shr->combined[3]= fac;
shr->combined[0]*= fac;
shr->combined[1]*= fac;
@ -1016,9 +1015,12 @@ void shade_input_set_shade_texco(ShadeInput *shi)
MTC_Mat4MulVecfl(R.viewinv, shi->gl);
if(shi->osatex) {
VECCOPY(shi->dxgl, shi->dxco);
MTC_Mat3MulVecfl(R.imat, shi->dxco);
// TXF: bug was here, but probably should be in convertblender.c, R.imat only valid if there is a world
//MTC_Mat3MulVecfl(R.imat, shi->dxco);
MTC_Mat4Mul3Vecfl(R.viewinv, shi->dxco);
VECCOPY(shi->dygl, shi->dyco);
MTC_Mat3MulVecfl(R.imat, shi->dyco);
//MTC_Mat3MulVecfl(R.imat, shi->dyco);
MTC_Mat4Mul3Vecfl(R.viewinv, shi->dyco);
}
}
@ -1121,6 +1123,8 @@ void shade_input_set_shade_texco(ShadeInput *shi)
if(tface && tface->tpage)
render_realtime_texture(shi, tface->tpage);
}
}
shi->dupliuv[0]= -1.0f + 2.0f*obi->dupliuv[0];

@ -71,6 +71,8 @@
#include "shading.h"
#include "texture.h"
#include "renderdatabase.h" /* needed for UV */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
/* only to be used here in this file, it's for speed */
@ -1499,6 +1501,94 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen
return in;
}
static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, float* dx, float* dy, float* texvec, float* dxt, float* dyt)
{
// new: first swap coords, then map, then trans/scale
if (tex->type == TEX_IMAGE) {
// placement
texvec[0] = mtex->projx ? co[mtex->projx - 1] : 0.f;
texvec[1] = mtex->projy ? co[mtex->projy - 1] : 0.f;
texvec[2] = mtex->projz ? co[mtex->projz - 1] : 0.f;
if (shi->osatex) {
if (mtex->projx) {
dxt[0] = dx[mtex->projx - 1];
dyt[0] = dy[mtex->projx - 1];
}
else dxt[0] = dyt[0] = 0.f;
if (mtex->projy) {
dxt[1] = dx[mtex->projy - 1];
dyt[1] = dy[mtex->projy - 1];
}
else dxt[1] = dyt[1] = 0.f;
if (mtex->projz) {
dxt[2] = dx[mtex->projz - 1];
dyt[2] = dy[mtex->projz - 1];
}
else dxt[2] = dyt[2] = 0.f;
}
do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
// translate and scale
texvec[0] = mtex->size[0]*(texvec[0] - 0.5f) + mtex->ofs[0] + 0.5f;
texvec[1] = mtex->size[1]*(texvec[1] - 0.5f) + mtex->ofs[1] + 0.5f;
if (shi->osatex) {
dxt[0] = mtex->size[0]*dxt[0];
dxt[1] = mtex->size[1]*dxt[1];
dyt[0] = mtex->size[0]*dyt[0];
dyt[1] = mtex->size[1]*dyt[1];
}
/* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
// TXF: bug was here, only modify texvec when repeat mode set, old code affected other modes too.
// New texfilters solve mirroring differently so that it also works correctly when
// textures are scaled (sizeXYZ) as well as repeated. See also modification in do_2d_mapping().
// (since currently only done in osa mode, results will look incorrect without osa TODO)
if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_XMIR)) {
if (tex->texfilter == TXF_DEFAULT)
texvec[0] -= floorf(texvec[0]); // this line equivalent to old code, same below
else if (texvec[0] < 0.f || texvec[0] > 1.f) {
const float tx = 0.5f*texvec[0];
texvec[0] = 2.f*(tx - floorf(tx));
if (texvec[0] > 1.f) texvec[0] = 2.f - texvec[0];
}
}
if (tex->extend == TEX_REPEAT && (tex->flag & TEX_REPEAT_YMIR)) {
if (tex->texfilter == TXF_DEFAULT)
texvec[1] -= floorf(texvec[1]);
else if (texvec[1] < 0.f || texvec[1] > 1.f) {
const float ty = 0.5f*texvec[1];
texvec[1] = 2.f*(ty - floorf(ty));
if (texvec[1] > 1.f) texvec[1] = 2.f - texvec[1];
}
}
}
else { // procedural
// placement
texvec[0] = mtex->size[0]*(mtex->projx ? (co[mtex->projx - 1] + mtex->ofs[0]) : mtex->ofs[0]);
texvec[1] = mtex->size[1]*(mtex->projy ? (co[mtex->projy - 1] + mtex->ofs[1]) : mtex->ofs[1]);
texvec[2] = mtex->size[2]*(mtex->projz ? (co[mtex->projz - 1] + mtex->ofs[2]) : mtex->ofs[2]);
if (shi->osatex) {
if (mtex->projx) {
dxt[0] = mtex->size[0]*dx[mtex->projx - 1];
dyt[0] = mtex->size[0]*dy[mtex->projx - 1];
}
else dxt[0] = 0.f;
if (mtex->projy) {
dxt[1] = mtex->size[1]*dx[mtex->projy - 1];
dyt[1] = mtex->size[1]*dy[mtex->projy - 1];
}
else dxt[1] = 0.f;
if (mtex->projz) {
dxt[2] = mtex->size[2]*dx[mtex->projz - 1];
dyt[2] = mtex->size[2]*dy[mtex->projz - 1];
}
else dxt[2]= 0.f;
}
}
}
void do_material_tex(ShadeInput *shi)
{
@ -1509,10 +1599,12 @@ void do_material_tex(ShadeInput *shi)
float fact, facm, factt, facmm, stencilTin=1.0;
float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0;
int tex_nr, rgbnor= 0, warpdone=0;
float nu[3], nv[3], nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping
int nunvdone= 0;
if (R.r.scemode & R_NO_TEX) return;
/* here: test flag if there's a tex (todo) */
for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
/* separate tex switching */
@ -1582,7 +1674,7 @@ void do_material_tex(ShadeInput *shi)
}
else {
ShadeInputUV *suv= &shi->uv[shi->actuv];
int i;
int i = shi->actuv;
if(mtex->uvname[0] != 0) {
for(i = 0; i < shi->totuv; i++) {
@ -1596,6 +1688,47 @@ void do_material_tex(ShadeInput *shi)
co= suv->uv;
dx= suv->dxuv;
dy= suv->dyuv;
// uvmapping only, calculation of normal tangent u/v partial derivatives
// (should not be here, dudnu, dudnv, dvdnu & dvdnv should probably be part of ShadeInputUV struct,
// nu/nv in ShadeInput and this calculation should then move to shadeinput.c, shade_input_set_shade_texco() func.)
// NOTE: test for shi->obr->ob here, since vlr/obr/obi can be 'fake' when called from fastshade(), another reason to move it..
if ((mtex->texflag & MTEX_NEW_BUMP) && shi->obr && shi->obr->ob) {
if(mtex->mapto & (MAP_NORM|MAP_DISPLACE|MAP_WARP)) {
MTFace* tf = RE_vlakren_get_tface(shi->obr, shi->vlr, i, NULL, 0);
int j1 = shi->i1, j2 = shi->i2, j3 = shi->i3;
vlr_set_uv_indices(shi->vlr, &j1, &j2, &j3);
if (tf) {
float *uv1 = tf->uv[j1], *uv2 = tf->uv[j2], *uv3 = tf->uv[j3];
const float an[3] = {fabsf(nn[0]), fabsf(nn[1]), fabsf(nn[2])};
const int a1 = (an[0] > an[1] && an[0] > an[2]) ? 1 : 0;
const int a2 = (an[2] > an[0] && an[2] > an[1]) ? 1 : 2;
const float dp1_a1 = shi->v1->co[a1] - shi->v3->co[a1];
const float dp1_a2 = shi->v1->co[a2] - shi->v3->co[a2];
const float dp2_a1 = shi->v2->co[a1] - shi->v3->co[a1];
const float dp2_a2 = shi->v2->co[a2] - shi->v3->co[a2];
const float du1 = uv1[0] - uv3[0], du2 = uv2[0] - uv3[0];
const float dv1 = uv1[1] - uv3[1], dv2 = uv2[1] - uv3[1];
const float dpdu_a1 = dv2*dp1_a1 - dv1*dp2_a1;
const float dpdu_a2 = dv2*dp1_a2 - dv1*dp2_a2;
const float dpdv_a1 = du1*dp2_a1 - du2*dp1_a1;
const float dpdv_a2 = du1*dp2_a2 - du2*dp1_a2;
float d = dpdu_a1*dpdv_a2 - dpdv_a1*dpdu_a2;
float uvd = du1*dv2 - dv1*du2;
if (uvd == 0.f) uvd = 1e-5f;
if (d == 0.f) d = 1e-5f;
d = uvd / d;
dudnu = (dpdv_a2*nu[a1] - dpdv_a1*nu[a2])*d;
dvdnu = (dpdu_a1*nu[a2] - dpdu_a2*nu[a1])*d;
dudnv = (dpdv_a2*nv[a1] - dpdv_a1*nv[a2])*d;
dvdnv = (dpdu_a1*nv[a2] - dpdu_a2*nv[a1])*d;
}
}
}
}
}
else if(mtex->texco==TEXCO_WINDOW) {
@ -1621,7 +1754,7 @@ void do_material_tex(ShadeInput *shi)
}
else continue; // can happen when texco defines disappear and it renders old files
/* de pointer defines if bumping happens */
/* the pointer defines if bumping happens */
if(mtex->mapto & (MAP_NORM|MAP_DISPLACE|MAP_WARP)) {
texres.nor= norvec;
norvec[0]= norvec[1]= norvec[2]= 0.0;
@ -1632,95 +1765,150 @@ void do_material_tex(ShadeInput *shi)
VECADD(tempvec, co, warpvec);
co= tempvec;
}
if(tex->type==TEX_IMAGE) {
/* new: first swap coords, then map, then trans/scale */
if(mtex->texflag & MTEX_NEW_BUMP) {
// compute ortho basis around normal
if(!nunvdone) {
// render normal is negated
nn[0] = -shi->vn[0];
nn[1] = -shi->vn[1];
nn[2] = -shi->vn[2];
VecOrthoBasisf(nn, nu, nv);
nunvdone= 1;
}
/* placement */
if(mtex->projx) texvec[0]= co[mtex->projx-1];
else texvec[0]= 0.0;
if(mtex->projy) texvec[1]= co[mtex->projy-1];
else texvec[1]= 0.0;
if(mtex->projz) texvec[2]= co[mtex->projz-1];
else texvec[2]= 0.0;
if(texres.nor) {
TexResult ttexr = {0, 0, 0, 0, 0, texres.talpha, NULL}; // temp TexResult
float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv;
const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0));
const float bf = 0.04f*Tnor*((mtex->maptoneg & MAP_NORM) ? -mtex->norfac : mtex->norfac);
// disable internal bump eval
float* nvec = texres.nor;
texres.nor = NULL;
// du & dv estimates, constant value defaults
du = dv = 0.01f;
if(shi->osatex) {
if(mtex->projx) {
dxt[0]= dx[mtex->projx-1];
dyt[0]= dy[mtex->projx-1];
// two methods, either constant based on main image resolution,
// (which also works without osa, though of course not always good (or even very bad) results),
// or based on tex derivative max values (osa only). Not sure which is best...
if (!shi->osatex && (tex->type == TEX_IMAGE) && tex->ima) {
// in case we have no proper derivatives, fall back to
// computing du/dv it based on image size
ImBuf* ibuf = BKE_image_get_ibuf(tex->ima, &tex->iuser);
if (ibuf) {
du = 1.f/(float)ibuf->x;
dv = 1.f/(float)ibuf->y;
}
}
else dxt[0]= dyt[0]= 0.0f;
if(mtex->projy) {
dxt[1]= dx[mtex->projy-1];
dyt[1]= dy[mtex->projy-1];
else if (shi->osatex) {
// we have derivatives, can compute proper du/dv
if (tex->type == TEX_IMAGE) { // 2d image, use u & v max. of dx/dy 2d vecs
const float adx[2] = {fabsf(dx[0]), fabsf(dx[1])};
const float ady[2] = {fabsf(dy[0]), fabsf(dy[1])};
du = MAX2(adx[0], ady[0]);
dv = MAX2(adx[1], ady[1]);
}
else { // 3d procedural, estimate from all dx/dy elems
const float adx[3] = {fabsf(dx[0]), fabsf(dx[1]), fabsf(dx[2])};
const float ady[3] = {fabsf(dy[0]), fabsf(dy[1]), fabsf(dy[2])};
du = MAX3(adx[0], adx[1], adx[2]);
dv = MAX3(ady[1], ady[1], ady[2]);
}
}
else dxt[1]= dyt[1]= 0.0f;
if(mtex->projz) {
dxt[2]= dx[mtex->projz-1];
dyt[2]= dy[mtex->projz-1];
}
else dxt[2]= dyt[2]= 0.0;
}
do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
/* translate and scale */
texvec[0]= mtex->size[0]*(texvec[0]-0.5) +mtex->ofs[0]+0.5;
texvec[1]= mtex->size[1]*(texvec[1]-0.5) +mtex->ofs[1]+0.5;
if(shi->osatex) {
dxt[0]= mtex->size[0]*dxt[0];
dxt[1]= mtex->size[1]*dxt[1];
dyt[0]= mtex->size[0]*dyt[0];
dyt[1]= mtex->size[1]*dyt[1];
// center, main return value
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
cd = fromrgb ? (texres.tr + texres.tg + texres.tb)*0.33333333f : texres.tin;
if (mtex->texco == TEXCO_UV) {
// for the uv case, use the same value for both du/dv,
// since individually scaling the normal derivatives makes them useless...
du = MIN2(du, dv);
idu = (du < 1e-6f) ? bf : (bf/du);
// +u val
tco[0] = co[0] + dudnu*du;
tco[1] = co[1] + dvdnu*du;
tco[2] = 0.f;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
// +v val
tco[0] = co[0] + dudnv*du;
tco[1] = co[1] + dvdnv*du;
tco[2] = 0.f;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
}
else {
float tu[3] = {nu[0], nu[1], nu[2]}, tv[3] = {nv[0], nv[1], nv[2]};
idu = (du < 1e-6f) ? bf : (bf/du);
idv = (dv < 1e-6f) ? bf : (bf/dv);
if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) {
Mat4Mul3Vecfl(shi->obr->ob->imat, tu);
Mat4Mul3Vecfl(shi->obr->ob->imat, tv);
Normalize(tu);
Normalize(tv);
}
else if (mtex->texco == TEXCO_GLOB) {
Mat4Mul3Vecfl(R.viewinv, tu);
Mat4Mul3Vecfl(R.viewinv, tv);
}
else if (mtex->texco == TEXCO_OBJECT && mtex->object) {
Mat4Mul3Vecfl(mtex->object->imat, tu);
Mat4Mul3Vecfl(mtex->object->imat, tv);
Normalize(tu);
Normalize(tv);
}
// +u val
tco[0] = co[0] + tu[0]*du;
tco[1] = co[1] + tu[1]*du;
tco[2] = co[2] + tu[2]*du;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
// +v val
tco[0] = co[0] + tv[0]*dv;
tco[1] = co[1] + tv[1]*dv;
tco[2] = co[2] + tv[2]*dv;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
multitex(tex, texv, dxt, dyt, shi->osatex, &ttexr, shi->thread, mtex->which_output);
vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin));
}
// bumped normal
nu[0] += ud*nn[0];
nu[1] += ud*nn[1];
nu[2] += ud*nn[2];
nv[0] += vd*nn[0];
nv[1] += vd*nn[1];
nv[2] += vd*nn[2];
Crossf(nvec, nu, nv);
nvec[0] = -nvec[0];
nvec[1] = -nvec[1];
nvec[2] = -nvec[2];
texres.nor = nvec;
rgbnor |= TEX_NOR;
}
/* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
if(tex->flag & TEX_REPEAT_XMIR) {
if(texvec[0]>1.0f) texvec[0] -= (int)(texvec[0]);
else if(texvec[0]<0.0f) texvec[0]+= 1-(int)(texvec[0]);
else {
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
}
if(tex->flag & TEX_REPEAT_YMIR) {
if(texvec[1]>1.0f) texvec[1] -= (int)(texvec[1]);
else if(texvec[1]<0.0f) texvec[1]+= 1-(int)(texvec[1]);
}
}
else {
/* placement */
if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
if(shi->osatex) {
if(mtex->projx) {
dxt[0]= mtex->size[0]*dx[mtex->projx-1];
dyt[0]= mtex->size[0]*dy[mtex->projx-1];
}
else dxt[0]= 0.0;
if(mtex->projy) {
dxt[1]= mtex->size[1]*dx[mtex->projy-1];
dyt[1]= mtex->size[1]*dy[mtex->projy-1];
}
else dxt[1]= 0.0;
if(mtex->projz) {
dxt[2]= mtex->size[2]*dx[mtex->projz-1];
dyt[2]= mtex->size[2]*dy[mtex->projz-1];
}
else dxt[2]= 0.0;
}
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
rgbnor = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
}
rgbnor= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
/* texture output */
if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
@ -1785,7 +1973,7 @@ void do_material_tex(ShadeInput *shi)
if(mtex->texflag & MTEX_VIEWSPACE) {
// rotate to global coords
if(mtex->texco==TEXCO_ORCO || mtex->texco==TEXCO_UV) {
if(shi->vlr && shi->obr->ob) {
if(shi->vlr && shi->obr && shi->obr->ob) {
float len= Normalize(texres.nor);
// can be optimized... (ton)
Mat4Mul3Vecfl(shi->obr->ob->obmat, texres.nor);
@ -1897,25 +2085,32 @@ void do_material_tex(ShadeInput *shi)
}
}
else {
float nor[3], dot;
if(shi->mat->mode & MA_TANGENT_V) {
shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
if (mtex->texflag & MTEX_NEW_BUMP) {
shi->vn[0] = texres.nor[0];
shi->vn[1] = texres.nor[1];
shi->vn[2] = texres.nor[2];
}
/* prevent bump to become negative normal */
nor[0]= Tnor*tex->norfac*texres.nor[0];
nor[1]= Tnor*tex->norfac*texres.nor[1];
nor[2]= Tnor*tex->norfac*texres.nor[2];
dot= 0.5f + 0.5f*INPR(nor, shi->vn);
shi->vn[0]+= dot*nor[0];
shi->vn[1]+= dot*nor[1];
shi->vn[2]+= dot*nor[2];
}
else {
float nor[3], dot;
if(shi->mat->mode & MA_TANGENT_V) {
shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
}
/* prevent bump to become negative normal */
nor[0]= Tnor*tex->norfac*texres.nor[0];
nor[1]= Tnor*tex->norfac*texres.nor[1];
nor[2]= Tnor*tex->norfac*texres.nor[2];
dot= 0.5f + 0.5f*INPR(nor, shi->vn);
shi->vn[0]+= dot*nor[0];
shi->vn[1]+= dot*nor[1];
shi->vn[2]+= dot*nor[2];
}
}
Normalize(shi->vn);
/* this makes sure the bump is passed on to the next texture */
@ -2628,7 +2823,7 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
texr.nor= NULL;
if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr);
if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr);
else imagewrap(tex, ima, NULL, texvec, &texr);
shi->vcol[0]*= texr.tr;