!!ARBvp1.0 OPTION ARB_position_invariant ; # SteveL #3879: Do not distort where the sampled texel would come from a surface closer than # the water surface. Fix for water distorting player weapon etc. Amendments to frag prog. # SteveL #4306: Output the "depth" of water between the player and the background into the alpha # channel, so that subsequent material stages can use it to blend correctly between their own colour and # the background color, giving the impression of murky water containing sediment. # # # input: # # attrib[8] (former texcoord[0]) TEX0 texcoords # # local[0] scroll # local[1] deform magnitude (1.0 is reasonable, 2.0 is twice as wavy, 0.5 is half as wavy, etc) # local[2] depth of this material needed to completely hide the background. #4306 # # output: # # texCoord[1] is the model surface texture coords # texCoord[2] is the copied deform magnitude # vertex color is used to pass the depth from local[2] to the fragment shader #4306 TEMP R0, R1, R2; # texture 1 takes the texture coordinates and adds a scroll ADD result.texcoord[1], vertex.attrib[8], program.local[0]; # texture 2 takes the deform magnitude and scales it by the projection distance PARAM vec = { 1, 0, 0, 1 }; MOV R0, vec; DP4 R0.z, vertex.position, state.matrix.modelview.row[2]; DP4 R1, R0, state.matrix.projection.row[0]; DP4 R2, R0, state.matrix.projection.row[3]; # don't let the recip get near zero for polygons that cross the view plane MAX R2, R2, 1; RCP R2, R2.w; MUL R1, R1, R2; # clamp the distance so the the deformations don't get too wacky near the view MIN R1, R1, 0.02; MUL result.texcoord[2], R1, program.local[1]; MOV result.color, program.local[2]; END #====================================================================== !!ARBfp1.0 OPTION ARB_precision_hint_fastest; # texture 0 is _currentRender # texture 1 is a normal map that we will use to deform texture 0 # texture 2 is _currentDepth # # env[0] is the 1.0 to _currentRender conversion # env[1] is the fragment.position to 0.0 - 1.0 conversion # # Hard-coded constants # depth_consts allows us to recover the original depth in Doom units of anything in the depth # buffer. TDM's projection matrix differs slightly from the classic projection matrix as it # implements a "nearly-infinite" zFar. The matrix is hard-coded in the engine, so we use hard-coded # constants here for efficiency. depth_consts is derived from the numbers in that matrix. # TEMP localNormal, R0; PARAM subOne = { -1, -1, -1, -1 }; PARAM scaleTwo = { 2, 2, 2, 2 }; # load the filtered normal map and convert to -1 to 1 range TEX localNormal, fragment.texcoord[1], texture[1], 2D; MOV localNormal.x, localNormal.a; MAD localNormal, localNormal, scaleTwo, subOne; # calculate the screen texcoord in the 0.0 to 1.0 range MUL R0, fragment.position, program.env[1]; # offset by the scaled localNormal and clamp it to 0.0 - 1.0 MAD_SAT R0, localNormal, fragment.texcoord[2], R0; # scale by the screen non-power-of-two-adjust MUL R0, R0, program.env[0]; # Get the displaced color TEMP displacedColor; TEX displacedColor, R0, texture[0], 2D; # Fix foreground object distortion. Get another sample from the opposite direction, # to use if the sample came from the foreground. TEMP altCoord, altColor, origCoord, chosenColor; MUL origCoord, program.env[0], program.env[1]; # Screen space to MUL origCoord, origCoord, fragment.position.xyxy; # tex coord conversion SUB altCoord.xy, R0, origCoord; # Diff between original coord and distorted coord ADD altCoord, origCoord, -altCoord; # Now distorted in the opposite direction TEX altColor, altCoord, texture[0], 2D; # Test whether the samples came from the foreground, rejecting them if so. # Start with the original undistorted color. We'll use this if both samples came # from the foreground. TEX chosenColor, origCoord, texture[0], 2D; # Next 4 lines are needed for #4306 -- alpha depth # #4306 In each case record the depth of the sample in the alpha channel w TEMP depth; MUL origCoord.xy, origCoord, program.env[4].zwzw; # zw holds the ratio of _currentRender size to _currentDepth size TEX depth, origCoord, texture[2], 2D; MOV chosenColor.w, depth.x; # Test whether the alt color came from the background, and use it in preference if so MUL altCoord.xy, altCoord, program.env[4].zwzw; # zw holds the ratio of _currentRender size to _currentDepth size TEX depth, altCoord, texture[2], 2D; MOV altColor.w, depth.x; #4306 SUB depth, depth.x, fragment.position.z; CMP chosenColor, depth, chosenColor, altColor; # Test whether the displaced color came from the background, and use it in preference if so MUL R0.xy, R0, program.env[4].zwzw; TEX depth, R0, texture[2], 2D; MOV displacedColor.w, depth.x; #4306 SUB depth, depth.x, fragment.position.z; CMP chosenColor, depth, chosenColor, displacedColor; # #4306 Calculate the opacity of the material using the depth difference between the # transparent surface and the solid background PARAM depth_consts = { 2, -2, 0.0, 0.0 }; TEMP scene_depth, surface_depth, final_rgba; # Calculate original depth in doom units from the nonlinear depth buffer values we captured earlier MIN chosenColor.w, chosenColor.w, 0.9994; # Required by TDM projection matrix. Equates to max recoverable # depth of 30k units, which is enough. 0.9995 is infinite depth. This # is needed only if there is caulk sky on show (which writes no depth, # so leaves 1 in the depth texture). MAD scene_depth, chosenColor.w, depth_consts.x, depth_consts.y; RCP scene_depth, scene_depth.x; # Find the depth of the transparent surface in doom units too MAD surface_depth, fragment.position.z, depth_consts.x, depth_consts.y; RCP surface_depth, surface_depth.x; # Calculate the depth diff, divide by the opaque threshold and clamp # NB depths are negative. We use -tmp in the division to give a positive # value where the surface is visible in front of the solid background ADD final_rgba, scene_depth, -surface_depth; MUL_SAT final_rgba.a, -final_rgba.r, fragment.color.r; MOV final_rgba.rgb, chosenColor; MOV result.color, final_rgba; END