I'm writing a vertex displacement shader that needs to do some operations in view space. The problem is, if I just use MODELVIEW_MATRIX or VIEW_MATRIX then the shadows get messed up (I'm guessing it uses a different transform matrix when rendering shadows or something). As a work around, I thought I'd make a mat4 global shader variable to hold the transform of my main camera and update it in my camera script whenever the camera moved like so:
RenderingServer.GlobalShaderParameterSet("CameraTransform", GetCameraTransform());

This code works, but the matrix it's passing to the shader doesn't. If I try just replacing "VIEW_MATRIX" with "CameraTransform" in the shader code, the result is messed up. One problem is I'm not totally sure what the VIEW_MATRIX is supposed to look like. What I get from my camera script looks right from what I can tell, but clearly it isn't the same matrix since I'm getting different results. I also tried using the transpose and inverse of the matrix, but neither looked any better. I have some screenshots below of the camera transform and how it's being applied to the global shader variable, as well as a snippet of the relevant shader code.

//The code below lives in a shader include file and is called from various shaders
//vec3 vertex is the vertex passed in from the actual shader
//model is MODELVIEW_MATRIX
//view is VIEW_MATRIX
global uniform float ScaleFactor;
global uniform mat4 CameraTransform;
global uniform vec3 CameraPos;
global uniform vec3 CameraDir;

vec3 ScaleOffsetVector(vec3 vertex, mat4 model, mat4 view) {
	//convert to World space
	vec3 wv = (model * vec4(vertex,1)).xyz;
	//convert to View space
	//vec3 vv = (view * vec4(wv,1)).xyz;
	vec3 vv = (CameraTransform * vec4(wv,1)).xyz;
	
	//Scale the vertex positions in view space
	float d = dot((wv.xz - CameraPos.xz), CameraDir.xz);
	float s = max(d*ScaleFactor,1.f);
	s = 1.f + (d*ScaleFactor -1.f ) * smoothstep(1.f/ScaleFactor,1.f/ScaleFactor+10.f,d);
	vv.xy /= s;
	
	//Convert back to model space
	//mat4 w = inverse(view);
	mat4 w = inverse(CameraTransform);
	vv = (w * vec4(vv,1.f)).xyz;
	vv = (inverse(model) * vec4(vv,1.f)).xyz;
	return vv;
}
  • xyz replied to this.
  • xyllar So MODELVIEW_MATRIX works as you want except for causing weird shadows?
    Try enlarging plane's bounding box by setting mesh instance's custom_aabb to something much larger than its original aabb that you can get by calling get_aabb(). If you're displacing an originally flat plane in y direction by much the final bounding box may end up being a lot larger. This can cause engine to wrongly estimate actual shadow map viewing frustum, leaving some parts of displaced plane out of it. Also try increasing directional shadow max distance.

    xyllar The problem is, if I just use MODELVIEW_MATRIX or VIEW_MATRIX then the shadows get messed up

    Messed up how? Do you displace out of mesh's original bounding box?

    Multiplying object space vertices with MODELVIEW_MATRIX should put them into view/camera space.

      xyz
      With MODELVIEW_MATRIX I get shadows that look wrong. It's hard to explain so I'll post some pictures. The idea is to create a view that looks like you are climbing a hill, with objects cresting over the top. Here's what it looks like with MODELVIEW_MATRIX (well, technically MODEL_MATRIX to convert model to world space then VIEW_MATRIX to convert to view space. It should be the same, but I wanted to keep things as consistent as possible for comparing the two methods and rule out any unrelated errors.) As you can see, there is a large shadow, which I'm guessing is coming from where the plane is projecting onto itself since the shadow pass is projected from a different viewpoint.

      Next I tried replacing it with the CameraTransform variable I created. As you can see, the part of the plane affected by the vertex displacement is highly distorted.

      Here is a view from another angle that better shows how it is distorted.

        xyllar
        Also as I mentioned in the original post, I also tried the transpose of the CameraTransform matrix. This actually looks much better and I suspect I may be on the right track, but there is still some distortion that isn't there in the original. The weird shadows are gone though, which supports my theory that the shadows use a different view transform matrix.

        • xyz replied to this.

          xyllar Your posted shader code multiplies with the matrix named model for which you state in the comment that it is MODELVIEW_MATRIX. Then you multiply the transformed vertex again with the VIEW_MATRIX or camera transform. This results in double multiplication with view matrix.

          In vertex() function it's enough to multiply input VERTEX with MODELVIEW_MATRIX to get the vertex in view space. No need for custom matrices. You should just use that.

          The problem with the shadow may be caused by displaced geometry going out of its bounding box.

          Btw, it's not entirely clear from your images how you want it to look versus how it actually looks.

            xyz
            Sorry, the comment is a typo. I checked and I am passing in MODEL_MATRIX not MODELVIEW_MATRIX (darn, I thought you'd solved it for a minute!). The first image is basically what I want except for the weird shadows, which are the main problem I'm trying to solve. If you have any alternate ideas for correcting the shadows I'd be open to suggestions there to. I could just turn off shadow cast for the large plane, but I'm worried that the issue may crop up again when I add more objects.

            • xyz replied to this.

              xyllar So MODELVIEW_MATRIX works as you want except for causing weird shadows?
              Try enlarging plane's bounding box by setting mesh instance's custom_aabb to something much larger than its original aabb that you can get by calling get_aabb(). If you're displacing an originally flat plane in y direction by much the final bounding box may end up being a lot larger. This can cause engine to wrongly estimate actual shadow map viewing frustum, leaving some parts of displaced plane out of it. Also try increasing directional shadow max distance.

                xyz
                Thanks, this works and was a much simpler solution than what I was trying to do.