Archiwum | OpenGL ES RSS for this section

OpenGL varying variables explained

Couple of months ago I posted a article about circle rendering using OpengES 2.

I have to admit, back then I did not understand varying variables fully.

Now I have much better understanding.

OK, let’s analyze simple vertex shader

uniform mat4 mvp_matrix;
uniform vec4 u_color;
 
attribute vec4 a_position;
attribute vec2 a_texcoord;
 
varying vec2 v_texcoord;
 
void main()
{
gl_Position = mvp_matrix * a_position;
v_texcoord = a_texcoord;
}

First, we have two uniform variables. Uniforms are set during runtime by main application.

Second, two variables marked as attribute.

Values of attribute variables are fetched from buffer. Buffer have to be filled with vertex/texture coordinates, plus OpenGL have to be informed about buffer data format.

Finally a single variable marked varying.

Couple of lines later varying variable have assigned value – it’s a copy of value stored inside a_texcoords attribute.

Now, lets look at fragment shader.

uniform sampler2D texture;

varying vec2 v_texcoord;

void main()
{
  gl_FragColor = texture2D(texture, v_texcoord);
}

gl_FragColor is a build-in OpenGL variable. Fragment color is determinated by value assigned to that variable.

texture2s(texture, v_textcoords) function calculates color value using current texture and texture coordinates.

But how texture coordinates are calculated? Only data we have, are UV-s stored inside buffer with vertex coordinates.

First, remember how shaders work. To render a triangle:

  • Vertex shader is executed for each vertex
  • Fragment shader is executed for each pixel

So, varying variable have value assigned three times (one time for each vertex shader)

Now, OpenGL calculates varying variable value for each fragment shader. Obviously varying variable value have to be different for each fragment shader call.

Calculation takes values of varying variable generated by vertex shader, and relative position of fragment.

Exact formula is not important. Can by googled. The point is – value of fragment shader varying variable is calculated – calculation formula is using fragment (relative) position, and varying values calculated by vertex shader.

Reklamy

How to draw point/circle/ellipse using OpenGL ES 2.0 GLSL

I have spend a quite some time experimenting with different solutions. Tried GL_POINT thing – didn’t work as i expected.

First, setup your render process to draw a quad. I do not want to go into details. Maybe I’ll cover 2d OpenGL ES rendering another time.

After setup, call glDrawElements.
As you see, I’m using GL_TRIANGLE_STRIP to draw quad.

glDrawElements(GL_TRIANGLE_STRIP, 4,
GL_UNSIGNED_SHORT, (void *)0);

My vertex shader:

#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

uniform mat4 mvp_matrix;
uniform vec4 u_color;

attribute vec4 a_position;
attribute vec2 a_texcoord;

varying vec4 v_color;
varying vec2 v_texcoord;

void main()
{
gl_Position = mvp_matrix * a_position;
v_color = u_color;
v_texcoord = a_texcoord;
}

u_color – I’m using this uniform to define point color.
v_color – varying shared between vertex and fragment shader. Used to transport color value to fragment shader.
a_texcoord – an attribute. Its value is determined on the basis of VBO contents.
v_textcoord – a variable used to transport texture coordinates to fragment shader.

Texture should be disabled before glDrawElements call;
Use glBindTexture(GL_TEXTURE_2D, 0);

Despite no active texture, shader will receive valid texture coordinates;

Fragment shader:


#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif

varying vec4 v_color;
varying vec2 v_texcoord;

void main()
{
float l = length(v_texcoord - vec2(0.5, 0.5));

if (l > 0.5)
discard;

gl_FragColor = v_color;
}

Here is the magic.

v_texcoord isn’t just copied from VBO. Value is interpolated for each fragment shader call.

float l = length(v_texcoord - vec2(0.5, 0.5));

variable l contains distance of current rendered quad pixel from center of quad.
Because texture coordinates are normalized ( values are in the range 0.0 and 1.0) 0.5,0.5 represents center of quad.

The function /length/ is OpenGL ES2 buildin. Calculates distance between two vectors.

If distance between currently rendered pixel and center of quad is more then 0.5 pixel is discarded. When distance is less or equal 0.5, fragment is rendered using color stored in v_Color;

point_rendering

I hope this picture help to understand how it works.

Blue are texture coordinates.
Pink area is rendered using u_color/v_color.
White space where fragment shader was discarded.
Green lines – distance between fragment coordinates and quad center. Calculated by length function.

Pros and cons of this solution:

Pros:

  • Looks same regardless of size.
  • Shader can be easily modified to produce blured „nova” effect.
  • Works both on mobile and desktop

Cons:

  • No antialiasing – sharp edges.