Modern OpenGL Tutorial 02--map

Source: Internet
Author: User

Guidance: Modern OpenGL Tutorial 01--Getting Started Guide
In this article, we'll add a map to the triangle, which involves adding some new variables to the vertex and fragment shader, creating and using the mapped object, and learning a bit about the mapping unit and mapping coordinates.

This article uses two new classes into the Tdogl namespace: Tdogl:bitmap and Tdogl:texture. These classes allow us to upload jpg,png or BMP images to video memory and use them for shaders. The Tdogl:program class also adds some related interfaces.

Get code

The ZIP package for all the example codes can be obtained from here: Https://github.com/tomdalling/opengl-series/archive/master.zip.

The code used in this series of articles is stored in: https://github.com/tomdalling/opengl-series. You can download the zip from the page, add it to git, or copy the repository.

This article code you can find in the Source/02_textures directory. With OS X system, you can open the opengl-series.xcodeproj in the root directory and select this project. With Windows systems, you can open Opengl-series.sln in Visual Studio 2013 and select the appropriate project.

All dependencies are included in the project, so you don't need to install or configure anything extra. If you have any problems compiling or running, please contact me.

Shader variables uniform and attribute

The shader variables in tutorial (i) are attribute, this article describes another type of variable: uniform variable.

There are two types of shader variables: uniform and attribute. The attribute variable can have different values on each vertex. The uniform variable maintains the same value on multiple vertices. For example, if you want to set a color for a triangle, you should use the uniform variable, and if you want each triangle vertex to have a different color, you should use the attribute variable. From here, I call them "uniforms" and "attributes".

Uniforms can be accessed by any shader, but attributes must first enter the vertex shader, not the fragment shader. The vertex shader passes the value to the fragment shader when it is needed. This is because uniforms are like constants-they are not changed by any shaders. However, attributes is not a constant. The vertex shader changes the value of the attribute variable before the fragment shader gets it. That is, the output of the vertex shader is the input to the fragment shader.

In order to set the value of uniform, we can call the gluniform* series function. Instead of setting the value of attribute, we need to save it in VBO and send it to the shader with Vao, just like the glvertexattribpointer in the previous tutorial. You can also use the Glvertexattrib* series function to set the attribute value if you don't want the value to exist in Vbo.

Map

The map, in general, is the 2D image you apply to a 3D object. It has other uses, but displaying 2D images is the most common in 3D geometry. There are 1d,2d,3d stickers, but this article only speaks 2D maps. For more in-depth reading, see the textures is not pictures section of the Learning Modern 3D Graphics programming book.

The stickers are stored in the video memory. That means you need to upload your decal data to the graphics card before you use it. This is similar to VBO in the previous role-vbo also need to be stored in memory before use.

the height and width of the map need to be a power of 2 . Like 16,32,64,128,256,512. This article uses an image of 256*256 as a map, as shown in.

We use TDOGL:BITMAP to load the raw pixel data of "hazard.png" into memory, see the Stb_image help documentation. We then use Tdogl:texture to upload the raw pixel data to the OpenGL map object. Fortunately, there is no real change in the way the map is created in OpenGL, so there are a lot of good articles on the web that create stickers. Although the mapping coordinates are transferred in a different way, creating the map is the same as before.

The following is a tdogl:texture constructor for OpenGL map creation.

123456789101112131415161718192021 Texture::Texture(const Bitmap& bitmap, GLint minMagFiler, GLint wrapMode) :    _originalWidth((GLfloat)bitmap.width()),    _originalHeight((GLfloat)bitmap.height()){    glGenTextures(1, &_object);    glBindTexture(GL_TEXTURE_2D, _object);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minMagFiler);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, minMagFiler);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);    glTexImage2D(GL_TEXTURE_2D,                 0,                  TextureFormatForBitmapFormat(bitmap.format()),                 (GLsizei)bitmap.width(),                  (GLsizei)bitmap.height(),                 0,                  TextureFormatForBitmapFormat(bitmap.format()),                  GL_UNSIGNED_BYTE,                  bitmap.pixelBuffer());    glBindTexture(GL_TEXTURE_2D, 0);}

Mapping coordinates

There is no doubt that the mapping coordinates are the coordinates on the map. What's strange about mapping coordinates is that they're not in pixels. They range from 0 to 1, (0, 0) to the lower left, and (1, 1) to the upper right corner. If the image you uploaded to OpenGL is reversed, then (0, 0) is the upper-left corner, not the lower-left corner. To convert pixel coordinates to mapping coordinates, you must divide the width and height of the map. For example, in a 256*256 image, the mapping coordinates of pixel coordinates (128, 256) are (0.5, 1).

Map coordinates are often referred to as UV coordinates. You can also call them XY coordinates, but XYZ is often used to represent vertices, and we don't want to confuse the two.

Map Image Unit

The map image unit, or "decal unit", is a slightly bizarre part of OpenGL. You cannot send stickers directly to shaders. First, you want to bind the map to the mapping unit, and then send the Map Unit's index to the shader

There is a limit to the number of mapping units. On low-end hardware, such as mobile phones, they have only two mapping units. That being the case, even if we have a lot of stickers, we can only use two map units in the shader at the same time. We only use one map in this article, so we only need one mapping unit, but it can be mixed in several different shaders.

Implement stickers

First, let's create a new global map.

1 tdogl::Texture* gTexture = NULL;

We have added a new function for loading the "hazard.png" image. This function can be called by Appmain.

12345 static void LoadTexture() {    tdogl::Bitmap bmp = tdogl::Bitmap::bitmapFromFile(ResourcePath("hazard.png"));    bmp.flipVertically();    gTexture = newtdogl::Texture(bmp);}

Next, we give the vertex of each triangle a mapping coordinate. If you compare UV coordinates, you can see that in order this coordinates (middle, upper), (left, bottom) and (right, bottom).

123456 GLfloat vertexData[] = {    // X,Y,Z,U,V    0.0f, 0.8f, 0.0f,0.5f,1.0f,    -0.8f,-0.8f,0.0f,0.0f,0.0f,    0.8f,-0.8f, 0.0f,1.0f,0.0f,};

Now we need to modify the fragment shader so that it can use map and map coordinates as input. Here is the new fragment shader code:

1234567 #version  150 UNIFORM SAMPLER2D TEX;  //this is the texture in  VEC2 FRAGTEXCOORD;  //this is the texture coord out vec4  finalcolor;  //this is the output color of  The pixel void main ()  {       finalcolor = texture (Tex, fragtexcoord);

The Uniform keyword indicates that tex is a uniform variable. The map is consistent because all the triangle vertices have the same map. SAMPLER2D is a variable type, which means it contains a 2D map.

Fragtexcoord is a attribute variable, because each triangle vertex is a different mapping coordinate.

The texture function is the pixel color used to find the coordinates of a given map. In older versions of GLSL, you should use the TEXTURE2D function to implement this functionality.

We cannot transmit attribute directly to the judging shader because the attribute must first pass through the vertex shader. Here is the modified vertex shader:

123456789 #version  150 in   vec3 vert; in  vec2 verttexcoord; out vec2 fragtexcoord; void main ()  {      Code class= "JS Comments" >// pass the tex coord straight through to the  fragment shader      fragtexcoord = verttexcoord;      gl_position = vec4 (vert, 1);

The vertex shader uses Verttexcoord as input and passes it without modification to the attribute fragment shader variable named Fragtexcoord.

The shader has two variables that we need to set: Verttexcoordattribute variables and texuniform variables. Let's start by setting the Tex variable. Open Main.cpp and locate the render () function. We set the Texuniform variable before we draw the triangle:

123 glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, gTexture->object());gProgram->setUniform("tex", 0); //set to 0 because the texture is bound to GL_TEXTURE0

A map is not available when it is not bound to a map cell. Glactivetexture tells OpenGL which mapping unit we want to use. GL_TEXTURE0 is the first mapping unit and we use it.

Next, we use Glbindtexture to bind our stickers to the active mapping unit.

We then set the Map Unit index to the texuniform shader variable. We use the number No. 0 mapping unit, so we set the Tex variable to an integer of 0. The Setuniform method simply calls the Glunifrom1i function.

The final step is to get the mapping coordinates to the Verttexcoordattribute variable. To implement it, we need to modify the Vao in the Loadtriangle () function. The previous code is this:

12345678910 // Put the three triangle vertices into the VBOGLfloat vertexData[] = {    //  X     Y     Z     0.0f, 0.8f, 0.0f,    -0.8f,-0.8f, 0.0f,     0.8f,-0.8f, 0.0f};// connect the xyz to the "vert" attribute of the vertex shaderglEnableVertexAttribArray(gProgram->attrib("vert"));glVertexAttribPointer(gProgram->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 0, NULL);

Now we need to change to this:

12345678910111213 // Put the three triangle vertices (XYZ) and texture coordinates (UV) into the VBOGLfloat vertexData[] = {    //  X     Y     Z       U     V     0.0f, 0.8f, 0.0f,   0.5f, 1.0f,    -0.8f,-0.8f, 0.0f,   0.0f, 0.0f,     0.8f,-0.8f, 0.0f,   1.0f, 0.0f,};// connect the xyz to the "vert" attribute of the vertex shaderglEnableVertexAttribArray(gProgram->attrib("vert"));glVertexAttribPointer(gProgram->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), NULL);// connect the uv coords to the "vertTexCoord" attribute of the vertex shaderglEnableVertexAttribArray(gProgram->attrib("vertTexCoord"));glVertexAttribPointer(gProgram->attrib("vertTexCoord"), 2, GL_FLOAT, GL_TRUE,  5*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));

We called Glvertexattribpointer the second time, but we also modified the first call. The most important is the last two parameters.

The second-to-last parameter of the two Glvertexattribpointer calls is 5*sizeof (glfloat). This is the "step" parameter. This parameter is the number of bytes that indicate the interval at which each value starts, or the amount of bytes to start at the next value. In two calls, each value is 5 glfloat length. For example, join us starting with "X", 5 values ahead, we will fall on the next "X" value. Starting from "U" is also the same, but also the number of 5 forward. This parameter is a byte unit, not a floating point unit, so we must multiply the number of bytes by the float type.

The last parameter, Glvertexattribpointer, is an "offset" parameter. This parameter needs to know how many bytes from the beginning to the first value. The start is XYZ, so the offset is set to NULL to indicate "the distance to start is 0 bytes". The first UV is not in front-there are 3 floating-point distances in the middle. Again, the parameter is in bytes, not floating point, so we have to multiply the number of bytes by the float type. And we have to convert the value to the const glvoid* type, because the parameter differs from the current "offset" in the old version of OpenGL.

Now, when you run the program, you can see the triangle at the top of the article.

Next trailer

In the next tutorial we'll learn some matrix-related things, use matrices to rotate cubes, move cameras, and add perspective projections. We'll also learn about depth buffering and time-based logic, such as animations.

More OpenGL Map Related resources

The texture page on the OpenGL wiki

The texturing chapters of the Learning Modern 3D Graphics programming book

Tutorial 16-basic Texture Mapping by Etay Meiri

The texturing example code by Jakob Progsch

Modern OpenGL Tutorial 02--map

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.