- Home /
Smooth normals in raycast?
Hi Everyone,
so I have my simple hover craft 'game'.
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.
Any other suggestions?
Cheers Fred
hey @FRED you $$anonymous$$UST PLEASE TELL US the size in meters exactly between vertices on the mesh, and the size in meters length/width of the craft.
thanks!
Ok ok :) Tonight I will rescale my scene as it is not currently scaled to Unity's physics engine. I believe it expects 1 unit = 1 meter? I'll post my measurements after that.
I just checked my scale and I had actually done it correctly if above assumption is true.
$$anonymous$$y Ship is a little more than 10m long, roughly 7m at its widest.
Average triangle size in the current ground mesh is about 12m on the right angle side.
Answer by Bunny83 · Feb 07, 2013 at 01:48 PM
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);
}
you just have to d it yourself ...
if your craft is 3 meters long, just have four markers (ie, empty game objects) with the craft. put each of those one meter outside of the craft (ie four points that surround the craft, each a meter away diagonally)
just shoot from those four and average
is that what you're looking for?
it's worth noting there is no specific, absolute answer to this - it depends on your strategy. what happens if the ground under the craft is lumpy of an order shorter than the length of the craft? there's no defined solution, you just have to choose something that works
for more ideas, please explain exactly how big on average the ground mesh is, and how big the craft is. this will tremendously affect approach you take. cheers!
Hey Fred I wanna make a point here,
in this overhead view note the four let's call them "$$anonymous$$easure Points" ($$anonymous$$Ps) in yellow.
As you can see, the metric is about on "90 cm". Each one is 90cm diagonally away from the relevant extremity.
(BTW as you can see I have made your HoverCraft in to a HoverTank - yeah!)
Let us call that distance (90cm in the drawing) the $$anonymous$$P$$anonymous$$etric.
now here's the thing ........ varying the $$anonymous$$P$$anonymous$$etric will literally vary the handling of your vehicle
Cool eh. In fact on a hovercraft, varying the $$anonymous$$P$$anonymous$$etric should be a normal thing you do dynamically, to make the behavior interesting.
Just as in a race game, you would vary mass, cog, spring strengths, and so on at development time, and of course you vary breaking power, engine power, wind friction etc at run time.
With a hovercraft, you probably actually want to vary this sucker $$anonymous$$P$$anonymous$$etric as it drives around.
So for example (I'd say) when you accelerate away, make $$anonymous$$P$$anonymous$$etric smaller (the craft will wibble and screw about more) ... once you are underway at top speed like a HGV {Hovercraft Grand Vitesse} then make $$anonymous$$P$$anonymous$$etric bigger, it will smooth your flight, react better (differently anyway) to upco$$anonymous$$g hills and so on.
(Funnily enough I was just talking with one of Europe's top "red $$anonymous$$m" fighter pilots who is a ground-following radar expert and conceptually it works like this - which is neat.)
Anyway I see the $$anonymous$$P$$anonymous$$etric as a dynamic part of your game -- not unlike using magneto-hydraulic suspension in a race car in a race game.
Hope the thought helps!
PS don't forget this all could be irrelevant depending on the SCALE of your game, the mesh V. the hovertank.
Ohh, as additional hint: The smoothed normal won't help much. The main problem is the hit distance which will be still quite jerky since the mesh actually has sharp edges. You would need something like displacement mapping.
Bunny this is great thanks a lot. I was oping that something like this was possible. I'll be trying this for sure. Thanks again.
Hi Fattie, I will pile on all these methods and will try shooting four rays from different 'corners'. But you are right, my mesh is so coarse that I expect a face might be larger than the footprint of my ship. I'll check that too and maybe I have to subdivide a bit too if nothing else helps. Cheers Fred
How did you get on using this? I just added it to my ships $$anonymous$$onobehaviour controller script and called it four times in a row as I also wanted to sample from the four corners of my ship. But as soon as I add a second call to the smooth normal function the game simulation slows right down to four fps. From 75 fps when I call it once.
This seems a bit odd to me wonder why this happens?
Edit: Could it be the copying of large amounts of triangle and normals data? Can this be referencenced straight from memory ins$$anonymous$$d somehow? As meshes must already be in memory?
Your answer
Follow this Question
Related Questions
Game Lags when 2 same Objects in scene 1 Answer
Baked Normal Map Discrepancies 1 Answer
Outlines Defined by Shading Groups? 0 Answers
Calculating a Second Set of Normals 0 Answers