Home PC Games Linux Windows Database Network Programming Server Mobile  
           
  Home \ Programming \ OpenGL Superb Learning Notes - Depth Texture and Shadows     - Use libcurl library download url image (Programming)

- Linux see whether there is a hacker program (Linux)

- Java NIO The Glob mode Detailed (Programming)

- Service Discovery: Zookeeper vs etcd vs Consul (Server)

- Linux hard drive failure Case Studies (Linux)

- grep command Series: grep command to search for multiple words (Linux)

- Oracle archive log summary (Database)

- Variables Python variables (Programming)

- ORA-00824: can not set sga_target due to existing problem-solving (Database)

- Linux shared libraries .so file name and Dynamic Link (Linux)

- Linux Log Clear (Linux)

- C # using the HttpClient Note: Preheat the long connection (Programming)

- Experience CoreCLR stack unwinding characteristics of initial implementation on Linux / Mac (Linux)

- OpenGL Superb Learning Notes - New Patterns (Programming)

- Using Python to find a particular file extension directory (Programming)

- Computer security perimeter recommendations (Linux)

- Vim useful plugin: YouCompleteMe (Linux)

- Two kinds of agents of Spring AOP (Programming)

- MySQL display operation control tips (Database)

- Oracle SDE and maintain common commands - Display space (Database)

 
         
  OpenGL Superb Learning Notes - Depth Texture and Shadows
     
  Add Date : 2017-08-31      
         
         
         
  Before we introduced a simple flatten the object to the projection plane to create shadows. However, this shadow has its limitations (such as the projection plane must be flat). In OpenGL 1.4 introduced a new method of shadow mapping to generate shadows.

The principle behind shadow maps is simple. When we look at the object from this position, we know which surfaces are illuminated (seen by the light source) and which are not (shaded) by the light source's position as the camera's position (The surface closest to the light source in one direction is illuminated and the latter surface is not illuminated). We turn on the depth test so that we can get a useful depth buffer data (the result of each pixel in the depth buffer), then we read the data from the depth buffer as a shadow texture, project back into the scene, Then we use the camera's perspective to render the object.

Light source perspective

First, we move the viewing angle to the position of the light source. We can use the glu library helper functions:

0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f) in the light-emitting region of the light-emitting region, respectively; gluLookAt (lightPos [0], lightPos [1], lightPos [

Set the position of the light source to the position to be observed.

In order to use space in an optimal way to generate shadow maps. From the perspective of the light source to see the perspective of the past to adapt to the perspective of the window area ratio, and perspective of the nearest plane position is the nearest plane in the light source, the farthest plane is the farthest object from the light plane plane. So that we can make full use of the scene information to fill the depth of the buffer zone to create a shadow map. We estimate that just wrap the whole scene of vision.

// The radius of the scene
GLfloat sceneBoundingRadius = 95.0f;

// The distance of the light
LightToSceneDistance = sqrt (lightPos [0] * lightPos [0] +
LightPos [1] * lightPos [1] +
LightPos [2] * lightPos [2]);

// near the clipping plane
NearPlane = lightToSceneDistance - sceneBoundingRadius;
// Let the scene fill the entire depth texture
FieldOfView = (GLfloat) m3dRadToDeg (2.0f * atan (sceneBoundingRadius / lightToSceneDistance));

GlMatrixMode (GL_PROJECTION);
GlLoadIdentity ();
GluPerspective (fieldOfView, 1.0f, nearPlane, nearPlane + (2.0f * sceneBoundingRadius));
 

In the code above, the center of the scene is at the origin, and all the objects in the scene are in the circle centered on the origin and with the radius of sceneBoundingRadius. This is a rough estimate of the scene.

Because we only need to get the pixel depth after the depth of the buffer after the test results. So we can get rid of all the unnecessary details, not to write data to the color buffer because it does not need to display.

GlShadeModel (GL_FLAT);
GlDisable (GL_LIGHTING);
GlDisable (GL_COLOR_MATERIAL);
GlDisable (GL_NORMALIZE);
GlColorMask (0,0,0,0);
...
 

If we can see the depth of the buffer zone, the depth of the buffer zone of the gray map is probably like this.

New textures

We need to copy the depth of the data to the texture as a shadow map. After OpenGL 1.4, glCopyTexImage2D allowed us to copy the data from the depth buffer. Texture data is a type of depth texture, its internal format includes GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32, the number represents the number of bits per texture unit. In general, we want the internal format to match the depth buffer's precision. OpenGL allows you to specify a generic GL_DEPTH_COMPONENT format to match your depth buffer. After drawing from the perspective of the light source, we copy the depth buffer data as a depth texture:

GlCopyTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, shadowWidth, shadowHeight, 0);

Only when the object moves or the light source moves, need to re-generate the depth texture. If only the camera is moving, we do not need to re-create the depth texture, because the light source point of view, the depth of the texture does not change. When the size of the window changes, we also need to produce a larger depth texture.

 

Depth The size of the texture

Prior to OpenGL 2.0, in the case of extensions that do not support a non-quadratic texture (GL_ARB_texture_non_power_of_two), we need to adjust the size of the depth texture to exactly the second power. For example, at 1024x768 resolution, the largest second power texture size is 1024x512.

Void ChangeSize (int w, int h)
{
WindowWidth = shadowWidth = w;
WindowHeight = shadowHeight = h;
// Non-secondary power texture sizes are not supported
If (! NptTextureAvailable)
{
Int i = 0;
Int j = 0;
// Get the width of the second power
While ((1 < < i) < = shadowWidth)
I ++;

ShadowWidth = (1 < < (i-1));
// The height of the second power
While ((1 < < j) < = shadowHeight)
J ++;

ShadowHeight = (1 < < (j-1));
}}

}}
 

First draw the shadow

If the shadow is defined to be completely unlit, then we do not need to draw it. For example, only a single spotlight as the light source, so that the shadow is all black enough to meet our requirements. If we do not want the shadows to be completely black, and we need some detail in the shaded area, we need to simulate some ambient light in the scene. At the same time, we also add some scattered light to help convey the shape of the information.

GLfloat lowAmbient [4] = {0.1f, 0.1f, 0.1f, 1.0f};
GLfloat lowDiffuse [4] = {0.35f, 0.35f, 0.35f, 1.0f};

GlLightfv (GL_LIGHT0, GL_AMBIENT, lowAmbient);
GlLightfv (GL_LIGHT0, GL_DIFFUSE, lowDiffuse);

// Draw the object in the scene
DrawModels ()
 

PS: At this point we do not need to swap the buffer (swapbuffers).

Some OpenGL implementations support a GL_ARB_shadow_ambient extension, which allows us to eliminate first-pass shadowing.

Then light

Now we have a very dark scene, to create shadows, I need a bright light area, to contrast with the shadow area. How to decide which areas to accept more light is the key to shadow mapping. In this bright region, we plot the light intensity twice as much as the shadow.

GLfloat ambientLight [] = {0.2f, 0.2f, 0.2f, 1.0f};
GLfloat diffuseLight [] = {0.7f, 0.7f, 0.7f, 1.0f};
...
GlLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
GlLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
 
The resulting shadows are not all black.
 
If you remove the previous draw the shadow of the results are:

Projection Shadow Map

Our goal is to project the shadow map into the scene (from the camera's location). These depth values representing the distance from the light source to the first object illuminated by the light are projected. Redirecting texture coordinates to the correct coordinate space requires some mathematical knowledge. Before we explain the process of transforming vertices from object space to visual space, transforming to cutting space, then transforming to normalized device coordinates, and finally transforming to window space. There are two sets of different transformation matrices, one for visual space conversion to the camera, and one for the visual space for transforming to the light source. Two sets of matrix transforms are used to obtain two scenes viewed from different angles.

We need to apply the transformation process to the visual linear texture coordinates. Texture projection is usually from the visual linear coordinates of the generation began. This process automatically generates texture coordinates. Unlike the generation of linear texture coordinates, the creation of visual linear coordinates is not fixed to any geometric figure. Instead, it looks like a projector is projecting the texture into the scene. Imagine the irregular shape of the body on the screen as you walk around the projector.

We now obtain the texture coordinates corresponding to the vertices in the camera's visual space. We need to make some transforms to get the texture coordinates of the vertices. At present, in the visual space of the camera, we first go back to the world coordinate system through the inverse transformation of the view matrix, and then transform to the visual space of the light source, and then to the cutting space of the light source. This series of transformations can be obtained by multiplying the following matrices:

M = Plight * MVlight * MVcamara-1

The normalized x, y, and z coordinates of the clipping space are between [-1, 1], whereas our texture coordinates are [0,1], so we need to transform [-1,1] [0,1], this transformation is very simple, we only need to zoom in [-1,1] half (S), and then offset 0.5 can be [0,1] (B).

M = B * S * Plight * MVlight * MVcamara-1

So we can get the texture coordinates of the transformed vertices. T1 = M * T;

PS: The multiplication of the inverse matrix of the current model view matrix is already included in the visual plane equation.

That is, in OpenGL texture automatic generation model GL_EYE_LINEAR, each sensory plane equation (eye plane equation) will automatically multiply MVcamara-1

One way to implement the above steps is to implement it manually step by step through glTranslatef, glScalef, glMultMatrixf. Another way is in texture automatic generation, we can set up a texture matrix to achieve the above transformation, the texture matrix as the visual linear coordinates of the visual plane equation GL_EYE_PLANE can be.

M = B * S * Plight * MVlight roughly the following code:

M3DMatrix44f tempMatrix;
M3dLoadIdentity44 (tempMatrix);
// Offset by 0.5
M3dTranslateMatrix44 (tempMatrix, 0.5f, 0.5f, 0.5f);
// Scales 0.5
M3dScaleMatrix44 (tempMatrix, 0.5f, 0.5f, 0.5f);
// Multiply the light source projection matrix
M3dMatrixMultiply44 (textureMatrix, tempMatrix, lightProjection);
// Multiply the light source view matrix
M3dMatrixMultiply44 (tempMatrix, textureMatrix, lightModelView);
/ / Matrix transpose, the plane equation s, t, r and q line
M3dTransposeMatrix44 (textureMatrix, tempMatrix);
 

Apply to the visual plane:

// Because the multiplication of the inverse matrix of the current model view matrix is already contained in the visual plane equation
// Make sure that the camera's model view matrix is set before glTexGenfv.
GlMatrixMode (GL_MODELVIEW);
GlLoadIdentity ();
GluLookAt (cameraPos [0], cameraPos [1], cameraPos [2],
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
...

// Set the visual plane for the shadow map projection
GlEnable (GL_TEXTURE_GEN_S);
GlEnable (GL_TEXTURE_GEN_T);
GlEnable (GL_TEXTURE_GEN_R);
GlEnable (GL_TEXTURE_GEN_Q);
GlTexGenfv (GL_S, GL_EYE_PLANE, & textureMatrix [0]);
GlTexGenfv (GL_T, GL_EYE_PLANE, & textureMatrix [4]);
GlTexGenfv (GL_R, GL_EYE_PLANE, & textureMatrix [8]);
GlTexGenfv (GL_Q, GL_EYE_PLANE, & textureMatrix [12]);
...
GlTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
GlTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
GlTexGeni (GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
GlTexGeni (GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
 

Shadow comparison

Now how do we know if the point seen from the camera's perspective is in the shadow? From the above steps, we know the depth texture coordinates of the vertices, then the depth texture coordinates correspond to the depth texture values we can know that the texture [s / q, t / q], the depth of the texture recorded in the The angle of light to see the depth of the past from the nearest point of light, we set the depth comparison function is glDepthFunc (GL_LEQUAL) ;. , And we know that (r / q) is the depth of the vertex in the real light source, which has been transformed to [0,1] by scaling and offset. Then we compare texture [s / q, t / q] and (r / q) if texture [s / q, t / q] < r / q then indicates that the point is in shadow.

Depth textures contain only one value for depth. However, in the context of the texture texture query, we need to return the value of the four components (RGBA). OpenGL provides several ways to extend this single depth value to other channels, including GL_ALPHA (0,0,0, D), GL_LUMINANCE (D, D, D, 1) and GL_INTENSITY (D, D, D, D). Here we extend the depth value to all depth channels.

GlTexParameteri (GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INSTENSITY);

In the OpenGL open shadow comparison, to produce a shadow effect. We compare the depth values to the R components of the texture coordinates.

/ / Set the shadow comparison

GlEnable (GL_TEXTURE_2D);

GlTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

Examples of code in the book:

// Called to regenerate the shadow map
Void RegenerateShadowMap (void)
{
  GLfloat lightToSceneDistance, nearPlane, fieldOfView;
  GLfloat lightModelview [16], lightProjection [16];
  GLfloat sceneBoundingRadius = 95.0f; // based on objects in scene

  // Save the depth precision for where it's useful
  LightToSceneDistance = sqrt (lightPos [0] * lightPos [0] +
    LightPos [1] * lightPos [1] +
    LightPos [2] * lightPos [2]);
  NearPlane = lightToSceneDistance - sceneBoundingRadius;
  // Keep the scene filling the depth texture
  FieldOfView = (GLfloat) m3dRadToDeg (2.0f * atan (sceneBoundingRadius / lightToSceneDistance));

  GlMatrixMode (GL_PROJECTION);
  GlLoadIdentity ();
  GluPerspective (fieldOfView, 1.0f, nearPlane, nearPlane + (2.0f * sceneBoundingRadius));
  GlGetFloatv (GL_PROJECTION_MATRIX, lightProjection);
  // Switch to light's point of view
  GlMatrixMode (GL_MODELVIEW);
  GlLoadIdentity ();
  GluLookAt (lightPos [0], lightPos [1], lightPos [2],
    0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
  GlGetFloatv (GL_MODELVIEW_MATRIX, lightModelview);
  GlViewport (0, 0, shadowWidth, shadowHeight);

  // Clear the depth buffer only
  GlClear (GL_DEPTH_BUFFER_BIT);

  // All we care about here is derived depth values
  GlShadeModel (GL_FLAT);
  GlDisable (GL_LIGHTING);
  GlDisable (GL_COLOR_MATERIAL);
  GlDisable (GL_NORMALIZE);
  GlColorMask (0, 0, 0, 0);

  // Overcome imprecision
  GlEnable (GL_POLYGON_OFFSET_FILL);

  // Draw objects in the scene except base plane
  // which never shadows anything
  DrawModels (GL_FALSE);

  // Copy depth values into depth texture
  GlCopyTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
    0, 0, shadowWidth, shadowHeight, 0);

  // Restore normal drawing state
  GlShadeModel (GL_SMOOTH);
  GlEnable (GL_LIGHTING);
  GlEnable (GL_COLOR_MATERIAL);
  GlEnable (GL_NORMALIZE);
  GlColorMask (1, 1, 1, 1);
  GlDisable (GL_POLYGON_OFFSET_FILL);

  // Set up texture matrix for shadow map projection,
  // which will be rolled into the eye linear
  // texture coordinate generation plane equations
  M3DMatrix44f tempMatrix;
  M3dLoadIdentity44 (tempMatrix);
  M3dTranslateMatrix44 (tempMatrix, 0.5f, 0.5f, 0.5f);
  M3dScaleMatrix44 (tempMatrix, 0.5f, 0.5f, 0.5f);
  M3dMatrixMultiply44 (textureMatrix, tempMatrix, lightProjection);
  M3dMatrixMultiply44 (tempMatrix, textureMatrix, lightModelview);
  // transpose to get the s, t, r, and q rows for plane equations
  M3dTransposeMatrix44 (textureMatrix, tempMatrix);
}}

// Called to draw scene
Void RenderScene (void)
{
  // Track camera angle
  GlMatrixMode (GL_PROJECTION);
  GlLoadIdentity ();
  If (windowWidth> windowHeight)
  {
    GLdouble ar = (GLdouble) windowWidth / (GLdouble) windowHeight;
    GlFrustum (-ar * cameraZoom, ar * cameraZoom, -cameraZoom, cameraZoom, 1.0, 1000.0);
  }}
  Else
  {
    GLdouble ar = (GLdouble) windowHeight / (GLdouble) windowWidth;
    GlFrustum (-cameraZoom, cameraZoom, -ar * cameraZoom, ar * cameraZoom, 1.0, 1000.0);
  }}

  GlMatrixMode (GL_MODELVIEW);
  GlLoadIdentity ();
  GluLookAt (cameraPos [0], cameraPos [1], cameraPos [2],
    0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

  GlViewport (0, 0, windowWidth, windowHeight);

  // Track light position
  GlLightfv (GL_LIGHT0, GL_POSITION, lightPos);

  // Clear the window with current clearing color
  GlClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  If (showShadowMap)
  {
    // Display shadow map for educational purposes
    GlMatrixMode (GL_PROJECTION);
    GlLoadIdentity ();
    GlMatrixMode (GL_MODELVIEW);
    GlLoadIdentity ();
    GlMatrixMode (GL_TEXTURE);
    GlPushMatrix ();
    GlLoadIdentity ();
    GlEnable (GL_TEXTURE_2D);
    GlDisable (GL_LIGHTING);
    GlTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    GlTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
    // Show the shadowMap at its actual size relative to window
    GlBegin (GL_QUADS);
    GlTexCoord2f (0.0f, 0.0f);
    GlVertex2f (-1.0f, -1.0f);
    GlTexCoord2f (1.0f, 0.0f);
    GlVertex2f (((GLfloat) shadowWidth / (GLfloat) windowWidth) * 2.0f-1.0f,
      -1.0f);
    GlTexCoord2f (1.0f, 1.0f);
    GlVertex2f (((GLfloat) shadowWidth / (GLfloat) windowWidth) * 2.0f-1.0f,
      ((GLfloat) shadowHeight / (GLfloat) windowHeight) * 2.0f-1.0f);
    GlTexCoord2f (0.0f, 1.0f);
    GlVertex2f (-1.0f,
      ((GLfloat) shadowHeight / (GLfloat) windowHeight) * 2.0f-1.0f);
    GlEnd ();
    GlDisable (GL_TEXTURE_2D);
    GlEnable (GL_LIGHTING);
    GlPopMatrix ();
    GlMatrixMode (GL_PROJECTION);
    GluPerspective (45.0f, 1.0f, 1.0f, 1000.0f);
    GlMatrixMode (GL_MODELVIEW);
  }}
  Else if (noShadows)
  {
    // Set up some simple lighting
    GlLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
    GlLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);

    // Draw objects in the scene including base plane
    DrawModels (GL_TRUE);
  }}
  Else
  {
    If (! AmbientShadowAvailable)
    {
      GLfloat lowAmbient [4] = {0.1f, 0.1f, 0.1f, 1.0f};
      GLfloat lowDiffuse [4] = {0.35f, 0.35f, 0.35f, 1.0f};

      // because there is no support for an "ambient"
      // shadow compare fail value, we'll have to
      // draw an ambient pass first ...
      GlLightfv (GL_LIGHT0, GL_AMBIENT, lowAmbient);
      GlLightfv (GL_LIGHT0, GL_DIFFUSE, lowDiffuse);

      // Draw objects in the scene, including base plane
      DrawModels (GL_TRUE);

      // Enable alpha test so that shadowed fragments are discarded
      GlAlphaFunc (GL_GREATER, 0.9f);
      GlEnable (GL_ALPHA_TEST);
    }}

    GlLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
    GlLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);

    // Set up shadow comparison
    GlEnable (GL_TEXTURE_2D);
    GlTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    GlTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
      GL_COMPARE_R_TO_TEXTURE);

    // Set up the eye plane for projecting the shadow map on the scene
    GlEnable (GL_TEXTURE_GEN_S);
    GlEnable (GL_TEXTURE_GEN_T);
    GlEnable (GL_TEXTURE_GEN_R);
    GlEnable (GL_TEXTURE_GEN_Q);
    GlTexGenfv (GL_S, GL_EYE_PLANE, & textureMatrix [0]);
    GlTexGenfv (GL_T, GL_EYE_PLANE, & textureMatrix [4]);
    GlTexGenfv (GL_R, GL_EYE_PLANE, & textureMatrix [8]);
    GlTexGenfv (GL_Q, GL_EYE_PLANE, & textureMatrix [12]);

    // Draw objects in the scene, including base plane
    DrawModels (GL_TRUE);

    GlDisable (GL_ALPHA_TEST);
    GlDisable (GL_TEXTURE_2D);
    GlDisable (GL_TEXTURE_GEN_S);
    GlDisable (GL_TEXTURE_GEN_T);
    GlDisable (GL_TEXTURE_GEN_R);
    GlDisable (GL_TEXTURE_GEN_Q);
  }}

  If (glGetError ()! = GL_NO_ERROR)
    Fprintf (stderr, "GL Error! \ N");

  // Flush drawing commands
  GlutSwapBuffers ();
}}
     
         
         
         
  More:      
 
- VNC configuration detailed analysis under Linux (Linux)
- Talk about the Linux folder permissions issue again (Linux)
- MySQL Tutorial: Using tpcc-mysql pressure measurement (Database)
- OpenCV cvFindCornerSubPix () to find sub-pixel Corner (Programming)
- Getting Started with Linux: Learn how to upgrade Docker in Ubuntu (Server)
- grep search from files and display the file name (Linux)
- SSL VPN SSL VPN access to security websites patron (Linux)
- SSH mutual trust configuration (Server)
- CentOS 6.5 dual card configuration, one of the external network, a local area network connection (Linux)
- Linux operating system Samba server configuration and use (Server)
- Upgrading to MySQL 5.7.9 MySQL 5.6.23 (Database)
- SUSE Linux install Oracle 10g and problem solving (Linux)
- Why did not Oracle privileges can also log in with sysdba (Database)
- Linux port scanning (Linux)
- Ora-00020: maximum number of processes (500) exceeded (Database)
- Three kinds of binary tree traversal recursive and iterative solution (Programming)
- How to use SVN to manage our source code (Server)
- XP virtual machine under VirtualBox solve occupy 100% CPU problem (Linux)
- Java Virtual Machine Basics (Programming)
- Volatile keyword in C language understanding (Programming)
     
           
     
  CopyRight 2002-2020 newfreesoft.com, All Rights Reserved.