/* Geometry shader implementation of quadrilateral barycentric interpolation scheme using mean value coordinates described in "A Quadrilateral Rendering Primitive" by Hormann and Tarini (2004 Graphics Hardware Workshop). */ // Vertex shader necessary for GLSL void vertexPassThru ( float4 position : POSITION, float4 color : COLOR0, out float4 oPosition : POSITION, out float4 oColor : COLOR0 ) { oPosition = position; oColor = color; } // Helper function to compute the 2D area between 2 vectors. */ float area(float2 a, float2 b) { return a.x*b.y - a.y*b.x; } // Pretend a 4-vertex "line adjacency" primitive represents a // quadrilateral #define QUAD LINE_ADJ // cgc -profile gp4gp -entry gs_interp_quad gs_interp_quad.cgfx QUAD TRIANGLE_OUT void gs_interp_quad(AttribArray<float4> position : POSITION, AttribArray<float3> rgb : COLOR) { float2 v[4]; float4 rgbOverW_oneOverW[4]; // .rgb = rgbOverW, .w = oneOverW unsigned int i, j, j_next; for (i=0; i<4; i++) { float oneOverW = 1/position[i].w; rgbOverW_oneOverW[i].rgb = rgb[i] * oneOverW; rgbOverW_oneOverW[i].w = oneOverW; v[i] = position[i].xy * oneOverW; } for (i=0; i<4; i++) { // Mapping of polygon vertex order to triangle strip vertex order. // // Quad (lines adjacency) Triangle strip // vertex order: vertex order: // // 1----2 1----3 // | | ===> | \ | // | | | \ | // 0----3 0----2 // const int reorder[4] = { 0, 1, 3, 2 }; const int ii = reorder[i]; float3 s_A[4]; // .xy = s[i], .z = A[i] for (j=0; j<4; j++) { s_A[j].xy = v[j] - v[ii]; } for (j=0; j<4; j++) { j_next = (j+1) % 4; s_A[j].z = area(s_A[j].xy, s_A[j_next].xy); } emitVertex(position[ii] / position[ii].w, s_A[0]:TEXCOORD0, s_A[1]:TEXCOORD1, s_A[2]:TEXCOORD2, s_A[3]:TEXCOORD3, rgbOverW_oneOverW[0]:TEXCOORD4, rgbOverW_oneOverW[1]:TEXCOORD5, rgbOverW_oneOverW[2]:TEXCOORD6, rgbOverW_oneOverW[3]:TEXCOORD7); } } // cgc -profile gp4fp -entry fs_interp_quad gs_interp_quad.cgfx float4 fs_interp_quad(float3 s_A[4] : TEXCOORD0, float4 rgbOverW_oneOverW[4] : TEXCOORD4) : COLOR { unsigned int i, i_next, i_prev; float2 s[4]; float A[4]; float3 rgbOverW[4]; float oneOverW[4]; for (i=0; i<4; i++) { s[i] = s_A[i].xy; A[i] = s_A[i].z; rgbOverW[i] = rgbOverW_oneOverW[i].rgb; oneOverW[i] = rgbOverW_oneOverW[i].w; } float D[4]; float r[4]; for (i=0; i<4; i++) { i_next = (i+1)%4; D[i] = dot(s[i], s[i_next]); r[i] = length(s[i]); if (oneOverW[i] < 0) { // is w[i] negative? r[i] = -r[i]; } } float t[4]; for (i=0; i<4; i++) { i_next = (i+1)%4; t[i] = (r[i]*r[i_next] - D[i]) / A[i]; } float uSum = 0; float u[4]; for (i=0; i<4; i++) { i_prev = (i-1)%4; u[i] = (t[i_prev] + t[i]) / r[i]; uSum += u[i]; } float3 interp_rgbOverW = 0; float interp_oneOverW = 0; float lambda[4]; for (i=0; i<4; i++) { lambda[i] = u[i] / uSum; } /* Discard fragments when all the weights are neither all negative nor all positive. */ float lambdaSignCount = 0; for (i=0; i<4; i++) { if (lambda[i] < 0) { lambdaSignCount--; } else { lambdaSignCount++; } } if (abs(lambdaSignCount) != 4) { discard; } for (i=0; i<4; i++) { interp_rgbOverW += lambda[i] * rgbOverW[i]; interp_oneOverW += lambda[i] * oneOverW[i]; } float3 interp_rgb = interp_rgbOverW / interp_oneOverW; float4 result; result = float4(interp_rgb, 1); return result; } QUAD TRIANGLE_OUT void quadToTrianglePair(AttribArray<float4> position : POSITION, AttribArray<float3> rgb : COLOR) { int i; for (i=0; i<4; i++) { // Mapping of polygon vertex order to triangle strip vertex order. const int reorder[4] = { 0, 1, 3, 2 }; int ii = reorder[i]; emitVertex(position[ii], rgb[ii]); } } float4 interpolateColor(float3 interp_rgb : COLOR) : COLOR { float4 result; result = float4(interp_rgb, 1); return result; } /* Technique for conventional quad rendering (breaking quads into a two-triangle strip). */ technique ConventionalQuadRendering { pass { VertexProgram = compile latest vertexPassThru(); GeometryProgram = compile latest quadToTrianglePair(); FragmentProgram = compile latest interpolateColor(); } } /* Technique for mean value coordinate-based quad rendering (interpolating attributes and testing ownership with mean value coordinates). */ technique ImprovedQuadRendering { pass { VertexProgram = compile latest vertexPassThru(); GeometryProgram = compile latest gs_interp_quad(); FragmentProgram = compile latest fs_interp_quad(); } }