080524 / Triangles

previous | next

Started programming outside of work again. Back to prototyping and testing some of my wild rendering ideas.

Comment on Voxels

Old news, but seems as if Carmack is returning to voxels. Some other thoughts on this on MollyRocket. Carmack does have a really good point there on fixing anti-aliasing by temporal jitter of pixel center position. Damn elegant solution IMO. As for the voxel stuff, looks to only be good for static geometry and simplifies static content into a compression problem. Should solve the LOD and transparency problem, but at the cost of per pixel searching (raycast or raytrace into octtree).

Triangles

In some ways rendering is to radix sort as raytracing/casting is to merge sort. One fundamental difference is searching for an answer to avoid doing work (raytracing), and doing work to avoid searching for an answer (rendering).

So yeah, I'm finally warming up to triangles, and perhaps I've got a few surprises on how to solve old problems given that I spend nearly 99% of my time thinking about non-triangle rendering...

SOLUTION TO LOD AND LARGE VIEW DISTANCE OCCLUSION : I don't like tessellation as it doesn't solve the problem of simplifying disjoint geometry. My solution, build surfaces up with layers of small triangles. Each layer independent. New LOD blends in new fine layer, blends out a previous course layer, keeping enough middle layers to insure a good effect. Course layers are mostly inner hulls, fine LOD layers mostly extend the surface, or split into disjoint shapes. Think of it somewhat as a painter paints a scene, laying out rough shapes and color (lower LOD layers), then refining (fine LOD layers). Occlusion culling is an easy and solved problem, with occlusion queries and a hierarchical layered world structure.

RETURNING TO AMORTIZING PIXEL COST IN THE VERTEX SHADER : With the LOD problem solved, one can control the overall size of triangles in a given region on the screen. Small triangles enables more work to be pushed back to the vertex shader. Even soft shadows and diffuse transparency effects. Gets rid of the need for multiple passes for lighting. All lighting + dynamic global illumination computed per vertex, interpolate spherical harmonics for single pass per pixel lighting. Keep in mind at 720P at 30fps, the GPU is solving for only 30 Mpix/sec, but has the capacity of over 200 Mtri/sec in setup. So small triangles are not a problem (until reaching the size of micro triangles, with bad pixel quad utilization).

SINGLE OR DUAL PASS FOR EVERYTHING : If have readable Z buffer (DX10, etc), and effective rough z sort of geometry, then perhaps only one pass needed, otherwise add pre-z pass.

POST PROCESSING BUILT INTO THIS SINGLE PASS : The pass involves only 2 RGBA 8-bit MRTs and no-blending. First RT is color (perhaps LOGLUV), second RT is normal+extra. Previous frames results used to compute new frame, and fragment shader gets current and previous frame pixel position. All post processing works with previous frame feedback, gathering samples from the 2 RTs of the previous frame of which a full mipmap is generated (very important). Also uses previous frame's mipmaped depth buffer (also very important). Mipmap generation cost for these 3 textures is only 3 texture lookups per screen pixel total. Post processing effects work by adjusting position and mipmap level of a set number of texture lookups from previous frame, and adjusting the weighted average of those samples with the resulting computed color for the current fragment. Motion blur, depth of field, anti-aliasing, etc, simply control the distribution of those lookups and parameters.

FRAME FEEDBACK SO TRIANGLES CAN EXCEED THEIR BOUNDS : Similar to how the post processing works, fragments can gather color+normal+extra+depth information from neighboring triangle's fragments through a previous frame lookups. So surfaces can either converge faster than your eye can focus on them, or slowly grow and change dynamically. So texture lookup is no longer ambient+diffuse+spec+bump+etc, but rather parameters which control how a fragment changes based on neighboring fragments. Combined this with fragment kill and binary cutout of textures. Single fragments will be able to generate diffuse effects far beyond their bounds, so I've got no plans for a transparent geometry pass. Blend in/out (key to LOD system) will be fragment kill based. Frame feedback will insure this is smooth and seamless without transparency. Other far reaching transparent effects will go into adjusting per vertex lighting (remember small triangles).

Why This Design

So I've wavered between motion stretched billboard (current running engine), forward and deferred rendering (with current engine), and point based rendering (lots of little prototypes), with my last idea to raycast an impostor cache (no time to fully try). Even with amortized searching in the impostor cache, I was still looking for a better way to use the hardware, something ideal, something with no searching.

Progress on the Prototype

I've spent a few evenings verifying the framebuffer feedback ideas, have a working prototype with anti-aliasing, fake image space refraction mapping, and initial motion blur. Working on final motion blur and depth of field code currently. Lots of cool stuff here, screen shots next time.