I am aligning the ship to the ground mesh using normals I got from a downwards ray cast hit.
The problem is it makes the movement jerky presumably because of the changing per face normals.
Is there a way to smooth out the normals without changing the mesh?
Like gouraud shading?
I am already saving samples over time and averaging using these.
I will also shoot four rays instead of one.
If your mesh does have smooth normals you can use the baricentric hit coordinates to calculate the normal at the hit point. The docs on barycentricCoordinate actually has exactly this example.
edit
I’ve just written an extension method since i need something like that myself at the moment
// C#
public static Vector3 SmoothedNormal(this RaycastHit aHit)
{
var MC = aHit.collider as MeshCollider;
if (MC == null)
return aHit.normal;
var M = MC.sharedMesh;
var normals = M.normals;
var indices = M.triangles;
var N0 = normals[indices[aHit.triangleIndex*3 + 0]];
var N1 = normals[indices[aHit.triangleIndex*3 + 1]];
var N2 = normals[indices[aHit.triangleIndex*3 + 2]];
var B = aHit.barycentricCoordinate;
var localNormal = (B[0] * N0 + B[1] * N1 + B[2] * N2).normalized;
return MC.transform.TransformDirection(localNormal);
}
Like all extension methods, just put it into a static class somewhere in your project and use it like this:
//C#
if (Physics.RayCast(..., out hit))
{
var normal = hit.SmoothedNormal();
}
edit
Here’s a version with caching. Keep in mind if you have large meshes this will increase your average memory usage a bit.
public class CMeshInfo
{
public Collider collider;
public Vector3[] normals;
public int[] indices;
}
private static int MAX_CACHE = 3;
private static List< CMeshInfo > m_MeshCache = new List< CMeshInfo >();
public static Vector3 SmoothedNormalCached(this RaycastHit aHit)
{
var MC = aHit.collider as MeshCollider;
if (MC == null)
return aHit.normal;
var cacheObj = m_MeshCache.Find(meshinfo => meshinfo.collider == MC);
if (cacheObj == null)
{
var M = MC.sharedMesh;
cacheObj = new CMeshInfo();
cacheObj.collider = MC;
cacheObj.indices = M.triangles;
cacheObj.normals = M.normals;
}
else
m_MeshCache.Remove(cacheObj);
m_MeshCache.Add(cacheObj);
while (m_MeshCache.Count > MAX_CACHE)
m_MeshCache.RemoveAt(0);
var N0 = cacheObj.normals[cacheObj.indices[aHit.triangleIndex*3 + 0]];
var N1 = cacheObj.normals[cacheObj.indices[aHit.triangleIndex*3 + 1]];
var N2 = cacheObj.normals[cacheObj.indices[aHit.triangleIndex*3 + 2]];
var B = aHit.barycentricCoordinate;
var localNormal = (B[0] * N0 + B[1] * N1 + B[2] * N2).normalized;
return MC.transform.TransformDirection(localNormal);
}