From a60c5901dc806f1567ccbb3b182f7a2e566797c8 Mon Sep 17 00:00:00 2001 From: Porteries Tristan Date: Sat, 29 Jul 2017 18:03:09 +0200 Subject: [PATCH] UPBGE: Fix parallax and normal tangent. Previously the tangent was not changed when the texture was rotated using the "rotation" value in texture panel. Because this vector was not rotated along the face normal it caused the normal mapping to not change the shading what ever the orientation and it caused parallax to use odd workaround to counter the wrong tangent vector. When the tangent is properly rotated around the normal thanks to the function mtex_tangent_rotate, this tangent is sent to the parallax and normal function as it. In consideration the size and mat attributes are not anymore sent to the parallax function. Note that the function mtex_mapping_transform now construct the matrix internally and justify the erasing of math_rot_mat. --- source/blender/gpu/intern/gpu_material.c | 56 +++++++++++-------- .../gpu/shaders/gpu_shader_material.glsl | 34 ++++++----- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 3af18b99d9d6..831b6dc29d83 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -1295,7 +1295,7 @@ static void do_material_tex(GPUShadeInput *shi) GPUMaterial *mat = shi->gpumat; MTex *mtex; Tex *tex; - GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac, *rotmat; + GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac, *tangent; GPUNodeLink *texco_norm, *texco_orco, *texco_object; GPUNodeLink *texco_global, *texco_uv = NULL; GPUNodeLink *newnor, *orn; @@ -1332,31 +1332,35 @@ static void do_material_tex(GPUShadeInput *shi) if (ma->mtex[tex_nr]) { mtex = ma->mtex[tex_nr]; tex = mtex->tex; - if (tex == NULL || !((mtex->texflag & MTEX_PARALLAX_UV) || (mtex->mapto & MAP_PARALLAX)) || mtex->texco != TEXCO_UV) { + + if (tex == NULL || !(mtex->mapto & MAP_PARALLAX)) { continue; } + GPU_link(mat, "mtex_tangent_rotate", GPU_attribute(CD_TANGENT, ""), orn, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + &tangent); + GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv); texco = texco_uv; - if (mtex->mapto & MAP_PARALLAX) { - GPU_link(mat, "mat_math_rot", GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), &rotmat); - GPU_link(mat, "mtex_mapping_transform", texco, rotmat, - GPU_select_uniform(mtex->ofs, GPU_DYNAMIC_TEX_UVOFFSET, NULL, ma), - GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), - &texco); - - discard = (mtex->parflag & MTEX_DISCARD_AT_EDGES) != 0 ? 1.0f : 0.0f; - GPU_link(mat, "parallax_out", texco, - GPU_builtin(GPU_VIEW_POSITION), GPU_attribute(CD_TANGENT, ""), - GPU_builtin(GPU_VIEW_NORMAL), - GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), rotmat, - GPU_image(tex->ima, &tex->iuser, false), - GPU_select_uniform(&mtex->parallaxsteps, GPU_DYNAMIC_TEX_PARALLAXSTEP, NULL, ma), - GPU_select_uniform(&mtex->parallaxbumpsc, GPU_DYNAMIC_TEX_PARALLAXBUMP, NULL, ma), - GPU_uniform(&discard), - &parco); - } + GPU_link(mat, "mtex_mapping_transform", texco, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + GPU_select_uniform(mtex->ofs, GPU_DYNAMIC_TEX_UVOFFSET, NULL, ma), + GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), + &texco); + + discard = (mtex->parflag & MTEX_DISCARD_AT_EDGES) != 0 ? 1.0f : 0.0f; + GPU_link(mat, "mtex_parallax", texco, + GPU_builtin(GPU_VIEW_POSITION), tangent, orn, + GPU_image(tex->ima, &tex->iuser, false), + GPU_select_uniform(&mtex->parallaxsteps, GPU_DYNAMIC_TEX_PARALLAXSTEP, NULL, ma), + GPU_select_uniform(&mtex->parallaxbumpsc, GPU_DYNAMIC_TEX_PARALLAXBUMP, NULL, ma), + GPU_uniform(&discard), + &parco); + + // only one parallax per material. + break; } } @@ -1410,8 +1414,8 @@ static void do_material_tex(GPUShadeInput *shi) (mtex->ofs[0] == 0.0f || mtex->ofs[1] == 0.0f) || (mtex->rot != 0.0f))) { - GPU_link(mat, "mat_math_rot", GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), &rotmat); - GPU_link(mat, "mtex_mapping_transform", texco, rotmat, + GPU_link(mat, "mtex_mapping_transform", texco, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), GPU_select_uniform(mtex->ofs, GPU_DYNAMIC_TEX_UVOFFSET, NULL, ma), GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), &texco); @@ -1547,18 +1551,22 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor); if (mtex->normapspace == MTEX_NSPACE_TANGENT) { + GPU_link(mat, "mtex_tangent_rotate", GPU_attribute(CD_TANGENT, ""), orn, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + &tangent); + if (iFirstTimeNMap != 0) { // use unnormalized normal (this is how we bake it - closer to gamedev) GPUNodeLink *vNegNorm; GPU_link(mat, "vec_math_negate", GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm); GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor); + tangent, vNegNorm, tnor, &newnor); iFirstTimeNMap = 0; } else { /* otherwise use accumulated perturbations */ GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor); + tangent, shi->vn, tnor, &newnor); } } else if (mtex->normapspace == MTEX_NSPACE_OBJECT) { diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index e4e866be3cfa..e5696b53ac14 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -494,13 +494,6 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot) outdot = dot(normalize(dir), nor); } -void mat_math_rot(float rot, out mat3 mat) -{ - mat = mat3(cos(rot), -sin(rot), 0.0, - sin(rot), cos(rot), 0.0, - 0.0, 0.0, 1.0); -} - void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec) { outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x; @@ -1384,14 +1377,25 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco) outtexco = texco + ofs; } +void mtex_tangent_rotate(vec4 tangent, vec3 n, float rot, out vec4 outtangent) +{ + float cosr = cos(rot); + float sinr = sin(rot); + outtangent.xyz = tangent.xyz * cosr + cross(tangent.xyz, n) * sinr - n * dot(tangent.xyz, n) * (1.0 - cosr); + outtangent.w = tangent.w; +} + void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco) { outtexco = size * texco; } -void mtex_mapping_transform(vec3 texco, mat3 mat, vec3 ofs, vec3 size, out vec3 outtexco) +void mtex_mapping_transform(vec3 texco, float rot, vec3 ofs, vec3 size, out vec3 outtexco) { - outtexco = (texco - vec3(0.5)) * mat * size + vec3(0.5) + ofs; + mat2 mat = mat2(cos(rot), -sin(rot), + sin(rot), cos(rot)); + + outtexco = vec3((texco.xy - vec2(0.5)) * mat, texco.z - 0.5) * size + vec3(0.5) + ofs; } void mtex_2d_mapping(vec3 vec, out vec3 outvec) @@ -4042,15 +4046,17 @@ void node_output_world(vec4 surface, vec4 volume, out vec4 result) result = surface; } -void parallax_out(vec3 texco, vec3 vp, vec4 tangent, vec3 vn, vec3 size, mat3 mat, sampler2D ima, float numsteps, +void mtex_parallax(vec3 texco, vec3 vp, vec4 tangent, vec3 vn, sampler2D ima, float numsteps, float bumpscale, float discarduv, out vec3 ptexcoord) { + // Compute binormal/bitangent from tangent and normal. vec3 binormal = cross(-vn, tangent.xyz) * tangent.w; + // Transform the fragment position in texture space. vec3 vvec = vec3(dot(tangent.xyz, vp), dot(binormal, vp), dot(-vn, vp)); vec3 vv = normalize(vvec); - // The uv shift per depth step, multitply by rotation and after size. - vec2 delta = (vec3(-vv.x, gl_FrontFacing ? vv.y : -vv.y, 0.0) * mat * size * bumpscale / vv.z).xy; + // The uv shift per depth step. + vec2 delta = (vec3(-vv.x, gl_FrontFacing ? vv.y : -vv.y, 0.0) * bumpscale / vv.z).xy; float height = 0.0; @@ -4103,8 +4109,8 @@ void parallax_out(vec3 texco, vec3 vp, vec4 tangent, vec3 vn, vec3 size, mat3 ma const vec2 clampmax = vec2(0.5); if ((discarduv == 1.0) && - (finaltexuv.x - 0.5 < clampmin.x * size.x || finaltexuv.x - 0.5 > clampmax.x * size.x || - finaltexuv.y - 0.5 < clampmin.y * size.y || finaltexuv.y - 0.5 > clampmax.y * size.y)) + (finaltexuv.x - 0.5 < clampmin.x || finaltexuv.x - 0.5 > clampmax.x || + finaltexuv.y - 0.5 < clampmin.y || finaltexuv.y - 0.5 > clampmax.y)) { discard; }