===================================================== Shadow Shader Unprojection and fixing ===================================================== Hi Helifax - well I got through my presentation and am able to breath a bit easier now ;-) I'll look at these shaders today for you. Quickly though, regarding your second message above. - Shadows are invariably a Pixel Shader effect, so there will (almost) always be a required fix there. The only exception I can think of with modern games is the Unity Engine. - When shadows are 2D, it is usually only a PS fix, BUT you may need to find a VS so you can pass parameters through for example - When shadows are "off", but not 2D - e.g. a slightly wrong depth - you usually have to find a shader that first makes them 2D, and then fix the PS that renders them. The shaders that make shadows 2D are invariably vertex shaders, and all you do is apply the negative correction. However, I have encountered one game (that I can remember) where I had to modify Pixel Shaders to make shadows 2D, and then fix other Pixel Shaders that rendered the shadows - that game was Metal Gear Rising. I have no idea how I worked that out, I guess I was "in the zone" at the time, but it was unusual. Unprojection: ust a quick reply, got a meeting in a few mins. The formula looks wrong - all it is doing is adding a scaled down correction of the separation to the x-coord. This is what you do for HUD, skybox etc, but not actual 3d objects. To make the shadows 2d you need to do something like this add r4.y, r3.w, -r4.y mul r4.x, r4.x, r4.y add r3.x, r3.x, -r4.x //Note the minus sign ===================================================== Disable Prechached shaders ===================================================== Regarding Risen and preshaders. Set ShaderOverride=2 in DX9Settings.ini, and then in the shader just comment out the preshader sections. That usually works. ===================================================== Shader Fixing Pattern: ===================================================== dcl_texcoord v0 dcl_texcoord1 v1.xyz dcl_2d s0 dcl_2d s1 dcl_2d s2 dcl_2d s3 rcp r0.x, v1.z mul r0.xyz, r0.x, v1 texldp r1, v0, s0 mul r0.xyz, r0, r1.x mad_sat r1.x, r1.x, c16.x, c16.y mov r0.w, c21.x //View coord: THIS NEEDS CORRECTING dp4 r1.y, r0, c12 //View to shadow transform dp4 r2.x, r0, c10 dp4 r2.y, r0, c11 I believe that the variable r0 is the VIEW COORD. The big giveaways are the way it is constructed i.e. dividing by v1.z, then multiplying by r1.x, and then setting r0.w = 1. To correct this requires 2 differences from the standard correction forumula: 1. using -r0.z instead of r0.w: sep*(-r0.z - conv) 2. Multiplying that lot by the P11 element of the Projection Matrix: sep*(-r0.z - conv)*P11 3. Sometimes (I forget the logic) you need to divide by the P11. If you have the InverseProj matrix, it is the inverse way around - so you basically try both to see which one works. The trouble you have is that you do not have the Projection matrix, or the InverseProjection matrix handy. There are two things you can do: 1. Find the VS that feeds into this PS and see if that has a Projection matrix in it (not ModelViewProj or ViewProj, just a Proj) and if so create a new output variable and set it to the first row of that matrix. In the PS, add that as an input variable vN and then P11 = vN.x. 2. If the VS does not have a Proj Matrix, look to see if it has a 4-vector constant called something like "projectionParams", "deferredProjectionParams" - if so, pass that to the PS, and the required paramater is usually the x-value. 3. Failing that, you need to find other VS that might have a projection matrix in, and share that through the DX9Settings.ini. Or more efficiently you can just share the first row element as a constant. 4. Failing that you might need to resort to creating a WORLD coordinate and correcting that: 4.1 To get a world coord from the view coordinate you will need the CameraPosition/ViewPosition 4.2 You can get this either by passing through from a VS if it is in there, or sharing the constant from other VS's, the same was as above 4.3 The formula is WC = CamPos + ViewVector, where ViewVector is the ViewPos with the w=0 4.4 You will then need to find VS's with a VPM in and share that through the DX9Settings.ini file, then in the code: - Create WC - Forward transform the WC using VPM - Stereo correct with normal NVidia formula - Transform back with Inverse VPM (also generated by DX9Settings) - Get the update ViewPos from the transformed WC ================================================ Matrix INFO: ================================================ - Model Space: the coordinate system centered on (0,0,0) (usually) in world space that defines the relative coordinates and position of each model, and essentially defines the models geometric shape. - World Space: The coordinate system for the game as a whole. All models are "moved" to the correct position and rotation in this space through the Model/World Matrix. Both terms are used, but it refers to moving the model into world space. Every model has its OWN Model/World transformation matrix, and thus they are not "reusable" - View Space: Sometime called Camera Space. This is a space derived from a COORDINATE TRANSFORMATION. Models do not move or change their relative positions. It is a transformation to the POV of the Camera/Eye. There is JUST ONE transformation that applies to all models in the scene, the View Transformation. The View Matrix is actually the Inverse of the camera's world matrix - Projection Space / Normalized Device Coordinates (NDC): The is a globally applied transformation (on all models in the scene), done by the Projection Matrix, on View Space, to "map" View Space onto a 2D surface (the screen). It also scales it all to fit into a unit-sized box (actually usually [-1,1], so its size 2, but I think DX and OGL use different conventions, so you need to check that), and also does what is known as a perspective divide, which is dividing by the View Space z-value, which is the scene depth. This is what makes things farther away look smaller etc. The maths is straightforward. Again there is only ONE Projection Matrix. ================================================= Other Shader Info ================================================= In the VS's I can see: g_vViewProjection g_vCamPosAndFar ...and this is in most of them. I would thus be very surprised if the VS that connects to the shadow VS does not have these as well. In which case you can pass in the CamPos straightup. You can use the DX9Settings.ini file to "share" the g_vViewProjection matrix and it's inverse with the PS. It's unfortunate there are no Inverse VP matrices. To get this working you may need to find a few VS's and share the VPs from all of them - I can show you how to do that. First find me the right VS for the shadow PS (actually for both of the PS's you sent me), and I will put something together. ================================================= Matrix Sharring between shaders ================================================= To get the matrix ================= Find a shader, usually a VS, but not always, that has the matrix in you want to share. Get the first register for that matrix e.g. it is a VPM that uses c0-c3. So "0" is the number. Create this in DX9settings.ini: [VSnnnnnn] UseMatrix=true GetMatrixFromReg = 0 MatrixReg = N InverseMatrix = true DoubleInverseMatrix = true So here, - the "0" means get the traix strating at the c0 register - the "N" is a number you decide you want to set it to. Choose this so that it does not conflict with a constant register in the shader you want to use it in - InverseMatrix = true means that cN will contain the inverse of c0-c3 in cN, c(N+1), c(N+1), c(N+3) - DoubleInverse = true means that the original matrix will be in c(N+4)-c(N+7) Identify the shader you want to use this matrix in, then create a second entry in DX9Settings.ini: [PSmmmmmmm] UseMatrix=true MatrixReg = N InverseMatrix = true DoubleInverseMatrix = true - here you see the cN value is specified. In the actual shader PSmmmmmmmm you can now use cN->c(N+7). The real tricky part is working out which fracking VS to use to get the original matrix. This is the programmatic constraint: - The shader with the original matrix must be called every frame, and before the shader that wants to reuse the matrix How do you find this out? No idea - maybe a profiler tool or something, but I usually use sensible guesswork. Most VS are called before a PS, so that's usually a good bet. If you can find a VS that is the 'parent' of a PS or set of PS's that is also a good candidate. Also, look for effects which are ubiquitous and bound to be called every frame, like a diffuse light, or one of the small geometry shaders - it's often guesswork. Importantly you can, and often must, specify more than one "source" VS. Sometimes I just find all shaders with the VPM in and add all of them to the DX9Settings.ini file (sometimes hundreds, though I have scripts to automate it from the Dumps folder). One other important things is that *it seems* that you need to have the VS's you use for matrix re-use in the vertexshaders folder. Sometimes this can cause other graphical artifacts and conflicts so you need to track down the cuplrits and get rid of them One last thing, the form you need to use for matrix multiplication must be the form used in its own original shader (which depends on whether the matrix is row or column major). The two forms are as follows: dp4 dp4 dp4 dp4 and mul mad mad add or mad The latter is actually the syntax for multiplying by the transpose of a matrix, which is why its used for column major matrices. To test if its working, and that the matrix is actually being shared, identify the coordinate register you want to fix, and simply do a forward transform followed by a backward transform, which should leave the coordinate exactly where it started, and when you press F10 the game should not change one little bit. If the effect disappears, or gets corrupted, the matrix is probably empty and you need to track down another VS. Example: The shared matrix was set to c100 So the inverse is c100-c103 And the forward is c104-c107 Assume the matrix form is dp4. Assume the coord register is r0 Do this: dp4 r1.x, r0, c104 dp4 r1.y, r0, c105 dp4 r1.z, r0, c106 dp4 r1.w, r0, c107 dp4 r0.x, r1, c100 dp4 r0.y, r1, c101 dp4 r0.z, r1, c102 dp4 r0.w, r1, c103 When this works, you know you have a matrix that is correct. If r0 is a world coord, you would the stereo correction right in the middle between these two operations. ======================================= Convergence Locking ======================================= If shadows are accurate at only at a particular convergence setting you can lock it. Create a dx9settings.ini [General] PresetsKeysList = 1; [KEY1] Key = 114 Presets = 9; Type = 1 [PRES9] UseSepSettings = true SaveSepSettings = true Convergence = 0x41500000 UseByDef = true ========================================== MATRICES ========================================== - InvProjectionMatrix is used which takes a coord from proj to view space - ViewMatrix is used which takes a coord from world to view space - To correct a world coord, so in this case the r1.xyz value will need a ViewProj and and InvViewProj, which we don't have directly in this shader (though the InvViewProj can be generated from the separate InView and InProjection matrices). r22.x -= stereo.x*(-r22.z - stereo.y)*_InvProjectionMatrix._m00; The differences with the "normal" stereo fix are: - use -r22.z instead of r22.w (because that does not exist) - multiply by _InvProjectionMatrix._m00. We happen to be fortunate that this shader contains this matrix. If it's not clear whether you need to multiply or divide by this parameter, or if you just plain forgot, try them both. If you have the ProjMatrix, you can use that too. To understand this you need to go through the maths of multiplying the Proj Matrix to see why it is this way, but I am not going to do that.