2

I'm programming a (hopefully) planetary shader for a Unity project. I'm relatively new to shaders, and as I understand the language here is a subset of CG Shader called ShaderLab.

My question is can this be done in a shader? I have the formulas to map coords to a sphere, but I just get a tangled mess. I used the same formulas in an XNA project to map planes from a unit cube to a unit sphere and it worked fine. What am I doing wrong?

Oh, and I'm testing this on a stock plane prefab in Unity placed at (0, 1, 0), scale (1, 1, 1).

Things to note:

  • appdata_base : a vertex format that consists of position, normal and one texture coordinate
  • _Object2World : current model matrix from Unity
  • UNITY_MATRIX_VP : current view * projection matrix from Unity

Here is my vertex shader:

struct v2f {
    float4 pos : SV_POSITION;
    float3 col : COLOR0;
};

v2f vert(appdata_base v) {
    v2f o;
    o.pos = v.vertex;
    o.pos = mul(_Object2World, o.pos); // _Object2World is the current model matrix from UNITY

    o.pos.x *= sqrt(1 - o.pos.y * o.pos.y / 2 - o.pos.z * o.pos.z / 2 + o.pos.y * o.pos.y * o.pos.z * o.pos.z / 3);
    o.pos.y *= sqrt(1 - o.pos.z * o.pos.z / 2 - o.pos.x * o.pos.x / 2 + o.pos.z * o.pos.z * o.pos.x * o.pos.x / 3);
    o.pos.z *= sqrt(1 - o.pos.x * o.pos.x / 2 - o.pos.y * o.pos.y / 2 + o.pos.x * o.pos.x * o.pos.y * o.pos.y / 3);

    o.pos = mul(UNITY_MATRIX_VP, o.pos);            
    o.col = v.normal * 0.5 + 0.5;

    return o;
}
Krizzen
  • 46
  • 4

1 Answers1

1

I found a silly mistake in my code. I was setting 'o.pos.x' to it's new value, then figuring the result for 'o.pos.y' using the new value I just calculated for 'o.pos.x'. The code below works satisfactorily in answering my question.

To comment further, mapping coordinates to a sphere is possible in a vertex shader in Unity. However, my end goal is impossible or much more challenging which is to map terrain coordinates onto a sphere. Unity doesn't allow terrain meshes to be rotated and seemingly imposes other restrictions. It might be possible to achieve such mapping with a more advanced vertex shader.

struct v2f {
    float4 pos : SV_POSITION;
    float3 col : COLOR0;
};

v2f vert(appdata_base v) {
    v2f o;

    float4 p = v.vertex;

    p.x *= sqrt(1 - v.vertex.y * v.vertex.y / 2 - v.vertex.z * v.vertex.z / 2 + v.vertex.y * v.vertex.y * v.vertex.z * v.vertex.z / 3);
    p.y *= sqrt(1 - v.vertex.z * v.vertex.z / 2 - v.vertex.x * v.vertex.x / 2 + v.vertex.z * v.vertex.z * v.vertex.x * v.vertex.x / 3);
    p.z *= sqrt(1 - v.vertex.x * v.vertex.x / 2 - v.vertex.y * v.vertex.y / 2 + v.vertex.x * v.vertex.x * v.vertex.y * v.vertex.y / 3);

    o.pos = mul(UNITY_MATRIX_MVP, p);
    o.col = v.normal * 0.5 + 0.5;

    return o;
}
Krizzen
  • 46
  • 4
  • What do you mean by "terrain mesh"? – Sergey Krusch Jun 08 '14 at 02:07
  • Also, why do you do transformation to sphere in shader? – Sergey Krusch Jun 08 '14 at 02:08
  • @SergeyKrusch To me, transform the terrain in a shader seems to be the easiest way to get spherical terrain. How would you propose I warp the terrain into a sphere? – Krizzen Jun 10 '14 at 16:56
  • You can do exactly the same thing in your application code (either in C# or JavaScript). It depend on how often you change the source mesh. If rarely: I would do it in application. If often, then, ok, shader is an option. – Sergey Krusch Jun 10 '14 at 19:46