|
|
|
@ -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,8 +2104,14 @@ 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) {
|
|
|
|
@ -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;
|
|
|
|
|
if(use_compat_bump) {
|
|
|
|
|
rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex,
|
|
|
|
|
&texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
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];
|
|
|
|
|