Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Full procedural sphere with Vertex Shader (source code)

Discussion in 'Shaders' started by Przemyslaw_Zaworski, Jul 30, 2019.

  1. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    192
    I think this small piece of code can be useful, so I share. It draws sphere with center at point (0,0,0)
    and has per-face lighting (normals reconstructed from screen space derivatives).

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DrawSphere : MonoBehaviour
    4. {
    5.     public Shader shader;
    6.     protected Material material;
    7.    
    8.     void Start()
    9.     {
    10.         material = new Material(shader);
    11.     }
    12.  
    13.     void OnRenderObject()
    14.     {
    15.         material.SetPass(0);
    16.         Graphics.DrawProcedural(MeshTopology.Triangles, 12288, 1);
    17.     }
    18. }
    19.  
    Code (CSharp):
    1. // Draws full procedural sphere with per-face lighting
    2. Shader "Draw Sphere"
    3. {
    4.     Subshader
    5.     {  
    6.         Pass
    7.         {
    8.             Cull Off
    9.             CGPROGRAM
    10.             #pragma vertex VSMain
    11.             #pragma fragment PSMain
    12.             #pragma target 5.0
    13.            
    14.             float4 VSMain (uint id:SV_VertexID, out float3 p:TEXCOORD0) : SV_POSITION
    15.             {
    16.                 float f = id;
    17.                 float v = f - 6.0 * floor(f/6.0);
    18.                 f = (f - v) / 6.;
    19.                 float a = f - 64.0 * floor(f/64.0);
    20.                 f = (f-a) / 64.;
    21.                 float b = f-16.;
    22.                 a += (v - 2.0 * floor(v/2.0));
    23.                 b += v==2. || v>=4. ? 1.0 : 0.0;
    24.                 a = a/64.*6.28318;
    25.                 b = b/64.*6.28318;
    26.                 p = float3(cos(a)*cos(b), sin(b), sin(a)*cos(b));
    27.                 return UnityObjectToClipPos(float4(p, 1.0));
    28.             }
    29.  
    30.             float4 PSMain (float4 s:SV_POSITION, float3 p:TEXCOORD0) : SV_Target
    31.             {
    32.                 float3 dx = ddx_fine( p );
    33.                 float3 dy = ddy_fine( p );
    34.                 float3 light1 = normalize(float3(5,0,100));
    35.                 float3 light2 = normalize(float3(-100,0,-102));
    36.                 float3 light3 = normalize(float3(100,0,-100));  
    37.                 float3 normal = normalize(cross(dx,dy));
    38.                 float3 diffuse1 = max(dot(light1,normal),0.0) * float3(0.9,0.0,0.0);
    39.                 float3 diffuse2 = max(dot(light2,normal),0.0) * float3(0.0,0.9,0.0);
    40.                 float3 diffuse3 = max(dot(light3,normal),0.0) * float3(0.0,0.0,1.0);
    41.                 return float4(diffuse1+diffuse2+diffuse3,1.0);
    42.             }
    43.             ENDCG
    44.         }
    45.        
    46.     }
    47. }

    upload_2019-7-30_21-3-35.png
     
    Namey5, bgolus and Invertex like this.
  2. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    192
    OK. Now version with "smooth" normals, sphere with center at point(50, 0, 0).

    Code (CSharp):
    1. Shader "Draw Sphere"
    2. {
    3.     Subshader
    4.     {  
    5.         Pass
    6.         {
    7.             Cull Off
    8.             CGPROGRAM
    9.             #pragma vertex VSMain
    10.             #pragma fragment PSMain
    11.             #pragma target 5.0
    12.            
    13.             float4 VSMain (uint id:SV_VertexID, out float3 p:TEXCOORD0, out float3 n:TEXCOORD1) : SV_POSITION
    14.             {
    15.                 float f = id;
    16.                 float v = f - 6.0 * floor(f/6.0);
    17.                 f = (f - v) / 6.;
    18.                 float a = f - 64.0 * floor(f/64.0);
    19.                 f = (f-a) / 64.;
    20.                 float b = f-16.;
    21.                 a += (v - 2.0 * floor(v/2.0));
    22.                 b += v==2. || v>=4. ? 1.0 : 0.0;
    23.                 a = a/64.*6.28318;
    24.                 b = b/64.*6.28318;
    25.                 p = float3(cos(a)*cos(b), sin(b), sin(a)*cos(b));
    26.                 n = normalize(p);
    27.                 p += float3(50.0, 0.0, 0.0);
    28.                 return UnityObjectToClipPos(float4(p, 1.0));
    29.             }
    30.  
    31.             float4 PSMain (float4 s:SV_POSITION, float3 p:TEXCOORD0, float3 n:TEXCOORD1) : SV_Target
    32.             {  
    33.                 return float4(max(dot(normalize(_WorldSpaceLightPos0).xyz, n),0.0).xxx + UNITY_LIGHTMODEL_AMBIENT, 1.0);
    34.             }
    35.             ENDCG
    36.         }
    37.        
    38.     }
    39. }

    Procedural sphere vs Unity built-in sphere with legacy diffuse shader and grayscale ambient lighting.
    Can you guess, which one is which one ?

    upload_2019-7-31_15-47-51.png
     
unityunity