diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 076e5db01a..808f8fb1fb 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -1407,7 +1407,10 @@ GLShader_lightMapping::GLShader_lightMapping( GLShaderManager *manager ) : u_ViewOrigin( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), u_numLights( this ), u_Lights( this ), GLDeformStage( this ), @@ -1457,7 +1460,10 @@ GLShader_vertexLighting_DBS_entity::GLShader_vertexLighting_DBS_entity( GLShader u_ModelViewProjectionMatrix( this ), u_Bones( this ), u_VertexInterpolation( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), u_EnvironmentInterpolation( this ), u_LightGridOrigin( this ), u_LightGridScale( this ), @@ -1518,7 +1524,10 @@ GLShader_vertexLighting_DBS_world::GLShader_vertexLighting_DBS_world( GLShaderMa u_ViewOrigin( this ), u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), u_LightWrapAround( this ), u_LightGridOrigin( this ), u_LightGridScale( this ), @@ -1579,7 +1588,10 @@ GLShader_forwardLighting_omniXYZ::GLShader_forwardLighting_omniXYZ( GLShaderMana u_ModelViewProjectionMatrix( this ), u_Bones( this ), u_VertexInterpolation( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), GLCompileMacro_USE_VERTEX_ANIMATION( this ), @@ -1637,7 +1649,10 @@ GLShader_forwardLighting_projXYZ::GLShader_forwardLighting_projXYZ( GLShaderMana u_ModelViewProjectionMatrix( this ), u_Bones( this ), u_VertexInterpolation( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), GLCompileMacro_USE_VERTEX_ANIMATION( this ), @@ -1698,7 +1713,10 @@ GLShader_forwardLighting_directionalSun::GLShader_forwardLighting_directionalSun u_ModelViewProjectionMatrix( this ), u_Bones( this ), u_VertexInterpolation( this ), - u_DepthScale( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalFormat( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), GLCompileMacro_USE_VERTEX_ANIMATION( this ), @@ -1777,10 +1795,16 @@ GLShader_reflection::GLShader_reflection( GLShaderManager *manager ): u_ModelMatrix( this ), u_ModelViewProjectionMatrix( this ), u_Bones( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), + u_NormalScale( this ), + u_NormalFormat( this ), u_VertexInterpolation( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), - GLCompileMacro_USE_VERTEX_ANIMATION( this ) + GLCompileMacro_USE_VERTEX_ANIMATION( this ), + GLCompileMacro_USE_PARALLAX_MAPPING( this ) { } @@ -1789,6 +1813,11 @@ void GLShader_reflection::BuildShaderVertexLibNames( std::string& vertexInlines vertexInlines += "vertexSimple vertexSkinning vertexAnimation "; } +void GLShader_reflection::BuildShaderFragmentLibNames( std::string& fragmentInlines ) +{ + fragmentInlines += "reliefMapping"; +} + void GLShader_reflection::BuildShaderCompileMacros( std::string& ) { } @@ -1872,6 +1901,7 @@ GLShader_heatHaze::GLShader_heatHaze( GLShaderManager *manager ) : u_ColorModulate( this ), u_Color( this ), u_Bones( this ), + u_NormalFormat( this ), u_VertexInterpolation( this ), GLDeformStage( this ), GLCompileMacro_USE_VERTEX_SKINNING( this ), @@ -1885,6 +1915,11 @@ void GLShader_heatHaze::BuildShaderVertexLibNames( std::string& vertexInlines ) vertexInlines += "vertexSimple vertexSkinning vertexAnimation vertexSprite "; } +void GLShader_heatHaze::BuildShaderFragmentLibNames( std::string& fragmentInlines ) +{ + fragmentInlines += "reliefMapping"; +} + void GLShader_heatHaze::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_NormalMap" ), 0 ); @@ -2016,8 +2051,7 @@ void GLShader_lightVolume_omni::SetShaderProgramUniforms( shaderProgram_t *shade } GLShader_liquid::GLShader_liquid( GLShaderManager *manager ) : - GLShader( "liquid", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT - , manager ), + GLShader( "liquid", ATTR_POSITION | ATTR_TEXCOORD | ATTR_QTANGENT, manager ), u_NormalTextureMatrix( this ), u_ViewOrigin( this ), u_RefractionIndex( this ), @@ -2027,7 +2061,11 @@ GLShader_liquid::GLShader_liquid( GLShaderManager *manager ) : u_FresnelPower( this ), u_FresnelScale( this ), u_FresnelBias( this ), + u_ParallaxDepthScale( this ), + u_ParallaxOffsetBias( this ), + u_HeightMapInNormalMap( this ), u_NormalScale( this ), + u_NormalFormat( this ), u_FogDensity( this ), u_FogColor( this ), u_SpecularExponent( this ), @@ -2037,6 +2075,11 @@ GLShader_liquid::GLShader_liquid( GLShaderManager *manager ) : { } +void GLShader_liquid::BuildShaderFragmentLibNames( std::string& fragmentInlines ) +{ + fragmentInlines += "reliefMapping"; +} + void GLShader_liquid::SetShaderProgramUniforms( shaderProgram_t *shaderProgram ) { glUniform1i( glGetUniformLocation( shaderProgram->program, "u_CurrentMap" ), 0 ); diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index cf724865c1..38931e27a6 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -1766,6 +1766,22 @@ class u_NormalScale : } }; +class u_NormalFormat : + GLUniform3f +{ +public: + u_NormalFormat( GLShader *shader ) : + GLUniform3f( shader, "u_NormalFormat" ) + { + } + + void SetUniform_NormalFormat( const vec3_t value ) + { + this->SetValue( value ); + } +}; + + class u_FogDensity : GLUniform1f { @@ -1976,6 +1992,51 @@ class u_DepthScale : } }; +class u_ParallaxDepthScale : + GLUniform1f +{ +public: + u_ParallaxDepthScale( GLShader *shader ) : + GLUniform1f( shader, "u_ParallaxDepthScale" ) + { + } + + void SetUniform_ParallaxDepthScale( float value ) + { + this->SetValue( value ); + } +}; + +class u_ParallaxOffsetBias : + GLUniform1f +{ +public: + u_ParallaxOffsetBias( GLShader *shader ) : + GLUniform1f( shader, "u_ParallaxOffsetBias" ) + { + } + + void SetUniform_ParallaxOffsetBias( float value ) + { + this->SetValue( value ); + } +}; + +class u_HeightMapInNormalMap : + GLUniform1i +{ +public: + u_HeightMapInNormalMap( GLShader *shader ) : + GLUniform1i( shader, "u_HeightMapInNormalMap" ) + { + } + + void SetUniform_HeightMapInNormalMap( int value ) + { + this->SetValue( value ); + } +}; + class u_EnvironmentInterpolation : GLUniform1f { @@ -2342,7 +2403,10 @@ class GLShader_lightMapping : public u_ViewOrigin, public u_ModelMatrix, public u_ModelViewProjectionMatrix, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public u_numLights, public u_Lights, public GLDeformStage, @@ -2370,7 +2434,10 @@ class GLShader_vertexLighting_DBS_entity : public u_ModelViewProjectionMatrix, public u_Bones, public u_VertexInterpolation, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public u_EnvironmentInterpolation, public u_LightGridOrigin, public u_LightGridScale, @@ -2404,7 +2471,10 @@ class GLShader_vertexLighting_DBS_world : public u_ViewOrigin, public u_ModelMatrix, public u_ModelViewProjectionMatrix, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public u_LightWrapAround, public u_LightGridOrigin, public u_LightGridScale, @@ -2444,7 +2514,10 @@ class GLShader_forwardLighting_omniXYZ : public u_ModelViewProjectionMatrix, public u_Bones, public u_VertexInterpolation, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, public GLCompileMacro_USE_VERTEX_ANIMATION, @@ -2482,7 +2555,10 @@ class GLShader_forwardLighting_projXYZ : public u_ModelViewProjectionMatrix, public u_Bones, public u_VertexInterpolation, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, public GLCompileMacro_USE_VERTEX_ANIMATION, @@ -2522,7 +2598,10 @@ class GLShader_forwardLighting_directionalSun : public u_ModelViewProjectionMatrix, public u_Bones, public u_VertexInterpolation, - public u_DepthScale, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalFormat, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, public GLCompileMacro_USE_VERTEX_ANIMATION, @@ -2567,14 +2646,21 @@ class GLShader_reflection : public u_ModelMatrix, public u_ModelViewProjectionMatrix, public u_Bones, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, + public u_NormalScale, + public u_NormalFormat, public u_VertexInterpolation, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, - public GLCompileMacro_USE_VERTEX_ANIMATION + public GLCompileMacro_USE_VERTEX_ANIMATION, + public GLCompileMacro_USE_PARALLAX_MAPPING { public: GLShader_reflection( GLShaderManager *manager ); void BuildShaderVertexLibNames( std::string& vertexInlines ); + void BuildShaderFragmentLibNames( std::string& fragmentInlines ); void BuildShaderCompileMacros( std::string& compileMacros ); void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ); }; @@ -2641,6 +2727,7 @@ class GLShader_heatHaze : public u_ColorModulate, public u_Color, public u_Bones, + public u_NormalFormat, public u_VertexInterpolation, public GLDeformStage, public GLCompileMacro_USE_VERTEX_SKINNING, @@ -2650,6 +2737,7 @@ class GLShader_heatHaze : public: GLShader_heatHaze( GLShaderManager *manager ); void BuildShaderVertexLibNames( std::string& vertexInlines ); + void BuildShaderFragmentLibNames( std::string& fragmentInlines ); void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ); }; @@ -2765,7 +2853,11 @@ class GLShader_liquid : public u_FresnelPower, public u_FresnelScale, public u_FresnelBias, + public u_ParallaxDepthScale, + public u_ParallaxOffsetBias, + public u_HeightMapInNormalMap, public u_NormalScale, + public u_NormalFormat, public u_FogDensity, public u_FogColor, public u_SpecularExponent, @@ -2775,6 +2867,7 @@ class GLShader_liquid : { public: GLShader_liquid( GLShaderManager *manager ); + void BuildShaderFragmentLibNames( std::string& fragmentInlines ); void SetShaderProgramUniforms( shaderProgram_t *shaderProgram ); }; diff --git a/src/engine/renderer/glsl_source/forwardLighting_fp.glsl b/src/engine/renderer/glsl_source/forwardLighting_fp.glsl index 975efee42c..7121d7d036 100644 --- a/src/engine/renderer/glsl_source/forwardLighting_fp.glsl +++ b/src/engine/renderer/glsl_source/forwardLighting_fp.glsl @@ -79,7 +79,8 @@ uniform float u_ShadowBlur; uniform mat4 u_ViewMatrix; -uniform float u_DepthScale; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; IN(smooth) vec3 var_Position; IN(smooth) vec4 var_TexDiffuse; @@ -954,45 +955,22 @@ void main() vec2 texSpecular = var_TexSpecular.st; // compute view direction in world space - vec3 V = normalize(u_ViewOrigin - var_Position.xyz); + vec3 viewDir = normalize(u_ViewOrigin - var_Position.xyz); #if defined(USE_PARALLAX_MAPPING) + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); - // ray intersect in view direction - - // compute view direction in tangent space - vec3 Vts = V * tangentToWorldMatrix; - Vts = normalize(Vts); - - // size and start position of search in texture space - vec2 S = Vts.xy * -u_DepthScale / Vts.z; - - float depth = RayIntersectDisplaceMap(texNormal, S, u_NormalMap); - - // compute texcoords offset - vec2 texOffset = S * depth; - - texDiffuse.st += texOffset; - texNormal.st += texOffset; - texSpecular.st += texOffset; + texDiffuse += texOffset; + texNormal += texOffset; + texSpecular += texOffset; #endif // USE_PARALLAX_MAPPING // compute half angle in world space - vec3 H = normalize(L + V); - - // compute normal in tangent space from normalmap - vec3 N = texture2D(u_NormalMap, texNormal.st).xyw; - N.x *= N.z; - N.xy = 2.0 * N.xy - 1.0; - N.z = sqrt(1.0 - dot(N.xy, N.xy)); - -#if defined(r_NormalScale) - N.z *= r_NormalScale; - normalize(N); -#endif + vec3 H = normalize(L + viewDir); - // transform normal into world space - N = normalize(tangentToWorldMatrix * N); + // compute normal in world space from normal map + vec3 N = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute the light term #if defined(r_WrapAroundLighting) diff --git a/src/engine/renderer/glsl_source/heatHaze_fp.glsl b/src/engine/renderer/glsl_source/heatHaze_fp.glsl index 0c4696e584..0bab406f93 100644 --- a/src/engine/renderer/glsl_source/heatHaze_fp.glsl +++ b/src/engine/renderer/glsl_source/heatHaze_fp.glsl @@ -33,11 +33,10 @@ DECLARE_OUTPUT(vec4) void main() { - vec4 color0, color1; + vec4 color; // compute normal in tangent space from normalmap - color0 = texture2D(u_NormalMap, var_TexNormal).rgba; - vec3 N = 2.0 * (color0.rgb - 0.5); + vec3 N = NormalInTangentSpace(u_NormalMap, var_TexNormal); // calculate the screen texcoord in the 0.0 to 1.0 range vec2 st = gl_FragCoord.st * r_FBufScale; @@ -46,7 +45,7 @@ void main() st += N.xy * var_Deform; st = clamp(st, 0.0, 1.0); - color0 = texture2D(u_CurrentMap, st); + color = texture2D(u_CurrentMap, st); - outputColor = color0; + outputColor = color; } diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index 34543ea22f..8f431f3c0b 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -29,7 +29,8 @@ uniform sampler2D u_LightMap; uniform sampler2D u_DeluxeMap; uniform float u_AlphaThreshold; uniform vec3 u_ViewOrigin; -uniform float u_DepthScale; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; IN(smooth) vec3 var_Position; IN(smooth) vec4 var_TexDiffuseGlow; @@ -47,41 +48,23 @@ DECLARE_OUTPUT(vec4) void main() { // compute view direction in world space - vec3 I = normalize(u_ViewOrigin - var_Position); + vec3 viewDir = normalize(u_ViewOrigin - var_Position); vec2 texDiffuse = var_TexDiffuseGlow.st; + vec2 texGlow = var_TexDiffuseGlow.pq; vec2 texNormal = var_TexNormalSpecular.st; vec2 texSpecular = var_TexNormalSpecular.pq; mat3 tangentToWorldMatrix = mat3(var_Tangent.xyz, var_Binormal.xyz, var_Normal.xyz); #if defined(USE_PARALLAX_MAPPING) - // ray intersect in view direction + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); - // compute view direction in tangent space - vec3 V = I * tangentToWorldMatrix; - V = normalize(V); - - // size and start position of search in texture space - vec2 S = V.xy * -u_DepthScale / V.z; - -#if 0 - vec2 texOffset = vec2(0.0); - for(int i = 0; i < 4; i++) { - vec4 Normal = texture2D(u_NormalMap, texNormal.st + texOffset); - float height = Normal.a * 0.2 - 0.0125; - texOffset += height * Normal.z * S; - } -#else - float depth = RayIntersectDisplaceMap(texNormal, S, u_NormalMap); - - // compute texcoords offset - vec2 texOffset = S * depth; -#endif - - texDiffuse.st += texOffset; - texNormal.st += texOffset; - texSpecular.st += texOffset; + texDiffuse += texOffset; + texGlow += texOffset; + texNormal += texOffset; + texSpecular += texOffset; #endif // USE_PARALLAX_MAPPING // compute the diffuse term @@ -97,11 +80,7 @@ void main() vec4 specular = texture2D(u_SpecularMap, texSpecular); // compute normal in world space from normalmap - vec3 N = texture2D(u_NormalMap, texNormal.st).xyw; - N.x *= N.z; - N.xy = 2.0 * N.xy - 1.0; - N.z = sqrt(1.0 - dot(N.xy, N.xy)); - N = normalize(tangentToWorldMatrix * N); + vec3 N = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute light color from world space lightmap vec3 lightColor = texture2D(u_LightMap, var_TexLight).xyz; @@ -121,11 +100,11 @@ void main() lightColor /= clamp(dot(normalize(var_Normal), L), 0.004, 1.0); // compute final color - computeLight( L, N, I, lightColor, diffuse, specular, color ); + computeLight( L, N, viewDir, lightColor, diffuse, specular, color ); } - computeDLights( var_Position, N, I, diffuse, specular, color ); + computeDLights( var_Position, N, viewDir, diffuse, specular, color ); - color.rgb += texture2D(u_GlowMap, var_TexDiffuseGlow.pq).rgb; + color.rgb += texture2D(u_GlowMap, texGlow).rgb; // convert normal to [0,1] color space N = N * 0.5 + 0.5; diff --git a/src/engine/renderer/glsl_source/liquid_fp.glsl b/src/engine/renderer/glsl_source/liquid_fp.glsl index d386a2c1ed..f096bbf549 100644 --- a/src/engine/renderer/glsl_source/liquid_fp.glsl +++ b/src/engine/renderer/glsl_source/liquid_fp.glsl @@ -33,6 +33,8 @@ uniform float u_RefractionIndex; uniform float u_FresnelPower; uniform float u_FresnelScale; uniform float u_FresnelBias; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; uniform float u_NormalScale; uniform mat4 u_ModelMatrix; uniform mat4 u_UnprojectMatrix; @@ -81,7 +83,7 @@ void ReadLightGrid(in vec3 pos, out vec3 lgtDir, void main() { // compute incident ray - vec3 I = normalize(u_ViewOrigin - var_Position); + vec3 viewDir = normalize(u_ViewOrigin - var_Position); mat3 tangentToWorldMatrix = mat3(var_Tangent.xyz, var_Binormal.xyz, var_Normal.xyz); if(gl_FrontFacing) @@ -94,37 +96,24 @@ void main() vec2 texNormal = var_TexNormal.st; #if defined(USE_PARALLAX_MAPPING) - // compute view direction in tangent space - vec3 V = I * tangentToWorldMatrix; - V = normalize(V); - // ray intersect in view direction - // size and start position of search in texture space - //vec2 S = V.xy * -u_DepthScale / V.z; - vec2 S = V.xy * -0.03 / V.z; - - float depth = RayIntersectDisplaceMap(texNormal, S, u_NormalMap); - - // compute texcoords offset - vec2 texOffset = S * depth; + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); - texScreen.st += texOffset; - texNormal.st += texOffset; + texScreen += texOffset; + texNormal += texOffset; #endif // compute normals vec3 N = normalize(var_Normal); - vec3 N2 = texture2D(u_NormalMap, texNormal.st).xyw; - N2.x *= N2.z; - N2.xy = 2.0 * N2.xy - 1.0; - N2.z = sqrt(1.0 - dot(N2.xy, N2.xy)); - N2 = normalize(tangentToWorldMatrix * N2); + // compute normal in world space from normalmap + vec3 N2 = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute fresnel term - float fresnel = clamp(u_FresnelBias + pow(1.0 - dot(I, N), u_FresnelPower) * + float fresnel = clamp(u_FresnelBias + pow(1.0 - dot(viewDir, N), u_FresnelPower) * u_FresnelScale, 0.0, 1.0); texScreen += u_NormalScale * N2.xy; @@ -164,7 +153,7 @@ void main() L, ambCol, lgtCol ); // compute half angle in world space - vec3 H = normalize(L + I); + vec3 H = normalize(L + viewDir); // compute the light term vec3 light = lgtCol * clamp(dot(N2, L), 0.0, 1.0); diff --git a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl index 7158b74aa1..1ca855450b 100644 --- a/src/engine/renderer/glsl_source/reflection_CB_fp.glsl +++ b/src/engine/renderer/glsl_source/reflection_CB_fp.glsl @@ -26,6 +26,8 @@ uniform samplerCube u_ColorMap; uniform sampler2D u_NormalMap; uniform vec3 u_ViewOrigin; uniform mat4 u_ModelMatrix; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; IN(smooth) vec3 var_Position; IN(smooth) vec2 var_TexNormal; @@ -37,26 +39,25 @@ DECLARE_OUTPUT(vec4) void main() { - // compute incident ray in world space - vec3 I = normalize(var_Position - u_ViewOrigin); - - // compute normal in tangent space from normalmap - vec3 N = texture2D(u_NormalMap, var_TexNormal.st).xyw; - N.x *= N.z; - N.xy = 2.0 * N.xy - 1.0; - N.z = sqrt(1.0 - dot(N.xy, N.xy)); -#if defined(r_NormalScale) - N.z *= r_NormalScale; - normalize(N); -#endif + // compute view direction in world space + vec3 viewDir = normalize(var_Position - u_ViewOrigin); mat3 tangentToWorldMatrix = mat3(var_Tangent.xyz, var_Binormal.xyz, var_Normal.xyz); - // transform normal into world space - N = normalize(tangentToWorldMatrix * N); + vec2 texNormal = var_TexNormal; + +#if defined(USE_PARALLAX_MAPPING) + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); + + texNormal += texOffset; +#endif // USE_PARALLAX_MAPPING + + // compute normal in tangent space from normal map + vec3 N = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute reflection ray - vec3 R = reflect(I, N); + vec3 R = reflect(viewDir, N); outputColor = textureCube(u_ColorMap, R).rgba; // outputColor = vec4(1.0, 0.0, 0.0, 1.0); diff --git a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl index b40b3d3fdb..cc7496a292 100644 --- a/src/engine/renderer/glsl_source/reliefMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/reliefMapping_fp.glsl @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // reliefMapping_vp.glsl - Relief mapping helper functions +uniform int u_HeightMapInNormalMap; +uniform vec3 u_NormalFormat; + struct light { vec4 center_radius; vec4 color_type; @@ -199,19 +202,95 @@ void computeDLights( vec3 P, vec3 N, vec3 I, vec4 diffuse, vec4 specular, #endif } +vec3 normalFlip(vec3 normal) +{ + // undefined (zero) means default means 1.0 means do nothing + + if (u_NormalFormat.x < 0.0) + { + normal.x *= -1.0; + } + + if (u_NormalFormat.y < 0.0) + { + normal.y *= -1.0; + } + + if (u_NormalFormat.z < 0.0) + { + normal.z *= -1.0; + } + + return normal; +} + +// compute normal in tangent space +vec3 NormalInTangentSpace(sampler2D normalMap, vec2 texNormal) +{ + vec3 normal; + if (u_HeightMapInNormalMap == 0) + { + // the Capcom trick abusing alpha channel of DXT1/5 formats to encode normal map + // https://github.com/DaemonEngine/Daemon/issues/183#issuecomment-473691252 + // + // the algorithm also works with normal maps in rgb format without alpha channel + // but we still must be sure there is no height map in alpha channel hence the test + // + // crunch -dxn seems to produce such files, since alpha channel is abused such format + // is unsuitable to embed height map, then height map must be distributed as loose file + normal = texture2D(normalMap, texNormal).rga; + normal.x *= normal.z; + normal.xy = 2.0 * normal.xy - 1.0; + normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); + } + else + { + // alpha channel contains the height map so do not try to restore the normal map from it + normal = texture2D(normalMap, texNormal).rgb; + normal = 2.0 * normal - 1.0; + } + + normal = normalFlip(normal); + +#if defined(r_NormalScale) + normal.z *= r_NormalScale; +#endif + + return normal; +} + +// compute normal in worldspace from normalmap +vec3 NormalInWorldSpace(sampler2D normalMap, vec2 texNormal, mat3 tangentToWorldMatrix) +{ + // compute normal in tangent space from normalmap + vec3 normal = NormalInTangentSpace(normalMap, texNormal); + // transform normal into world space + return normalize(tangentToWorldMatrix * normal); +} + #if defined(USE_PARALLAX_MAPPING) -float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap) +// compute texcoords offset from heightmap +// most of the code doing somewhat the same is likely to be named +// RayIntersectDisplaceMap in other id tech3-based engines +// so please keep the comment above to enable cross-tree look-up +vec2 ParallaxTexOffset(sampler2D normalMap, vec2 rayStartTexCoords, float parallaxParallaxDepthScale, float parallaxParallaxOffsetBias, vec3 viewDir, mat3 tangentToWorldMatrix) { + // compute view direction in tangent space + vec3 tangentViewDir = normalize(viewDir * tangentToWorldMatrix); + + vec2 displacement = tangentViewDir.xy * -parallaxParallaxDepthScale / tangentViewDir.z; + const int linearSearchSteps = 16; const int binarySearchSteps = 6; float depthStep = 1.0 / float(linearSearchSteps); + float topDepth = 1.0 - parallaxParallaxOffsetBias; // current size of search window - float size = depthStep; + float currentSize = depthStep; // current depth position - float depth = 0.0; + float currentDepth = 0.0; // best match found (starts with last position 1.0) float bestDepth = 1.0; @@ -219,39 +298,37 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap) // search front to back for first point inside object for(int i = 0; i < linearSearchSteps - 1; ++i) { - depth += size; + currentDepth += currentSize; - vec4 t = texture2D(normalMap, dp + ds * depth); + float heightMapDepth = topDepth - texture2D(normalMap, rayStartTexCoords + displacement * currentDepth).a; - if(bestDepth > 0.996) // if no depth found yet - if(depth >= t.w) - bestDepth = depth; // store best depth + if(bestDepth > 0.996) // if no depth found yet + { + if(currentDepth >= heightMapDepth) + { + bestDepth = currentDepth; + } + } } - depth = bestDepth; + currentDepth = bestDepth; // recurse around first point (depth) for closest match for(int i = 0; i < binarySearchSteps; ++i) { - size *= 0.5; + currentSize *= 0.5; - vec4 t = texture2D(normalMap, dp + ds * depth); + float heightMapDepth = topDepth - texture2D(normalMap, rayStartTexCoords + displacement * currentDepth).a; - if(depth >= t.w) -#ifdef RM_DOUBLEDEPTH - if(depth <= t.z) -#endif - { - bestDepth = depth; - depth -= 2.0 * size; - } + if(currentDepth >= heightMapDepth) + { + bestDepth = currentDepth; + currentDepth -= 2.0 * currentSize; + } - depth += size; + currentDepth += currentSize; } - return bestDepth; + return bestDepth * displacement; } #endif - - - diff --git a/src/engine/renderer/glsl_source/vertexLighting_DBS_entity_fp.glsl b/src/engine/renderer/glsl_source/vertexLighting_DBS_entity_fp.glsl index 51924a78eb..86a45078c9 100644 --- a/src/engine/renderer/glsl_source/vertexLighting_DBS_entity_fp.glsl +++ b/src/engine/renderer/glsl_source/vertexLighting_DBS_entity_fp.glsl @@ -33,7 +33,8 @@ uniform float u_EnvironmentInterpolation; uniform float u_AlphaThreshold; uniform vec3 u_ViewOrigin; -uniform float u_DepthScale; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; uniform sampler3D u_LightGrid1; uniform sampler3D u_LightGrid2; @@ -82,9 +83,10 @@ void main() L, ambCol, lgtCol ); // compute view direction in world space - vec3 V = normalize(u_ViewOrigin - var_Position); + vec3 viewDir = normalize(u_ViewOrigin - var_Position); vec2 texDiffuse = var_TexDiffuse.st; + vec2 texGlow = var_TexGlow; mat3 tangentToWorldMatrix = mat3(var_Tangent.xyz, var_Binormal.xyz, var_Normal.xyz); @@ -92,54 +94,25 @@ void main() vec2 texSpecular = var_TexNormalSpecular.zw; #if defined(USE_PARALLAX_MAPPING) + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); - // ray intersect in view direction - - // compute view direction in tangent space - vec3 Vts = (u_ViewOrigin - var_Position.xyz) * tangentToWorldMatrix; - Vts = normalize(Vts); - - // size and start position of search in texture space - vec2 S = Vts.xy * -u_DepthScale / Vts.z; - -#if 0 - vec2 texOffset = vec2(0.0); - for(int i = 0; i < 4; i++) { - vec4 Normal = texture2D(u_NormalMap, texNormal.st + texOffset); - float height = Normal.a * 0.2 - 0.0125; - texOffset += height * Normal.z * S; - } -#else - float depth = RayIntersectDisplaceMap(texNormal, S, u_NormalMap); - - // compute texcoords offset - vec2 texOffset = S * depth; -#endif - - texDiffuse.st += texOffset; - texNormal.st += texOffset; - texSpecular.st += texOffset; + texDiffuse += texOffset; + texGlow += texOffset; + texNormal += texOffset; + texSpecular += texOffset; #endif // USE_PARALLAX_MAPPING // compute normal in world space from normalmap - vec3 N = texture2D(u_NormalMap, texNormal.st).xyw; - N.x *= N.z; - N.xy = 2.0 * N.xy - 1.0; - N.z = sqrt(1.0 - dot(N.xy, N.xy)); - -#if defined(r_NormalScale) - N.z *= r_NormalScale; -#endif - - N = normalize(tangentToWorldMatrix * N); + vec3 N = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute the specular term #if defined(USE_REFLECTIVE_SPECULAR) vec4 specBase = texture2D(u_SpecularMap, texSpecular).rgba; - vec4 envColor0 = textureCube(u_EnvironmentMap0, reflect(-V, N)).rgba; - vec4 envColor1 = textureCube(u_EnvironmentMap1, reflect(-V, N)).rgba; + vec4 envColor0 = textureCube(u_EnvironmentMap0, reflect(-viewDir, N)).rgba; + vec4 envColor1 = textureCube(u_EnvironmentMap1, reflect(-viewDir, N)).rgba; specBase.rgb *= mix(envColor0, envColor1, u_EnvironmentInterpolation).rgb; @@ -160,21 +133,21 @@ void main() // add Rim Lighting to highlight the edges #if defined(r_RimLighting) - float rim = pow(1.0 - clamp(dot(N, V), 0.0, 1.0), r_RimExponent); + float rim = pow(1.0 - clamp(dot(N, viewDir), 0.0, 1.0), r_RimExponent); vec3 emission = ambCol * rim * rim * 0.2; #endif // compute final color vec4 color = vec4(ambCol * r_AmbientScale * diffuse.xyz, diffuse.a); - computeLight( L, N, V, lgtCol, diffuse, specBase, color ); + computeLight( L, N, viewDir, lgtCol, diffuse, specBase, color ); - computeDLights( var_Position, N, V, diffuse, specBase, color ); + computeDLights( var_Position, N, viewDir, diffuse, specBase, color ); #if defined(r_RimLighting) color.rgb += 0.7 * emission; #endif - color.rgb += texture2D(u_GlowMap, var_TexGlow).rgb; + color.rgb += texture2D(u_GlowMap, texGlow).rgb; // convert normal to [0,1] color space N = N * 0.5 + 0.5; diff --git a/src/engine/renderer/glsl_source/vertexLighting_DBS_world_fp.glsl b/src/engine/renderer/glsl_source/vertexLighting_DBS_world_fp.glsl index 5fbd71f6cf..3bdc6cff77 100644 --- a/src/engine/renderer/glsl_source/vertexLighting_DBS_world_fp.glsl +++ b/src/engine/renderer/glsl_source/vertexLighting_DBS_world_fp.glsl @@ -28,7 +28,8 @@ uniform sampler2D u_SpecularMap; uniform sampler2D u_GlowMap; uniform float u_AlphaThreshold; -uniform float u_DepthScale; +uniform float u_ParallaxDepthScale; +uniform float u_ParallaxOffsetBias; uniform float u_LightWrapAround; uniform sampler3D u_LightGrid1; @@ -74,7 +75,9 @@ void main() { vec2 texDiffuse = var_TexDiffuseGlow.st; vec2 texGlow = var_TexDiffuseGlow.pq; - vec3 V = normalize(u_ViewOrigin - var_Position); + + // compute view direction in world space + vec3 viewDir = normalize(u_ViewOrigin - var_Position); mat3 tangentToWorldMatrix = mat3(var_Tangent.xyz, var_Binormal.xyz, var_Normal.xyx); @@ -86,33 +89,13 @@ void main() vec2 texSpecular = var_TexNormalSpecular.pq; #if defined(USE_PARALLAX_MAPPING) + // compute texcoords offset from heightmap + vec2 texOffset = ParallaxTexOffset(u_NormalMap, texNormal, u_ParallaxDepthScale, u_ParallaxOffsetBias, viewDir, tangentToWorldMatrix); - // ray intersect in view direction - - // compute view direction in tangent space - vec3 Vts = V * tangentToWorldMatrix; - Vts = normalize(Vts); - - // size and start position of search in texture space - vec2 S = Vts.xy * -u_DepthScale / Vts.z; - -#if 0 - vec2 texOffset = vec2(0.0); - for(int i = 0; i < 4; i++) { - vec4 Normal = texture2D(u_NormalMap, texNormal.st + texOffset); - float height = Normal.a * 0.2 - 0.0125; - texOffset += height * Normal.z * S; - } -#else - float depth = RayIntersectDisplaceMap(texNormal, S, u_NormalMap); - - // compute texcoords offset - vec2 texOffset = S * depth; -#endif - - texDiffuse.st += texOffset; - texNormal.st += texOffset; - texSpecular.st += texOffset; + texDiffuse += texOffset; + texGlow += texOffset; + texNormal += texOffset; + texSpecular += texOffset; #endif // USE_PARALLAX_MAPPING // compute the diffuse term @@ -126,23 +109,14 @@ void main() vec4 specular = texture2D(u_SpecularMap, texSpecular); - // compute normal in tangent space from normalmap - vec3 N = texture2D(u_NormalMap, texNormal.st).xyw; - N.x *= N.z; - N.xy = 2.0 * N.xy - 1.0; - N.z = sqrt(1.0 - dot(N.xy, N.xy)); - -#if defined(r_NormalScale) - N.z *= r_NormalScale; -#endif - - N = normalize(tangentToWorldMatrix * N); + // compute normal in world space from normalmap + vec3 N = NormalInWorldSpace(u_NormalMap, texNormal, tangentToWorldMatrix); // compute final color vec4 color = vec4( ambCol * diffuse.xyz, diffuse.a ); - computeLight( L, N, V, dirCol, diffuse, specular, color ); + computeLight( L, N, viewDir, dirCol, diffuse, specular, color ); - computeDLights( var_Position, N, V, diffuse, specular, color ); + computeDLights( var_Position, N, viewDir, diffuse, specular, color ); color.rgb += texture2D(u_GlowMap, texGlow).rgb; diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 140b21ca2a..8a83c8cb6f 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -2019,6 +2019,7 @@ static const cubeMapLoader_t cubeMapLoaders[] = struct multifileCubeMapFormat_t { const char *name; + const char *sep; const char *suffixes[6]; bool flipX[6]; bool flipY[6]; @@ -2029,6 +2030,7 @@ static const multifileCubeMapFormat_t multifileCubeMapFormats[] = { { "OpenGL", + "_", { "px", "nx", "py", "ny", "pz", "nz" }, { false, false, false, false, false, false }, { false, false, false, false, false, false }, @@ -2036,13 +2038,23 @@ static const multifileCubeMapFormat_t multifileCubeMapFormats[] = }, { "Quake", + "_", { "rt", "lf", "bk", "ft", "up", "dn" }, { true, true, false, true, true, false }, { false, false, true, false, false, true }, { 90, -90, 0, 0, 90, -90 }, }, + { + "DarkPlaces", + "", + { "px", "nx", "py", "ny", "pz", "nz" }, + { false, false, false, false, false, false }, + { false, false, false, false, false, false }, + { 0, 0, 0, 0, 0, 0 }, + }, { "Doom 3", + "_", { "forward", "back", "left", "right", "up", "down" }, { true, true, false, true, true, false }, { false, false, true, false, false, true }, @@ -2116,7 +2128,9 @@ image_t *R_FindCubeImage( const char *imageName, int bits, filterType_t filterTy for ( i = 0; i < 6; i++ ) { - Com_sprintf( filename, sizeof( filename ), "%s_%s", buffer, format.suffixes[ i ] ); + Com_sprintf( filename, sizeof( filename ), "%s%s%s", buffer, format.sep, format.suffixes[ i ] ); + + Log::Debug( "looking for %s cube map face '%s'", format.name, filename ); filename_p = &filename[ 0 ]; R_LoadImage( &filename_p, &pic[ i ], &width, &height, &numLayers, &numMips, &bits ); @@ -2168,15 +2182,15 @@ image_t *R_FindCubeImage( const char *imageName, int bits, filterType_t filterTy if ( width != height ) { - Log::Warn("cubemap face '%s_%s' is not a square with %d×%d dimension, resizing to %d×%d", - imageName, format.suffixes[ j ], width, height, greatestEdge, greatestEdge ); + Log::Warn("cubemap face '%s%s%s' is not a square with %d×%d dimension, resizing to %d×%d", + imageName, format.sep, format.suffixes[ j ], width, height, greatestEdge, greatestEdge ); badSize = true; } if ( width < greatestEdge || height < greatestEdge ) { - Log::Warn("cubemap face '%s_%s' is too small with %d×%d dimension, resizing to %d×%d", - imageName, format.suffixes[ j ], width, height, greatestEdge, greatestEdge ); + Log::Warn("cubemap face '%s%s%s' is too small with %d×%d dimension, resizing to %d×%d", + imageName, format.sep, format.suffixes[ j ], width, height, greatestEdge, greatestEdge ); badSize = true; } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 1d894ae511..73a897d94f 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1100,6 +1100,10 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) uint32_t stateBits; // GLS_xxxx mask + bool heightMapInNormalMap; + + bool isCubeMap; + int deformIndex; bool overrideNoPicMip; // for images that must always be full resolution bool overrideFilterType; // for console fonts, 2D elements, etc. @@ -1205,7 +1209,13 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) fogPass_t fogPass; // draw a blended pass, possibly with depth test equals bool noFog; - bool parallax; // material has normalmaps suited for parallax mapping + bool heightMapInNormalMap; // material has normalmap suited for parallax mapping + bool noParallax; // disable parallax for this material even if it's available + bool parallax; // what is finally used by renderer to know what to do + float parallaxOffsetBias; // offset the heightmap top relatively to the floor + float parallaxDepthScale; // per-shader parallax depth scale + + vec3_t normalFormat; // normalmap format (channel flip) bool noShadows; bool fogLight; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 37361ef49f..56665610cd 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -733,7 +733,7 @@ static void Render_vertexLighting_DBS_entity( int stage ) GL_BindToTMU( 8, tr.lighttileRenderImage ); - gl_vertexLightingShader_DBS_entity->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_vertexLightingShader_DBS_entity->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); gl_vertexLightingShader_DBS_entity->SetReflectiveSpecular( normalMapping && tr.cubeHashTable != nullptr ); @@ -784,12 +784,17 @@ static void Render_vertexLighting_DBS_entity( int stage ) // u_DeformGen gl_vertexLightingShader_DBS_entity->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); - if ( r_parallaxMapping->integer && tess.surfaceShader->parallax ) + if ( r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_vertexLightingShader_DBS_entity->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_vertexLightingShader_DBS_entity->SetUniform_ParallaxDepthScale( depthScale ); + gl_vertexLightingShader_DBS_entity->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_vertexLightingShader_DBS_entity->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } // bind u_DiffuseMap @@ -808,6 +813,9 @@ static void Render_vertexLighting_DBS_entity( int stage ) gl_vertexLightingShader_DBS_entity->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_vertexLightingShader_DBS_entity->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( pStage->bundle[ TB_SPECULARMAP ].image[ 0 ] ) { @@ -950,7 +958,7 @@ static void Render_vertexLighting_DBS_world( int stage ) // choose right shader program ---------------------------------- GL_BindToTMU( 8, tr.lighttileRenderImage ); - gl_vertexLightingShader_DBS_world->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_vertexLightingShader_DBS_world->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); tess.vboVertexSprite = false; @@ -1023,9 +1031,14 @@ static void Render_vertexLighting_DBS_world( int stage ) if ( r_parallaxMapping->integer ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_vertexLightingShader_DBS_world->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_vertexLightingShader_DBS_world->SetUniform_ParallaxDepthScale( depthScale ); + gl_vertexLightingShader_DBS_world->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_vertexLightingShader_DBS_world->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } if( tr.world ) { @@ -1049,6 +1062,9 @@ static void Render_vertexLighting_DBS_world( int stage ) gl_vertexLightingShader_DBS_world->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_vertexLightingShader_DBS_world->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( pStage->bundle[ TB_SPECULARMAP ].image[ 0 ] ) { @@ -1147,7 +1163,7 @@ static void Render_lightMapping( int stage, bool asColorMap, bool normalMapping, // choose right shader program ---------------------------------- GL_BindToTMU( 8, tr.lighttileRenderImage ); - gl_lightMappingShader->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_lightMappingShader->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); tess.vboVertexSprite = false; @@ -1184,9 +1200,14 @@ static void Render_lightMapping( int stage, bool asColorMap, bool normalMapping, if ( r_parallaxMapping->integer ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_lightMappingShader->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_lightMappingShader->SetUniform_ParallaxDepthScale( depthScale ); + gl_lightMappingShader->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_lightMappingShader->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } // bind u_DiffuseMap @@ -1212,6 +1233,9 @@ static void Render_lightMapping( int stage, bool asColorMap, bool normalMapping, gl_lightMappingShader->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_lightMappingShader->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( pStage->bundle[ TB_SPECULARMAP ].image[ 0 ] ) { @@ -1430,7 +1454,7 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *diffuseStage, gl_forwardLightingShader_omniXYZ->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); gl_forwardLightingShader_omniXYZ->SetVertexAnimation( glState.vertexAttribsInterpolation > 0 ); - gl_forwardLightingShader_omniXYZ->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_forwardLightingShader_omniXYZ->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); gl_forwardLightingShader_omniXYZ->SetShadowing( shadowCompare ); @@ -1475,9 +1499,14 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *diffuseStage, if ( r_parallaxMapping->integer ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &diffuseStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_forwardLightingShader_omniXYZ->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_forwardLightingShader_omniXYZ->SetUniform_ParallaxDepthScale( depthScale ); + gl_forwardLightingShader_omniXYZ->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_forwardLightingShader_omniXYZ->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } // set uniforms @@ -1548,6 +1577,9 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *diffuseStage, gl_forwardLightingShader_omniXYZ->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_forwardLightingShader_omniXYZ->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( r_forceSpecular->integer ) { @@ -1614,7 +1646,7 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *diffuseStage, gl_forwardLightingShader_projXYZ->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); gl_forwardLightingShader_projXYZ->SetVertexAnimation( glState.vertexAttribsInterpolation > 0 ); - gl_forwardLightingShader_projXYZ->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_forwardLightingShader_projXYZ->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); gl_forwardLightingShader_projXYZ->SetShadowing( shadowCompare ); @@ -1659,9 +1691,14 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *diffuseStage, if ( r_parallaxMapping->integer ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &diffuseStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_forwardLightingShader_projXYZ->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_forwardLightingShader_projXYZ->SetUniform_ParallaxDepthScale( depthScale ); + gl_forwardLightingShader_projXYZ->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_forwardLightingShader_projXYZ->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } // set uniforms @@ -1733,6 +1770,9 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *diffuseStage, gl_forwardLightingShader_projXYZ->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_forwardLightingShader_projXYZ->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( r_forceSpecular->integer ) { @@ -1797,7 +1837,7 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *diffuseStage, gl_forwardLightingShader_directionalSun->SetVertexSkinning( glConfig2.vboVertexSkinningAvailable && tess.vboVertexSkinning ); gl_forwardLightingShader_directionalSun->SetVertexAnimation( glState.vertexAttribsInterpolation > 0 ); - gl_forwardLightingShader_directionalSun->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax ); + gl_forwardLightingShader_directionalSun->SetParallaxMapping( normalMapping && r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax ); gl_forwardLightingShader_directionalSun->SetShadowing( shadowCompare ); @@ -1842,9 +1882,14 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *diffuseStage, if ( r_parallaxMapping->integer ) { float depthScale; + float parallaxDepthScale; depthScale = RB_EvalExpression( &diffuseStage->depthScaleExp, r_parallaxDepthScale->value ); - gl_forwardLightingShader_directionalSun->SetUniform_DepthScale( depthScale ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_forwardLightingShader_directionalSun->SetUniform_ParallaxDepthScale( depthScale ); + gl_forwardLightingShader_directionalSun->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_forwardLightingShader_directionalSun->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); } // set uniforms @@ -1920,6 +1965,9 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *diffuseStage, gl_forwardLightingShader_directionalSun->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_NormalFormat + gl_forwardLightingShader_directionalSun->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + // bind u_SpecularMap if ( r_forceSpecular->integer ) { @@ -1995,6 +2043,8 @@ static void Render_reflection_CB( int stage ) // end choose right shader program ------------------------------ + gl_reflectionShader->SetParallaxMapping(r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax); + gl_reflectionShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); // in world space gl_reflectionShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); @@ -2031,8 +2081,26 @@ static void Render_reflection_CB( int stage ) { GL_BindToTMU( 1, tr.flatImage ); } + gl_reflectionShader->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_NORMALMAP ] ); + // bind u_depthScale u_parallaxOffsetBias + if ( r_parallaxMapping->integer ) + { + float depthScale; + float parallaxDepthScale; + + depthScale = RB_EvalExpression( &pStage->depthScaleExp, r_parallaxDepthScale->value ); + parallaxDepthScale = tess.surfaceShader->parallaxDepthScale; + depthScale *= parallaxDepthScale == 0 ? 1 : parallaxDepthScale; + gl_reflectionShader->SetUniform_ParallaxDepthScale( depthScale ); + gl_reflectionShader->SetUniform_ParallaxOffsetBias( tess.surfaceShader->parallaxOffsetBias ); + gl_reflectionShader->SetUniform_HeightMapInNormalMap( tess.surfaceShader->heightMapInNormalMap ); + } + + // bind u_NormalFormat + gl_reflectionShader->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + gl_reflectionShader->SetRequiredVertexPointers(); Tess_DrawElements(); @@ -2192,6 +2260,9 @@ static void Render_heatHaze( int stage ) GL_BindToTMU( 0, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); gl_heatHazeShader->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); + // bind u_NormalFormat + gl_heatHazeShader->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + GL_BindToTMU( 1, tr.currentRenderImage[ backEnd.currentMainFBO ] ); gl_heatHazeShader->SetRequiredVertexPointers(); @@ -2212,7 +2283,7 @@ static void Render_liquid( int stage ) { vec3_t viewOrigin; float fogDensity; - GLfloat fogColor[ 3 ]; + vec3_t fogColor; shaderStage_t *pStage = tess.surfaceStages[ stage ]; GLimp_LogComment( "--- Render_liquid ---\n" ); @@ -2221,17 +2292,17 @@ static void Render_liquid( int stage ) GL_State( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ) ); // choose right shader program - gl_liquidShader->SetParallaxMapping(r_parallaxMapping->integer && tess.surfaceShader->parallax); + gl_liquidShader->SetParallaxMapping(r_parallaxMapping->integer && tess.surfaceShader->parallax && !tess.surfaceShader->noParallax); // enable shader, set arrays - gl_liquidShader->BindProgram(); + gl_liquidShader->BindProgram( pStage->deformIndex ); gl_liquidShader->SetRequiredVertexPointers(); // set uniforms VectorCopy( backEnd.viewParms.orientation.origin, viewOrigin ); // in world space fogDensity = RB_EvalExpression( &pStage->fogDensityExp, 0.001 ); - VectorCopy( tess.svars.color, fogColor ); + VectorCopy( tess.svars.color.ToArray(), fogColor ); gl_liquidShader->SetUniform_ViewOrigin( viewOrigin ); gl_liquidShader->SetUniform_RefractionIndex( RB_EvalExpression( &pStage->refractionIndexExp, 1.0 ) ); @@ -2262,6 +2333,9 @@ static void Render_liquid( int stage ) GL_BindToTMU( 3, pStage->bundle[ TB_COLORMAP ].image[ 0 ] ); gl_liquidShader->SetUniform_NormalTextureMatrix( tess.svars.texMatrices[ TB_COLORMAP ] ); + // bind u_NormalFormat + gl_liquidShader->SetUniform_NormalFormat( tess.surfaceShader->normalFormat ); + Tess_DrawElements(); GL_CheckErrors(); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 2a030d1eec..56326cd5bc 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -1415,7 +1415,7 @@ static bool LoadMap( shaderStage_t *stage, const char *buffer ) imageBits |= IF_NORMALMAP; } - if ( stage->type == stageType_t::ST_NORMALMAP && shader.parallax ) + if ( stage->type == stageType_t::ST_NORMALMAP && shader.heightMapInNormalMap ) { imageBits |= IF_DISPLACEMAP; } @@ -1437,18 +1437,37 @@ static bool LoadMap( shaderStage_t *stage, const char *buffer ) wrapType_t wrapType = stage->overrideWrapType ? stage->wrapType : shader.wrapType; // try to load the image - stage->bundle[ 0 ].image[ 0 ] = R_FindImageFile( buffer, imageBits, filterType, wrapType ); + if ( stage->isCubeMap ) + { + stage->bundle[ 0 ].image[ 0 ] = R_FindCubeImage( buffer, imageBits, filterType, wrapType ); - if ( !stage->bundle[ 0 ].image[ 0 ] ) + if ( !stage->bundle[ 0 ].image[ 0 ] ) + { + Log::Warn("R_FindCubeImage could not find image '%s' in shader '%s'", buffer, shader.name ); + return false; + } + } + else { - Log::Warn("R_FindImageFile could not find image '%s' in shader '%s'", buffer, shader.name ); - return false; + stage->bundle[ 0 ].image[ 0 ] = R_FindImageFile( buffer, imageBits, filterType, wrapType ); + + if ( !stage->bundle[ 0 ].image[ 0 ] ) + { + Log::Warn("R_FindImageFile could not find image '%s' in shader '%s'", buffer, shader.name ); + return false; + } } // enable parallax if an heightmap is found + // and not explicitely disabled by a shader keyword if ( stage->bundle[ 0 ].image[ 0 ]->bits & IF_DISPLACEMAP ) { - shader.parallax = true; + if ( stage->bundle[ 0 ].image[ 0 ]->bits & IF_NORMALMAP ) + { + Log::Debug("found heightmap embedded in normalmap '%s'", buffer); + shader.heightMapInNormalMap = true; + shader.parallax = true; + } } return true; @@ -3153,6 +3172,7 @@ static void ParseReflectionMap( shaderStage_t *stage, const char **text ) if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { + stage->isCubeMap = true; LoadMap( stage, buffer ); } } @@ -3170,6 +3190,7 @@ static void ParseReflectionMapBlended( shaderStage_t *stage, const char **text ) if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { + stage->isCubeMap = true; LoadMap( stage, buffer ); } } @@ -3358,6 +3379,13 @@ static bool ParseShader( const char *_text ) Log::Debug( "found extra %s '%s'", parser.description, extraMapName.c_str() ); const char *name = extraMapName.c_str(); parser.parser( &stages[ s ], &name ); + + if ( Q_stricmp( "norm", parser.suffix ) == 0 ) + { + // Xonotic uses -Y (DirectX) while this engine uses Y (OpenGL) + shader.normalFormat[ 1 ] = -1; + } + s++; } } @@ -3571,10 +3599,184 @@ static bool ParseShader( const char *_text ) continue; } + // normalFormat + // + // expects OpenGL format as default + // + // OpenGL format is described there: + // https://github.com/KhronosGroup/glTF/tree/2.0/specification/2.0#materialnormaltexture + // + // > The normal vectors use OpenGL conventions where +X is right and +Y is up. + // > +Z points toward the viewer. + // + // example of formats: + // + // 1 1 1 OpenGL format (default) + // 1 -1 1 DirectX format with reverted green (Y) channel + // -1 1 1 weird other format with reverted red (X) channel + else if ( !Q_stricmp( token, "normalFormat" ) ) + { + for ( int i = 0; i < 3; i++ ) + { + token = COM_ParseExt2( text, false ); + + if ( token[ 0 ] == '\0' ) + { + Log::Warn("missing normalFormat parm in shader '%s'", shader.name ); + continue; + } + + if ( !Q_stricmp( token, "-1" ) ) + { + shader.normalFormat[ i ] = -1; + } + else if ( !Q_stricmp( token, "1" ) ) + { + // do nothing, that's the default + } + else + { + Log::Warn("unknown normalFormat parm '%s' in '%s'", token, shader.name ); + break; + } + } + SkipRestOfLine( text ); + continue; + } // parallax mapping - else if ( !Q_stricmp( token, "parallax" ) ) + else if ( !Q_stricmp( token, "parallax" ) + || ( *r_dpMaterial && !Q_stricmp( token, "dpoffsetmapping" ) ) ) { - shader.parallax = true; + char* keyword = token; + token = COM_ParseExt2( text, false ); + + if ( !token[ 0 ] ) + { + // legacy lone “parallax” XreaL keyword was + // never used, it had purpose to enable parallax + // for the current shader + // + // the engine also relied on this to know + // that height map was stored in normal map + // but there was no other storage options + // + // since engine now automatically loads + // and enable height map stored in normal map, + // this seems pretty useless, but it costs + // nothing to keep the behavior + // + // this is only done if the “parallax” keyword + // is called alone + // + // note that DarkPlaces expects heightmap to be + // stored in normalmap, so even a mistakenly + // lone “dpoffsetmapping” keyword will not produce + // something wrong + shader.heightMapInNormalMap = true; + continue; + } + + if ( !Q_stricmp( token, "none" ) ) + { + shader.noParallax = true; + } + else if ( !Q_stricmp( token, "disable" ) ) + { + shader.noParallax = true; + } + else if ( !Q_stricmp( token, "off" ) ) + { + shader.noParallax = true; + } + else if ( !Q_stricmp( token, "default" ) ) + { + // do nothing more + } + else if ( !Q_stricmp( token, "normal" ) ) + { + // do nothing more (same as default) + } + else if ( !Q_stricmp( token, "linear" ) ) + { + // not implemented yet + Log::Warn("unsupported parm for '%s' keyword in shader '%s'", keyword, shader.name ); + } + else if ( !Q_stricmp( token, "relief" ) ) + { + // the only implemented algorithm + // hence the default + // do nothing more + } + else if ( !Q_stricmp( token, "-" ) ) + { + // do nothing, that's just a filler + } + else + { + Log::Warn("invalid parm for '%s' keyword in shader '%s'", keyword, shader.name ); + SkipRestOfLine( text ); + continue; + } + + token = COM_ParseExt2( text, false ); + + if ( !token[ 0 ] ) + { + Log::Warn("missing parm for '%s' keyword in shader '%s'", keyword, shader.name ); + continue; + } + + shader.parallaxDepthScale = atof( token ); + + token = COM_ParseExt2( text, false ); + + // dpoffsetmapping - 2 + if ( !token[ 0 ] ) + { + continue; + } + + // dpoffsetmapping - 2 match8 65 + float off; + float div; + + if ( !Q_stricmp( token, "bias" ) ) + { + off = 0.0f; + div = 1.0f; + } + else if ( !Q_stricmp( token, "match" ) ) + { + off = 1.0f; + div = 1.0f; + } + else if ( !Q_stricmp( token, "match8" ) ) + { + off = 1.0f; + div = 255.0f; + } + else if ( !Q_stricmp( token, "match16" ) ) + { + off = 1.0f; + div = 65535.0f; + } + else + { + Log::Warn("invalid parm for '%s' keyword in shader '%s'", keyword, shader.name ); + SkipRestOfLine( text ); + continue; + } + + token = COM_ParseExt2( text, false ); + + if ( !token[ 0 ] ) + { + Log::Warn("missing parm for '%s' keyword in shader '%s'", keyword, shader.name ); + continue; + } + + float bias = atof( token ); + shader.parallaxOffsetBias = off - bias / div; continue; } // entityMergable, allowing sprite surfaces from multiple entities @@ -3817,7 +4019,8 @@ static bool ParseShader( const char *_text ) continue; } // reflectionMapBlended - else if ( !Q_stricmp( token, "reflectionMapBlended" ) ) + else if ( !Q_stricmp( token, "reflectionMapBlended" ) + || ( *r_dpMaterial && !Q_stricmp( token, "dpreflectcube" ) ) ) { ParseReflectionMapBlended( &stages[ s ], text ); s++; @@ -3895,6 +4098,19 @@ static bool ParseShader( const char *_text ) { continue; } + else if ( !Q_strnicmp( token, "dp", 2 ) ) + { + if ( *r_dpMaterial ) + { + Log::Warn("unknown DarkPlaces shader parameter '%s' in '%s'", token, shader.name ); + } + else + { + Log::Warn("disabled DarkPlaces shader parameter '%s' in '%s'", token, shader.name ); + } + SkipRestOfLine( text ); + continue; + } else { Log::Warn("unknown general shader parameter '%s' in '%s'", token, shader.name ); @@ -5529,6 +5745,7 @@ static void ScanAndLoadShaderFiles() shaderTable_t *tb; bool alreadyCreated; + // zeroes all shaders, booleans can be assumed as false Com_Memset( &table, 0, sizeof( table ) ); token = COM_ParseExt2( &p, true );