new bumpmapping options for the renderer
authorM.G. Kishalmi <lmg@kishalmi.net>
Sat, 29 Jan 2011 11:56:11 +0000 (11:56 +0000)
committerM.G. Kishalmi <lmg@kishalmi.net>
Sat, 29 Jan 2011 11:56:11 +0000 (11:56 +0000)
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)

release/scripts/ui/properties_texture.py
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/texture.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_texture_types.h
source/blender/makesrna/intern/rna_material.c
source/blender/render/intern/include/texture.h
source/blender/render/intern/source/texture.c

index 701fa1eb3360db69351100d16170e13efede6060..bd9f1a3b13fd2fee0d3cf3b1716418edd8ed9b0b 100644 (file)
@@ -994,11 +994,6 @@ class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel):
         # color is used on grayscale textures even when use_rgb_to_intensity is disabled.
         col.prop(tex, "color", text="")
 
-        if isinstance(idblock, bpy.types.Material):
-            sub = layout.row()
-            sub.prop(tex, "bump_method", text="Bump Method")
-            sub.active = tex.use_map_normal
-
         col = split.column()
         col.prop(tex, "invert", text="Negative")
         col.prop(tex, "use_stencil")
@@ -1006,6 +1001,21 @@ class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel):
         if isinstance(idblock, bpy.types.Material) or isinstance(idblock, bpy.types.World):
             col.prop(tex, "default_value", text="DVar", slider=True)
 
+        if isinstance(idblock, bpy.types.Material):
+            row = layout.row()
+            row.label(text="Bump Mapping:")
+
+            row = layout.row()
+            # only show bump settings if activated but not for normalmap images
+            row.active = tex.use_map_normal and not( tex.texture.type == 'IMAGE' and tex.texture.use_normal_map )
+
+            col = row.column()
+            col.prop(tex, "bump_method", text="Method")
+
+            col = row.column()
+            col.prop(tex, "bump_objectspace", text="Space")
+            col.active = tex.bump_method in ('BUMP_DEFAULT', 'BUMP_BEST_QUALITY')
+
 
 class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, bpy.types.Panel):
     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
index c22384a6bdc3639c1f68c0d5f62bf79f21b802f2..c49d8310789d1712ebe26c3045d2cbc98a90bd83 100644 (file)
@@ -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;
index 11c0ce74b4aded4fcc9f168bee55321936526a93..48903fa5f5f3aed7c563348b83b1e6629f5303e1 100644 (file)
@@ -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;
index e34a84139aaeee37e57ca4078ed8498f2cc8070f..772306373424e127be89c7438c094206841dda3e 100644 (file)
@@ -9991,12 +9991,15 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                        for(a=0; a<MAX_MTEX; a++) {
                                if(ma->mtex[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;
+                                               }
                                        }
                                }
                        }
index 4d11890f5a546f304e92e6858635407f8eb8d615..41eebca821c0c02c4ca488fe0a7c302d344ab027 100644 (file)
@@ -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
index aecb89a0fee6929af622892e99d3beae52939611..4c8ed475a8d132595abe8ab2f4b8f8bebfcf7a83 100644 (file)
@@ -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)
index fb941d1b7f3335d7ebf8ca22164b115be6d7d741..8eb91f3299f1d3c514a78e4261fa02dfdb522016 100644 (file)
@@ -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;
index 9563e80294538855803222efcd7cb175036a5f95..a243149254e227ce115e138a4471f4530ec3309c 100644 (file)
@@ -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; c<nr_channels; c++) {
+                       // dx contains the derivatives (du/dx, dv/dx)
+                       // dy contains the derivatives (du/dy, dv/dy)
+                       STll[c] = texvec[c];
+                       STlr[c] = texvec[c]+dxt[c];
+                       STul[c] = texvec[c]+dyt[c];
+               }
+
+               // clear unused derivatives
+               for(c=nr_channels; c<3; c++) {
+                       STll[c] = 0.0f;
+                       STlr[c] = 0.0f;
+                       STul[c] = 0.0f;
+               }
+
+               // use texres for the center sample, set rgbnor
+               rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres);
+               Hll = (fromrgb)? RGBTOBW(texres->tr, 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; c<nr_channels; c++) {
+                       STc[c] = texvec[c];
+                       STl[c] = texvec[c] - 0.5f*dxt[c];
+                       STr[c] = texvec[c] + 0.5f*dxt[c];
+                       STd[c] = texvec[c] - 0.5f*dyt[c];
+                       STu[c] = texvec[c] + 0.5f*dyt[c];
+               }
+
+               // clear unused derivatives
+               for(c=nr_channels; c<3; c++) {
+                       STc[c] = 0.0f;
+                       STl[c] = 0.0f;
+                       STr[c] = 0.0f;
+                       STd[c] = 0.0f;
+                       STu[c] = 0.0f;
+               }
+
+               // use texres for the center sample, set rgbnor
+               rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres);
+               Hc = (fromrgb)? RGBTOBW(texres->tr, 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];