Jump to content
  • Advertisement
calioranged

OpenGL Shader Queries:

Recommended Posts

Posted (edited)

*** Beginner question - some terminology may not be correct ***

I will relay my understanding of OpenGL shaders in this post in the hope that members can confirm the areas where I am correct and redress the areas where my understanding falls short.

Firstly, here is my shader:

#shader vertex
#version 330 core

layout(location = 0) in vec4 position;  
layout(location = 1) in vec2 tex_coord; 

out vec2 v_tex_coord;

void main()
{
	gl_Position = position;  
	v_tex_coord = tex_coord; 
};

#shader fragment
#version 330 core

layout(location = 0) out vec4 colour;

in vec2 v_tex_coord;

uniform sampler2D u_Texture;

void main()
{
	vec4 tex_colour = texture(u_Texture,v_tex_coord);
	colour = tex_colour;
};

First Query:

I have been following a tutorial on shaders and have replicated the code used in the tutorial. My program renders a square, onto which a texture (image) is placed. I have bound the vertex position coordinates to the first attribute index of the vertex array, and the texture coordinates to the second attribute index of the vertex array *1*.  The program works without any issues, but there are some aspects which have me confused and I therefore seek clarification from forum members.

The vertex shader features the below lines:

layout(location = 0) in vec4 position;  
layout(location = 1) in vec2 tex_coord;

 From my understanding, these lines are essentially saying: "take the layout of attribute 0 and place it in the 'position' variable" and "take the layout of attribute 1 and place in the 'tex_coord' variable". This makes sense to me since the vertex shader determines the position of each vertex on the screen. However, in the fragment shader, I am more dubious:

layout(location = 0) out vec4 colour;

If the lines in the previous snippet are saying "take the layout of attribute x and place it in the 'y' variable", then what exactly is the above line saying? Specifically, why is the layout from the position attribute (attribute 0) being used and not the texture attribute (attribute 1)? 

Second Query:

I understand that the input variable in the fragment shader (v_tex_coord) is supplied by the output variable from the vertex shader (which originally gathered its data from the layout of attribute 1). But how is the final colour for each pixel here actually set? In the main() function of the fragment shader, the texture() function is used. From what I have gathered this function samples the colour of each pixel in the texture.

Once a texture has been bound to a specific slot, we can set the uniform outside of the shader with glUniform() by returning the location of the uniform variable (location of "u_Texture" in this case) and then linking it to the previously bound slot. Presumably this is the step which links together the texture image and the uniform - meaning that 'u_Texture' now has access to the texture image via the slot to which it was bound (please correct me if I am wrong here).  The next assumption is that the texture() function will sample the corresponding colour value through its parameters ('u_Texture' - which now contains the texture image (or at least has access to the slot to which the texture image is bound) and 'v_tex_coord' which contains the coordinates to which the texture should be rendered). 

Here is the part that confuses me most:

The outcome of the texture() function is returned to the vec4 variable 'tex_colour' which then reassigns its value to the output vec4 variable 'colour'. What was the point in this last step? 'tex_colour' already contained the result of the texture() function so why does it then need to be reassigned to 'colour'? 'colour' is not predefined by OpenGL, I can change the name to 'the_colour', 'a_colour' or 'the_ice_cream_man' and the texture image is still rendered perfectly fine. Is it the case that the variable defined as the output in the fragment shader will be used to render the colour of each pixel regardless of its name? I suppose that the reason I ask this is because the 'gl_Position' variable in the vertex shader which sets the position appears to be a variable predefined by OpenGL whereas in the fragment shader this doesn't appear to be the case with the variable which sets the colour... some clarification of this would be greatly appreciated. 

 

*1* - terminology may be wrong here but essentially I have used glVertexAttribPointer() to set the below vertices position coordinates to attribute 0 and the below texture position coordinates to attribute 1. The full program consists of 16 files and it didn't want to include source code for each file because most of it is irrelevant to the questions I am asking.

float positions[] 
  =	{	 
  // vertices	// texture
  -0.5F,-0.5F,	0.0F,0.0F, // x and y coordinates
   0.5F,-0.5F,	1.0F,0.0F,
   0.5F, 0.5F,	1.0F,1.0F,
  -0.5F, 0.5F,	0.0F,1.0F
};

 

Edited by calioranged

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)
3 minutes ago, 1024 said:

For your second question: if you have only one out variable in the fragment shader, that out will be used as the color.

Here's a discussion about that on StackOverflow: How does the fragment shader know what variable to use for the color of a pixel?

And if there is more than one out variable in the fragment shader?

EDIT: Actually I think the page you have linked addresses that follow up question. Thanks.

Edited by calioranged

Share this post


Link to post
Share on other sites
15 hours ago, calioranged said:

From my understanding, these lines are essentially saying: "take the layout of attribute 0 and place it in the 'position' variable" and "take the layout of attribute 1 and place in the 'tex_coord' variable"

— "At the first there was a chunk of memory on the Graphics Card, then the programer bound attributes and the Shader will be light" :D

And this is where your input and output variables live. The GPU dosen't know anything about data structures and how you arange them in your input buffer when you call the attributes binding. You can pass a vec4 into it and a single float and will still end up with the locations vec3 and vec2 to point to the correct data because you just tell the Shader Compiler to handle the input buffer as that. Think of it as your program stack except that you have to define the order of input you want to read from it.

Output variables are placed onto another of those stacks that is before the render function is computed after any part of your shader has been processed. The render function expects just a 4 component color value to place as pixel into the backbuffer.

You could imagine the processing of your shader as the following program

unsigned char AttributesBuffer[6 * sizeof(float)] = { 0 };
unsigned char RenderBuffer[4 * sizeof(float)] = { 0 };

void ExecuteUserCode()
{
    //bind attributes here
  	int someHiddenPointer = 0;
  
    //vec4
    *((float*)AttributesBuffer + someHiddenPointer) = 1; //X
    someHiddenPointer++;
    *((float*)AttributesBuffer + someHiddenPointer) = 0; //Y
    someHiddenPointer++;
    *((float*)AttributesBuffer + someHiddenPointer) = 1; //Z
    someHiddenPointer++;
    *((float*)AttributesBuffer + someHiddenPointer) = 0; //W
    someHiddenPointer++;
  
    //vec2
    *((float*)AttributesBuffer + someHiddenPointer) = 0; //U
    someHiddenPointer++;
    *((float*)AttributesBuffer + someHiddenPointer) = 0; //V
    someHiddenPointer++;
}

void ExecuteShaderCode()
{
    //bind attributes to locations defined in shader
  	int someHiddenPointer = 0;
  
    //vec4 (location 0)
    float position_x = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float position_y = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float position_z = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float position_w = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
  	//someHiddenPointer now has sizeof vec4
  
    //vec2 (location 1)
    float tex_coord_u = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float tex_coord_v = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    //someHiddenPointer now has sizeof vec4 + vec2
  
  	float v_tex_coord_u;
    float v_tex_coord_v;
    void VertexShadeCode
    (
       //in position
       position_x,
       position_y,
       position_z,
       position_w,
      
       //in tex_coord
       tex_coord_u,
       tex_coord_v,
      
       //out v_tex_coord
       &v_tex_coord_u,
       &v_tex_coord_v
    );
  
    float colour_x;
    float colour_y;
    float colour_z;
    float colour_w;
    void FragmentShadeCode
    (
       //in v_tex_coord
       v_tex_coord_u,
       v_tex_coord_v,
      
       //out colour
       &colour_x,
       &colour_y,
       &colour_z,
       &colour_w,
    );
  
    //bind output to RenderBuffer
  	int someHiddenPointer = 0;
  
    //vec4 (location 0)
    *((float*)RenderBuffer + someHiddenPointer) = colour_x;
    someHiddenPointer++;
    *((float*)RenderBuffer + someHiddenPointer) = colour_y;
    someHiddenPointer++;
    *((float*)RenderBuffer + someHiddenPointer) = colour_z;
    someHiddenPointer++;
    *((float*)RenderBuffer + someHiddenPointer) = colour_w;
    someHiddenPointer++;
}

void ExecuteRendererCode()
{
    //bind attributes to locations defined in shader
  	int someHiddenPointer = 0;
  
    //vec4 (location 0)
    float a = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float r = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float g = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
    float b = *((float*)AttributesBuffer + someHiddenPointer);
    someHiddenPointer++;
  	//someHiddenPointer now has sizeof vec4
  
    /*
     Place pixel into output buffer
    */
}

int main()
{
    ExecuteUserCode();
    ExecuteShaderCode();
    ExecuteRendererCode();
    return 0; 
}

(I do not guaranty for any errors)

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!