Draw a Circle in Opengl Using Shaders

In the previous affiliate the basics of using a shader to render simple primitives were introduced. This affiliate introduces bones usage of the fragment shader. In particular, this affiliate shows a few things that can exist done in fragment shaders using one the nearly basic congenital-in inputs and functions. After chapters will build on these examples.

Drawing Circles Using gl_FragCoord

It would seem that a fragment shader such as Effigy�two, "Simple fragment shader" would have no inputs when paired with a vertex shader such as Effigy�1, "Uncomplicated vertex shader". Even so, every fragment shader has at least one built-in input: the current fragment position. The variable gl_FragCoord contains the window position of the current fragment in its X and Y components. The Z component contains fragment's depth value on the range [0, 1].

Figure�1.�Simple vertex shader

                ane void master(void)  2 {  three     gl_Position = gl_Vertex;  4 }              

Figure�2.�Simple fragment shader

                i void main(void)  2 {  3     gl_FragColor = vec4(0.0, one.0, 0.0, 1.0);  4 }              

The fragment shader in Figure�three, "Circle fragment shader" uses gl_FragCoord to return a simple pattern. The shader partitions the window into l-by-50 pixel squares. Line 3 in the shader computes the position of the current fragment relative to the center of the 50-by-50 pixel region that contains it. Line 4 computes the squared distance from the center. Lines 6 through viii use that distance to write either greyness or blue to gl_FragColor . The leftmost image of Figure�iv, "Output of circumvolve fragment shader" is a sample paradigm rendered by this shader. The upshot is a series of 20 pixel diameter greyness circles.

Figure�iii.�Circle fragment shader

                1 void principal(void)  ii {  3     vec2 pos = mod(gl_FragCoord.xy, vec2(50.0)) - vec2(25.0);  four     bladder dist_squared = dot(pos, pos);  5   6     gl_FragColor = (dist_squared < 400.0)   7         ? vec4(.90, .xc, .ninety, one.0)  viii         : vec4(.20, .20, .40, 1.0);  9 }              

Figure�4.�Output of circumvolve fragment shader

Output of circle fragment shader

Output of circle fragment shader

Output of circle fragment shader

From left to right: Epitome produced without interpolation of colors. Image produced using linearstep. Image produced using smoothstep.


The shader in Figure�3, "Circle fragment shader" can be rewritten to utilize 2 useful functions that are built into GLSL. The footstep function returns 0.0 for each component of value that is less than edge .

genType step(genType edge, genType value);  genType step(float edge, genType value);        

Like many functions in GLSL, step has parameters and render values with the type genType. This is shorthand for float, vec2, vec3, and vec4. The total set of overloaded versions of step is:

float step(float edge, float value); vec2 step(vec2 edge, vec2 value); vec3 step(vec3 edge, vec3 value); vec4 step(vec4 edge, vec4 value);  vec2 step(float edge, vec2 value); vec3 stride(float edge, vec3 value); vec4 pace(bladder edge, vec4 value);        

The mix role calculates the component-wise linear interpolation of v0 and v1 using t as the blend factor. More precisely, mix computes 5 0 ( 1.0 t ) + v ane t . Annotation that t need not be limited to the range [0, 1].

genType mix(genType v0, genType v1, genType t);  genType mix(genType v0, genType v1, float t);        

Using stride and mix the shader in Figure�3, "Circle fragment shader" can be rewritten as the shader in Effigy�5, "Circumvolve fragment shader using mix and stride". Both shaders should produce identical output.

Figure�five.�Circumvolve fragment shader using mix and step

                1 void main(void)  2 {  3     vec2 pos = mod(gl_FragCoord.xy, vec2(fifty.0)) - vec2(25.0);  4     float dist_squared = dot(pos, pos);  5   6     gl_FragColor = mix(vec4(.90, .90, .90, i.0), vec4(.20, .xx, .xl, 1.0),  7                        stride(400.0, dist_squared));  eight }              

A close examination of the leftmost Figure�4, "Output of circumvolve fragment shader" reveals an unpleasant sharp boundary at the edge of the circle. In this implementation, each pixel is either greyness or blue. The exact edge of a 20 pixel radius circle actually passes through a different portion of each pixel along the edge. Equally a consequence, pixels along the border should be fatigued with some combination of blue and grayness. The can be acomplished by adjusting the 3rd parameter to the mix function.

If the distance from the centre is below some threshold, say 19.five, the pixel should exist completely greyness. If the distance from the eye is higher up another threshold, say 20.5, the pixel should be completely blueish. If the distance between these two thresholds, the pixel should exist some combination of blue and gray. This new blend factor could be implemented as in Effigy�six, "linearstep function". Using linearstep in identify of pace in Figure�5, "Circle fragment shader using mix and footstep" results in the center image in Figure�4, "Output of circle fragment shader".

Effigy�vi.�linearstep role

                1 bladder linearstep(float lo, float hullo, bladder 10)  2 {  3     return (clamp(x, lo, hi) - lo) / (howdy - lo);  4 }              

Notice that the edges have gone from likewise sharp to too blury. Instead of a simple linear interpolation, an interpolator that change slowly near the edges and quickly through the middle will produce better results. The Hermite interpolator, f ( t ) = 3 t 2 2 t 3 , does this exactly. There is a part congenital into GLSL, smoothstep, which computes this value over a given range. linearstep can exist directly replaced with smoothstep to produce the rightmost epitome in Figure�4, "Output of circle fragment shader". The last shader appears in Effigy�7, "Circumvolve fragment shader using mix and smoothstep".

genType smoothstep(genType low_edge, genType high_edge, genType value);  genType smoothstep(float low_edge, float high_edge, genType value);        

Figure�7.�Circle fragment shader using mix and smoothstep

                1 void main(void)  ii {  3     vec2 pos = mod(gl_FragCoord.xy, vec2(l.0)) - vec2(25.0);  4     bladder dist_squared = dot(pos, pos);  5   six     gl_FragColor = mix(vec4(.ninety, .90, .ninety, one.0), vec4(.20, .twenty, .xl, 1.0),  seven                        smoothstep(380.25, 420.25, dist_squared));  8 }              

Rotated Circles

Since gl_FragCoord is just a two-dimensional coordinate, transformations can be applied to it. Using a unproblematic coordinate transformation, every bit in Effigy�eight, "Rotated circle fragment shader", the orientation of the circles can be changed. The output of this shader is shown in Figure�9, "Output of rotated circle fragment shader". The matrix used in the shader may non wait like the usual rotation matrix. Matrices in OpenGL are typically column-major. The start two elements of this matrix represent the first column of the matrix.

Figure�viii.�Rotated circle fragment shader

                1 #define M_PI iii.14159265358979323846  2   3 const mat2 rotation = mat2( cos(M_PI/4.0), sin(M_PI/four.0),  4                            -sin(M_PI/4.0), cos(M_PI/4.0));  five void chief(void)  6 {  seven     vec2 pos = mod(rotation * gl_FragCoord.xy, vec2(50.0)) - vec2(25.0);  8     float dist_squared = dot(pos, pos);  ix  10     gl_FragColor = mix(vec4(.90, .90, .90, ane.0), vec4(.20, .20, .40, i.0), 11                        smoothstep(380.25, 420.25, dist_squared)); 12 }              

Figure�9.�Output of rotated circle fragment shader

Output of rotated circle fragment shader


There is i big disadvantage of the shader in Effigy�viii, "Rotated circle fragment shader". If the application wants to change the rotation bending, it has to change the shader source. A later chapter will bear witness a method for passing parameters into shaders that are constant across a group of primitives.

Cut Holes

Occasionally it is useful to take "holes" in the rendered image. A special fragment shader keyword discard tin can do this. In lines 6 and 7 of Figure�10, "Circumvolve fragment shader using discard" compare the squared radius to the range [100, 575]. Any fragments outside that range are discarded[one]. In Effigy�eleven, "Output of circle fragment shader that uses discard" the black pixels are the background color. This shows through where fragments are discarded.

Figure�10.�Circumvolve fragment shader using discard

                1 void main(void)  two {  3     vec2 pos = modern(gl_FragCoord.xy, vec2(50.0)) - vec2(25.0);  4     bladder dist_squared = dot(pos, pos);  5   half-dozen     if ((dist_squared > 575.0) || (dist_squared < 100.0))  seven             discard;  8   9     gl_FragColor = mix(vec4(.xc, .ninety, .90, 1.0), vec4(.20, .20, .40, ane.0), 10                        smoothstep(380.25, 420.25, dist_squared)); xi }              

Effigy�xi.�Output of circle fragment shader that uses discard

Output of circle fragment shader that uses discard


It is tempting the think of discard as analogous to calling exit in a C programme. Consider the code in Figure�12, "Shader with a possible infinite loop". Lines 2 and 3 discard the fragment if the variable x is less than some pocket-sized value. Lines 5 through seven loop using 10 as a loop control. If x is very pocket-sized or zero, the number of loop iterations is very large or infinite.

Figure�12.�Shader with a possible infinite loop

                1     /* If x is less than ane/32nd, get out. */  ii     if (x < 0.03125)  three         discard;  4   5     for (int i = 0; i < int(1.0 / 10); i++) {  6         /* ... do some work ... */  7     }              

Lines 2 and three are designed to terminate the shader to prevent this from occuring. Hardware typically runs fragment shaders on small-scale blocks of fragments, ordinarily 2x2, together. If one fragment in a group does not execute the discard, all of the fragments in the may continue executing. The shader may enter an space loop even though the programmer has attempted to foreclose it. The solution is to surround the remainder of the shader in the else portion of the if-statement.

parksweas1991.blogspot.com

Source: https://people.freedesktop.org/~idr/OpenGL_tutorials/03-fragment-intro.html

0 Response to "Draw a Circle in Opengl Using Shaders"

Postar um comentário

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel