Permalink
Browse files

Decal rendering #2: Clipping

  • Loading branch information...
LogicAndTrick committed Feb 7, 2013
1 parent beb0315 commit 1041ba5c192fbcaf04e51c3f20f43b232b2dc31f
Showing with 63 additions and 7 deletions.
  1. +63 −7 Sledge.DataStructures/MapObjects/Entity.cs
@@ -137,11 +137,12 @@ public void CalculateDecalGeometry()
// Get the faces that intersect with the decal's radius
var faces = root.GetAllNodesIntersectingWith(box).OfType<Solid>()
.SelectMany(x => x.Faces).Where(x => x.IntersectsWithBox(box));
var idg = new IDGenerator(); // Dummy generator
foreach (var face in faces)
{
// Project the decal onto the face
var center = face.Plane.Project(Origin);
var decalFace = new Face(int.MinValue) // Use a dummy ID
var decalFace = new Face(idg.GetNextFaceID())
{
Colour = Colour,
IsSelected = IsSelected,
@@ -160,20 +161,75 @@ public void CalculateDecalGeometry()
}
};
// Re-project the vertices in case the texture axes are not on the face plane
// Also add a tiny bit to the normal axis to ensure the decal is rendered in front of the face
var normalAdd = face.Plane.Normal * 0.2m;
var xShift = face.Texture.UAxis * face.Texture.XScale * Decal.Width / 2;
var yShift = face.Texture.VAxis * face.Texture.YScale * Decal.Height / 2;
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center + xShift - yShift) + normalAdd, decalFace)); // Bottom Right
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center + xShift + yShift) + normalAdd, decalFace)); // Top Right
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center - xShift + yShift) + normalAdd, decalFace)); // Top Left
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center - xShift - yShift) + normalAdd, decalFace)); // Bottom Left
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center + xShift - yShift), decalFace)); // Bottom Right
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center + xShift + yShift), decalFace)); // Top Right
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center - xShift + yShift), decalFace)); // Top Left
decalFace.Vertices.Add(new Vertex(face.Plane.Project(center - xShift - yShift), decalFace)); // Bottom Left
decalFace.UpdateBoundingBox();
// TODO: verify this covers all situations and I don't have to manually calculate the texture coordinates
decalFace.FitTextureToPointCloud(new Cloud(decalFace.Vertices.Select(x => x.Location)));
// Next, the decal geometry needs to be clipped to the face so it doesn't spill into the void
// Create a fake solid out of the decal geometry and clip it against all the brush planes
var fake = CreateFakeDecalSolid(decalFace);
foreach (var f in face.Parent.Faces.Except(new[] { face }))
{
Solid back, front;
fake.Split(f.Plane, out back, out front, idg);
fake = back ?? fake;
}
// Extract out the original face
decalFace = fake.Faces.First(x => x.Plane.EquivalentTo(face.Plane));
// Add a tiny bit to the normal axis to ensure the decal is rendered in front of the face
var normalAdd = face.Plane.Normal * 0.2m;
decalFace.Transform(new UnitTranslate(normalAdd));
_decalGeometry.Add(decalFace);
}
}
private static Solid CreateFakeDecalSolid(Face face)
{
var s = new Solid(0)
{
Colour = face.Colour,
IsVisgroupHidden = face.IsHidden,
IsSelected = face.IsSelected
};
s.Faces.Add(face);
var p = face.BoundingBox.Center - face.Plane.Normal * 10; // create a new point underneath the face
var p1 = face.Vertices[0].Location;
var p2 = face.Vertices[1].Location;
var p3 = face.Vertices[2].Location;
var p4 = face.Vertices[3].Location;
var faces = new[]
{
new[] { p2, p1, p},
new[] { p3, p2, p},
new[] { p4, p3, p},
new[] { p1, p4, p}
};
foreach (var ff in faces)
{
var f = new Face(-1)
{
Colour = face.Colour,
IsSelected = face.IsSelected,
IsHidden = face.IsHidden,
Plane = new Plane(ff[0], ff[1], ff[2])
};
f.Vertices.AddRange(ff.Select(x => new Vertex(x, f)));
f.UpdateBoundingBox();
s.Faces.Add(f);
}
s.UpdateBoundingBox(false);
return s;
}
public override void Transform(IUnitTransformation transform)
{
Origin = transform.Transform(Origin);

0 comments on commit 1041ba5

Please sign in to comment.