OpenGL Learning Footprints: cube texture and sky bounding box (Cubemaps and Skybox)

Source: Internet
Author: User

Write in front
Prior to learning 2D texture mapping, there are actually other types of textures that we need to learn further, the cube texture (cubemaps) to be learned in this section is a technique for compounding multiple texture images onto a cube surface. In the game the use of more sky bounding box can be implemented using CUBEMAP. The sample programs in this section are available for download on my github.

This section is organized from:
1.Tutorial 25:skybox
2.www.learnopengl.com Cubemaps

Create CubeMap

CubeMap is a texture that is created using 6 2D textures bound to the Gl_texture_cube_map target. The GL_TEXTURE_CUBE_MAP consists of 6 faces, respectively:

binding target Texture Direction
Gl_texture_cube_map_positive_x Right
Gl_texture_cube_map_negative_x Left
Gl_texture_cube_map_positive_y Top of
Gl_texture_cube_map_negative_y Bottom
Gl_texture_cube_map_positive_z Back
Gl_texture_cube_map_negative_z Front

As shown, form a cubic texture (from [cubemaps]
(https://scalibq.wordpress.com/2013/06/23/cubemaps/)) :

It is important to note that in OpenGL the camera defaults to the-Z direction, so gl_texture_cube_map_negative_z represents the front, and Gl_texture_cube_map_positive_z represents the back. In the construction of the cubemaps, it is common to use the enumeration constant increment feature, once bound to the above 6 targets. For example, in OpenGL, the enumeration constants are defined as:

#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A

You can see that the above 6 enumerated constants are incremented once, and we can use loops to create this cube texture and encapsulate the function in Texture.h as follows:

   / * * Load a cubemap * /StaticGluint Loadcubemaptexture (STD:: Vector<const char*>Picfilepathvec, Glint Internalformat = Gl_rgb, glenum picformat = gl_rgb,glenum Picdatatype = GL_UNSIGNED_BYTE,intLoadchannels = Soil_load_rgb) {Gluint textid; Glgentextures (1, &textid);    Glbindtexture (Gl_texture_cube_map, Textid); Glubyte *imagedata = NULL;intPicwidth, Picheight; for(STD:: Vector<const char*>:: Size_type i =0; I < picfilepathvec.size (); ++i) {intChannels =0; ImageData = Soil_load_image (Picfilepathvec[i], &picwidth, &picheight, &channels, loadchannels);if(ImageData = = NULL) {STD::Cerr<<"error::loadcubemaptexture could not load texture file:"<< Picfilepathvec[i] <<STD:: Endl;return 0; } glteximage2d (gl_texture_cube_map_positive_x + i,0, Internalformat, Picwidth, Picheight,0, Picformat, Picdatatype, ImageData);    Soil_free_image_data (ImageData);    } gltexparameteri (Gl_texture_cube_map, Gl_texture_mag_filter, gl_linear);    Gltexparameteri (Gl_texture_cube_map, Gl_texture_min_filter, gl_linear);    Gltexparameteri (Gl_texture_cube_map, gl_texture_wrap_s, Gl_clamp_to_edge);    Gltexparameteri (Gl_texture_cube_map, gl_texture_wrap_t, Gl_clamp_to_edge);    Gltexparameteri (Gl_texture_cube_map, Gl_texture_wrap_r, Gl_clamp_to_edge); Glbindtexture (Gl_texture_cube_map,0);returnTextid;}

The Gl_texture_wrap_r parameter in the code is explained later.

Load 6 2D texture images as they are actually used, as shown below:

    faces.push_back("sky_rt.jpg");    faces.push_back("sky_lf.jpg");    faces.push_back("sky_up.jpg");    faces.push_back("sky_dn.jpg");    faces.push_back("sky_bk.jpg");    faces.push_back("sky_ft.jpg");    GLuint skyBoxTextId = TextureHelper::loadCubeMapTexture(faces);

Note the order in which the pictures are loaded we use gl_texture_cube_map_positive_x + I to create 6 2D textures at a time, and the order in which the images are loaded needs to correspond to the order in which the enumeration variables are defined.

Using Cubemaps

Cubemaps Create a cube texture, how do you sample the texture?
Unlike texture coordinates (S,T) used with 2D textures, we need to use three-dimensional texture coordinates (S,T,R), as shown (from Www.learnopengl.com cubemaps):

The orange direction vector in the graph, when the center of the cube is at the origin, represents the position of the vertex of the cube surface, which is the three-dimensional texture coordinate. When using (s,t,r) to determine texture sampling, first determine which polygon to sample based on the maximum component (S,T,R), and then use the remaining 2 coordinates to do 2D texture sampling on the corresponding polygon. For example, according to the largest S component of the (S,T,R) medium, and the symbol is positive, the +x polygon is selected as the sampled 2D texture, and then the 2D texture is sampled on the +x polygon using (t,r) coordinates. The explanation of this computational process can be referred to cubemaps.

In the 2D texture mapping section We mention that the Wrap parameter determines how the texture is sampled when the texture coordinates are outside the [0,1] range. In the above code, we use:

glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

The parameter Gl_clamp_to_edge is mainly used to specify that when the (s,t,r) coordinates do not fall on which side, but rather the texture samples falling between two polygons, using the Gl_clamp_to_edge parameter indicates that the edge texture value is used when sampling between two faces.

Create a Sky bounding box

The above describes the way to create and use CubeMap, the actual game is used more is to use the cubemap to achieve the sky bounding box. The main realization of the sky bounding box is:
Drawing a cube of cubemap texture samples in the scene, the cube is always placed at the outermost of the scene, allowing the player to feel as if the scene is very large, touching it like the sky, that is, the player is close to some, the sky is still very far away from the feeling.
For example, we have drawn a bounding box:

The bounding box is drawn with the 1x1x1 cube as the bounding box, and the cubemap created above is mapped to the bounding box. The center of the cube is at the origin, so the vertex position on the cube is used as the previously mentioned vector for texture sampling.
Implemented in the vertex shader as:

#version 330 core0) in vec3 position;uniform mat4 projection;uniform mat4 view;out vec3 TextCoord;void main(){    1.0);     TextCoord = position;  // 当立方体中央处于原点时 立方体上位置即等价于向量}

You only need to sample the texture in the slice shader:

   #version 330 corein vec3 TextCoord;uniform samplerCube  skybox;  // 从sampler2D改为samplerCubeout vec4 color;void main(){    color = texture(skybox, TextCoord);}

To place the bounding box in the scene, outermost, the basic way is to temporarily turn off the deep cache write, first draw the bounding box, so that the bounding box is always at the outermost edge of the scene. At the same time the implementation of the need to pay attention to how to keep the player moving, the bounding box looks very large feeling, there are two ways to achieve.

The first way is to remove the part (translate part) that is moved by the view transform, but to preserve other components such as rotation, so that when you move around in the scene, when you turn the camera, the bounding box is still displayed at a normal angle, but the bounding box does not move because the player's forward and backward, This looks more normal. This approach is implemented as:

 //first draw Skybox  Gldepthmask (Gl_false); //prohibit write depth buffer  skyboxshader.use (); Glm::mat4 projection = GLM::p erspective ( Camera.mouse_zoom, (glfloat) (window_width)/window_height, 0.1f , 100.0f ); //projection matrix  glm::mat4 view = GLM::MAT4 (GLM::MAT3 (Camera.getviewmatrix ())); //view transformation matrix Remove translate section  GLUNIFORMMATRIX4FV (Glgetuniformlocation ( Skyboxshader.programid,  "projection" ), 1 , Gl_        FALSE, glm::value_ptr (projection)); GLUNIFORMMATRIX4FV (Glgetuniformlocation (Skyboxshader.programid,  "view" ), 1 , Gl_false, glm::value_ptr (view));  

The second way , each time the center of the bounding box is set in the player's position, at the same time to a certain proportion of the bounding box, so that the effect is basically the same, but the disadvantage is that if the scale is inappropriate, the scene of the object may move beyond the bounding box, and cause visual bugs. This approach is implemented as:

"projection"),1"view"),1, GL_FALSE, glm::value_ptr(view));model = glm::translate(glm::mat4(), camera.position);model = glm::scale(model, glm::vec3(20.0f20.0f20.0f"model"),1, GL_FALSE, glm::value_ptr(model));
The improvement of the sky bounding box

Above in the sky bounding box, we first close the depth cache write, draw the bounding box, so that it is at the outermost part of the scene, this will certainly work, the disadvantage is that if the scene object needs to be displayed in front of the bounding box, the final bounding box of some parts will be obscured, according to the above-mentioned drawing method we still draw this part Causes unnecessary shader calls, which is a performance loss.

An improved strategy is to draw the object in the scene first, then compare it with the depth value of the bounding box and the current depth value, and draw the bounding box if the depth test is used. We know that by default, a value of 1.0 is used to clear the depth cache, so we also want to use 1.0来 to represent the depth value of the bounding box so that it is always at the outermost edge of the scene, and when we do deep testing, we change the default test function, which changes from gl_less to Gl_lequal, As follows:

   // 深度测试条件 小于等于

So how do you get the depth value of the bounding box to always be 1.0? We know that in the vertex shader, gl_position represents the coordinates of the clipping coordinate system for the current vertex (the corresponding z-component is z clip ), and the final depth value of a vertex is the NDC coordinates obtained by perspective division (the corresponding z-component is Z ndc ), and the last viewport transform to get the window coordinates Z win Value is determined. For the calculation of this depth value, if you feel unfamiliar, you can go back and look at the depth test section. The technique used here is to manually set the Z-value of the gl_position to W, which is output in the vertex main color:

   void main(){    1.0);     gl_Position = pos.xyww;  // 此处让z=w 则对应的深度值变为depth = w / w = 1.0    TextCoord = position;  // 当立方体中央处于原点时 立方体上位置即等价于向量}

This gives the depth value of the perspective Division and viewport transformations that are performed by OpenGL by default Z win =1.0 , to achieve our purpose. This method first draws the object in the scene and finally renders the bounding box. It is important to note that when you draw the bounding box, the depth test function becomes:

   glDepthFunc(GL_LEQUAL);

Once the drawing is complete, the default gl_less is restored. Using a different bounding box material, we get another bounding box effect as shown:

The final note

When implementing the bounding box, you need to make the bounding box look far and wide by removing the translate section (the first method above) or by setting the bounding box as the observer origin and enlarging the bounding box (the second way above). If the error is incorrectly set, the effect might be as follows:

In the implementation of the bounding box, pay attention to adjust the appropriate projection transformation parameters, here we set the parameters are:

   glm::mat4 projection = glm::perspective(camera.mouse_zoom,            0.1f100.0f// 投影矩阵

If the projection parameter is not set properly, the result of the error may be as follows:

To get more bounding boxes, you can access online resources.

CubeMap can also be used to implement techniques such as environment mapping, which will be learned in the next section.

Resources

1.https://scalibq.wordpress.com/2013/06/23/cubemaps/
2.https://www.opengl.org/wiki/skybox
3.http://learnopengl.com/#!advanced-opengl/cubemaps
4.http://www.c-jump.com/bcc/common/talk3/opengl/wk13_skybox/wk13_skybox.html

OpenGL Learning Footprints: cube texture and sky bounding box (Cubemaps and Skybox)

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.