Hi everyone, I can't read the Normal of a terrain Making a raycast I have the correct result, reading it from terraindata gives me an incorrect value. I attach code and screenshots In update : Code (CSharp): RaycastHit hit; Ray raggio = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 posiz = new Vector3(36f, 15f, 7f); if (Physics.Raycast(posiz + (Vector3.up*5),Vector3.down, out hit, Mathf.Infinity, MyGLB_E.layer_Terreno)) { Terrain at = Terrain.activeTerrain; float normalizedX, normalizedY; Vector3 normale; hPoint = hit.point; normalizedX = posiz.x / at.terrainData.size.x ; normalizedY = posiz.z / at.terrainData.size.z ; normale = at.terrainData.GetInterpolatedNormal(normalizedX, normalizedY); hpointAngolo = at.terrainData.GetSteepness(normalizedX, normalizedY); hString = "TERRAINDDATA:\n\rSP : " + hpointAngolo.ToString() + "\n\rUP : " + Vector3.Angle(Vector3.up,normale ).ToString() + "\n\rDW : " + Vector3.Angle(normale, Vector3.down).ToString() + "\n\rFW : " + Vector3.Angle(normale, Vector3.forward).ToString() + "\n\rBW : " + Vector3.Angle(normale, Vector3.back).ToString() + "\n\rRG : " + Vector3.Angle(normale, Vector3.right).ToString() + "\n\rLF : " + Vector3.Angle(normale, Vector3.left).ToString() + "\n\rNR : " + normale; hN = normale; normale = hit.normal; hN0 = normale; hString0 = "RAYCAST\n\rUP : " + Vector3.Angle(normale, Vector3.up).ToString() + "\n\rDW : " + Vector3.Angle(normale, Vector3.down).ToString() + "\n\rFW : " + Vector3.Angle(normale, Vector3.forward).ToString() + "\n\rBW : " + Vector3.Angle(normale, Vector3.back).ToString() + "\n\rRG : " + Vector3.Angle(normale, Vector3.right).ToString() + "\n\rLF : " + Vector3.Angle(normale, Vector3.left).ToString() + "\n\rNR : " + hit.normal; } onGizmo : Code (CSharp): GUIStyle style = new GUIStyle(GUI.skin.label); style.alignment = TextAnchor.MiddleLeft; Handles.Label(hPoint, hString0, style); Handles.Label(hPoint + Vector3.right, hString, style); Gizmos.color = Color.green; Gizmos.DrawLine(hPoint,hPoint + ( hN * 1)); Gizmos.color = Color.red; Gizmos.DrawLine(hPoint, hPoint + (hN0 * 1)); risultato : tanks for your help
I'm not sure what to tell you here. Perhaps just use the correct one you get from Raycast? AFAIK, TerrainData does not contain normal data. The heightmap is used to construct geometry, and from that you can get the normal, which is what raycast does. I suppose you could recreate it yourself from the heightmap data, but to do that you would need to know the heightmap-to-mesh code that Unity uses, or else yours would not match.
Sorry, but then the terrainData.GetInterpolatedNormal function that the unity guide exposes, what is it for? As I understand it should (passing the normalized coordinates) give the value of the normal. I have seen some examples, and they use it for this very reason, but I do not understand why things should never go as shown and used by others.
The docs say that it returns normalized quantities and ONLY the X,Z directions. You would have to experiment to see what a 2-coordinate "normalized" value even means in a 3D world. Is it just the slope of the raw heightmap data? Does it take into account scale of the terrain? It doesn't say. Are you scaling appropriate to the presentation size of your terrain? Same goes for GetSteepness... those return normalized quantities too. If others are using it, use their code. Otherwise you have to figure out what the data coming back even means in your space.
I tried using the same code, but nothing The scale is 1, the coordinates 0,0,0, the dimensions 500,500,500 However I have seen they use the normal and stepness to keep the gameobjects parallel to the ground under them (therefore in a 3D environment) I would not like to use raycasts as multiplied by the various gameobjects would result in a heavy calculation, while accessing the data already contained in the map eases the calculations a lot I just need to know if I have an inclination greater than 35 degrees in a certain point However I look for more information and help, I hope to resolve. Thank you very much for your interest and help!
Was playing around with this and got a basic setup working. Not sure if it helps the OP, but hopefully is useful to someone. I'm confused as to why the height values in this are being scaled. What I mean is: --the height values for the gizmo drawing are about 5X out from where they should be: at (0,0) they are correct, at (10,5) they show the height that's actually at (2,1), etc. --the normal vectors are correct, as in: they point in the right direction relative to the terrain's slope. The screenshot shows it in "corrected" mode, where I've manually scaled where the heights are grabbed from so they line up with the sloping (pretty much). What I don't understand is WHY it works like this, seems like the scaling shouldn't be needed! Attach this script to your terrain GameObject (keep it small for better interaction) and give it a go: Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class forumNormals : MonoBehaviour { Terrain terrain; // recommend not a huge terrain, for smoother interaction [Range(0.1f, 20)] public float rayScale = 2; // length of gizmo ray void Start() { terrain = GetComponent<Terrain>(); } void OnDrawGizmos() { Vector3 terrainSize = terrain.terrainData.size; for (int i = 0; i < terrainSize.x; i += 2) // use steps of more than 1 for smoother interaction in editor { for (int k = 0; k < terrainSize.z; k += 2) { // not sure why the gizmo y-heights are scaled out from 0,0 (about 5X) when doing it this way. // Uncomment this and comment the second one to see: //Vector3 pivot = new Vector3(i, terrain.terrainData.GetHeight(i, k), k); // this way fixes it (pretty much)--WHY?? Vector3 pivot = new Vector3(i, terrain.terrainData.GetHeight(i * 5, k * 5), k); float x = pivot.x / terrainSize.x; float z = pivot.z / terrainSize.z; Vector3 interpolatedNormal = terrain.terrainData.GetInterpolatedNormal(x, z); GUI.color = Color.blue; Gizmos.DrawSphere(pivot, 0.2f); Gizmos.color = Color.cyan; Gizmos.DrawRay(pivot, interpolatedNormal * rayScale); } } } }
First of all, thank you for your reply I tried, but the results are weird .. I took 2 screenshots The first with the multiplier * 5, the second without a multiplier. However, the limitation of not having precise points through the getHeight I think affects, as and for this reason in the second case the pivots are far from contact with the ground .. maybe .. However I try to deepen Thank you very much
I figured out the issue with mine---I had set the Terrain width and length to 100 x 100 so things were smoother in the Inspector. I didn't change the heightmap resolution to match! DOH. Makes perfect sense that 5X *almost* fixed it...default heightmap resolution is 513. So, if you do change the terrain height/width, recommend using a power of 2, then adjust heightmap resolution to match + 1. 128x128 terrain --> 129x129 heightmap (these are the vertices). Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class forumNormals : MonoBehaviour { Terrain terrain; // recommend not a huge terrain, for smoother interaction // When resizing terrain (width and length), use a power of 2 for each side: 128, 512 (default), etc. // After resizing, set heightmap resolution to match: Side+1 in each dimension, so // 128x128 map => 129X129 Heightmap (these are the vertices, so one more is needed) [Range(0.1f, 20)] public float rayScale = 2; // length of gizmo ray void Start() { terrain = GetComponent<Terrain>(); } void OnDrawGizmos() { Vector3 terrainSize = terrain.terrainData.size; for (int i = 0; i < terrainSize.x; i += 10) // use steps of more than 1 for smoother interaction in editor { for (int k = 0; k < terrainSize.z; k += 10) { Vector3 pivot = new Vector3(i, terrain.terrainData.GetHeight(i, k), k); float x = pivot.x / terrainSize.x; float z = pivot.z / terrainSize.z; Vector3 interpolatedNormal = terrain.terrainData.GetInterpolatedNormal(x, z); GUI.color = Color.blue; Gizmos.DrawSphere(pivot, 0.2f); Gizmos.color = Color.cyan; Gizmos.DrawRay(pivot, interpolatedNormal * rayScale); } } } }
@Alieno79 , check your terrain size versus heightmap resolution. Default terrain size is 1000x1000, heightmap res is 513x513, so there's interpolation. Not an issue unless we're trying something like showing normals on every texel (at least as I understand it). Try matching the size to heightmap res + 1 and see if the points line up on the ground. Mine look correct, this is 512x512 and 513x513:
i try it but result is the same.. at integer coordinates it's ok, but in float coordinates.. is it wrong.. i think must use raycast thanks you all
I know I am a bit late but Ii anybody else is having this issue, I managed to find the solution. Here is the code : Code (CSharp): public Vector3 CalculateTerrainNormal(Vector3 terrainPosition) { var offset = 0.1f; var heightLeft = _terrain.SampleHeight(terrainPosition + Vector3.left * offset); var heightRight = _terrain.SampleHeight(terrainPosition + Vector3.right * offset); var heightForward = _terrain.SampleHeight(terrainPosition + Vector3.forward * offset); var heightBack = _terrain.SampleHeight(terrainPosition + Vector3.back * offset); var tangentX = new Vector3(2.0f * offset, heightRight - heightLeft, 0).normalized; var tangentZ = new Vector3(0, heightForward - heightBack, 2.0f * offset).normalized; var normal = Vector3.Cross(tangentZ, tangentX).normalized; return normal; } terrainPosition is the world position you are checknig for a normal