Unity Glsl Link Error: Warning: Output of Vertex Shader 'vs_texcoord0' Not Read by Fragment Shader
Shaders
Getting-started/Shaders
As mentioned in the Hello Triangle chapter, shaders are niggling programs that rest on the GPU. These programs are run for each specific section of the graphics pipeline. In a basic sense, shaders are nil more than programs transforming inputs to outputs. Shaders are also very isolated programs in that they're non immune to communicate with each other; the merely communication they have is via their inputs and outputs.
In the previous chapter we briefly touched the surface of shaders and how to properly utilize them. We volition now explicate shaders, and specifically the OpenGL Shading Language, in a more full general fashion.
GLSL
Shaders are written in the C-like language GLSL. GLSL is tailored for use with graphics and contains useful features specifically targeted at vector and matrix manipulation.
Shaders always brainstorm with a version declaration, followed by a listing of input and output variables, uniforms and its
A shader typically has the post-obit structure:
#version version_number in blazon in_variable_name; in type in_variable_name; out type out_variable_name; compatible blazon uniform_name; void main() { // process input(s) and do some weird graphics stuff ... // output processed stuff to output variable out_variable_name = weird_stuff_we_processed; } When we're talking specifically almost the vertex shader each input variable is also known as a
int nrAttributes; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes); std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl; This oftentimes returns the minimum of sixteen which should be more than plenty for most purposes.
Types
GLSL has, like any other programming language, data types for specifying what kind of variable nosotros want to work with. GLSL has nigh of the default basic types we know from languages like C: int, float, double, uint and bool. GLSL as well features two container types that nosotros'll be using a lot, namely vectors and matrices. Nosotros'll discuss matrices in a later chapter.
Vectors
A vector in GLSL is a 2,3 or 4 component container for any of the basic types simply mentioned. They can accept the following form (north represents the number of components):
-
vecn: the default vector ofnorthwardfloats. -
bvecn: a vector ofnbooleans. -
ivecn: a vector ofnorthintegers. -
uvecn: a vector ofnunsigned integers. -
dvecn: a vector ofnorthwarddouble components.
Most of the fourth dimension we volition be using the basic vecn since floats are sufficient for most of our purposes.
Components of a vector can be accessed via vec.10 where x is the first component of the vector. You tin use .x, .y, .z and .westward to access their showtime, second, 3rd and fourth component respectively. GLSL too allows you to use rgba for colors or stpq for texture coordinates, accessing the aforementioned components.
The vector datatype allows for some interesting and flexible component pick called
vec2 someVec; vec4 differentVec = someVec.xyxx; vec3 anotherVec = differentVec.zyw; vec4 otherVec = someVec.xxxx + anotherVec.yxzy; You can use any combination of upward to 4 letters to create a new vector (of the same type) as long equally the original vector has those components; it is not allowed to access the .z component of a vec2 for example. Nosotros tin also pass vectors every bit arguments to different vector constructor calls, reducing the number of arguments required:
vec2 vect = vec2(0.5, 0.7); vec4 issue = vec4(vect, 0.0, 0.0); vec4 otherResult = vec4(result.xyz, 1.0); Vectors are thus a flexible datatype that nosotros can employ for all kinds of input and output. Throughout the book y'all'll run across plenty of examples of how we can creatively manage vectors.
Ins and outs
Shaders are dainty little programs on their own, only they are part of a whole and for that reason nosotros want to have inputs and outputs on the private shaders so that we can move stuff around. GLSL defined the in and out keywords specifically for that purpose. Each shader can specify inputs and outputs using those keywords and wherever an output variable matches with an input variable of the adjacent shader stage they're passed along. The vertex and fragment shader differ a bit though.
The vertex shader should receive some class of input otherwise it would be pretty ineffective. The vertex shader differs in its input, in that it receives its input direct from the vertex data. To define how the vertex information is organized we specify the input variables with location metadata and then we tin can configure the vertex attributes on the CPU. We've seen this in the previous chapter as layout (location = 0). The vertex shader thus requires an extra layout specification for its inputs and then we tin link it with the vertex data.
layout (location = 0) specifier and query for the attribute locations in your OpenGL code via The other exception is that the fragment shader requires a vec4 color output variable, since the fragment shaders needs to generate a last output color. If yous fail to specify an output color in your fragment shader, the color buffer output for those fragments will be undefined (which usually means OpenGL will render them either blackness or white).
And so if nosotros desire to transport information from one shader to the other we'd accept to declare an output in the sending shader and a similar input in the receiving shader. When the types and the names are equal on both sides OpenGL will link those variables together and so it is possible to transport data between shaders (this is done when linking a program object). To testify you lot how this works in practise we're going to alter the shaders from the previous affiliate to let the vertex shader decide the color for the fragment shader.
Vertex shader
#version 330 core layout (location = 0) in vec3 aPos; // the position variable has attribute position 0 out vec4 vertexColor; // specify a color output to the fragment shader void main() { gl_Position = vec4(aPos, one.0); // see how we directly give a vec3 to vec4's constructor vertexColor = vec4(0.five, 0.0, 0.0, one.0); // set the output variable to a dark-scarlet color } Fragment shader
#version 330 core out vec4 FragColor; in vec4 vertexColor; // the input variable from the vertex shader (same name and aforementioned type) void main() { FragColor = vertexColor; } Yous can run into we declared a vertexColor variable as a vec4 output that nosotros set in the vertex shader and we declare a similar vertexColor input in the fragment shader. Since they both have the aforementioned blazon and name, the vertexColor in the fragment shader is linked to the vertexColor in the vertex shader. Because nosotros set up the color to a dark-red color in the vertex shader, the resulting fragments should be dark-red too. The following epitome shows the output:
There we go! Nosotros just managed to send a value from the vertex shader to the fragment shader. Permit's spice information technology up a bit and see if we can transport a color from our application to the fragment shader!
Uniforms
To declare a compatible in GLSL we only add the uniform keyword to a shader with a blazon and a name. From that betoken on nosotros tin can use the newly declared compatible in the shader. Allow's see if this time nosotros can set the color of the triangle via a uniform:
#version 330 cadre out vec4 FragColor; compatible vec4 ourColor; // we fix this variable in the OpenGL code. void main() { FragColor = ourColor; } Nosotros declared a uniform vec4 ourColor in the fragment shader and fix the fragment'south output colour to the content of this uniform value. Since uniforms are global variables, we can ascertain them in any shader phase we'd like and then no need to go through the vertex shader over again to go something to the fragment shader. Nosotros're not using this compatible in the vertex shader so there's no need to define information technology there.
The uniform is currently empty; we haven't added whatever data to the uniform yet so let'southward try that. We offset need to find the index/location of the compatible attribute in our shader. One time we have the index/location of the uniform, we can update its values. Instead of passing a single color to the fragment shader, let's spice things upwards by gradually changing colour over fourth dimension:
float timeValue = glfwGetTime (); float greenValue = (sin(timeValue) / two.0f) + 0.5f; int vertexColorLocation = glGetUniformLocation (shaderProgram, "ourColor"); glUseProgram (shaderProgram); glUniform 4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); First, we retrieve the running fourth dimension in seconds via 0.0 - 1.0 by using the
So we query for the location of the ourColor uniform using -1, information technology could non find the location. Lastly we can prepare the uniform value using the
Because OpenGL is in its core a C library it does non take native support for part overloading, so wherever a function can exist called with different types OpenGL defines new functions for each type required;
-
f: the office expects afloatas its value. -
i: the function expects anintas its value. -
ui: the function expects anunsigned intequally its value. -
3f: the function expects 3bladdersouthward as its value. -
fv: the function expects afloatvector/array equally its value.
fv version). Now that we know how to fix the values of uniform variables, we can apply them for rendering. If nosotros want the color to gradually alter, nosotros want to update this uniform every frame, otherwise the triangle would maintain a single solid colour if nosotros only set information technology once. And so we summate the greenValue and update the uniform each return iteration:
while(!glfwWindowShouldClose (window)) { // input processInput(window); // return // clear the colorbuffer glClear Color (0.2f, 0.3f, 0.3f, 1.0f); glClear (GL_COLOR_BUFFER_BIT); // be sure to actuate the shader glUseProgram (shaderProgram); // update the compatible color bladder timeValue = glfwGetTime (); bladder greenValue = sin(timeValue) / ii.0f + 0.5f; int vertexColorLocation = glGetUniformLocation (shaderProgram, "ourColor"); glUniform 4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f); // now render the triangle glBindVertexArray (VAO); glDrawArrays (GL_TRIANGLES, 0, 3); // bandy buffers and poll IO events glfwSwapBuffers (window); glfwPollEvents (); } The lawmaking is a relatively straightforward adaptation of the previous lawmaking. This time, we update a uniform value each frame before drawing the triangle. If y'all update the compatible correctly you should see the color of your triangle gradually alter from green to blackness and back to green.
Check out the source code here if you lot're stuck.
As you can see, uniforms are a useful tool for setting attributes that may modify every frame, or for interchanging data betwixt your application and your shaders, but what if we desire to set a colour for each vertex? In that case we'd take to declare as many uniforms as we take vertices. A better solution would be to include more data in the vertex attributes which is what nosotros're going to practise at present.
More attributes!
We saw in the previous chapter how nosotros tin make full a VBO, configure vertex aspect pointers and store it all in a VAO. This time, we also want to add color data to the vertex data. We're going to add color data as 3 floats to the vertices array. Nosotros assign a blood-red, green and blue color to each of the corners of our triangle respectively:
bladder vertices[] = { // positions // colors 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // lesser right -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top }; Since we at present accept more data to send to the vertex shader, information technology is necessary to conform the vertex shader to too receive our color value as a vertex aspect input. Notation that nosotros set the location of the aColor attribute to 1 with the layout specifier:
#version 330 core layout (location = 0) in vec3 aPos; // the position variable has aspect position 0 layout (location = 1) in vec3 aColor; // the color variable has attribute position 1 out vec3 ourColor; // output a color to the fragment shader void principal() { gl_Position = vec4(aPos, 1.0); ourColor = aColor; // set ourColor to the input color nosotros got from the vertex information } Since we no longer use a uniform for the fragment's color, but at present use the ourColor output variable we'll have to change the fragment shader likewise:
#version 330 cadre out vec4 FragColor; in vec3 ourColor; void primary() { FragColor = vec4(ourColor, ane.0); } Because nosotros added another vertex attribute and updated the VBO's retention we have to re-configure the vertex attribute pointers. The updated data in the VBO'due south memory at present looks a bit like this:
Knowing the current layout we can update the vertex format with
// position attribute glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(bladder), (void*)0); glEnable VertexAttribArray (0); // colour attribute glVertexAttribPointer (1, iii, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float))); glEnable VertexAttribArray (1); The first few arguments of 1. The color values accept a size of iii floatdue south and we do non normalize the values.
Since we now have two vertex attributes nosotros accept to re-calculate the stride value. To get the next attribute value (e.g. the side by side 10 component of the position vector) in the information array we take to move 6 floats to the right, three for the position values and iii for the color values. This gives u.s. a stride value of six times the size of a float in bytes (= 24 bytes).
Too, this fourth dimension we have to specify an offset. For each vertex, the position vertex aspect is first and so we declare an offset of 0. The colour attribute starts after the position data and then the starting time is three * sizeof(float) in bytes (= 12 bytes).
Running the application should result in the following prototype:
Check out the source code here if you're stuck.
The image may not exist exactly what you would expect, since we merely supplied iii colors, not the huge color palette nosotros're seeing right now. This is all the result of something called
Based on these positions, it 70% of the line, its resulting color input attribute would and then be a linear combination of green and blue; to be more precise: 30% blue and 70% green.
This is exactly what happened at the triangle. We have 3 vertices and thus 3 colors, and judging from the triangle'south pixels it probably contains effectually 50000 fragments, where the fragment shader interpolated the colors among those pixels. If yous take a practiced look at the colors you'll encounter it all makes sense: carmine to blue offset gets to purple and so to blue. Fragment interpolation is applied to all the fragment shader'due south input attributes.
Our ain shader class
Writing, compiling and managing shaders can exist quite cumbersome. As a final bear upon the shader field of study nosotros're going to make our life a chip easier by building a shader class that reads shaders from disk, compiles and links them, checks for errors and is piece of cake to apply. This also gives y'all a scrap of an idea how we can encapsulate some of the knowledge we learned so far into useful abstract objects.
Nosotros will create the shader form entirely in a header file, mainly for learning purposes and portability. Let'due south showtime by adding the required includes and by defining the class construction:
#ifndef SHADER_H #ascertain SHADER_H #include <glad/glad.h> // include glad to get all the required OpenGL headers #include <string> #include <fstream> #include <sstream> #include <iostream> class Shader { public: // the program ID unsigned int ID; // constructor reads and builds the shader Shader(const char* vertexPath, const char* fragmentPath); // employ/activate the shader void use(); // utility compatible functions void setBool(const std::string &name, bool value) const; void setInt(const std::string &name, int value) const; void setFloat(const std::string &proper noun, float value) const; };
0 Response to "Unity Glsl Link Error: Warning: Output of Vertex Shader 'vs_texcoord0' Not Read by Fragment Shader"
Postar um comentário