I am thinking about splat decals and I need to be able to check if any part of a triangle (represented by 3 Vector3s) is inside a sphere (represented by a point and radius).
Talking on the IRC channel it looks like the best way to check is to get the point on the triangle that is closest to the center of the sphere, and then check if the distance between it and the center on the sphere is < radius.
What I have thought up to do for starters is this: Is the distance between the center of the triangle and any of it’s vertices greater than the distance between the center of the triangle and the center of the sphere minus the radius.
Here is my code as it is right now.
//TextureSplat.js
var material : Material;
var rotationAcuracy = 10;
var radius = 0.00;
var splatSize = 0.00;
class Root
{
var meshes = new Array();
var transform : Transform;
}
function Start ()
{
var hit : RaycastHit;
var rays = 0;
var hits = 0;
var direction : Vector3;
var explosionDirection : Vector3;
while(rays < rotationAcuracy)
{
direction = (-direction / 2) + Random.onUnitSphere;
if(Physics.Raycast(transform.position, direction, hit, radius))
{
explosionDirection += ((-direction.normalized / 2) + hit.normal.normalized) * (1 - (hit.distance / radius));
hits ++;
}
rays ++;
}
if(hits == 0)
{
return;
}
else
{
transform.rotation = Quaternion.LookRotation(explosionDirection);
}
var roots = new Array();
colliders = Physics.OverlapSphere (transform.position, radius);
for(collider in colliders)
{
m = collider.gameObject.GetComponent(MeshFilter);
if(m)
{
found = null;
for(r in roots)
{
if(collider.transform.root == r.transform) found = r;
}
if(found)
{
found.meshes.Add(m);
}
else
{
r = new Root();
r.transform = collider.transform.root;
r.meshes.Add(m);
roots.Add(r);
}
}
}
for(r in roots)
{
newVertices = new Array();
newNormals = new Array();
newTriangles = new Array();
totalVerts = 0;
for(var m : MeshFilter in r.meshes)
{
totalVerts += m.mesh.vertices.length;
}
usedVertices = new int[totalVerts];
usedCount = 0;
otherMeshVerts = 0;
for(var envMesh : MeshFilter in r.meshes)
{
i = 0;
while(i < envMesh.mesh.triangles.length)
{
p1 = envMesh.transform.TransformPoint(envMesh.mesh.vertices[envMesh.mesh.triangles[i]]);
p2 = envMesh.transform.TransformPoint(envMesh.mesh.vertices[envMesh.mesh.triangles[i + 1]]);
p3 = envMesh.transform.TransformPoint(envMesh.mesh.vertices[envMesh.mesh.triangles[i + 2]]);
center = (p1 / 3) + (p2 / 3) + (p3 / 3);
toHereFromFace = transform.position - center;
distanceFromCenter = toHereFromFace.magnitude - radius;
if(distanceFromCenter < (center - p1).magnitude || distanceFromCenter < (center - p2).magnitude || distanceFromCenter < (center - p3).magnitude)
{
faceNormal = Vector3.Cross(envMesh.mesh.vertices[envMesh.mesh.triangles[i + 2]] - envMesh.mesh.vertices[envMesh.mesh.triangles[i + 1]], envMesh.mesh.vertices[envMesh.mesh.triangles[i + 1]] - envMesh.mesh.vertices[envMesh.mesh.triangles[i]]);
if((-envMesh.transform.TransformDirection(faceNormal).normalized - toHereFromFace.normalized).magnitude < 1.6)
{
if(!usedVertices[envMesh.mesh.triangles[i] + otherMeshVerts])
{
usedVertices[envMesh.mesh.triangles[i] + otherMeshVerts] = usedCount;
newVertices.Add(p1);
newNormals.Add(envMesh.transform.TransformDirection(envMesh.mesh.normals[envMesh.mesh.triangles[i]]));
newTriangles.Add(usedCount);
usedCount ++;
}
else
{
newTriangles.Add(usedVertices[envMesh.mesh.triangles[i] + otherMeshVerts]);
}
if(!usedVertices[envMesh.mesh.triangles[i + 1] + otherMeshVerts])
{
usedVertices[envMesh.mesh.triangles[i + 1] + otherMeshVerts] = usedCount;
newVertices.Add(p2);
newNormals.Add(envMesh.transform.TransformDirection(envMesh.mesh.normals[envMesh.mesh.triangles[i + 1]]));
newTriangles.Add(usedCount);
usedCount ++;
}
else
{
newTriangles.Add(usedVertices[envMesh.mesh.triangles[i + 1] + otherMeshVerts]);
}
if(!usedVertices[envMesh.mesh.triangles[i + 2] + otherMeshVerts])
{
usedVertices[envMesh.mesh.triangles[i + 2] + otherMeshVerts] = usedCount;
newVertices.Add(p3);
newNormals.Add(envMesh.transform.TransformDirection(envMesh.mesh.normals[envMesh.mesh.triangles[i + 2]]));
newTriangles.Add(usedCount);
usedCount ++;
}
else
{
newTriangles.Add(usedVertices[envMesh.mesh.triangles[i + 2] + otherMeshVerts]);
}
}
}
i += 3;
}
otherMeshVerts += envMesh.mesh.vertices.length;
}
if(newVertices.length > 0)
{
decal = new GameObject("Decal");
decal.transform.position = transform.position;
decal.transform.rotation = transform.rotation;
decal.transform.parent = r.transform;
decal.transform.localScale = Vector3(1, 1, 1);
newUV = new Vector2[newVertices.length];
newColors = new Color[newVertices.length];
i = 0;
for(v in newVertices)
{
v = decal.transform.InverseTransformPoint(v);
newUV[i].x = (v.x / splatSize) + 0.5;
newUV[i].y = (v.y / splatSize) + 0.5;
a = Mathf.Abs(v.z) / radius;
newColors[i] = Color.Lerp(Color.white, Color.clear, a * a * a);
newNormals[i] = decal.transform.InverseTransformDirection(newNormals[i]).normalized;
i ++;
}
dMesh = decal.AddComponent(MeshFilter);
ren = decal.AddComponent(MeshRenderer);
ren.material = material;
var mesh = new Mesh ();
mesh.vertices = newVertices;
mesh.normals = newNormals;
mesh.uv = newUV;
mesh.colors = newColors;
mesh.triangles = newTriangles;
dMesh.mesh = mesh;
}
}
}