From b88aaa4360480c2616df816f83f4e9c03de387e5 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Fri, 25 Jan 2013 16:45:58 +0100 Subject: [PATCH] start with motion blur fixes --- dpsoftrast.h | 6 +- gl_rmain.c | 155 +++++++++++++++++++++++++++++++++++++++++++------- render.h | 1 + shader_glsl.h | 34 +++++++++++ 4 files changed, 176 insertions(+), 20 deletions(-) diff --git a/dpsoftrast.h b/dpsoftrast.h index 007d4e36..4996cd13 100644 --- a/dpsoftrast.h +++ b/dpsoftrast.h @@ -120,7 +120,9 @@ typedef enum gl20_texunit_e // fake reflections GL20TU_REFLECTMASK = 5, GL20TU_REFLECTCUBE = 6, - GL20TU_FOGHEIGHTTEXTURE = 14 + GL20TU_FOGHEIGHTTEXTURE = 14, + // Dither + GL20TU_DITHER = 3 } gl20_texunit; @@ -160,6 +162,7 @@ typedef enum shadermode_e SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color SHADERMODE_DEFERREDGEOMETRY, ///< (deferred) render material properties to screenspace geometry buffers SHADERMODE_DEFERREDLIGHTSOURCE, ///< (deferred) use directional pixel shading from light source (rtlight) on screenspace geometry buffers + SHADERMODE_GHOSTMOTIONBLUR, ////< (motionblur) As used in ghosttexture SHADERMODE_COUNT } shadermode_t; @@ -310,6 +313,7 @@ typedef enum DPSOFTRAST_UNIFORM_e DPSOFTRAST_UNIFORM_NormalmapScrollBlend, DPSOFTRAST_UNIFORM_OffsetMapping_LodDistance, DPSOFTRAST_UNIFORM_OffsetMapping_Bias, + DPSOFTRAST_UNIFORM_Dither, DPSOFTRAST_UNIFORM_TOTAL } DPSOFTRAST_UNIFORM; diff --git a/gl_rmain.c b/gl_rmain.c index 06922c1d..794222bd 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -53,7 +53,7 @@ r_refdef_t r_refdef; cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"}; cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"}; -cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"}; +cvar_t r_motionblur_slowmo = {CVAR_SAVE, "r_motionblur_slowmo", "0", "0: Slowmo does not affect the amount of blur. 1: Slowmo scales the damage/motion blur. - NOTE: You might need to increase r_viewfbo to compensate for the high blur."}; cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"}; cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"}; cvar_t r_motionblur_velocityfactor = {CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"}; @@ -260,6 +260,7 @@ rtexture_t *r_texture_gammaramps; unsigned int r_texture_gammaramps_serial; //rtexture_t *r_texture_fogintensity; rtexture_t *r_texture_reflectcube; +rtexture_t *r_texture_dither; // TODO: hash lookups? typedef struct cubemapinfo_s @@ -414,6 +415,26 @@ static void R_BuildWhiteCube(void) r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL); } +static void R_BuildDither(void) +{ +#define DITHERSIZE 512 + int i; + unsigned char *data; + data = (unsigned char *)Mem_Alloc(tempmempool, DITHERSIZE*DITHERSIZE*4); + for(i=0;iloc_Texture_ReflectMask = qglGetUniformLocation(p->program, "Texture_ReflectMask"); p->loc_Texture_ReflectCube = qglGetUniformLocation(p->program, "Texture_ReflectCube"); p->loc_Texture_BounceGrid = qglGetUniformLocation(p->program, "Texture_BounceGrid"); + p->loc_Texture_Dither = qglGetUniformLocation(p->program, "Texture_Dither"); p->loc_Alpha = qglGetUniformLocation(p->program, "Alpha"); p->loc_BloomBlur_Parameters = qglGetUniformLocation(p->program, "BloomBlur_Parameters"); p->loc_ClientTime = qglGetUniformLocation(p->program, "ClientTime"); @@ -1191,6 +1219,9 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->loc_NormalmapScrollBlend = qglGetUniformLocation(p->program, "NormalmapScrollBlend"); p->loc_BounceGridMatrix = qglGetUniformLocation(p->program, "BounceGridMatrix"); p->loc_BounceGridIntensity = qglGetUniformLocation(p->program, "BounceGridIntensity"); + p->loc_BitValue = qglGetUniformLocation(p->program, "BitValue"); + p->loc_Rand1f = qglGetUniformLocation(p->program, "Rand1f"); + p->loc_Rand2f = qglGetUniformLocation(p->program, "Rand2f"); // initialize the samplers to refer to the texture units we use p->tex_Texture_First = -1; p->tex_Texture_Second = -1; @@ -1221,6 +1252,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode p->tex_Texture_ReflectMask = -1; p->tex_Texture_ReflectCube = -1; p->tex_Texture_BounceGrid = -1; + p->tex_Texture_Dither = -1; sampler = 0; if (p->loc_Texture_First >= 0) {p->tex_Texture_First = sampler;qglUniform1i(p->loc_Texture_First , sampler);sampler++;} if (p->loc_Texture_Second >= 0) {p->tex_Texture_Second = sampler;qglUniform1i(p->loc_Texture_Second , sampler);sampler++;} @@ -1251,6 +1283,7 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode if (p->loc_Texture_ReflectMask >= 0) {p->tex_Texture_ReflectMask = sampler;qglUniform1i(p->loc_Texture_ReflectMask , sampler);sampler++;} if (p->loc_Texture_ReflectCube >= 0) {p->tex_Texture_ReflectCube = sampler;qglUniform1i(p->loc_Texture_ReflectCube , sampler);sampler++;} if (p->loc_Texture_BounceGrid >= 0) {p->tex_Texture_BounceGrid = sampler;qglUniform1i(p->loc_Texture_BounceGrid , sampler);sampler++;} + if (p->loc_Texture_Dither >= 0) {p->tex_Texture_Dither = sampler;qglUniform1i(p->loc_Texture_Dither , sampler);sampler++;} CHECKGLERROR Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler); } @@ -1308,6 +1341,17 @@ static void R_SetupShader_SetPermutationGLSL(unsigned int mode, unsigned int per if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f); if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f); if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time); + if (r_glsl_permutation->loc_Rand1f >= 0) qglUniform1f(r_glsl_permutation->loc_Rand1f, lhrandom(-1.0,1.0)); + if (r_glsl_permutation->loc_Rand2f >= 0) qglUniform2f(r_glsl_permutation->loc_Rand2f, lhrandom(-1.0,1.0), lhrandom(-1.0,1.0)); + if (r_glsl_permutation->loc_BitValue >= 0){ + switch(r_viewfbo.integer){ + case 0: + case 1: qglUniform1f(r_glsl_permutation->loc_BitValue, pow(2, -8)); break; + case 2: qglUniform1f(r_glsl_permutation->loc_BitValue, pow(2,-10)); break; + case 3: + default: qglUniform1f(r_glsl_permutation->loc_BitValue, pow(2,-23)); + }; + } } #ifdef SUPPORTD3D @@ -2037,6 +2081,41 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean } } +//Updates the render buffer to First*Alpha+Second*(1.0-Alpha) +void R_SetupShader_GhostMotionBlur(rtexture_t *first,rtexture_t *second,rtexture_t *dither,float alpha) +{ + switch (vid.renderpath) + { + case RENDERPATH_D3D9: +#ifdef SUPPORTD3D + R_SetupShader_SetPermutationHLSL(SHADERMODE_GENERIC, permutation); + R_Mesh_TexBind(GL20TU_FIRST , first ); + R_Mesh_TexBind(GL20TU_SECOND, second); + R_Mesh_TexBind(GL20TU_DITHER, dither); +#endif + break; + case RENDERPATH_D3D10: + Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_D3D11: + Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__); + break; + case RENDERPATH_GL20: + case RENDERPATH_GLES2: + R_SetupShader_SetPermutationGLSL(SHADERMODE_GHOSTMOTIONBLUR, 0); + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first ); + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second); + R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Dither, dither); + if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha,alpha); + break; + case RENDERPATH_GL13: + case RENDERPATH_GLES1: + case RENDERPATH_GL11: + case RENDERPATH_SOFT: + break; + } +} + void R_SetupShader_ShowDepth(qboolean notrippy) { int permutation = 0; @@ -3977,6 +4056,7 @@ static void gl_main_start(void) r_texture_fogattenuation = NULL; r_texture_fogheighttexture = NULL; r_texture_gammaramps = NULL; + r_texture_dither = NULL; r_texture_numcubemaps = 0; r_loaddds = r_texture_dds_load.integer != 0; @@ -4185,7 +4265,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_motionblur); Cvar_RegisterVariable(&r_damageblur); Cvar_RegisterVariable(&r_motionblur_averaging); - Cvar_RegisterVariable(&r_motionblur_randomize); + Cvar_RegisterVariable(&r_motionblur_slowmo); Cvar_RegisterVariable(&r_motionblur_minblur); Cvar_RegisterVariable(&r_motionblur_maxblur); Cvar_RegisterVariable(&r_motionblur_velocityfactor); @@ -6548,21 +6628,48 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture) { // declare variables + // Note: f(t)=e^-Lt + // In his code we are working the L to change the blending speed, NOT the e ! float blur_factor, blur_mouseaccel, blur_velocity; - static float blur_average; - static vec3_t blur_oldangles; // used to see how quickly the mouse is moving + static float blur_average; + static vec3_t oldviewforward; // used to see how quickly the mouse is moving + float dt; //Delta Time (time passed) + static double oldrealtime=0; + float old_target_fps=60; + float view_arclength; //The distance that would have been traveled on a sphere after rotating view + //float temp_alpha_blend; //Temp var to use in local code + + //Calc the delta-time + if (r_motionblur_slowmo.value>0){ + dt = (cl.time-cl.oldtime) * slowmo.value; + }else{ + dt = realtime - oldrealtime; + oldrealtime = realtime; + } // set a goal for the factoring + // r_refdef.view.forward + // 1800/PI / OrgTarget_FPS + + view_arclength = asin(VectorDistance(oldviewforward, r_refdef.view.forward) / 2) * 2; + view_arclength *= 1800/(M_PI*dt*old_target_fps); + VectorCopy( r_refdef.view.forward, oldviewforward ); + blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1); - blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) + blur_mouseaccel = bound(0, (view_arclength - r_motionblur_mousefactor_minspeed.value) / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1); blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) + (blur_mouseaccel * r_motionblur_mousefactor.value)); // from the goal, pick an averaged value between goal and last value - cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1); + cl.motionbluralpha = bound(0, dt / max(0.001, r_motionblur_averaging.value), 1); blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha; + + //@Div: Replace with below ? + //cl.motionbluralpha = bound(0, dt / max(0.001, r_motionblur_averaging.value), 1); + //temp_alpha_blend = exp(-cl.motionbluralpha); + //blur_average = blur_average * temp_alpha_blend + blur_factor * (1 - temp_alpha_blend); // enforce minimum amount of blur blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value; @@ -6579,17 +6686,26 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext / max(0.0001, cl.time - cl.oldtime) // fps independent ); - - // randomization for the blur value to combat persistent ghosting - cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value); + //@Div: Replace with ??? + //cl.motionbluralpha = 1 - exp(- + // ( + // (r_motionblur.value * blur_factor / 80) + // + + // (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600)) + // ) + // * + // dt // fps independent + // * old_target_fps * old_target_fps //FPSFIX fps^2 to offset old bug -> Calc into 80 and 1600 + // ); + // Only apply max_blur, random is nolonger needed cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value); // apply the blur R_ResetViewRendering2D(fbo, depthtexture, colortexture); - if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid) + //0.0 = Instant fading: no need to mix + if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid) { - GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GL_Color(1, 1, 1, cl.motionbluralpha); + GL_BlendFunc(GL_ONE, GL_ZERO); switch(vid.renderpath) { case RENDERPATH_GL11: @@ -6606,18 +6722,19 @@ static void R_BlendView(int fbo, rtexture_t *depthtexture, rtexture_t *colortext R_Mesh_PrepareVertices_Generic_Arrays(4, r_d3dscreenvertex3f, NULL, r_fb.screentexcoord2f); break; } - R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true); + if(!r_texture_dither) R_BuildDither(); + R_SetupShader_GhostMotionBlur(r_fb.ghosttexture,r_fb.colortexture,r_texture_dither,cl.motionbluralpha); R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; } - // updates old view angles for next pass - VectorCopy(cl.viewangles, blur_oldangles); - - // copy view into the ghost texture - R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + //1.0 = Forever fading blur: no need to ghost texture, it's identical + if(cl.motionbluralpha<1.0){ + // copy view into the ghost texture + R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); + r_fb.ghosttexture_valid = true; + } r_refdef.stats.bloom_copypixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; - r_fb.ghosttexture_valid = true; } } else diff --git a/render.h b/render.h index fef5d46f..ec9895ee 100644 --- a/render.h +++ b/render.h @@ -475,6 +475,7 @@ void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean void R_SetupShader_ShowDepth(qboolean notrippy); void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *waterplane, qboolean notrippy); void R_SetupShader_DeferredLight(const rtlight_t *rtlight); +void R_SetupShader_GhostMotionBlur(rtexture_t *first, rtexture_t *second, rtexture_t *dither, float alpha); typedef struct r_waterstate_waterplane_s { diff --git a/shader_glsl.h b/shader_glsl.h index cc0f88b1..e4cb2b1e 100644 --- a/shader_glsl.h +++ b/shader_glsl.h @@ -440,6 +440,39 @@ "\n" "\n" "\n" +"#ifdef MODE_GHOSTMOTIONBLUR\n" + "dp_varying mediump vec2 TexCoord1;\n" + "uniform sampler2D Texture_First;\n" + "uniform sampler2D Texture_Second;\n" + "uniform sampler2D Texture_Dither;\n" + "uniform highp float BitValue;\n" + "uniform mediump float Alpha;\n" + "uniform highp vec2 Rand2f;\n" + "\n" + "#ifdef VERTEX_SHADER\n" + "void main(void)\n" + "{\n" + " gl_Position = ModelViewProjectionMatrix * Attrib_Position;\n" + " TexCoord1 = Attrib_TexCoord0.xy;\n" + "}\n" + "#endif\n" + "\n" + "#ifdef FRAGMENT_SHADER\n" + "void main(void){\n;" + " vec4 tex1 = dp_texture2D(Texture_First , TexCoord1);\n" + " vec4 tex2 = dp_texture2D(Texture_Second, TexCoord1);\n" + " vec4 tex3 = dp_texture2D(Texture_Dither, TexCoord1*8.0+Rand2f);\n" + " dp_FragColor = (Alpha)*tex1 + (1.0-Alpha)*tex2 + (tex3-0.5-1/512)*BitValue;\n" + "// dp_FragColor = tex3*0.5; //To check the quality of the noise\n" + "// dp_FragColor = tex2*0.95+tex3*0.05*0.5; //To check for patterns in the noise (should be gray)\n" + "}\n" + "#endif\n" + "\n" +"#else // !MODE_GHOSTMOTIONBLUR\n" +"\n" +"\n" +"\n" +"\n" "#ifdef MODE_BLOOMBLUR\n" "dp_varying mediump vec2 TexCoord;\n" "#ifdef VERTEX_SHADER\n" @@ -1718,6 +1751,7 @@ "#endif // !MODE_WATER\n" "#endif // !MODE_REFRACTION\n" "#endif // !MODE_BLOOMBLUR\n" +"#endif // !MODE_GHOSTMOTIONBLUR\n" "#endif // !MODE_GENERIC\n" "#endif // !MODE_POSTPROCESS\n" "#endif // !MODE_SHOWDEPTH\n" -- 2.39.2