Search Unity

Problem with bending terrain shader

Discussion in 'Shaders' started by Waliactico, Feb 20, 2014.

  1. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    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:

    $problemCurvedShaderSmall.png
    Here with higher quality: http://i.imgur.com/BncqIk7.png

    And this is the shader itself:
    Code (csharp):
    1.  
    2. Shader "Mobile/Curved" {
    3. Properties {
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     _QOffset ("Offset", Vector) = (0,0,0,0)
    6.     _Dist ("Distance", Float) = 100.0
    7. }
    8. SubShader {
    9.     Tags { "RenderType"="Opaque" }
    10.     LOD 150
    11.  
    12.     CGPROGRAM
    13.     #pragma exclude_renderers flash
    14.     #pragma surface surf Lambert noforwardadd vertex:vert
    15.    
    16.     sampler2D _MainTex;
    17.     float4 _QOffset;
    18.     float _Dist;
    19.    
    20.     struct Input {
    21.         float2 uv_MainTex;
    22.     };
    23.    
    24.     void vert (inout appdata_full v) {
    25.         // Get the view space vertex position
    26.         float4 vertex_view = mul(UNITY_MATRIX_MV, v.vertex);
    27.         // Calculate the offset in view space
    28.         float zOff = vertex_view.z / _Dist;
    29.         // Convert the offset back to object space and add it to vertex
    30.         v.vertex.xyz += mul(UNITY_MATRIX_IT_MV, _QOffset*zOff*zOff).xyz;
    31.     }
    32.    
    33.     void surf (Input IN, inout SurfaceOutput o) {
    34.         fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
    35.         o.Albedo = c.rgb;
    36.         o.Alpha = c.a;
    37.     }
    38.    
    39.     ENDCG
    40. }
    41.  
    42. Fallback "Mobile/VertexLit"
    43. }
    44.  
    I hope you can help me, I really need to get this fixed! Thank you very much!
     
  2. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    Can anyone help me, please?
     
  3. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Where is _QOffset coming from?

    Why are you multiplying by the inverse transpose of MV?
     
  4. AdBar

    AdBar

    Joined:
    Feb 1, 2014
    Posts:
    17
    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.
     
  5. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    _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?
     
  6. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    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).
     
  7. AdBar

    AdBar

    Joined:
    Feb 1, 2014
    Posts:
    17
    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.
     
  8. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    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.
     
  9. AdBar

    AdBar

    Joined:
    Feb 1, 2014
    Posts:
    17
    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.
     
  10. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    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.
     
  11. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    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?
     
  12. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    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.
     
  13. Waliactico

    Waliactico

    Joined:
    Jan 16, 2013
    Posts:
    91
    Ok guys, I've replaced
    Code (csharp):
    1. v.vertex.xyz += mul(UNITY_MATRIX_IT_MV, _QOffset*zOff*zOff).xyz;
    by
    Code (csharp):
    1. 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!
     
  14. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    Subway surfers did the exact same thing in their game.
     
  15. Dharma_raj

    Dharma_raj

    Joined:
    Jun 21, 2013
    Posts:
    109
    Hi, This Shader works great!! Can anyone help me on how to make it as a unlit and unlit transparent shader.

    Thanks