title: Unity Shader Normals wrong
body: <p>just wondering if anyone can lend a hand, spent hours so far on this:</p>
  
  <p><a href="https://i.stack.imgur.com/vM65H.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/vM65H.png" alt="enter image description here"></a></p>
  
  <p>Does anyone know why this is happening??? as I move along, the bottom is always brighter than the top.</p>
  
  <p>the basic flow of the vert:
  *get point that is +X and a point that is +Z for use in cross multiplication later to get normal</p>
  
  <p>*translate those points to world space so that I may look for obsticals in real space</p>
  
  <p>*figure out the y axis displacement for our point + the extras made in step one for cross</p>
  
  <p>*increment object space values by displacement</p>
  
  <p>*find new normal using cross</p>
  
  <p>*set normal</p>
  
  <p>*set vertex.</p>
  
  <p>What I think is happening is that the normals are on the wrong axis... any help apreciated</p>
  
  <p><a href="https://i.stack.imgur.com/5Zy9w.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5Zy9w.jpg" alt="enter image description here"></a></p>
  
  <pre><code>Shader "Custom/ExtrudePointArray" {
      Properties {
          _Color ("Color", Color) = (1,1,1,1)
          _MainTex ("Albedo (RGB)", 2D) = "white" {}
          _Glossiness("Smoothness", Range(0,1)) = 0.5
          _Metallic("Metallic", Range(0,1)) = 0.0
  
              //water stuff
              _Scale("Scale", float) = 1
              _Speed("Speed", float) = 1
              _Frequency("Frequency", float) = 1
  
              // wave maker
              _Height("_Height", float) = 1.0
              _Extrude_Close("_Extrude_Close", float) = 3.0
  
              [HideInInspector]_ExtrudePointCount("_ExtrudePointCount", int) = 0
      }
      SubShader {
          Tags { "RenderType"="Opaque" }
          LOD 200
  
          CGPROGRAM
          // Physically based Standard lighting model, and enable shadows on all light types
  #pragma surface surf Standard fullforwardshadows  vertex:vert
  
          //debug normals
  //#pragma surface surf Standard fullforwardshadows  vertex:vert finalcolor:showNormals
  
          // Use shader model 3.0 target, to get nicer looking lighting
          #pragma target 4.0
  
          sampler2D _MainTex;
  
          struct Input {
              float2 uv_MainTex;
              float3 newNormal;
              half3 debugColor;
          };
  
          half _Glossiness;
          half _Metallic;
          fixed4 _Color;
  
          // water stuff
          float _Scale, _Speed, _Frequency;
  
  
          float _Extrude_Close, _Height;
          uniform float _ExtrudePointX[20], _ExtrudePointZ[20], _ExtrudePointCount;
  
          float calcWaveHeight(float2 worvldLoc) {
              //disruption
              half offsetvertDis = ((worvldLoc.x * worvldLoc.x) + (worvldLoc.y * worvldLoc.y));
              half valueDis = _Scale * sin(_Time.w * _Speed + offsetvertDis * _Frequency*1000);
              // diag wave
              half offsetvertDiag =  worvldLoc.x +worvldLoc.y;
              half valueDiag = _Scale * sin(_Time.w * _Speed * _Frequency + offsetvertDiag);
  
              return valueDis + valueDiag;
          }
  
          float calcDistFromPoint(float2 worldLoc, float2 pointToCheck) {
              float closePercent = 0;
              float dist = abs(distance(worldLoc, pointToCheck));
  
              if (dist &lt; _Extrude_Close) {
                  closePercent = (_Extrude_Close - dist / _Extrude_Close);
              }
              return closePercent;
          }
  
          float calcVertNewPos(float3 worldLoc) {
              float highestPos = 0;
              float2 worldLocHor = float2(worldLoc.x, worldLoc.z);
  
              for (int i = 0; i &lt; _ExtrudePointCount; i++) {
                  float2 boxPos = float2(_ExtrudePointX[i], _ExtrudePointZ[i]);
  
                  float newPos = calcDistFromPoint(worldLocHor, boxPos) * _Height;
  
                  // the value returned is a float so don't check for zero, check that it's not above zero
                  if (newPos &lt; 0.001) {
                      newPos = calcWaveHeight(worldLocHor);
                  }
  
                  if (newPos &gt; highestPos) {
                      highestPos = newPos;
                  }
                  //highestPos = worldLoc.x * i;
              }
  
              return highestPos;
          }
  
          void vert(inout appdata_full v, out Input o)
          {
              UNITY_INITIALIZE_OUTPUT(Input, o);
  
              float3 v0 = v.vertex.xyz;
              float3 v1 = v0 + float3(0.05, 0, 0); // +X
              float3 v2 = v0 + float3(0, 0, 0.05); // +Z
  
              float3 w0 = mul(unity_ObjectToWorld, v.vertex).xyz;
              float3 w1 = w0 + float3(0.05, 0, 0); // +X
              float3 w2 = w0 + float3(0, 0, 0.05); // +Z
  
              float h0 = calcVertNewPos(w0);
              float h1 = calcVertNewPos(w1);
              float h2 = calcVertNewPos(w2);
  
              v0.y = h0;
              v1.y = h1;
              v2.y = h2;
  
              float3 vna = cross(v2 - v0, v1 - v0);
  
              // debug
              //o.debugColor = (normalize(v0) * 0.5) + 0.5;
              //o.debugColor = (normalize(v.vertex.xyz) * 0.5) + 0.5;
              //o.debugColor = (normalize(vna) * 0.5) + 0.5;
  
              // Put normals back in object space
              //float3x3 worlspace = float3x3(unity_WorldToObject.xyz);
  
              v.normal = normalize(vna);
              o.newNormal = v.normal;
  
              v.vertex.xyz = v0;
          }
  
          void showNormals(Input IN, SurfaceOutputStandard o, inout fixed4 color) {
              color.rgb = IN.debugColor.rgb;
              color.a = 1;
          }
  
          void surf (Input IN, inout SurfaceOutputStandard o) {
              // Albedo comes from a texture tinted by color
              fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
              o.Albedo = c.rgb;
              // Metallic and smoothness come from slider variables
              o.Metallic = _Metallic;
              o.Smoothness = _Glossiness;
              o.Alpha = c.a;
              o.Normal = IN.newNormal;
          }
          ENDCG
      }
      FallBack "Diffuse"
  }
  </code></pre>
  
  <p>I know I'm almost certainly doing somthing wrong reguarding normal calculation.. But I can't find any good resources on it and the only thing I did find: <a href="https://www.youtube.com/watch?v=1G37-Yav2ZM" rel="nofollow noreferrer">https://www.youtube.com/watch?v=1G37-Yav2ZM</a> was written for an earlier version of the shader language and the site to download source is malware now :( This is killing me</p>
  
  <p>Also here's the code that runs the shader's extrude points if you need it:</p>
  
  <pre><code>using System;
  using System.Collections;
  using System.Collections.Generic;
  using UnityEngine;
  
  public class ExtrudePoint : MonoBehaviour {
  
      public GameObject[] Waves;
      private Renderer _renderer;
  
      // Use this for initialization
      void Start()
      {
          if (Waves == null || Waves.Length &gt; 8)
          {
              throw new Exception("Max of 8 waves, min of 1");
          }
  
          _renderer = GetComponent&lt;Renderer&gt;();
  
      }
  
      // Update is called once per frame
      void Update()
      {
          int totWaves = 0;
          // probably slow
          var floatArrayX = new float[Waves.Length];
          var floatArrayZ = new float[Waves.Length];
          for (var i = 0; i &lt; Waves.Length; i++)
          {
              var wave = Waves[i];
              if (wave != null)
              {
                  totWaves++;
                  floatArrayX[totWaves - 1] = wave.gameObject.transform.position.x;
                  floatArrayZ[totWaves - 1] = wave.gameObject.transform.position.z;
                  //_renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointX, wave.gameObject.transform.position.x);
                  //_renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointZ, wave.gameObject.transform.position.z);
  
                  //Debug.Log(wave.gameObject.transform.position);
              }
          }
  
          // probably slow
          var xWaveArray = new float[totWaves];
          var zWaveArray = new float[totWaves];
  
          for(int i = 0; i &lt; totWaves; i++)
          {
              xWaveArray[i] = floatArrayX[i];
              zWaveArray[i] = floatArrayZ[i];
          }
  
          //Debug.Log(totWaves);
  
          _renderer.material.SetFloatArray(WavePointExtruderConstants._ExtrudePointX, xWaveArray);
          _renderer.material.SetFloatArray(WavePointExtruderConstants._ExtrudePointZ, zWaveArray);
          _renderer.material.SetFloat(WavePointExtruderConstants._ExtrudePointCount, totWaves);
      }
  }
  
  public static class WavePointExtruderConstants
  {
      public static string _Extrude_Close = "_Extrude_Close";
      public static string _ExtrudePointX = "_ExtrudePointX";
      public static string _ExtrudePointZ = "_ExtrudePointZ";
      public static string _ExtrudePointCount = "_ExtrudePointCount";
  }
  </code></pre>
  
  <p>the setup is a plain with the shader material + code above. You then make any gameobject and place it into the scripts Waves array.</p>