I figured it was about time I played around with volume rendering...
The volume is generated from a height map.
-
Here's a small class for building vertex and index data. I used this sort of thing a while ago when I was just starting on my planet renderer. I quickly found out that it, while putting everything into one nice vertex buffer and index buffer (saving me draw calls), became way to expensive to use when I started using much larger amounts of data. Nonetheless, it's still useful for making smaller things, such as boxes.
Anyways, the code:
public sealed class GeometryBuilder{List<Vector3>vertices = new List <Vector3>();List<int>indices = new List <int>();
public void AddTriangle(Vector3 v0, Vector3 v1, Vector3 v2){AddVertex(v0);AddVertex(v1);AddVertex(v2);}
private void AddVertex(Vector3 vertex){if (!vertices.Contains(vertex))vertices.Add(vertex);
indices.Add(vertices.IndexOf(vertex));}
public Tuple<Vector3[], int[]>GetData() {return Tuple.Create(vertices.ToArray(), indices.ToArray());}}
And a sample usage (yes it's a box):
GeometryBuilder builder = new GeometryBuilder();builder.AddTriangle(new Vector3(-1, 1, 1), new Vector3(1, 1, 1), new Vector3(-1, -1, 1));builder.AddTriangle(new Vector3(1, 1, 1), new Vector3(1, -1, 1), new Vector3(-1, -1, 1));builder.AddTriangle(new Vector3(-1, 1, -1), new Vector3(-1, -1, -1), new Vector3(1, 1, -1));builder.AddTriangle(new Vector3(1, 1, -1), new Vector3(-1, -1, -1), new Vector3(1, -1, -1));
builder.AddTriangle(new Vector3(-1, 1, -1), new Vector3(-1, 1, 1), new Vector3(-1, -1, -1));builder.AddTriangle(new Vector3(-1, 1, 1), new Vector3(-1, -1, 1), new Vector3(-1, -1, -1));builder.AddTriangle(new Vector3(1, 1, -1), new Vector3(1, -1, -1), new Vector3(1, 1, 1));builder.AddTriangle(new Vector3(1, 1, 1), new Vector3(1, -1, -1), new Vector3(1, -1, 1));
builder.AddTriangle(new Vector3(-1, 1, -1), new Vector3(1, 1, -1), new Vector3(-1, 1, 1));builder.AddTriangle(new Vector3(1, 1, -1), new Vector3(1, 1, 1), new Vector3(-1, 1, 1));builder.AddTriangle(new Vector3(-1, -1, -1), new Vector3(-1, -1, 1), new Vector3(1, -1, -1));builder.AddTriangle(new Vector3(1, -1, -1), new Vector3(-1, -1, 1), new Vector3(1, -1, 1));
Tuple<Vector3[], int[]>data = builder.GetData(); vertices = data.Item1.Select(n => new VertexPositionTexture(n, Vector2.Zero)).ToArray();indices = data.Item2;
Once again, the code works for me. Feel free to post comments on any problems/improvements.
YellPika0Add a comment
-
OK, I lied.
I've been looking at LOD again, except this time around, I'm using triangles, not square patches. I've hacked out a couple useful methods, namely:
- Closest Point on Triangle
- Distance from Point to Triangle
Closest Point on TriangleThis one was a pain, especially given my limited mathematical knowledge (don't worry, I'm working on it).
The basic idea is to project the point onto a plane defined by the triangle, then constrain the projected point to the triangle based on other planes defined by the sides.
Projecting a point onto a plane is quite simple. First, we the equation of the plane:
ax + by + cz + d = 0
Where (a, b, c) is the normal of the plane, (x, y, z) is any point on the plane, and d is the distance of the plane from the origin. Say, ax + by + cz looks a lot like the dot product... perhaps:
v . n + d = 0
Where v is (x, y, z) and n is (a, b, c).
We also need the equation of the projected point relative to the original point. So:
p' = p - n * s
Where p is the original point, n is the plane normal, and s is the distance between the plane and p.
So, with a little rearranging...
p' . n + d = 0ap'x + bp'y + cp'z + d = 0a(px - nxs) + b(py - nys) + c(pz - nzs) + d = 0a(px - as) + b(py - bs) + c(pz - cs) + d = 0apx - a^2s + bpy - b^2s + cpz - c^2s + d = 0-s(a^2 + b^2 + c^2) + apx + bpy + cpz + d = 0-s(n . n) + n . p + d = 0-s = -(d - n . p) / (n . n)s = (d + n . p) / (n . n)
Assuming the normal is normalized, then n . n would result in 1, yielding:
s = n . p + d
To find, p', just use the third equation, p' = p - n * s, or p' = p - n * (n . p + d).
That's all easy enough, so how to constrain the projected point to the triangle? An interesting thing about s is that it's positive or negative depending on which side of the plane it's on. All we have to do is find the planes of the three sides, and the project the point to each plane if s is positive.
...What?
The sides of triangles are lines, how are we supposed to turn that into a plane!?
What I should have added earlier is, the planes have to be perpendicular to the plane defined by the triangle. Now that our number choices have been narrowed down from infinite to one, how do we find that one plane?
I define my planes using more triangles. For that, we need three points. First two are easy - the two vertices of the side. Just add the normal of the original triangle to one of the vertices, and you have your third point.
So how do we do that in XNA?
public Vector3 Project(Vector3 a, Vector3 b, Vector3 c, Vector3 point)
{
Plane plane = new Plane(a, b, c); // Find the plane defined by the points.
// Project point onto plane.
float dist = Vector3.Dot(plane.Normal, point) + plane.D;
Vector3 proj = point - plane.Normal * dist;
// Find the planes defined by the sides.
Plane ab = new Plane(a, b, a + plane.Normal);
Plane bc = new Plane(b, c, b + plane.Normal);
Plane ca = new Plane(c, a, c + plane.Normal);
// Find the distances from proj to the planes.
float abDist = Vector3.Dot(ab.Normal, proj) + ab.D;
float bcDist = Vector3.Dot(bc.Normal, proj) + bc.D;
float caDist = Vector3.Dot(ca.Normal, proj) + ca.D;
// If any of the distances are positive, then the point is not on the triangle.
// Project the point onto the corresponding plane.
if (abDist > 0)
proj = proj - ab.Normal * abDist;
if (bcDist > 0)
proj = proj - bc.Normal * bcDist;
if (caDist > 0)
proj = proj - ca.Normal * caDist;
return proj;
}
Distance from Point to Triangle
This one is nice and easy. It's the distance between the point and the closest point on the triangle.
public void Distance(Vector3 a, Vector3 b, Vector3 c, Vector3 point)
{
return Vector3.Distance(point, Project(a, b, c, point));
}
The Triangle Class
Below is a useful class.
public struct Triangle
{
public Vector3 A, B, C;
public Triangle(Vector3 a, Vector3 b, Vector3 c)
{
A = a;
B = b;
C = c;
}
public float Distance(Vector3 point)
{
return Vector3.Distance(point, Project(point));
}
public Vector3 Project(Vector3 point)
{
Plane plane = new Plane(A, B, C);
float dist = Vector3.Dot(plane.Normal, point) + plane.D;
Vector3 proj = point - plane.Normal * dist;
Plane ab = new Plane(A, B, A + plane.Normal);
Plane bc = new Plane(B, C, B + plane.Normal);
Plane ca = new Plane(C, A, C + plane.Normal);
float abDist = Vector3.Dot(ab.Normal, proj) + ab.D;
float bcDist = Vector3.Dot(bc.Normal, proj) + bc.D;
float caDist = Vector3.Dot(ca.Normal, proj) + ca.D;
if (abDist > 0)
proj = proj - ab.Normal * abDist;
if (bcDist > 0)
proj = proj - bc.Normal * bcDist;
if (caDist > 0)
proj = proj - ca.Normal * caDist;
return proj;
}
}
Well, that's it for now. Hopefully this is useful to somebody other than me. The code works fine for me, but if anyone has any disagreements/problems, feel free to post a comment.
YellPika
0Add a comment
-
Where did all the stuff go?
My posts were all over the place. I was also getting very lazy about posting new content.
Overall, the blog wasn't quite turning out how I wanted it to be...
So, I'm starting over.
I'll be laying off the procedurals for a while. If there's anything I've learned up 'till now... it's that my laptop's 8200 simply can't handle what I'm trying to do. On to the desktop.
When I get to the desktop, that is. Until then, sit tight.0Add a comment
Add a comment