280 likes | 455 Views
A Non-Photorealistic Fragment Shader in OpenGL 2.0. Bert Freudenberg Institut für Simulation und Graphik University of Magdeburg, Germany. Outline. OpenGL 2.0 proposal Vertex and fragment shaders Non-photorealistic shading Anti-aliasing in a shader Lighting Adding noise Conclusion.
E N D
A Non-Photorealistic Fragment Shader in OpenGL 2.0 Bert Freudenberg Institut für Simulation und GraphikUniversity of Magdeburg, Germany
Outline • OpenGL 2.0 proposal • Vertex and fragment shaders • Non-photorealistic shading • Anti-aliasing in a shader • Lighting • Adding noise • Conclusion
OpenGL 2.0 Proposal • Shading Language • High-level language for • vertex shaders • fragment shaders • even more • Experimentally implemented as GL2 extension • available on 3Dlabs Wildcat VP
Base for our shader • Scott F. Johnston’s “Mock Media” • From “Advanced RenderMan: Beyond the Companion” (SIGGRAPH ’98 Course #11) • RenderMan surface shader for woodprint-like appearance • Shading by lines of varying width
Vertex Shader • Uses constant and per-vertex data to set up attributes varying across the primitive • Our shader: • one surface parameter • screen-space position
Vertex Shader • varying float v; • void main(void) • { • v = gl_MultiTexCoord0.s; • gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; • }
Fragment Shader • Gets interpolated varyingparameters • Similar to RenderMan surface shader • Evaluates some function to output color at a certain point in parameter space • Our shader: • output black or white to create lines
Parameter • varying float v; • v = texcoord0.s; • Assigned in vertex shader • Interpolated value in fragment shader
Sawtooth wave • sawtooth = fract( v * 16. );
Triangle wave • triangle = abs(2. * sawtooth - 1.);
Square wave • square = step(0.5, triangle); • Aliasing!
Anti-aliasing • FSAA will not help • just raises resolution • Need to remove higher frequencies • manually • Step function has unlimited frequency • use smooth step instead
Constant width smoothstep() • square =smoothstep(0.4, 0.6, triangle); • Buggy, hence: • edge0 = 0.4; edge1 = 0.6; • t = clamp((triangle - edge0) / (edge1 - edge0), 0., 1.); • square = t * t * (3. - 2. * t); • Aliasing + blurring
Derivatives • dPdx(v), dPdy(v) • Derivative of parameter v in screen x and y
Length of derivative • dp = length(vec2(dPdx, dPdy));
Adaptive filter width • filterstep() • float edge = 0.5; • float w = 64. * dp; • float square = clamp((triangle + 0.5 * w - edge) / w, 0., 1.);
Raising frequency • No more individual lines • Too dense in certain regions • Adjust frequency based on screen space density
Partitioning by derivative • ilogdp = floor(log2(dp)); • No log2() yet • Texture as lookup table • vec3 tex0 = texture3(0, dp * 8.); • float logdp = (tex0.r - 0.5) * 256. + tex0.g;
Adjusting frequency • exp2(floor(log2(dp))) * f; • frequency doubles in discrete steps • also works for distance!
Tapering ends • linearly interpolate to double frequency • t = fract(log2(dp)); • triangle = abs((1. + t) * triangle - t);
Lighting • Vertex Shader • pos = vec3(gl_ModelViewMatrix * gl_Vertex); • tnorm = normalize(gl_NormalMatrix * gl_Normal); • vec3 lightVec = normalize(LightPosition - pos); • lightIntensity = max(dot(lightVec, tnorm), 0.0);
Lighting • Line width dependent on lighting • Adjust threshold by light intensity • square = step(lightIntensity, triangle);
Noise • No noise() yet • 3D tilable noise tex = ( • F(x,y,z)*(t-x)*(t-y)*(t-z)+ • F(x-t,y,z)*(x)*(t-y)*(t-z)+ • F(x-t,y-t,z)*(x)*(y)*(t-z)+ • F(x,y-t,z)*(t-x)*(y)*(t-z)+ • F(x,y,z-t)*(t-x)*(t-y)*(z)+ • F(x-t,y,z-t)*(x)*(t-y)*(z)+ • F(x-t,y-t,z-t)*(x)*(y)*(z)+ • F(x,y-t,z-t)*(t-x)*(y)*(z)) • /(t*t*t);
Noisy width • Bias threshold
Conclusion • Learn about RenderMan shaders • Translate to OpenGL 2.0 • almost straight-forward • Anti-aliasing is an issue • use derivatives • Non-photorealistic Rendering is cool!