Problem with bending terrain shader

Hi, I’m having trouble with a shader that should curve the terrain. The problem is that the objects with this shader act differently according to their rotation. For example, I have a long corridor and a set of 3 spheres. If all of the GOs have zero rotation, everything looks fine. But if I change the rotation of one of those spheres, it goes up and down, and I don’t want that, since sometimes the scene looks all messed up. Here are some pics illustrating this problem:


Here with higher quality: Imgur: The magic of the Internet

And this is the shader itself:

Shader "Mobile/Curved" {
Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_QOffset ("Offset", Vector) = (0,0,0,0)
	_Dist ("Distance", Float) = 100.0
}
SubShader {
	Tags { "RenderType"="Opaque" }
	LOD 150

	CGPROGRAM
	#pragma exclude_renderers flash
	#pragma surface surf Lambert noforwardadd vertex:vert
	
	sampler2D _MainTex;
	float4 _QOffset;
	float _Dist;
	
	struct Input {
		float2 uv_MainTex;
	};
	
	void vert (inout appdata_full v) {
		// Get the view space vertex position
	    float4 vertex_view = mul(UNITY_MATRIX_MV, v.vertex);
	    // Calculate the offset in view space
	    float zOff = vertex_view.z / _Dist;
	    // Convert the offset back to object space and add it to vertex
	    v.vertex.xyz += mul(UNITY_MATRIX_IT_MV, _QOffset*zOff*zOff).xyz;
	}
	
	void surf (Input IN, inout SurfaceOutput o) {
		fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
		o.Albedo = c.rgb;
		o.Alpha = c.a;
	}
	
	ENDCG
}

Fallback "Mobile/VertexLit"
}

I hope you can help me, I really need to get this fixed! Thank you very much!

Can anyone help me, please?

Where is _QOffset coming from?

Why are you multiplying by the inverse transpose of MV?

If you want to send back the vertices you dont need to transpose, just do the inverse. As for your rotation problem, are you sure its the shader? does it rotate properly with a regular diffuse? Anyways try to remove the transpose might fix your issue.

_QOffset is a parameter, it’s configurable. The multiplication by UNITY_MATRIX_IT_MV is for getting back to object space. I thought it was the correct way to covert from view to object space, am I missing something? As far as I know, there’s no built in matrix for modelview inversed and not transposed, is it? https://docs.unity3d.com/Documentation/Components/SL-BuiltinValues.html
How can I do what you guys suggest?

I think you’d need to do the bending in world space, then put it back into object space.

Otherwise all of the positions/rotations values are relative to the object’s origin, rather than a constant point (world origin).

I think he wants to do the bending based on the camera’s position, thats why the changes are made in the view matrix, so they are relative to the camera’s position. As for getting just the inverse, to revert a transpose, you just transpose again. Inversing is not enabled in unity’s implementation of CG , its a much more demanding operation than transposing, so you can just transpose the IT_MV and youll get the I_MV basically. Hope that helps.

There’s a lot of confusion in this thread. My guess is that this distortion is supposed to happen in world space. MV and IT_MV convert points and normals, respectively, from object space to eye space. Neither of those matrices should be used if you want to perform any calculations in world space. Instead, use Unity’s built-in _Object2World and _World2Object matrices. They have easier-to-read names and do exactly what (I think) you want.

I’ve seen curvature shaders that work in view space, but they look stupid because the curvature is always relative to your view. Rotating the camera around its Z axis will make it clear why that’s a bad idea.

It would definetly help if he posted what type of game this was, view space modification would work if it was an infinite runner for example where rotation of the camera doesn’t really happen. But that is more on topic of game design than anything else.

Good point. More information would definitely be useful, and view space transformations could make sense.

In any case, IT_MV is not the inverse of MV.

Well, the game is indeed an infinite runner, that’s why the bending is calculated in view space. I’m not quite sure if a bending in world space would give the same results (as you can see, I’m no expert in shaders…). So, with that being said, do you recommend to do the bending in world or view space?

Bending in view space is fine as long as the camera never rotates. Otherwise, bending in world space will make the bending stable in world space, regardless of how the camera is rotated.

Ok guys, I’ve replaced v.vertex.xyz += mul(UNITY_MATRIX_IT_MV, _QOffset*zOff*zOff).xyz; by v.vertex.xyz += mul(_QOffset*zOff*zOff, UNITY_MATRIX_IT_MV).xyz; in order to not transpone the matrix, and now everything looks fine. I can’t assure it will in every situation though, but I think it’s ok now!
If anyone is interested in why I started by bending in view space, it’s because that way all game calculations are made as if the path is completely straight. The camera is only rotating in the corners, but it does it quickly and there’s no noticeable deformation.
Thank you very much guys, I appreciate your help!

Subway surfers did the exact same thing in their game.

Hi, This Shader works great!! Can anyone help me on how to make it as a unlit and unlit transparent shader.

Thanks