3D Mesh Simulations
CS 493/693 Lecture, Dr. Lawlor
Although we almost always use 2D textures, OpenGL has always supported 3D or "solid textures":
- You upload the texture data with glTexImage3D.
- Texture coordinates are 3D; upload them with glTexCoord3f.
- As usual, glEnable(GL_TEXTURE_3D); to have the fixed-function hardware read from the 3D texture.
- In GLSL, use a "uniform sampler3D" to represent a texture unit, and the "texture3D" function to look up values from it.
- Sadly, unlike the 2D case gluBuild3DMipmaps
needs glu 1.3, and Windows comes with 1.2. Instead, either ask
the driver to build your mipmaps using glTexParameteri(GL_TEXTURE_3D,
GL_GENERATE_MIPMAP_SGIS, GL_TRUE); or else glEnable(GL_TEXTURE_3D); and
glGenerateMipmap(GL_TEXTURE_3D);
Texture wrapping and sampling modes are identical to 2D:
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
GL_LINEAR means "trilinear" interpolation for a 3D texture
(interpolation along each 3D axis), and GL_LINEAR_MIPMAP_LINEAR uses
"quadrilinear interpolation" (interpolation along each3D axis, and then across mipmap levels).
Annoyingly, you can't bind an entire 3D texture as the framebuffer's
attachment for writing, but you can attach to a given Z layer of the
texture using
glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_3D,
your_tex_handle, 0, destination_layer);
You'll need to loop over and write to each layer of the texture separately. It's a little weird that you can read from anywhere in 3D, but only write to a 2D surface.
Similarly, with fixed-function hardware you can only draw a 2D slice of
a 3D texture. To get the whole thing, you need to either draw a
bunch of slices (hopefully not oriented so the camera can see between
the slices), or just run a shader, and loop over the depth range of
interest.
The big problem with 3D simulations is that 3D gets really huge really fast:
- 1024x1024 is 1 million pixels. 4MB for RGBA8, 8MB for
16-bit float RGBA. At 1 billion finished pixels per second, we
can do 1,000fps. No problem!
- 1024x1024x1024 is 1 billion "voxels". 4GB for RGBA8, 8GB
for 16-bit float RGBA. At 1 billion pixels per second, we can do
1fps. Big problem!
On modern high-end hardware, I seem to be able to comfortably render 512^3 volumes (1024^3 runs out of storage space and render bandwidth). But the extra reads and binds needed for simulation
means I can only get to about 128^3, and that's pushing it. Big
dense 3D simulations are one of the few things capable of bringing a
modern GPU to its knees!