Search Unity

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:
    171
    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:
    171
    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