From 19feb02d8624895aa2cd84b5f6112d69a757b4bd Mon Sep 17 00:00:00 2001 From: vortex Date: Tue, 23 Aug 2011 22:13:07 +0000 Subject: [PATCH] Experimental r_glsl_offsetmapping_lod cvar which applies a distance-based correction to number of offsetmapping steps, makes up to 40% fps boost on open area maps with lots of reliefmapped surfaces and no quality loss, gives about 5-10% on generic case (requires accurate tweaking for best results). git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11292 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rmain.c | 19 ++++++++++++--- render.h | 2 ++ shader_glsl.h | 64 +++++++++++++++++++++++++++++---------------------- shader_hlsl.h | 62 +++++++++++++++++++++++++++---------------------- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/gl_rmain.c b/gl_rmain.c index 4a9cbef4..7bd584fb 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -163,6 +163,8 @@ cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_re cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"}; cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"}; cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"}; +cvar_t r_glsl_offsetmapping_lod = {CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"}; +cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."}; cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"}; cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"}; cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"}; @@ -825,6 +827,7 @@ typedef struct r_glsl_permutation_s int loc_LightDir; int loc_LightPosition; int loc_OffsetMapping_ScaleSteps; + int loc_OffsetMapping_LodDistance; int loc_PixelSize; int loc_ReflectColor; int loc_ReflectFactor; @@ -871,9 +874,10 @@ enum SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5, ///< postprocess uservec4 is enabled - SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6 // use both alpha layers while blending materials, allows more advanced microblending + SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending + SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7, ///< LOD for offsetmapping }; -#define SHADERSTATICPARMS_COUNT 7 +#define SHADERSTATICPARMS_COUNT 8 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT]; static int shaderstaticparms_count = 0; @@ -904,6 +908,8 @@ qboolean R_CompileShader_CheckStaticParms(void) if (r_glsl_postprocess_uservec4_enable.integer) R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4); } + if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0) + R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD); return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0; } @@ -924,6 +930,7 @@ void R_CompileShader_AddStaticParms(unsigned int mode, unsigned int permutation) R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4"); R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS"); + R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD"); } /// information about each possible shader permutation @@ -1142,6 +1149,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->loc_LightDir = qglGetUniformLocation(p->program, "LightDir"); p->loc_LightPosition = qglGetUniformLocation(p->program, "LightPosition"); p->loc_OffsetMapping_ScaleSteps = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps"); + p->loc_OffsetMapping_LodDistance = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance"); p->loc_PixelSize = qglGetUniformLocation(p->program, "PixelSize"); p->loc_ReflectColor = qglGetUniformLocation(p->program, "ReflectColor"); p->loc_ReflectFactor = qglGetUniformLocation(p->program, "ReflectFactor"); @@ -1381,7 +1389,8 @@ typedef enum D3DPSREGISTER_e D3DPSREGISTER_ViewToLight = 44, // float4x4 D3DPSREGISTER_ModelToReflectCube = 48, // float4x4 D3DPSREGISTER_NormalmapScrollBlend = 52, - // next at 53 + D3DPSREGISTER_OffsetMapping_LodDistance = 53, + // next at 54 } D3DPSREGISTER_t; @@ -2619,6 +2628,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); + hlslPSSetParameter1f(D3DPSREGISTER_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer) hlslPSSetParameter2f(D3DPSREGISTER_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); hlslPSSetParameter2f(D3DPSREGISTER_PixelToScreenTexCoord, 1.0f/vid.width, 1.0/vid.height); @@ -2779,6 +2789,7 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer), max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer) ); + if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer); if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]); if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height); if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegridmatrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);} @@ -4265,6 +4276,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps); Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps); Cvar_RegisterVariable(&r_glsl_offsetmapping_scale); + Cvar_RegisterVariable(&r_glsl_offsetmapping_lod); + Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance); Cvar_RegisterVariable(&r_glsl_postprocess); Cvar_RegisterVariable(&r_glsl_postprocess_uservec1); Cvar_RegisterVariable(&r_glsl_postprocess_uservec2); diff --git a/render.h b/render.h index 79b1198b..de8c57ef 100644 --- a/render.h +++ b/render.h @@ -191,6 +191,8 @@ extern cvar_t r_textureunits; extern cvar_t r_glsl_offsetmapping; extern cvar_t r_glsl_offsetmapping_reliefmapping; extern cvar_t r_glsl_offsetmapping_scale; +extern cvar_t r_glsl_offsetmapping_lod; +extern cvar_t r_glsl_offsetmapping_lod_distance; extern cvar_t r_glsl_deluxemapping; extern cvar_t gl_polyblend; diff --git a/shader_glsl.h b/shader_glsl.h index 5a00e7a7..befd8b53 100644 --- a/shader_glsl.h +++ b/shader_glsl.h @@ -671,33 +671,43 @@ "\n" "#ifdef USEOFFSETMAPPING\n" "uniform mediump vec4 OffsetMapping_ScaleSteps;\n" -"vec2 OffsetMapping(vec2 TexCoord, vec2 dPdx, vec2 dPdy)\n" -"{\n" -" float i;\n" -"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" -" float f;\n" -" // 14 sample relief mapping: linear search and then binary search\n" -" // this basically steps forward a small amount repeatedly until it finds\n" -" // itself inside solid, then jitters forward and back using decreasing\n" -" // amounts to find the impact\n" -" //vec3 OffsetVector = vec3(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1), -1);\n" -" //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n" -" vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1), -1);\n" -" vec3 RT = vec3(TexCoord, 1);\n" -" OffsetVector *= OffsetMapping_ScaleSteps.z;\n" -" for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\n" -" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n" -" for(i = 0.0, f = 1.0; i < OffsetMapping_ScaleSteps.w; ++i, f *= 0.5)\n" -" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n" -" return RT.xy;\n" -"#else\n" -" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n" -" //vec2 OffsetVector = vec2(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * OffsetMapping_ScaleSteps.x) * vec2(-1, 1));\n" -" //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n" -" vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * OffsetMapping_ScaleSteps.x * vec2(-1, 1));\n" -" OffsetVector *= OffsetMapping_ScaleSteps.z;\n" -" for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n" -" TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n" +"#ifdef USEOFFSETMAPPING_LOD\n" +"uniform mediump float OffsetMapping_LodDistance;\n" +"#endif\n" +"vec2 OffsetMapping(vec2 TexCoord, vec2 dPdx, vec2 dPdy)\n" +"{\n" +" float i;\n" +" // distance-based LOD\n" +"#ifdef USEOFFSETMAPPING_LOD\n" +" mediump float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +" mediump vec4 ScaleSteps = vec4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +"#else\n" +" #define ScaleSteps OffsetMapping_ScaleSteps\n" +"#endif\n" +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" +" float f;\n" +" // 14 sample relief mapping: linear search and then binary search\n" +" // this basically steps forward a small amount repeatedly until it finds\n" +" // itself inside solid, then jitters forward and back using decreasing\n" +" // amounts to find the impact\n" +" //vec3 OffsetVector = vec3(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * ScaleSteps.x) * vec2(-1, 1), -1);\n" +" //vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xy) * ScaleSteps.x * vec2(-1, 1), -1);\n" +" vec3 OffsetVector = vec3(normalize(EyeVectorFogDepth.xyz).xy * ScaleSteps.x * vec2(-1, 1), -1);\n" +" vec3 RT = vec3(TexCoord, 1);\n" +" OffsetVector *= ScaleSteps.z;\n" +" for(i = 1.0; i < ScaleSteps.y; ++i)\n" +" RT += OffsetVector * step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n" +" for(i = 0.0, f = 1.0; i < ScaleSteps.w; ++i, f *= 0.5)\n" +" RT += OffsetVector * (step(dp_textureGrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n" +" return RT.xy;\n" +"#else\n" +" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n" +" //vec2 OffsetVector = vec2(EyeVectorFogDepth.xy * ((1.0 / EyeVectorFogDepth.z) * ScaleSteps.x) * vec2(-1, 1));\n" +" //vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xy) * ScaleSteps.x * vec2(-1, 1));\n" +" vec2 OffsetVector = vec2(normalize(EyeVectorFogDepth.xyz).xy * ScaleSteps.x * vec2(-1, 1));\n" +" OffsetVector *= ScaleSteps.z;\n" +" for(i = 0.0; i < ScaleSteps.y; ++i)\n" +" TexCoord += OffsetVector * (1.0 - dp_textureGrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n" " return TexCoord;\n" "#endif\n" "}\n" diff --git a/shader_hlsl.h b/shader_hlsl.h index 12967113..b7bc5f37 100644 --- a/shader_hlsl.h +++ b/shader_hlsl.h @@ -544,33 +544,40 @@ "#endif\n" "\n" "#ifdef USEOFFSETMAPPING\n" -"float2 OffsetMapping(float2 TexCoord, float4 OffsetMapping_ScaleSteps, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\n" +"float2 OffsetMapping(float2 TexCoord, float4 OffsetMapping_ScaleSteps, float OffsetMapping_LodDistance, float3 EyeVector, sampler Texture_Normal, float2 dPdx, float2 dPdy)\n" "{\n" " float i;\n" -"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" -" // 14 sample relief mapping: linear search and then binary search\n" -" // this basically steps forward a small amount repeatedly until it finds\n" -" // itself inside solid, then jitters forward and back using decreasing\n" -" // amounts to find the impact\n" -" //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_ScaleSteps.x) * float2(-1, 1), -1);\n" -" //float3 OffsetVector = float3(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n" -" float3 OffsetVector = float3(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1), -1);\n" -" float3 RT = float3(TexCoord, 1);\n" -" OffsetVector *= OffsetMapping_ScaleSteps.z;\n" -" for(i = 1.0; i < OffsetMapping_ScaleSteps.y; ++i)\n" -" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n" -" for(i = 0.0, f = 1.0; i < OffsetMapping_ScaleSteps.w; ++i, f *= 0.5)\n" -" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n" -" return RT.xy;\n" -"#else\n" -" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n" -" //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_ScaleSteps.x) * float2(-1, 1));\n" -" //float2 OffsetVector = float2(normalize(EyeVector.xy) * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n" -" float2 OffsetVector = float2(normalize(EyeVector).xy * OffsetMapping_ScaleSteps.x * float2(-1, 1));\n" -" OffsetVector *= OffsetMapping_ScaleSteps.z;\n" -" for(i = 0.0; i < OffsetMapping_ScaleSteps.y; ++i)\n" -" TexCoord += OffsetVector * (1.0 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n" -" return TexCoord;\n" +" // distance-based LOD\n" +"#ifdef USEOFFSETMAPPING_LOD\n" +" float LODFactor = min(1.0, OffsetMapping_LodDistance / EyeVectorFogDepth.z);\n" +" mediump vec4 ScaleSteps = float4(OffsetMapping_ScaleSteps.x, OffsetMapping_ScaleSteps.y * LODFactor, OffsetMapping_ScaleSteps.z / LODFactor, OffsetMapping_ScaleSteps.w * LODFactor);\n" +"#else\n" +" #define ScaleSteps OffsetMapping_ScaleSteps\n" +"#endif\n" +"#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n" +" // 14 sample relief mapping: linear search and then binary search\n" +" // this basically steps forward a small amount repeatedly until it finds\n" +" // itself inside solid, then jitters forward and back using decreasing\n" +" // amounts to find the impact\n" +" //float3 OffsetVector = float3(EyeVector.xy * ((1.0 / EyeVector.z) * ScaleSteps.x) * float2(-1, 1), -1);\n" +" //float3 OffsetVector = float3(normalize(EyeVector.xy) * ScaleSteps.x * float2(-1, 1), -1);\n" +" float3 OffsetVector = float3(normalize(EyeVector).xy * ScaleSteps.x * float2(-1, 1), -1);\n" +" float3 RT = float3(TexCoord, 1);\n" +" OffsetVector *= ScaleSteps.z;\n" +" for(i = 1.0; i < ScaleSteps.y; ++i)\n" +" RT += OffsetVector * step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z);\n" +" for(i = 0.0, f = 1.0; i < ScaleSteps.w; ++i, f *= 0.5)\n" +" RT += OffsetVector * (step(tex2Dgrad(Texture_Normal, RT.xy, dPdx, dPdy).a, RT.z) * f - 0.5 * f);\n" +" return RT.xy;\n" +"#else\n" +" // 2 sample offset mapping (only 2 samples because of ATI Radeon 9500-9800/X300 limits)\n" +" //float2 OffsetVector = float2(EyeVector.xy * ((1.0 / EyeVector.z) * ScaleSteps.x) * float2(-1, 1));\n" +" //float2 OffsetVector = float2(normalize(EyeVector.xy) * ScaleSteps.x * float2(-1, 1));\n" +" float2 OffsetVector = float2(normalize(EyeVector).xy * ScaleSteps.x * float2(-1, 1));\n" +" OffsetVector *= ScaleSteps.z;\n" +" for(i = 0.0; i < ScaleSteps.y; ++i)\n" +" TexCoord += OffsetVector * (1.0 - tex2Dgrad(Texture_Normal, TexCoord, dPdx, dPdy).a);\n" +" return TexCoord;\n" "#endif\n" "}\n" "#endif // USEOFFSETMAPPING\n" @@ -786,6 +793,7 @@ "#endif\n" "#ifdef USEOFFSETMAPPING\n" "uniform float4 OffsetMapping_ScaleSteps : register(c24),\n" +"uniform float4 OffsetMapping_LodDistance : register(c53),\n" "#endif\n" "uniform half SpecularPower : register(c36),\n" "#ifdef HLSL\n" @@ -801,7 +809,7 @@ " // apply offsetmapping\n" " float2 dPdx = ddx(TexCoord);\n" " float2 dPdy = ddy(TexCoord);\n" -" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\n" +" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, OffsetMapping_LodDistance, EyeVector, Texture_Normal, dPdx, dPdy);\n" "# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n" "#else\n" "# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n" @@ -1285,7 +1293,7 @@ " // apply offsetmapping\n" " float2 dPdx = ddx(TexCoord);\n" " float2 dPdy = ddy(TexCoord);\n" -" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, EyeVector, Texture_Normal, dPdx, dPdy);\n" +" float2 TexCoordOffset = OffsetMapping(TexCoord, OffsetMapping_ScaleSteps, OffsetMapping_LodDistance, EyeVector, Texture_Normal, dPdx, dPdy);\n" "# define offsetMappedTexture2D(t) tex2Dgrad(t, TexCoordOffset, dPdx, dPdy)\n" "#else\n" "# define offsetMappedTexture2D(t) tex2D(t, TexCoord)\n" -- 2.39.2