Search code examples
unity-game-enginegeometryshaderhlslvertex-shader

Spherical mapping


I'm having trouble projecting objects (for example a plane) onto a spherical surface.

The shader just have to take vertex local position (P0), convert it in world coordinates (P1), then find the vector from a given center (C) to P1 (P1 - C). So normalize this vector and multiply by a given coefficient, and finally convert back to local coordinates.

I'm working in Unity with surface shaders

Shader "Custom/testShader" {
   Properties {
      _MainTex("texture", 2D) = "white" {}
      _Center("the given center", Vector) = (0,0,0)
      _Height("the given coefficient", Range(1, 1000) = 10
   }
   Subshader {
      CGPROGRAM
      #pragma surface surf Standard vertex:vert
      sampler2D _MainTex;
      float3 _Center;
      float _Height;

      struct Input { float2 uv_MainTex; }

      // IMPORTANT STUFF
      void vert (inout appdata_full v) {
         float3 world_vertex = mul(unity_ObjectToWorld, v.vertex) - _Center;
         world_vertex = normalize(world_vertex) * _Height;
         v.vertex = mul(unity_WorldToObject, world_vertex);
      }
      // END OF IMPORTANT STUFF

      void surf (Input IN, inout SurfaceOutputStandard o) {
         o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
   }
}

Now the problem is that in the scene, where I have some planes with this shader, they look split and much more little that what they are supposed to be. Any ideas?

EDIT

Here are some screenshots: The meshes without the shader The same meshes with the shader


Solution

  • You are transforming world_vertex as a direction (X,Y,Z,0) instead of position (X,Y,Z,1). See this for more info.

    So this line
    v.vertex = mul(unity_WorldToObject, world_vertex);
    should be
    v.vertex = mul(unity_WorldToObject, float4(world_vertex, 1) );