2.5: Bump Mapping
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 21 Jul 2009 13:46:49 +0000 (13:46 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Tue, 21 Jul 2009 13:46:49 +0000 (13:46 +0000)
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.

release/ui/buttons_data_mesh.py
source/blender/blenkernel/intern/material.c
source/blender/blenkernel/intern/texture.c
source/blender/blenlib/intern/arithb.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/source/convertblender.c
source/blender/render/intern/source/shadeinput.c
source/blender/render/intern/source/texture.c

index d4bf9698a895d3d9326286df17ae350a857af94f..757745d039ea87db0d4bf7734699bc7f49a3f49f 100644 (file)
@@ -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"
index 088b1b6e0c204351c73e4784e7c0918d18dd97e3..bee63f497ca4884de8174a0b156a04ab0460061d 100644 (file)
@@ -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;
index db864dc9f1eb999048ede02430f9579ab915a691..1c7dab15d5cdd3b46ab82c76e3e2a51c079c9e55 100644 (file)
@@ -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;
index 03be10dd0b12f26b7b21901db6679fcc51fd944f..f7313c8b37aa54e1c65d9cc45dfbf1c38ec1ac68 100644 (file)
@@ -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];
        }
 }
 
index 6da444bc88eb791b42da158f926af51937dc60d4..bbe85c5f3781b1ccfa19d3f789e618fd73a98281 100644 (file)
@@ -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) {
index e1dd21a8ccb14b3e3ed1f74ec58d14f5bdf57ab4..0760825670dc74cf350541347ef4142792e2530e 100644 (file)
@@ -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
index 6686d43d0759dfc1225ceee9d64a7fe45041d1fc..fd54dd959b24fab78ae213cfd713ac1237aeb889 100644 (file)
@@ -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)
index da77d578efc94fb597209982c9832821d1c638f6..5853b51a6b1616d39a51c3b4c7acc87c766f4558 100644 (file)
@@ -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;
index 931595eae60736fc77079b048989996cdabdfe6a..6b1d11be6f34fb2874c3fc0c43d593ade6a97365 100644 (file)
@@ -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];
index 9466bd454208b33e4555d82101bfcff0e8ef8466..3f7ffc5b9bb4440c59831c61cb70bd795d506031 100644 (file)
@@ -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,94 +1765,149 @@ 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 */
 
-                               /* 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(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;
+                               }
 
-                               if(shi->osatex) {
-                                       
-                                       if(mtex->projx) {
-                                               dxt[0]= dx[mtex->projx-1];
-                                               dyt[0]= dy[mtex->projx-1];
-                                       }
-                                       else dxt[0]= dyt[0]= 0.0f;
-                                       
-                                       if(mtex->projy) {
-                                               dxt[1]= dx[mtex->projy-1];
-                                               dyt[1]= dy[mtex->projy-1];
+                               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;
+
+                                       // 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[1]= dyt[1]= 0.0f;
-                                       if(mtex->projz) {
-                                               dxt[2]= dx[mtex->projz-1];
-                                               dyt[2]= dy[mtex->projz-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[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];
-                               }
-                               
-                               /* 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]);
-                               }
-                               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]);
+                                       // 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]};
 
-                               if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
-                               else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+                                               idu = (du < 1e-6f) ? bf : (bf/du);
+                                               idv = (dv < 1e-6f) ? bf : (bf/dv);
 
-                               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 ((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);
+                                               }
 
-                               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];
+                                               // +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));
                                        }
-                                       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;
+
+                                       // 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;
+                               }
+                               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);
                                }
                        }
-
-                       rgbnor= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output);
+                       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);
+                       }
 
                        /* texture output */
 
@@ -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;