From c709524dc9a2489c9f0af7107ad5246952d2250f Mon Sep 17 00:00:00 2001 From: "M.G. Kishalmi" Date: Sat, 29 Jan 2011 11:56:11 +0000 Subject: new bumpmapping options for the renderer oldbump -> original newbump -> compatible *new* -> default (3tap) *new* -> best quality (5tap) the latter two have an option to apply bumpmapping in viewspace - much like displacement mapping objectspace - default (scales with the object) texturespace - much like normal mapping (scales) --- source/blender/blenkernel/intern/material.c | 2 +- source/blender/blenkernel/intern/texture.c | 3 +- source/blender/blenloader/intern/readfile.c | 13 +- source/blender/makesdna/DNA_texture_types.h | 6 +- source/blender/makesrna/intern/rna_material.c | 16 +- source/blender/render/intern/include/texture.h | 1 + source/blender/render/intern/source/texture.c | 619 +++++++++++++++++-------- 7 files changed, 463 insertions(+), 197 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index c22384a6bdc..c49d8310789 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -820,7 +820,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) /* always get derivatives for these textures */ 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; + else if(mtex->texflag & (MTEX_COMPAT_BUMP|MTEX_3TAP_BUMP|MTEX_5TAP_BUMP)) ma->texco |= TEXCO_OSA; if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1; else if(ma->texco & (TEXCO_GLOB|TEXCO_UV|TEXCO_OBJECT|TEXCO_SPEED)) needuv= 1; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 11c0ce74b4a..48903fa5f5f 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -630,7 +630,8 @@ void default_mtex(MTex *mtex) mtex->size[1]= 1.0; mtex->size[2]= 1.0; mtex->tex= 0; - mtex->texflag= MTEX_NEW_BUMP; + mtex->texflag= MTEX_3TAP_BUMP; + mtex->texflag= MTEX_BUMP_OBJECTSPACE; mtex->colormodel= 0; mtex->r= 1.0; mtex->g= 0.0; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index e34a84139aa..77230637342 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9991,12 +9991,15 @@ static void do_versions(FileData *fd, Library *lib, Main *main) for(a=0; amtex[a]) { tex= ma->mtex[a]->tex; - if(!tex) - ma->mtex[a]->texflag |= MTEX_NEW_BUMP; - else { + if(!tex) { + ma->mtex[a]->texflag |= MTEX_3TAP_BUMP; + ma->mtex[a]->texflag |= MTEX_BUMP_OBJECTSPACE; + } else { tex= (Tex*)newlibadr(fd, ma->id.lib, tex); - if(tex && tex->type == 0) /* invalid type */ - ma->mtex[a]->texflag |= MTEX_NEW_BUMP; + if(tex && tex->type == 0) { /* invalid type */ + ma->mtex[a]->texflag |= MTEX_3TAP_BUMP; + ma->mtex[a]->texflag |= MTEX_BUMP_OBJECTSPACE; + } } } } diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 4d11890f5a5..41eebca821c 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -454,7 +454,11 @@ typedef struct TexMapping { #define MTEX_VIEWSPACE 16 #define MTEX_DUPLI_MAPTO 32 #define MTEX_OB_DUPLI_ORIG 64 -#define MTEX_NEW_BUMP 128 +#define MTEX_COMPAT_BUMP 128 +#define MTEX_3TAP_BUMP 256 +#define MTEX_5TAP_BUMP 512 +#define MTEX_BUMP_OBJECTSPACE 1024 +#define MTEX_BUMP_TEXTURESPACE 2048 /* blendtype */ #define MTEX_BLEND 0 diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index aecb89a0fee..4c8ed475a8d 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -378,9 +378,17 @@ static void rna_def_material_mtex(BlenderRNA *brna) static EnumPropertyItem prop_bump_method_items[] = { {0, "BUMP_ORIGINAL", 0, "Original", ""}, - {MTEX_NEW_BUMP, "BUMP_IMPROVED", 0, "Improved", ""}, + {MTEX_COMPAT_BUMP, "BUMP_COMPATIBLE", 0, "Compatible", ""}, + {MTEX_3TAP_BUMP, "BUMP_DEFAULT", 0, "Default", ""}, + {MTEX_5TAP_BUMP, "BUMP_BEST_QUALITY", 0, "Best Quality", ""}, {0, NULL, 0, NULL, NULL}}; + static EnumPropertyItem prop_bump_space_items[] = { + {0, "BUMP_VIEWSPACE", 0, "ViewSpace", ""}, + {MTEX_BUMP_OBJECTSPACE, "BUMP_OBJECTSPACE", 0, "ObjectSpace", ""}, + {MTEX_BUMP_TEXTURESPACE, "BUMP_TEXTURESPACE", 0, "TextureSpace", ""}, + {0, NULL, 0, NULL, NULL}}; + srna= RNA_def_struct(brna, "MaterialTextureSlot", "TextureSlot"); RNA_def_struct_sdna(srna, "MTex"); RNA_def_struct_ui_text(srna, "Material Texture Slot", "Texture slot for textures in a Material datablock"); @@ -687,6 +695,12 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_enum_items(prop, prop_bump_method_items); RNA_def_property_ui_text(prop, "Bump Method", "Method to use for bump mapping"); RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop= RNA_def_property(srna, "bump_objectspace", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "texflag"); + RNA_def_property_enum_items(prop, prop_bump_space_items); + RNA_def_property_ui_text(prop, "Bump Space", "Space to apply bump mapping in"); + RNA_def_property_update(prop, 0, "rna_Material_update"); } static void rna_def_material_colors(StructRNA *srna) diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h index fb941d1b7f3..8eb91f3299f 100644 --- a/source/blender/render/intern/include/texture.h +++ b/source/blender/render/intern/include/texture.h @@ -48,6 +48,7 @@ if(tex->saturation != 1.0f) { \ hsv_to_rgb(_hsv[0], _hsv[1], _hsv[2], &texres->tr, &texres->tg, &texres->tb); \ } \ +#define RGBTOBW(r,g,b) ( r*0.35 + g*0.45 + b*0.2 ) /* keep this in sync with gpu_shader_material.glsl:rgbtobw */ struct HaloRen; struct ShadeInput; diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 9563e802945..a243149254e 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1607,6 +1607,7 @@ static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, floa 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) { @@ -1615,6 +1616,7 @@ static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, floa 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. @@ -1667,6 +1669,410 @@ static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, floa } } +/* Bump code from 2.5 development cycle, has a number of bugs, but here for compatibility */ + +typedef struct CompatibleBump { + float nu[3], nv[3], nn[3]; + float dudnu, dudnv, dvdnu, dvdnv; + int nunvdone; +} CompatibleBump; + +static void compatible_bump_init(CompatibleBump *compat_bump) +{ + memset(compat_bump, 0, sizeof(*compat_bump)); + + compat_bump->dudnu = 1.0f; + compat_bump->dvdnv = 1.0f; +} + +static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, int i) +{ + // 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.. + // NOTE: shi->v1 is NULL when called from displace_render_vert, assigning verts in this case is not trivial because the shi quad face side is not know. + if ((mtex->texflag & MTEX_COMPAT_BUMP) && shi->obr && shi->obr->ob && shi->v1) { + if(mtex->mapto & (MAP_NORM|MAP_WARP) && !((mtex->tex->type==TEX_IMAGE) && (mtex->tex->imaflag & TEX_NORMALMAP))) { + 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); + + // compute ortho basis around normal + if(!compat_bump->nunvdone) { + // render normal is negated + compat_bump->nn[0] = -shi->vn[0]; + compat_bump->nn[1] = -shi->vn[1]; + compat_bump->nn[2] = -shi->vn[2]; + ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn); + compat_bump->nunvdone= 1; + } + + if (tf) { + float *uv1 = tf->uv[j1], *uv2 = tf->uv[j2], *uv3 = tf->uv[j3]; + const float an[3] = {fabsf(compat_bump->nn[0]), fabsf(compat_bump->nn[1]), fabsf(compat_bump->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; + + compat_bump->dudnu = (dpdv_a2*compat_bump->nu[a1] - dpdv_a1*compat_bump->nu[a2])*d; + compat_bump->dvdnu = (dpdu_a1*compat_bump->nu[a2] - dpdu_a2*compat_bump->nu[a1])*d; + compat_bump->dudnv = (dpdv_a2*compat_bump->nv[a1] - dpdv_a1*compat_bump->nv[a2])*d; + compat_bump->dvdnv = (dpdu_a1*compat_bump->nv[a2] - dpdu_a2*compat_bump->nv[a1])*d; + } + } + } +} + +static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, float Tnor, float *co, float *dx, float *dy, float *texvec, float *dxt, float *dyt) +{ + 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->norfac; + int rgbnor; + // disable internal bump eval + float* nvec = texres->nor; + texres->nor = NULL; + // du & dv estimates, constant value defaults + du = dv = 0.01f; + + // compute ortho basis around normal + if(!compat_bump->nunvdone) { + // render normal is negated + negate_v3_v3(compat_bump->nn, shi->vn); + ortho_basis_v3v3_v3(compat_bump->nu, compat_bump->nv, compat_bump->nn); + compat_bump->nunvdone= 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 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]); + } + } + + // center, main return value + texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); + rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres); + 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-5f) ? bf : (bf/du); + + // +u val + tco[0] = co[0] + compat_bump->dudnu*du; + tco[1] = co[1] + compat_bump->dvdnu*du; + tco[2] = 0.f; + texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); + + // +v val + tco[0] = co[0] + compat_bump->dudnv*du; + tco[1] = co[1] + compat_bump->dvdnv*du; + tco[2] = 0.f; + texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt); + multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); + } + else { + float tu[3], tv[3]; + + copy_v3_v3(tu, compat_bump->nu); + copy_v3_v3(tv, compat_bump->nv); + + idu = (du < 1e-5f) ? bf : (bf/du); + idv = (dv < 1e-5f) ? bf : (bf/dv); + + if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) { + mul_mat3_m4_v3(shi->obr->ob->imat, tu); + mul_mat3_m4_v3(shi->obr->ob->imat, tv); + normalize_v3(tu); + normalize_v3(tv); + } + else if (mtex->texco == TEXCO_GLOB) { + mul_mat3_m4_v3(R.viewinv, tu); + mul_mat3_m4_v3(R.viewinv, tv); + } + else if (mtex->texco == TEXCO_OBJECT && mtex->object) { + mul_mat3_m4_v3(mtex->object->imat, tu); + mul_mat3_m4_v3(mtex->object->imat, tv); + normalize_v3(tu); + normalize_v3(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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + 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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); + vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb)*0.33333333f : ttexr.tin)); + } + + // bumped normal + compat_bump->nu[0] += ud*compat_bump->nn[0]; + compat_bump->nu[1] += ud*compat_bump->nn[1]; + compat_bump->nu[2] += ud*compat_bump->nn[2]; + compat_bump->nv[0] += vd*compat_bump->nn[0]; + compat_bump->nv[1] += vd*compat_bump->nn[1]; + compat_bump->nv[2] += vd*compat_bump->nn[2]; + cross_v3_v3v3(nvec, compat_bump->nu, compat_bump->nv); + + nvec[0] = -nvec[0]; + nvec[1] = -nvec[1]; + nvec[2] = -nvec[2]; + texres->nor = nvec; + + rgbnor |= TEX_NOR; + return rgbnor; +} + +/* Improved bump code from later in 2.5 development cycle */ + +typedef struct NTapBump { + int nunvdone; + + // bumpmapping + float vNacc[3]; // original surface normal minus the surface gradient of every bump map which is encountered + float vR1[3], vR2[3]; // cross products (sigma_y, original_normal), (original_normal, sigma_x) + float sgn_det; // sign of the determinant of the matrix {sigma_x, sigma_y, original_normal} +} NTapBump; + +static void ntap_bump_init(NTapBump *ntap_bump) +{ + memset(ntap_bump, 0, sizeof(*ntap_bump)); +} + +static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres, float Tnor, float *co, float *dx, float *dy, float *texvec, float *dxt, float *dyt) +{ + TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; // temp TexResult + + const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0)); + // TODO: solve this Hscale issue more elegantly. + float Hscale = 0.1f * Tnor*mtex->norfac; // factor 0.1 proved to look like the previous bump code + if( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) + Hscale *= 130.0f; + + // 2 channels for 2D texture and 3 for 3D textures. + const int nr_channels = (mtex->texco == TEXCO_UV)? 2 : 3; + int c, rgbnor; + float dHdx, dHdy; + + // disable internal bump eval in sampler, save pointer + float *nvec = texres->nor; + texres->nor = NULL; + + if(!(mtex->texflag & MTEX_5TAP_BUMP)) { + // compute height derivatives with respect to output image pixel coordinates x and y + float STll[3], STlr[3], STul[3]; + float Hll, Hlr, Hul; + + texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); + + for(c=0; ctr, texres->tg, texres->tb) : texres->tin; + + // use ttexr for the other 2 taps + multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr); + Hlr = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + + multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr); + Hul = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + + dHdx = Hscale*(Hlr - Hll); + dHdy = Hscale*(Hul - Hll); + } + else { + /* same as above, but doing 5 taps, increasing quality at cost of speed */ + float STc[3], STl[3], STr[3], STd[3], STu[3]; + float Hc, Hl, Hr, Hd, Hu; + + texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); + + for(c=0; ctr, texres->tg, texres->tb) : texres->tin; + + // use ttexr for the other taps + multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr); + Hl = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr); + Hr = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr); + Hd = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr); + Hu = (fromrgb)? RGBTOBW(ttexr.tr, ttexr.tg, ttexr.tb) : ttexr.tin; + + dHdx = Hscale*(Hr - Hl); + dHdy = Hscale*(Hu - Hd); + } + + // restore pointer + texres->nor = nvec; + + /* replaced newbump with code based on listing 1 and 2 of + [Mik10] Mikkelsen M. S.: Bump Mapping Unparametrized Surfaces on the GPU. + -> http://jbit.net/~sparky/sfgrad_bump/mm_sfgrad_bump.pdf */ + + if(!ntap_bump->nunvdone) { + // initialize normal perturbation vectors + int xyz; + float fDet, abs_fDet; + // object2view and inverted matrix + float obj2view[3][3], view2obj[3][3], tmp[4][4]; + // local copies of derivatives and normal + float dPdx[3], dPdy[3], vN[3]; + VECCOPY(dPdx, shi->dxco); + VECCOPY(dPdy, shi->dyco); + VECCOPY(vN, shi->vn); + + if( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) { + // TODO: these calculations happen for every pixel! + // -> move to shi->obi + mul_m4_m4m4(tmp, shi->obr->ob->obmat, R.viewmat); + copy_m3_m4(obj2view, tmp); // use only upper left 3x3 matrix + invert_m3_m3(view2obj, obj2view); + + // generate the surface derivatives in object space + mul_m3_v3(view2obj, dPdx); + mul_m3_v3( view2obj, dPdy ); + // generate the unit normal in object space + mul_transposed_m3_v3( obj2view, vN ); + normalize_v3(vN); + } + + cross_v3_v3v3(ntap_bump->vR1, dPdy, vN); + cross_v3_v3v3(ntap_bump->vR2, vN, dPdx); + fDet = dot_v3v3(dPdx, ntap_bump->vR1); + ntap_bump->sgn_det = (fDet < 0)? -1.0f: 1.0f; + abs_fDet = ntap_bump->sgn_det * fDet; + + if( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) { + // crazy hack solution that gives results similar to normal mapping - part 1 + normalize_v3(ntap_bump->vR1); + normalize_v3(ntap_bump->vR2); + abs_fDet = 1.0f; + } + + for(xyz=0; xyz<3; xyz++) + ntap_bump->vNacc[xyz] = abs_fDet * vN[xyz]; + + if( mtex->texflag & MTEX_BUMP_OBJECTSPACE ) { + // pre do transform of texres->nor by the inverse transposed of obj2view + mul_transposed_m3_v3( view2obj, ntap_bump->vNacc ); + mul_transposed_m3_v3( view2obj, ntap_bump->vR1 ); + mul_transposed_m3_v3( view2obj, ntap_bump->vR2 ); + } + + ntap_bump->nunvdone= 1; + } + + if( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) { + // crazy hack solution that gives results similar to normal mapping - part 2 + float vec[2]; + vec[0] = tex->ima->gen_x*dxt[0]; + vec[1] = tex->ima->gen_y*dxt[1]; + dHdx *= 1.0f/len_v2(vec); + vec[0] = tex->ima->gen_x*dyt[0]; + vec[1] = tex->ima->gen_y*dyt[1]; + dHdy *= 1.0f/len_v2(vec); + } + + // subtract the surface gradient from vNacc + for(c=0; c<3; c++) { + float vSurfGrad_compi = ntap_bump->sgn_det * (dHdx * ntap_bump->vR1[c] + dHdy * ntap_bump->vR2[c]); + ntap_bump->vNacc[c] -= vSurfGrad_compi; + texres->nor[c] = ntap_bump->vNacc[c]; // copy + } + + rgbnor |= TEX_NOR; + return rgbnor; +} + void do_material_tex(ShadeInput *shi) { MTex *mtex; @@ -1676,8 +2082,13 @@ 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] = {0,0,0}, nv[3] = {0,0,0}, nn[3] = {0,0,0}, dudnu = 1.f, dudnv = 0.f, dvdnu = 0.f, dvdnv = 1.f; // bump mapping - int nunvdone= 0, newbump; + + CompatibleBump compat_bump; + NTapBump ntap_bump; + int use_compat_bump, use_ntap_bump; + + compatible_bump_init(&compat_bump); + ntap_bump_init(&ntap_bump); if (R.r.scemode & R_NO_TEX) return; /* here: test flag if there's a tex (todo) */ @@ -1693,9 +2104,15 @@ void do_material_tex(ShadeInput *shi) tex= mtex->tex; if(tex==0) continue; + use_compat_bump= (mtex->texflag & MTEX_COMPAT_BUMP); + use_ntap_bump= (mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP)); + /* XXX texture node trees don't work for this yet */ - newbump= (mtex->texflag & MTEX_NEW_BUMP) && !(tex->nodetree && tex->use_nodes); - + if(tex->nodetree && tex->use_nodes) { + use_compat_bump = 0; + use_ntap_bump = 0; + } + /* which coords */ if(mtex->texco==TEXCO_ORCO) { if(mtex->texflag & MTEX_DUPLI_MAPTO) { @@ -1769,57 +2186,7 @@ void do_material_tex(ShadeInput *shi) 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.. - // NOTE: shi->v1 is NULL when called from displace_render_vert, assigning verts in this case is not trivial because the shi quad face side is not know. - if ((mtex->texflag & MTEX_NEW_BUMP) && shi->obr && shi->obr->ob && shi->v1) { - if(mtex->mapto & (MAP_NORM|MAP_WARP) && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) { - 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); - - // 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]; - ortho_basis_v3v3_v3( nu, nv,nn); - nunvdone= 1; - } - - 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; - } - } - } + compatible_bump_uv_derivs(&compat_bump, shi, mtex, i); } } else if(mtex->texco==TEXCO_WINDOW) { @@ -1858,138 +2225,14 @@ void do_material_tex(ShadeInput *shi) } /* XXX texture node trees don't work for this yet */ - if(newbump) { - // 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]; - ortho_basis_v3v3_v3( nu, nv,nn); - nunvdone= 1; - } - - if(texres.nor && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) { - 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*stencilTin*mtex->norfac; - // disable internal bump eval - float* nvec = texres.nor; - texres.nor = NULL; - // du & dv estimates, constant value defaults - du = dv = 0.01f; - - // 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 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]); - } - } - - // center, main return value - texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); - rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres); - 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-5f) ? 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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); - 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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); - 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-5f) ? bf : (bf/du); - idv = (dv < 1e-5f) ? bf : (bf/dv); - - if ((mtex->texco == TEXCO_ORCO) && shi->obr && shi->obr->ob) { - mul_mat3_m4_v3(shi->obr->ob->imat, tu); - mul_mat3_m4_v3(shi->obr->ob->imat, tv); - normalize_v3(tu); - normalize_v3(tv); - } - else if (mtex->texco == TEXCO_GLOB) { - mul_mat3_m4_v3(R.viewinv, tu); - mul_mat3_m4_v3(R.viewinv, tv); - } - else if (mtex->texco == TEXCO_OBJECT && mtex->object) { - mul_mat3_m4_v3(mtex->object->imat, tu); - mul_mat3_m4_v3(mtex->object->imat, tv); - normalize_v3(tu); - normalize_v3(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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); - 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_mtex(shi, mtex, texv, dxt, dyt, &ttexr); - 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]; - cross_v3_v3v3(nvec, nu, nv); - - nvec[0] = -nvec[0]; - nvec[1] = -nvec[1]; - nvec[2] = -nvec[2]; - texres.nor = nvec; - rgbnor |= TEX_NOR; + if(texres.nor && !((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP))) { + if(use_compat_bump) { + rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex, + &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt); + } + else if(use_ntap_bump) { + rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex, + &texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt); } else { texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt); @@ -2184,7 +2427,7 @@ void do_material_tex(ShadeInput *shi) } else { /* XXX texture node trees don't work for this yet */ - if (newbump) { + if (use_compat_bump || use_ntap_bump) { shi->vn[0] = texres.nor[0]; shi->vn[1] = texres.nor[1]; shi->vn[2] = texres.nor[2]; -- cgit v1.2.3