13.12.2012 Views

ShaderX Shader Programming Tips & Tricks With DirectX 9

ShaderX Shader Programming Tips & Tricks With DirectX 9

ShaderX Shader Programming Tips & Tricks With DirectX 9

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Making It Fast Using a Linear Basis<br />

Evaluating N-Patches via a vertex shader can be quite expensive. If you are also<br />

using a displacement map, the inherent surface curve usually isn’t very important<br />

anyway. Usually when using displacement compression, we would like a basis that<br />

has a smooth surface normal but relies on the displacement map to handle the<br />

position. A linear basis has all these properties: The surface normal is smooth<br />

between patches (assuming the vertex normals are smooth), but the position<br />

before the displacement is planar. The surface normal is generated from the linear<br />

interpolation of the vertex normals (in a similar manner to how Phong shading<br />

interpolates the lighting normal).<br />

A linear basis only requires the mesh vertex data, and as these can be shared<br />

between patches, it’s usually better to store vertex indices rather than a triangle<br />

index at every interior point. This usually increases the number of vertices that<br />

can be stored in constant memory, which increases performance as more patches<br />

can be evaluated per call at the expense of slightly larger per-vertex data.<br />

//HLSL for a displaced linear basis surface with indexed vertices<br />

float MAX DISPLACEMENT HEIGHT = 100; // this is just an example value<br />

float3 VertexPos[NUM BASE VERTICES];<br />

float3 VertexNormal[NUM BASE VERTICES];<br />

float2 VertexUV[NUM BASE VERTICES];<br />

struct VS IN<br />

{<br />

float2 barycentric;<br />

float3 indices;<br />

float displacement;<br />

};<br />

void main( VS IN input )<br />

{<br />

float i = input.barycentric.x;<br />

float j = input.barycentric.y<br />

float k=1.0–i–j;<br />

float i0 = input.indices.x * 256;<br />

float i1 = input.indices.y * 256;<br />

float i2 = input.indices.z * 256;<br />

}<br />

Section I — Geometry Manipulation <strong>Tricks</strong><br />

Using Vertex <strong>Shader</strong>s for Geometry Compression<br />

float3 pos = i*VertexPos[i0] + j*VertexPos[i1] + k*VertexPos[i2];<br />

float3 normal = i* VertexNormal[i0] + j* VertexNormal[i1] + k* VertexNormal[i2];<br />

float2 uv = i* VertexUV[i0] + j* VertexUV[i1] + k* VertexUV[i2];<br />

normal = normalized( normal );<br />

pos = pos + input.displacement * normal * MAX DISPLACEMENT HEIGHT;<br />

Barycentric coordinates are in the range [0,1] and are the same for each triangle<br />

at a particular subdivision. Indices only require a maximum of 256 values (there<br />

are currently only 256 constants). So a byte per index is enough. For the triangle<br />

indexed version, this is 1 byte + 1 byte displacement and a shared 8 bytes (two<br />

11

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!