Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[Solved] Calculating Polygon Normal

Discussion in 'Scripting' started by AlucardJay, Feb 18, 2015.

  1. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Hello, and thank you for reading.




    The Setting :

    I am generating a 'terrain' mesh, and I wish to generate a Vector3 normal for each 'quad' in the mesh.

    The Process :

    (for this test) Heightmap is declared and assigned values using perlin noise.
    Spheres are instantiated at each position in the heightmap array, using the height value for the Y_axis (and index X for position X, and index Y for position Z).
    (all good so far)

    Now the calculations for the quad normals.
    Each vertex of the quad is found by :
    Code (csharp):
    1. Vert_Bottom_Left = new Vector3( indexX, heightmap[x,y], indexY );
    2. Vert_Bottom_Right = new Vector3( indexX + 1, heightmap[x,y], indexY );
    3. Vert_Top_Left = new Vector3( indexX, heightmap[x,y], indexY + 1 );
    4. Vert_Top_Right = new Vector3( indexX + 1, heightmap[x,y], indexY + 1 );
    5.  
    6. .   Y
    7. . 1 |  *-----*
    8. .   |  |     |
    9. .   |  |     |
    10. . 0 |  *-----*
    11. .   +--------- X
    12. .      0     1
    This should assume a normalized Vector3 for each vertex(heightmap value) in the quad being processed.

    This array of 4 calculated 'quad vertex' points is then passed to a function I found online for calculating the normal of a n-sided polygon (Newell's Method) : https://www.opengl.org/wiki/Calculating_a_Surface_Normal


    The Problem(s) :

    The normal is not being calculated correctly. I have no idea why.
    I had more information to add here, but am currently too burned out to think ...


    The Test :

    Attach this script to a quad :

    position : 5, 0, 5
    rotation : 90, 0, 0
    scale : 10, 10, 1

    (disable the renderer to see more clearly. The quad is to display my control texture when this works and I can generate it).

    On Play, a grid of spheres shows the heightmap array. Gizmo Lines show the calculated normal for each value in the normals array.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5.  
    6. public class ControlTextureTest : MonoBehaviour
    7. {
    8.    public float pScale = 3.27f;
    9.    
    10.    public int step = 32;
    11.    
    12.    public float gizmoHeight = 0.15f; // 0.002f; // 0.15f;
    13.  
    14.    public float[] slopeAngles = { 0f, 4f, 8f, 18f, 26f, 34f, 40f };
    15.  
    16.    private float[,] heightmap;
    17.    private float[,] slopeMap;
    18.    private float[,,] alphamap;
    19.    
    20.    private Vector3[,] slopeNormals;
    21.  
    22.    private List< GameObject > spheres = new List< GameObject >();
    23.    
    24.    
    25.    void Start()
    26.    {
    27.      DoTest();
    28.    }
    29.  
    30.  
    31.    void Update()
    32.    {
    33.      if ( Input.GetMouseButtonDown(0) )
    34.        DoTest();
    35.    }
    36.  
    37.  
    38.    void DoTest()
    39.    {
    40.      DestroySpherePool();
    41.      
    42.      GenerateHeightmap();
    43.  
    44.      GenerateControlTexture();
    45.    }
    46.    
    47.    
    48.    void DestroySpherePool()
    49.    {
    50.      if ( spheres.Count > 0 )
    51.      {
    52.        for (int i = 0; i < spheres.Count; i++)
    53.        {
    54.          Destroy( spheres[ i ] );
    55.        }
    56.        
    57.        spheres = new List< GameObject >();
    58.      }
    59.    }
    60.    
    61.    
    62.    void GenerateHeightmap()
    63.    {
    64.      int heightmapWidth = 1025;
    65.      int heightmapHeight = 1025;
    66.  
    67.      heightmap = new float[ heightmapWidth, heightmapHeight ];
    68.  
    69.      int x, y;
    70.  
    71.      float pX, pY, val;
    72.  
    73.      for ( x = 0; x < heightmapWidth; x ++ )
    74.      {
    75.        for ( y = 0; y < heightmapHeight; y ++ )
    76.        {
    77.          pX = (float)x / 1025f;
    78.          pX *= pScale;
    79.          pY = (float)y / 1025f;
    80.          pY *= pScale;
    81.  
    82.          val = Mathf.PerlinNoise( pX, pY );
    83.  
    84.          heightmap[ x, y ] = val;
    85.  
    86.          if ( x % step == 0 && y % step == 0 )
    87.          {
    88.            GameObject go  = GameObject.CreatePrimitive( PrimitiveType.Sphere );
    89.            go.transform.localScale = Vector3.one * 0.05f;
    90.            go.transform.parent = transform;
    91.            spheres.Add( go );
    92.  
    93.            Vector3 pos = new Vector3( x, 0, y );
    94.            pos.x /= 1025f;
    95.            pos.x *= transform.localScale.x;
    96.            pos.z /= 1025f;
    97.            pos.z *= transform.localScale.y;
    98.            pos.y = val;
    99.  
    100.            go.transform.position = pos;
    101.          }
    102.        }
    103.      }
    104.    }
    105.    
    106.    
    107.    void GenerateControlTexture()
    108.    {
    109.      slopeNormals = WorldUtils.CalculateSlopeNormals( heightmap );
    110.  
    111.      //slopeMap = WorldUtils.CalculateSlopeAngles( heightmap );
    112.      //alphamap = WorldUtils.GenerateAlphamap( slopeMap, slopeAngles );
    113.      //Texture2D controlTexture = WorldUtils.GenerateControlTexture( alphamap );
    114.      //renderer.material.mainTexture = controlTexture;
    115.    }
    116.  
    117.  
    118.  
    119.    void OnDrawGizmos()
    120.    {
    121.      if ( slopeNormals == null )
    122.        return;
    123.      
    124.      Gizmos.color = Color.red;
    125.  
    126.      int w = slopeNormals.GetLength( 0 );
    127.      int h = slopeNormals.GetLength( 1 );
    128.  
    129.      Vector3 pos, dir;
    130.  
    131.  
    132.      for ( int x = 0; x < w; x ++ )
    133.      {
    134.        for ( int y = 0; y < h; y ++ )
    135.        {
    136.          if ( x % step == 0 && y % step == 0 )
    137.          {
    138.            pos = new Vector3( x, 0, y );
    139.            pos.x /= 1024f;
    140.            pos.x *= transform.localScale.x;
    141.            pos.z /= 1024f;
    142.            pos.z *= transform.localScale.y;
    143.            pos.y = heightmap[ x, y ];
    144.  
    145.            dir = slopeNormals[ x, y ];
    146.  
    147.            Gizmos.DrawLine( pos, pos + ( dir * gizmoHeight ) );
    148.            //Gizmos.DrawLine( pos, pos + ( dir * gizmoHeight * slopeMap[ x, y ] ) );
    149.          }
    150.        }
    151.      }
    152.    }
    153. }
    And the WorldUtils script (that does the heavy lifting) :

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5.  
    6. public static class WorldUtils
    7. {
    8.    // https://www.opengl.org/wiki/Calculating_a_Surface_Normal
    9.    /*
    10.      Newell's Method
    11.  
    12.      Begin Function CalculateSurfaceNormal (Input Polygon) Returns Vector
    13.  
    14.        Set Vertex Normal to (0, 0, 0)
    15.  
    16.        Begin Cycle for Index in [0, Polygon.vertexNumber)
    17.  
    18.        Set Vertex Current to Polygon.verts[Index]
    19.        Set Vertex Next  to Polygon.verts[(Index plus 1) mod Polygon.vertexNumber]
    20.  
    21.        Set Normal.x to Sum of Normal.x and (multiply (Current.y minus Next.y) by (Current.z plus Next.z))
    22.        Set Normal.y to Sum of Normal.y and (multiply (Current.z minus Next.z) by (Current.x plus Next.x))
    23.        Set Normal.z to Sum of Normal.z and (multiply (Current.x minus Next.x) by (Current.y plus Next.y))
    24.  
    25.        End Cycle
    26.  
    27.        Returning Normalize(Normal)
    28.  
    29.      End Function
    30.    */
    31.    
    32.    
    33.    //   -----------------------------------------------------------------  POLYGON NORMAL
    34.    
    35.    
    36.    public static Vector3 GetPolygonNormal( Vector3[] vertices )
    37.    {
    38.      Vector3 normal = Vector3.zero;
    39.      Vector3 currVert, nextVert;
    40.      
    41.      for ( int i = 0; i < vertices.Length; i ++ )
    42.      {
    43.        currVert = vertices[ i ];
    44.        nextVert = vertices[ ( (i + 1) % vertices.Length ) ];
    45.  
    46.        normal.x += ( currVert.y - nextVert.y ) * ( currVert.z + nextVert.z );
    47.        normal.y += ( currVert.z - nextVert.z ) * ( currVert.x + nextVert.x );
    48.        normal.z += ( currVert.x - nextVert.x ) * ( currVert.y + nextVert.y );
    49.      }
    50.      
    51.      return normal.normalized;
    52.    }
    53.    
    54.    
    55.    //   -----------------------------------------------------------------  SLOPE NORMALS
    56.    
    57.    
    58.    public static Vector3[,] CalculateSlopeNormals( float[,] heightmap )
    59.    {
    60.      int w = heightmap.GetLength( 0 ) - 1;
    61.      int h = heightmap.GetLength( 1 ) - 1;
    62.  
    63.      
    64.      Vector3[,] slopeNormals = new Vector3[ w, h ];
    65.  
    66.      Vector3[] vertices = new Vector3[ 4 ];
    67.      
    68.      int x, y;
    69.  
    70.  
    71.      for ( x = 0; x < w; x ++ )
    72.      {
    73.        for ( y = 0; y < h; y ++ )
    74.        {
    75.          vertices[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f );
    76.          vertices[ 1 ] = new Vector3( 0f, heightmap[ x + 0, y + 1 ], 1f );
    77.          vertices[ 2 ] = new Vector3( 1f, heightmap[ x + 1, y + 0 ], 0f );
    78.          vertices[ 3 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f );
    79.  
    80.          slopeNormals[ x, y ] = GetPolygonNormal( vertices );
    81.        }
    82.      }
    83.      
    84.      
    85.      return slopeNormals;
    86.    }
    87.  
    88. }
     
  2. vintar

    vintar

    Joined:
    Sep 18, 2014
    Posts:
    90
    Just guessing as this is all beyond me, but have you tried making the top corners -1 instead of +1. ?
     
  3. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    You're drawing your quad in the wrong order in two functions I believe:

    Code (csharp):
    1.  
    2. Vert_Bottom_Left = new Vector3( indexX, heightmap[x,y], indexY );
    3. Vert_Bottom_Right = new Vector3( indexX + 1, heightmap[x,y], indexY );
    4. Vert_Top_Left = new Vector3( indexX, heightmap[x,y], indexY + 1 );
    5. Vert_Top_Right = new Vector3( indexX + 1, heightmap[x,y], indexY + 1 );
    6.  
    and

    Code (csharp):
    1.  
    2. for ( x = 0; x < w; x ++ )
    3.      {
    4.        for ( y = 0; y < h; y ++ )
    5.        {
    6.          vertices[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f );
    7.          vertices[ 1 ] = new Vector3( 0f, heightmap[ x + 0, y + 1 ], 1f );
    8.          vertices[ 2 ] = new Vector3( 1f, heightmap[ x + 1, y + 0 ], 0f );
    9.          vertices[ 3 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f );
    10.  
    11.          slopeNormals[ x, y ] = GetPolygonNormal( vertices );
    12.        }
    13.      }
    14.  
    I'm not really familiar with that method for computing a normal, so I'm not sure how it works. I always just compute each individual triangle's normal and then average them...

    But, in 99% of drawing a polygon you want to draw it clockwise: (0,0), (0,1), (1,1) (1,0)

    It may be that it needs to be backward in some way for that algorithm to work - but I'm guessing its your vertex order primarily.
     
    AlucardJay likes this.
  4. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    Well, I dont quiet know a solution to your problem in place but I have a suggestion for you which you should consider.
    Using quads introduces one big problem, there are cases in which a quad can have 2 surface normals plus their respective inverse since all 4 points might not always lie on the same plane.
    Therefore, instead of quads use triangles! The normal of triangles is simply the crossproduct of their points:

    Let A, B and C be the 3 points of the Triangle and N its respective surface normal:
    N = ( B - A ) x ( C - A )
    x is the Crossproduct: Vector3.Cross( B - A, C - A ):
    But be sure of the correct winding of the triangle. You may aswell just check if the produced normal points towards a point above or below the terrain in order to get the normal pointing upwards. Vector3.Dot( N, Vector3.up ) > 0
     
  5. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Thank you all for your replies.

    vintar : its kinda hard to explain.
    heightmap is 2^n+1, while slopemap is 2^n. visually :
    Code (csharp):
    1. X-----X
    2. |     |
    3. |  O  |
    4. |     |
    5. X-----X
    the X is the heightmap, the O is the slopemap. So if I am at index 0 for both maps, to get each X for O,
    Code (csharp):
    1. Xbottomleft = 0, 0
    2. Xbottomright = 1, 0
    3. Xtopleft = 0, 1
    4. Xtopright = 1, 1
    Thank you for your suggestion.

    bloomingdedalus : I gave myself a good kicking. For all my mesh stuff I didn't even factor in the winding rotation, massive help, thanks. /me headdesks again

    Sharp Development : when I first looked into calculating the normals, I did consider using the cross examples I found, just using the vertex with the highes Y, and the 2 lowest Ys. I did a test that got the normals for both triangles, added them then halved the result for an 'average'.

    So after fixing the winding order in the original script, the normals all returned Vector3.up. I then wrote a different method with the 2 triangle average, and that also returns the result Vector3.up. Which only leaves me to think how I'm assigning the Vector3 value for each vertex is wrong. I really don't know what to try next, sorry.

    triangle vertex :
    x is either 0 or 1
    y is the heightmap [x,y] (value betwwen 0 and 1)
    z is either 0 or 1

    all my debugging shows that these vertex values have a magnitude greater than zero.

    my test modifications to WorldUtils :

    Code (csharp):
    1. //   -----------------------------------------------------------------  SLOPE NORMALS
    2.  
    3.  
    4.    public static Vector3[,] CalculateSlopeNormals( float[,] heightmap )
    5.    {
    6.      int w = heightmap.GetLength( 0 ) - 1;
    7.      int h = heightmap.GetLength( 1 ) - 1;
    8.  
    9.    
    10.      Vector3[,] slopeNormals = new Vector3[ w, h ];
    11.  
    12.      //Vector3[] vertices = new Vector3[ 4 ];
    13.    
    14.      Vector3[] triangle1 = new Vector3[ 3 ];
    15.      Vector3[] triangle2 = new Vector3[ 3 ];
    16.  
    17.      Vector3 normal1, normal2;
    18.    
    19.      int x, y;
    20.  
    21.      float min = 1000f;
    22.      float max = -1000f;
    23.  
    24.  
    25.      for ( x = 0; x < w; x ++ )
    26.      {
    27.        for ( y = 0; y < h; y ++ )
    28.        {
    29.          /*
    30.          1 --- 2
    31.          |  |
    32.          0 --- 3
    33.          */
    34.  
    35.  
    36.          /* // with correct winding now (thanks bloomingdedalus!), this gives the same result as below
    37.          vertices[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f ); // 0
    38.          vertices[ 1 ] = new Vector3( 0f, heightmap[ x + 0, y + 1 ], 1f ); // 1
    39.          vertices[ 2 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f ); // 2
    40.          vertices[ 3 ] = new Vector3( 1f, heightmap[ x + 1, y + 0 ], 0f ); // 3
    41.  
    42.          slopeNormals[ x, y ] = GetPolygonNormal( vertices );
    43.          */
    44.  
    45.  
    46.          /* // this vertex order, and below give the same result
    47.          triangle1[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 1 ], 1f ); // 1
    48.          triangle1[ 1 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f ); // 2
    49.          triangle1[ 2 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f ); // 0
    50.        
    51.          triangle2[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f ); // 0
    52.          triangle2[ 1 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f ); // 2
    53.          triangle2[ 2 ] = new Vector3( 1f, heightmap[ x + 1, y + 0 ], 0f ); // 3
    54.          */
    55.        
    56.          triangle1[ 0 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f ); // 0
    57.          triangle1[ 1 ] = new Vector3( 0f, heightmap[ x + 0, y + 1 ], 1f ); // 1
    58.          triangle1[ 2 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f ); // 2
    59.  
    60.          triangle2[ 0 ] = new Vector3( 1f, heightmap[ x + 1, y + 1 ], 1f ); // 2
    61.          triangle2[ 1 ] = new Vector3( 1f, heightmap[ x + 1, y + 0 ], 0f ); // 3
    62.          triangle2[ 2 ] = new Vector3( 0f, heightmap[ x + 0, y + 0 ], 0f ); // 0
    63.  
    64.  
    65.          normal1 = GetTriangleNormal( triangle1 );
    66.          normal2 = GetTriangleNormal( triangle2 );
    67.  
    68.          slopeNormals[ x, y ] = ( normal1 + normal2 ) * 0.5f;
    69.  
    70.          // check heightmap value
    71.          float val = heightmap[ x + 0, y + 0 ];
    72.  
    73.          if ( min > val )
    74.            min = val;
    75.          else if ( max < val )
    76.            max = val;
    77.  
    78.          // check triangle vertex value
    79.          if ( x % 64 == 0 && y % 64 == 0 )
    80.          {
    81.            Debug.Log( "verts1 : 0 = " + triangle1[ 0 ].magnitude + " : 1 = " + triangle1[ 1 ].magnitude + " : 2 = " + triangle1[ 2 ].magnitude );
    82.            Debug.Log( "verts2 : 0 = " + triangle2[ 0 ].magnitude + " : 1 = " + triangle2[ 1 ].magnitude + " : 2 = " + triangle2[ 2 ].magnitude );
    83.            // example results
    84.            // verts1 : 0 = 0.4652731 : 1 = 1.102941 : 2 = 1.489458
    85.            // verts2 : 0 = 1.489458 : 1 = 1.10385 : 2 = 0.4652731
    86.          }
    87.        }
    88.      }
    89.    
    90.      Debug.Log( "HEIGHTS : min = " + min + " : max = " + max );
    91.    
    92.    
    93.      return slopeNormals;
    94.    }
    95.  
    96.  
    97.    //   -----------------------------------------------------------------  TRIANGLE NORMAL
    98.  
    99.    // http://forum.unity3d.com/threads/calculating-polygon-normal.298875/#post-1968624
    100.    // # Sharp Development
    101.  
    102.    /*
    103.    Let A, B and C be the 3 points of the Triangle and N its respective surface normal:
    104.    N = ( B - A ) x ( C - A )
    105.    x is the Crossproduct: Vector3.Cross( B - A, C - A ):
    106.    */
    107.  
    108.    public static Vector3 GetTriangleNormal( Vector3[] vertices )
    109.    {
    110.      Vector3 side1 = vertices[ 1 ] - vertices[ 0 ];
    111.      Vector3 side2 = vertices[ 2 ] - vertices[ 0 ];
    112.  
    113.      Vector3 normal = Vector3.Cross( side1, side2 );
    114.    
    115.      return normal.normalized;
    116.    }
     

    Attached Files:

  6. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    You may have missunderstood me. I did not mean to calculate the normal of a quad based on its triangles but rather to treat the heightmap as triangles instead of quads. This will result in two slopenormals per quad ( since a quad consists of two triangles ) and therefore a slopemap which is based on the respective triangles.

    Your slope normal array would be of size (( x - 1 ) * ( y - 1 )) * 2 where x and y are respective sizes of your heightmap.
    slopeNormals[0,x,y] would be normal1 and slopeNormals[1,x,y] would be normal2.
     
  7. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Are you posting because theres still a problem? Because you code both looks and works fine for me


    Code (CSharp):
    1.     float[,] heights;
    2.     public float scale, tallness;
    3.     Vector3[,] normals;
    4.     public int gridSize = 10;
    5.  
    6.     void Reset () {
    7.         heights = new float[gridSize, gridSize];
    8.         for ( int i = 0; i < gridSize; i++ ) {
    9.             for ( int j = 0; j < gridSize; j++ ) {
    10.                 heights[i, j] = Mathf.PerlinNoise( i * scale, j * scale ) * tallness;
    11.             }
    12.         }
    13.         normals = CalculateSlopeNormals( heights );
    14.     }
    15.  
    16.     void Start () {
    17.         Reset();
    18.     }
    19.  
    20.     void OnGUI () {
    21.         if ( GUILayout.Button( "Reset" ) ) {
    22.             Reset();
    23.         }
    24.     }
    25.  
    26.     void DrawX ( Vector3 v, float size ) {
    27.         Debug.DrawLine( new Vector3( v.x + size, v.y, v.z + size ), new Vector3( v.x - size, v.y, v.z - size ) );
    28.         Debug.DrawLine( new Vector3( v.x + size, v.y, v.z - size ), new Vector3( v.x - size, v.y, v.z + size ) );
    29.     }
    30.  
    31.     void DrawPoly ( int x, int y ) {
    32.         Debug.DrawLine( new Vector3( x, heights[x, y], y ), new Vector3( x, heights[x, y + 1], y + 1 ) );
    33.         Debug.DrawLine( new Vector3( x, heights[x, y + 1], y + 1 ), new Vector3( x + 1, heights[x + 1, y + 1], y + 1 ) );
    34.         Debug.DrawLine( new Vector3( x + 1, heights[x + 1, y + 1], y + 1 ), new Vector3( x + 1, heights[x + 1, y], y ) );
    35.         Debug.DrawLine( new Vector3( x + 1, heights[x + 1, y], y ), new Vector3( x, heights[x, y], y ) );
    36.     }
    37.  
    38.     void Update () {
    39.         if ( heights == null ) Reset();
    40.         for ( int i = 0; i < gridSize; i++ ) {
    41.             for ( int j = 0; j < gridSize; j++ ) {
    42.                 DrawX( new Vector3( i, heights[i, j], j ), 0.15f );
    43.             }
    44.         }
    45.  
    46.         for ( int i = 0; i < gridSize - 1; i++ ) {
    47.             for ( int j = 0; j < gridSize - 1; j++ ) {
    48.                 DrawPoly( i, j );
    49.                 Vector3 center = new Vector3( i + 0.5f, ( heights[i, j] + heights[i, j + 1] + heights[i + 1, j + 1] + heights[i + 1, j] ) / 4, j + 0.5f );
    50.                 Debug.DrawRay( center, normals[i, j], Color.red );
    51.             }
    52.         }
    53.     }
    54.  
    55.     //your code, sans comments
    56.     Vector3[,] CalculateSlopeNormals ( float[,] heightmap ) {
    57.         int w = heightmap.GetLength( 0 ) - 1;
    58.         int h = heightmap.GetLength( 1 ) - 1;
    59.  
    60.         Vector3[,] slopeNormals = new Vector3[w, h];
    61.         Vector3[] triangle1 = new Vector3[3];
    62.         Vector3[] triangle2 = new Vector3[3];
    63.  
    64.         Vector3 normal1, normal2;
    65.  
    66.         int x, y;
    67.  
    68.         float min = 1000f;
    69.         float max = -1000f;
    70.  
    71.         for ( x = 0; x < w; x++ ) {
    72.             for ( y = 0; y < h; y++ ) {
    73.                 triangle1[0] = new Vector3( 0f, heightmap[x + 0, y + 0], 0f ); // 0
    74.                 triangle1[1] = new Vector3( 0f, heightmap[x + 0, y + 1], 1f ); // 1
    75.                 triangle1[2] = new Vector3( 1f, heightmap[x + 1, y + 1], 1f ); // 2
    76.  
    77.                 triangle2[0] = new Vector3( 1f, heightmap[x + 1, y + 1], 1f ); // 2
    78.                 triangle2[1] = new Vector3( 1f, heightmap[x + 1, y + 0], 0f ); // 3
    79.                 triangle2[2] = new Vector3( 0f, heightmap[x + 0, y + 0], 0f ); // 0
    80.  
    81.  
    82.                 normal1 = GetTriangleNormal( triangle1 );
    83.                 normal2 = GetTriangleNormal( triangle2 );
    84.  
    85.                 slopeNormals[x, y] = ( normal1 + normal2 ) * 0.5f;
    86.  
    87.                 float val = heightmap[x + 0, y + 0];
    88.  
    89.                 if ( min > val )
    90.                     min = val;
    91.                 else if ( max < val )
    92.                     max = val;
    93.             }
    94.         }
    95.         return slopeNormals;
    96.     }
    97.  
    98.     Vector3 GetTriangleNormal ( Vector3[] vertices ) {
    99.         Vector3 side1 = vertices[1] - vertices[0];
    100.         Vector3 side2 = vertices[2] - vertices[0];
    101.         Vector3 normal = Vector3.Cross( side1, side2 );
    102.         return normal.normalized;
    103.     }
     
  8. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Sharp Developer : ok, interesting, I get the multidimensional array now, just not sure what I would use separate triangle normal lookups for. The slopeNormal is just the start, I wish to calculate a float angle value from the normal
    Code (csharp):
    1. slopeMap[ x, y ] = Vector3.Angle( slopeNormals[ x, y ], Vector3.up );
    This float angle is then used to calculate rgba values for a control texture like used in Unitys terrain shader, or layer shader, pretty much the same as my method here : http://forum.unity3d.com/threads/texture-terrain-using-slope-angles.209755/#post-1413472


    hpjohn : yes, I still have a problem, I have no idea why my results differ to yours (I included a screenshot in my last post).
    All the min/max stuff was just to show me that I was sending expected values around.
     
  9. Sharp-Development

    Sharp-Development

    Joined:
    Nov 14, 2013
    Posts:
    353
    The triangle normals are the slopenormals, just not per quad but per triangle. You'd use them in the same way you'd use your quad slopenormals.

    However, all this is based on the assumption that the four vertices of your quads are not always on the same plane which forces you to use triangles to get accurate results based on your geometry. However, incase your quads are always a plane, the normal of the quad is always the normal of triangle1 or triangle2. Which of the normals you take doesnt matter at all, they are equal.
     
  10. hpjohn

    hpjohn

    Joined:
    Aug 14, 2012
    Posts:
    2,190
    Maybe your test scene is just too flat to see, or you're not drawing them correctly

    Edit: just spotted your testing code in the OP, so maybe not
     
    Last edited: Feb 18, 2015
  11. AlucardJay

    AlucardJay

    Joined:
    May 28, 2012
    Posts:
    328
    Sharp Development : you are correct, there is a very slim chance of the quad being on the same plane. Thank you for the advice on better accuracy.

    hpjohn : So I've been playing with my gizmos to check my debugging, with the same results. It was only after setting my perlin scale to a high value I could see that my sample was so large, i could not see the differences in the normal debugging rays. Thank you for taking the time to test the script.

    bloomingdedalus actually nailed it : the whole problem was the winding order. Thanks again :)

    Everyone has been really helpful, I am grateful. All the Best.
     

    Attached Files:

    Last edited: Feb 18, 2015