openGL Projective texture mapping

原文链接:https://sites.google.com/site/gsucomputergraphics/educational/advanced-texture-mapping/projective-texture-mapping

Example

  此示例演示了投影纹理贴图,这是阴影贴图,光照贴图和纹理贴图的基础。

在常规纹理贴图中,每个顶点的纹理坐标都是静态的,通常是在建模软件(例如Maya,3DS Max或Blender)中计算的。在投影纹理贴图中,每个顶点的纹理坐标不是静态的,而是根据顶点的位置计算得出的。基本思想是将顶点从投影仪的视点投影到2D图片。然后,将投影顶点的2D坐标用作其纹理坐标。

首先,从投影仪的角度构造一个视图-投影-偏置矩阵,然后将该矩阵传递给顶点着色器。在顶点着色器中,将顶点位置与此投影机MVPB矩阵相乘,然后将转换后位置的前两个分量用作该顶点的纹理坐标。

关键函数是buildProjectorMatrices(),它为投影仪构建视图-投影-偏置矩阵。然后,在顶点着色器中,以下代码行计算顶点的纹理坐标:

textureCoordProj = textureMatrix * modelMatrix * vPos

在片段着色器中,使用textureProj()查找投影纹理。

代码和图像附在此页面的底部。 您应该修改计算机的纹理图像文件路径。

在以下示例中,突出显示了与投影纹理映射直接相关的代码行。

/*
   This example demonstrates projective texture mapping, which
   is the basis for shadow mapping, lightmap, and texture decal.
  此示例演示了投影纹理贴图,这是阴影贴图,光照贴图和纹理贴花的基础。  

   In regular texture mapping, the texture coordinates from each
   vertex is static, often calculated in the modeling software
   such as Maya, 3DS Max, or Blender. In projective texture mapping,
   the texture coordinates for each vertex are not static,
   but calculated from the position of the vertice. The basic idea
   is to project the vertex from the projector's viewpoint to a
   2D picture. The 2D coordinates of the projected vertex are then
   used as its texture coordinates.
  在常规纹理贴图中,每个顶点的纹理坐标都是静态的,通常是在建模软件
 (例如Maya,3DS Max或Blender)中计算的。 在投影纹理贴图中,每个
  顶点的纹理坐标不是静态的,而是根据顶点的位置计算得出的。 基本思想
   是将顶点从投影仪的视点投影到2D图片。 然后将投影顶点的2D坐标用作其纹理坐标

   First, construct a view-projection-bias matrix
   from the projector's perspective, and then pass this matrix to the vertex shader.
   In the vertex shader, multiply the vertex position with this matrix, and then use
   the first two component's of the transformed position as
   the texture coordinates for this vertex.
   首先,从投影仪的角度构造一个视图-投影-偏置矩阵,然后将该矩阵传递给顶点着色器。 在顶点着色器中,
   将顶点位置与此矩阵相乘,然后将转换后位置的前两个分量用作该顶点的纹理坐标。

   The key function is buildProjectorMatrices(), which builds the
   view-projection-bias matrix for the projector. Then in the
   vertex shader, the following line of code calculates the
   texture coordinates for the vertex:
   关键函数是buildProjectorMatrices(),它为投影仪构建视图-投影-偏置矩阵。
    然后,在顶点着色器中,以下代码行计算顶点的纹理坐标:
       textureCoord = textureMatrix * modelMatrix * vPos;

Ying Zhu
Georgia State University 佐治亚州立大学

November 2016
*/

// GLEW header
#include <GL/glew.h> // This must appear before freeglut.h 必须在freeglut.h之前出现

// Freeglut header
#include <GL/freeglut.h>

// GLM header files
#include <glm/glm.hpp> 

#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtx/transform2.hpp>
#include <glm/gtc/matrix_access.hpp>
#include <glm/gtx/projection.hpp>
#include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/type_ptr.hpp> 

// Simple OpenGL Image Library header file  简单的OpenGL图像库头文件
#include <SOIL.h>

#include <check_error.hpp>

// C++ header files
#include <iostream>

using namespace std;
using namespace glm;

#define BUFFER_OFFSET(offset) ((GLvoid *) offset)

/*
// A square with two triangles. 有两个三角形的正方形。
GLfloat vertices[][4] = {
    { 1.368670f, 1.321428f, 0.094483f, 1.0f },
    { -1.274187f, 1.321429f, 0.094483f, 1.0f },
    { -1.274187f, -1.321428f, 0.094483f, 1.0f },
    { 1.368670f, 1.321428f, 0.094483f, 1.0f },
    { -1.274187f, -1.321428f, 0.094483f, 1.0f },
    { 1.368670f, -1.321429f, 0.094483f, 1.0f }
};

int numVertices = 6;

GLfloat normals[][4] = {
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
    { 0.000000f, 0.000000f, 1.000000f, 1.0f },
};

// Specify texture coordinates. 指定纹理坐标。
GLfloat textureCoords[][2] = {
    { 0.000000f, 0.000000f },
    { 1.000000f, 0.000000f },
    { 1.000000f, 1.000000f },
    { 0.000000f, 0.000000f },
    { 1.000000f, 1.000000f },
    { 0.000000f, 1.000000f }
};

*/

// A pyramid object.  金字塔对象。
GLfloat vertices[][4] = {
    { 1.0f, -1.0f, 1.0f, 1.0f }, // face 1
    { -1.0f, -1.0f, -1.0f, 1.0f },
    { 1.0f, -1.0f, -1.0f, 1.0f },
    { 1.0f, -1.0f, -1.0f, 1.0f }, // face 2
    { 0.0f, 1.0f, 0.0f, 1.0f },
    { 1.0f, -1.0f, 1.0f, 1.0f },
    { 1.0f, -1.0f, 1.0f, 1.0f }, // face 3
    { 0.0f, 1.0f, 0.0f, 1.0f },
    { -1.0f, -1.0f, 1.0f, 1.0f },
    { -1.0f, -1.0f, 1.0f, 1.0f }, // face 4
    { 0.0f, 1.0f, 0.0f, 1.0f },
    { -1.0f, -1.0f, -1.0f, 1.0f },
    { 0.0f, 1.0f, 0.0f, 1.0f }, // face 5
    { 1.0f, -1.0f, -1.0f, 1.0f },
    { -1.0f, -1.0f, -1.0f, 1.0f },
    { 1.0f, -1.0f, 1.0f, 1.0f }, // face 6
    { -1.0f, -1.0f, 1.0f, 1.0f },
    { -1.0f, -1.0f, -1.0f, 1.0f }
};

int numVertices = 18;

GLfloat normals[][4] = {
    { 0.0f, -1.0f, 0.0f, 1.0f }, // normal 1
    { 0.0f, -1.0f, 0.0f, 1.0f },
    { 0.0f, -1.0f, 0.0f, 1.0f },
    { 0.8944f, 0.4472f, 0.0f, 1.0f }, // normal 2
    { 0.8944f, 0.4472f, 0.0f, 1.0f },
    { 0.8944f, 0.4472f, 0.0f, 1.0f },
    { -0.0f, 0.4472f, 0.8944f, 1.0f }, // normal 3
    { -0.0f, 0.4472f, 0.8944f, 1.0f },
    { -0.0f, 0.4472f, 0.8944f, 1.0f },
    { -0.8944f, 0.4472f, 0.0f, 1.0f }, // normal 4
    { -0.8944f, 0.4472f, 0.0f, 1.0f },
    { -0.8944f, 0.4472f, 0.0f, 1.0f },
    { 0.0f, 0.4472f, -0.8944f, 1.0f }, // normal 5
    { 0.0f, 0.4472f, -0.8944f, 1.0f },
    { 0.0f, 0.4472f, -0.8944f, 1.0f },
    { 0.0f, -1.0f, 0.0f, 1.0f }, // normal 6
    { 0.0f, -1.0f, 0.0f, 1.0f },
    { 0.0f, -1.0f, 0.0f, 1.0f }
};

GLfloat textureCoords[][2] = {
    { 0.0319, 0.4192 }, // textureCoord 1
    { 0.3546, 0.0966 },
    { 0.3546, 0.4192 },
    { 0.4223, 0.5177 },    // textureCoord 2
    { 0.2541, 0.8753 },
    { 0.0996, 0.5116 },
    { 0.8047, 0.5250 },    // textureCoord 3
    { 0.6434, 0.8857 },
    { 0.4820, 0.5250 },
    { 0.6637, 0.0981 },    // textureCoord 4
    { 0.5130, 0.4184 },
    { 0.3748, 0.0926 },
    { 0.8416, 0.4227 },    // textureCoord 5
    { 0.6922, 0.0988 },
    { 0.9834, 0.0954 },
    { 0.0319, 0.4192 },    // textureCoord 6
    { 0.0319, 0.0966 },
    { 0.3546, 0.0966 }
};

// Remeber to update the texture image file path for your computer. 
// 记住要更新计算机的纹理图像文件路径。

const char *imageFileName = "..\\..\\Images\\marble1.jpg";
const char *projectiveTextureImageName = "..\\..\\Images\\mona_lisa.jpg";

// VBO buffer IDs VBO缓冲区ID
GLuint vertexArrayBufferID = 0;
GLuint normalArrayBufferID = 0;
GLuint texCoordArrayBufferID = 0;

GLuint program; // shader program ID  着色器程序ID

// Shader variable IDs  着色器变量ID
GLint vPos; // vertex attribute: position  顶点属性:位置
GLint normalID; // vertex attribute: normal  顶点属性:正常
GLint textureCoordID; // vertex attribute: texture coordinates  顶点属性:纹理坐标

GLint mvpMatrixID; // uniform variable: model, view, projection matrix 统一变量:模型,视图,投影矩阵
GLint modelMatrixID; // uniform variable: model, view matrix  统一变量:模型,视图矩阵
GLint normalMatrixID; // uniform variable: normal matrix for transforming normals 统一变量:用于转换法线的法线矩阵
GLint textureMatrixID; // uniform variable: texture matrix for calculating texture  统一变量:用于计算纹理的纹理矩阵
                       // coordinates for projective texture mapping  投影纹理映射的坐标

GLint lightSourcePositionID; // uniform variable: for lighting calculation 统一变量:用于照明计算
GLint diffuseLightProductID; // uniform variable: for lighting calculation
GLint ambientID;
GLint attenuationAID;
GLint attenuationBID;
GLint attenuationCID;

GLint textureSamplerID; // texture sampler ID  纹理采样器ID
GLint projTextureSamplerID; // projective texture sampler ID  投影纹理采样器ID

// Texture object ID  纹理对象ID
GLuint textureID;
GLuint projTextureID;

// Texture unit ID  纹理单元ID
// These two values must be consistent.  这两个值必须一致。
GLenum textureUnitID = GL_TEXTURE1;
// Sometimes, setting this to 0 will connect the sampler to any active texture unit. 
// 有时,将此值设置为0会将采样器连接到任何活动纹理单元。
// But it's better to avoid using this "trick". 
// 但是最好避免使用此“技巧”。

GLuint textureSamplerValue = 1;

// Texture unit ID for the projective texture 投影纹理的纹理单元ID
// These two values must be consistent.  这两个值必须一致
GLenum projTextureUnitID = GL_TEXTURE2;
// Sometimes, setting this to 0 will connect the sampler to any active texture unit. 
// 有时,将此值设置为0会将采样器连接到任何活动纹理单元。
// But it's better to avoid using this "trick". 
GLuint projTextureSamplerValue = 2;

// Transformation matrices
mat4 projMatrix;
mat4 mvpMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
mat3 normalMatrix;  // Normal matrix for transforming normals 用于变换法线的法线矩阵

mat4 textureCoordTransformationMatrix;

// Light parameters  灯光参数
vec4 lightSourcePosition = vec4(0.0f, 4.0f, 0.0f, 1.0f);
vec4 diffuseMaterial = vec4(0.5f, 0.5f, 0.5f, 1.0f);
vec4 diffuseLightIntensity = vec4(1.0f, 1.0f, 1.0f, 1.0f);
vec4 ambient = vec4(0.2f, 0.2f, 0.2f, 1.0f);
float attenuationA = 1.0f;
float attenuationB = 0.2f;
float attenuationC = 0.0f;

vec4 diffuseLightProduct;

// Camera parameters
vec3 eyePosition = vec3(0.0f, 0.0f, 4.0f);
vec3 lookAtCenter = vec3(0.0f, 0.0f, 0.0f);
vec3 upVector = vec3(0.0f, 1.0f, 0.0f);
float fieldOfView = 30.0f;
float nearPlane = 0.1f;
float farPlane = 1000.0f;

// Mouse controlled rotation angles  鼠标控制旋转角度
float rotateX = 0;
float rotateY = 0;

// Projector parameters  投影机参数
// Define the projector's location and orientation. 
// 定义投影机的位置和方向。

vec3 projectorPosition = vec3(0.0f, 1.0f, 0.0f);
vec3 projectorLookAtPosition = vec3(0.5f, 0.0f, 0.0f);
vec3 projectorUpVector = vec3(0.0f, 0.0f, 1.0f);
float projectorFOV = 60.0f;

//---------------------------------------------------------------
// Initialize vertex arrays and VBOs
// 初始化顶点数组和VBO

void prepareVBOs() {
    // Define a 3D pyramid.  定义3D金字塔

    // Get an unused buffer object name. Required after OpenGL 3.1. 
  // 获取未使用的缓冲区对象名称。 在OpenGL 3.1之后需要。

    glGenBuffers(1, &vertexArrayBufferID);

    // If it's the first time the buffer object name is used, create that buffer. 
  // 如果是第一次使用缓冲区对象名称,请创建该缓冲区。

    glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);

    // Allocate memory for the active buffer object. 
    // 1. Allocate memory on the graphics card for the amount specified by the 2nd parameter.
    // 2. Copy the data referenced by the third parameter (a pointer) from the main memory to the 
    //    memory on the graphics card. 
    // 3. If you want to dynamically load the data, then set the third parameter to be NULL. 
      //为活动缓冲区对象分配内存。
      // 1.在图形卡上分配第二个参数指定的内存量。
      // 2.将第三个参数(指针)引用的数据从主存储器复制到
      //显卡上的内存。
      // 3.如果要动态加载数据,则将第三个参数设置为NULL。


    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &normalArrayBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(normals), normals, GL_STATIC_DRAW);

    // Create a buffer object to store the texture coordinates. 
    // Later we will passt his over to the shader. 
     //创建一个缓冲区对象以存储纹理坐标。
     //稍后我们将其传递给着色器。


    glGenBuffers(1, &texCoordArrayBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, texCoordArrayBufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW);
}

//-------------------------------------------------------------------
void prepareShaders() {
    // Vertex shader source code
    // The vertex position and normal vector are transformed and then passed on to the fragment shader. 
  
    //顶点着色器源代码
    //将顶点位置和法向矢量转换,然后传递到片段着色器。


    const char* vSource = {
        "#version 330\n"
        "in vec4 vPos;"
        "in vec4 normal;"
        "in vec2 vTextureCoord;"

        "uniform mat4x4 mvpMatrix;"
        "uniform mat4x4 modelMatrix;"
        "uniform mat3x3 normalMatrix;"

        // The model-view-projection matrix for the projector
        // This matrix is used to calculate the texture coordinates for the vertex. 
         //投影机的模型-视图-投影矩阵
         //此矩阵用于计算顶点的纹理坐标。


        "uniform mat4x4 textureMatrix;"

        "out vec4 transformedPosition;"
        "out vec3 transformedNormal;"
        "out vec2 textureCoord;"
        "out vec4 textureCoordProj;"

        "void main() {"
        "   gl_Position = mvpMatrix * vPos;"
        // Transform the vertex position to the world space. 
        // //将顶点位置转换为世界空间。

        "   transformedPosition = modelMatrix * vPos;"
        // Transform the normal vector to the world space. 
        // 将法线向量转换为世界空间。

        "   transformedNormal = normalize(normalMatrix * normal.xyz);"

        "   textureCoord = vTextureCoord;"

        // Calculates the texture coordinates for the vertex
        // Project the vertex to a 2D picture and then take the 2D coordinates as 
        // the texture coordinates. 
        // 计算顶点的纹理坐标
        // 将顶点投影到2D图片,然后将2D坐标作为
        // 纹理坐标。

        "   textureCoordProj = textureMatrix * modelMatrix * vPos;"

        // If modelMatrix is removed from this calculation, the projected texture will
        // "stick" to the object, rather than be fixed in space. This is called texture decal. 
        // "   textureCoordProj = textureMatrix * vPos;"
          //如果从此计算中删除了modelMatrix,则投影的纹理将
           //“粘贴”到对象,而不是固定在空间中。 这称为纹理贴花。
           //“ textureCoordProj = textureMatrix * vPos;”


        "}"
    };

    // Fragment shader source code
    // A point light source is implemented. 
    // For simplicity, only the ambient and diffuse components are implemented. 
    // The lighting is calculated in world space, not in camera space. 

    // Note that the transformedPosition and transformedNormal in the fragment shader are for each fragment (pixel).
    // They are interpolated from the vertex positions and vertex normals in the (invisible) rasterization stage. 
  
    //片段着色器源代码
    //实现点光源。
    //为简单起见,仅实现了环境和漫反射组件。
    //光照是在世界空间而不是摄影机空间中计算的。


    //请注意,片段着色器中的transformdPosition和transformedNormal是针对每个片段(像素)的。
    //它们是在(不可见的)光栅化阶段从顶点位置和顶点法线插值的。


    const char* fSource = {
        "#version 330\n"
        "in vec4 transformedPosition;"
        "in vec3 transformedNormal;"
        "in vec2 textureCoord;"
        "in vec4 textureCoordProj;"

        "uniform vec4 lightSourcePosition;"
        "uniform vec4 diffuseLightProduct;"
        "uniform vec4 ambient;"
        "uniform float attenuationA;"
        "uniform float attenuationB;"
        "uniform float attenuationC;"

        // Don't use the reserved word "texture" as variable name. 
     //不要使用保留字“ texture”作为变量名。

        "uniform sampler2D tex;"  // Regular texture image  常规纹理图像
        "uniform sampler2D texProj;"  // Projected texture image 投影的纹理图像

        "out vec4 fragColor;"
        "void main() {"
        // Light direction 灯光方向
        "    vec3 lightVector = normalize(transformedPosition.xyz - lightSourcePosition.xyz);"
        // Distance between the light source and vertex 光源和顶点之间的距离
        "   float dist = distance(lightSourcePosition.xyz, transformedPosition.xyz);"
        // Attenuation factor 衰减系数
        "   float attenuation = 1.0f / (attenuationA + (attenuationB * dist) + (attenuationC * dist * dist));"
        // Calculate the diffuse component of the lighting equation. 计算照明方程的漫反射分量。
        "    vec4 diffuse = attenuation * (max(dot(transformedNormal, lightVector), 0.0) * diffuseLightProduct);"

        // For regular texture mapping 用于常规纹理映射
        "   vec4 textureColor = texture(tex, textureCoord);"

        // For perspective projection effect 透视投影效果
        "   vec4 textureColorProj = textureProj(texProj, textureCoordProj);"

        // Combine the ambient component and diffuse component. 合并环境成分和扩散成分。
        "   vec4 lightTextureMix = mix((ambient + diffuse), textureColor, 0.6f);"

        "   fragColor = mix(lightTextureMix, textureColorProj, 0.4f);"
        "}"
    };
 
    // Declare shader IDs 声明着色器ID
    GLuint vShader, fShader;

    // Create empty shader objects  创建空的着色器对象
    vShader = glCreateShader(GL_VERTEX_SHADER);
    checkGlCreateXError(vShader, "vShader");

    fShader = glCreateShader(GL_FRAGMENT_SHADER);
    checkGlCreateXError(fShader, "fShader");

    // Attach shader source code the shader objects 附加着色器源代码着色器对象
    glShaderSource(vShader, 1, &vSource, NULL);
    glShaderSource(fShader, 1, &fSource, NULL);

    // Compile shader objects  编译着色器对象
    glCompileShader(vShader);
    printShaderInfoLog(vShader);

    glCompileShader(fShader);
    printShaderInfoLog(fShader);

    // Create an empty shader program object 创建一个空的着色器程序对象
    program = glCreateProgram();
    checkGlCreateXError(program, "program");

    // Attach vertex and fragment shaders to the shader program
    // 将顶点和片段着色器附加到着色器程序

    glAttachShader(program, vShader);
    glAttachShader(program, fShader);

    // Link the shader program
    // 链接着色器程序

    glLinkProgram(program);
    printShaderProgramInfoLog(program);
}

//---------------------------------------------------------------
// Retrieve the IDs of the shader variables. Later we will
// use these IDs to pass data to the shaders. 
// 检索着色器变量的ID。 稍后,我们将使用这些ID将数据传递到着色器。

void getShaderVariableLocations(GLuint shaderProgram) {

    // Retrieve the ID of a vertex attribute, i.e. position 检索顶点属性的ID,即位置
    vPos = glGetAttribLocation(shaderProgram, "vPos");
    checkGlGetXLocationError(vPos, "vPos");

    normalID = glGetAttribLocation(shaderProgram, "normal");
    checkGlGetXLocationError(normalID, "normal");

    // get the ID of the texture coordinate variable in the shader. 
    // 获取着色器中纹理坐标变量的ID。

    textureCoordID = glGetAttribLocation(shaderProgram, "vTextureCoord");
    checkGlGetXLocationError(textureCoordID, "vTextureCoord");

    mvpMatrixID = glGetUniformLocation(shaderProgram, "mvpMatrix");
    checkGlGetXLocationError(mvpMatrixID, "mvpMatrix");

    modelMatrixID = glGetUniformLocation(shaderProgram, "modelMatrix");
    checkGlGetXLocationError(modelMatrixID, "modelMatrix");

    normalMatrixID = glGetUniformLocation(shaderProgram, "normalMatrix");
    checkGlGetXLocationError(normalMatrixID, "normalMatrix");

    lightSourcePositionID = glGetUniformLocation(shaderProgram, "lightSourcePosition");
    checkGlGetXLocationError(lightSourcePositionID, "lightSourcePosition");

    diffuseLightProductID = glGetUniformLocation(shaderProgram, "diffuseLightProduct");
    checkGlGetXLocationError(diffuseLightProductID, "diffuseLightProduct");

    ambientID = glGetUniformLocation(shaderProgram, "ambient");
    checkGlGetXLocationError(ambientID, "ambient");

    attenuationAID = glGetUniformLocation(shaderProgram, "attenuationA");
    checkGlGetXLocationError(attenuationAID, "attenuationA");

    attenuationBID = glGetUniformLocation(shaderProgram, "attenuationB");
    checkGlGetXLocationError(attenuationBID, "attenuationB");

    attenuationCID = glGetUniformLocation(shaderProgram, "attenuationC");
    checkGlGetXLocationError(attenuationCID, "attenuationC");

    // get the ID of the texture sampler in the shader. 
    // 获取着色器中纹理采样器的ID。

    textureSamplerID = glGetUniformLocation(shaderProgram, "tex");
    checkGlGetXLocationError(textureSamplerID, "tex");

    textureMatrixID = glGetUniformLocation(shaderProgram, "textureMatrix");
    checkGlGetXLocationError(textureMatrixID, "textureMatrix");

    projTextureSamplerID = glGetUniformLocation(shaderProgram, "texProj");
    checkGlGetXLocationError(projTextureSamplerID, "texProj");
}

//---------------------------------------------------------------
void setShaderVariables() {
    // value_ptr is a glm function
    // value_ptr是glm函数

    glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, value_ptr(mvpMatrix));
    glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, value_ptr(modelMatrix));
    glUniformMatrix3fv(normalMatrixID, 1, GL_FALSE, value_ptr(normalMatrix));

    glUniformMatrix4fv(textureMatrixID, 1, GL_FALSE, value_ptr(textureCoordTransformationMatrix));

    glUniform4fv(lightSourcePositionID, 1, value_ptr(lightSourcePosition));
    glUniform4fv(diffuseLightProductID, 1, value_ptr(diffuseLightProduct));
    glUniform4fv(ambientID, 1, value_ptr(ambient));
    glUniform1f(attenuationAID, attenuationA);
    glUniform1f(attenuationBID, attenuationB);
    glUniform1f(attenuationCID, attenuationC);

    // Specify the current active texture unit number. 
    //
    // There are certain number of texture units on the graphics card (for example 32).
    // Check OpenGL extension viewer to find out how many texture units are on your card. 
    //
    // The shader accesses the texture through texture units, not the texture IDs. 
    // In other words, the shader does not know the texture IDs; it only sees 
    // (for example) 32 texture units.
    // You can have more than 32 texture images stored in the graphics card's memory, but
    // at any given time, the shader only sees 32 texture units. In the OpenGL program,
    // you can associate a texture unit with any texture ID, and change it at any time. 
    // This is how you can transfer potentially large numbers of texture images to the 
    // shader through a limited channel. 
  
      //指定当前的活动纹理单位编号。


     //图形卡上有一定数量的纹理单位(例如32)。
     //检查OpenGL扩展查看器,找出卡上有多少个纹理单位。
     //
    //着色器通过纹理单位而不是纹理ID访问纹理。
    //换句话说,着色器不知道纹理ID。 例如,它只能看到32个纹理单位。
    //您可以在图形卡的内存中存储32个以上的纹理图像,但是
     //在任何给定时间,着色器只能看到32个纹理单位。 在OpenGL程序中
     //您可以将纹理单元与任何纹理ID关联,并随时更改它。
     //通过这种方式,您可以通过有限的通道将大量的纹理图像传输到着色器。

// 
    glActiveTexture(textureUnitID);

    // Bind the texture ID with the active texture unit number. 
    // In this case, texture ID "textureID" is associated with texture unit #2. 
    // When the shader reads texture unit #2, it will read the texture identified by ID textureID. 
    //将纹理ID与活动的纹理单位编号绑定。
    //在这种情况下,纹理ID“ textureID”与纹理单元#2相关联。
    //当着色器读取纹理单元#2时,它将读取ID TextureID标识的纹理。


    glBindTexture(GL_TEXTURE_2D, textureID);

    // Associate texture sampler ID in the shader with the active texture unit number.
    // glActiveTexture() function and glUniform1i(textUnit, ...) function calls must be consistent. 
    // If you change texture unit number in one function all, you must change the texture unit 
    // in the other function call. 
    //将着色器中的纹理采样器ID与活动的纹理单位编号相关联。
    // glActiveTexture()函数和glUniform1i(textUnit,...)函数调用必须保持一致。
    //如果您在一项功能中更改了纹理单位编号,则必须更改纹理单位
    //在另一个函数调用中。


    glUniform1i(textureSamplerID, textureSamplerValue);

    glActiveTexture(projTextureUnitID);
    glBindTexture(GL_TEXTURE_2D, projTextureID);

    glUniform1i(projTextureSamplerID, projTextureSamplerValue);
}

//---------------------------------------------------------------
// Set lighting related parameters
// //设置照明相关参数

void setLightingParam() {
    diffuseLightProduct = diffuseMaterial * diffuseLightIntensity;
}

void prepareTextureImage() {
    // Use SOIL to load a picture.  使用SOIL加载图片
    textureID = SOIL_load_OGL_texture(imageFileName,
        SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y); // Adding SOIL_FLAG_MIPMAPS is also fine. 添加SOIL_FLAG_MIPMAPS也可以。

    // SOIL will call glGenTexture() and glTexImage2D() to specify textures.  SOIL将调用glGenTexture()和glTexImage2D()来指定纹理。
    // If textureID is 0, then there is an error.  如果textureID为0,则存在错误。
    checkGlCreateXError(textureID, "textureID");

    projTextureID = SOIL_load_OGL_texture(projectiveTextureImageName,
        SOIL_LOAD_RGBA, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);  

    // SOIL will call glGenTexture() and glTexImage2D() to specify textures. 
    // SOIL将调用glGenTexture()和glTexImage2D()来指定纹理。
    // If textureID is 0, then there is an error. 如果textureID为0,则存在错误。
    checkGlCreateXError(projTextureID, "projTextureID");
}

//---------------------------------------------------------------
// Build the model matrix. This matrix will transform the 3D object to the proper place. 
// 建立模型矩阵。 该矩阵会将3D对象转换到正确的位置

mat4 buildModelMatrix() {

    mat4 rotationXMatrix = rotate(mat4(1.0f), radians(rotateX), vec3(1.0f, 0.0f, 0.0f));
    mat4 rotationYMatrix = rotate(mat4(1.0f), radians(rotateY), vec3(0.0f, 1.0f, 0.0f));

    mat4 matrix = rotationYMatrix * rotationXMatrix;

    return matrix;
}

//---------------------------------------------------------------
// This function build a view-projection matrix from a
// projector's viewpoint. 
mat4 buildProjectorMatrices() {

    // Construct a view-projection matrix as if the camera is placed at the projector.
    // If we use this view-projection matrix to transform the object, the object will
    // be projected from the projector to a 2D space, which is the texture space
    // for the projector view. The texture coordinates in this 2D space are the
    // texture coordinates for the projective texture. 

    // The view matrix from the projector's viewpoint. 
    mat4 projectorViewMatrix = lookAt(projectorPosition,
        projectorLookAtPosition, projectorUpVector);

    // The projection matrix for the projector. 
    mat4 projectorProjectionMatrix = perspective(projectorFOV, 1.0f, 0.5f, 10.0f);
    // mat4 projectorProjectionMatrix = ortho(0.3f, 0.3f, 0.3f, 0.0f, 0.5f, 10.0f);

    // After the initial projection, the origin is at the center of the window. 
    // However, the origin of a texture image is at the lower left corner. 
    // The scale and bias matrix is used to transform the origin from the center 
    // to the corner. 
    mat4 scaleBiasMatrix = scale(translate(mat4(1.0f), vec3(0.5, 0.5, 0.5)), vec3(0.5f));

    // Construct the combined matrix to transform the vertex position to its projective
    // texture coordiantes. 
    mat4 projectorTransformMatrix = scaleBiasMatrix * projectorProjectionMatrix *
        projectorViewMatrix;

    return projectorTransformMatrix;
}

//---------------------------------------------------------------
void buildMatrices() {
    modelMatrix = buildModelMatrix();

    mvpMatrix = projMatrix * viewMatrix * modelMatrix;

    normalMatrix = column(normalMatrix, 0, vec3(modelMatrix[0][0], modelMatrix[0][1], modelMatrix[0][2]));
    normalMatrix = column(normalMatrix, 1, vec3(modelMatrix[1][0], modelMatrix[1][1], modelMatrix[1][2]));
    normalMatrix = column(normalMatrix, 2, vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]));

    // Use glm::inverseTranspose() to create a normal matrix, which is used to transform normal vectors. 
    normalMatrix = inverseTranspose(normalMatrix);

    textureCoordTransformationMatrix = buildProjectorMatrices();
}

//---------------------------------------------------------------
// Handles the display event
void display()
{
    // Clear the window with the background color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    buildMatrices();

    setShaderVariables();

    // Activate the shader program
    glUseProgram(program);

    // If the buffer object already exists, make that buffer the current active one. 
    // If the buffer object name is 0, disable buffer objects. 
    glBindBuffer(GL_ARRAY_BUFFER, vertexArrayBufferID);

    // Associate the vertex array in the buffer object with the vertex attribute: "position"
    glVertexAttribPointer(vPos, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    // Enable the vertex attribute: "position"
    glEnableVertexAttribArray(vPos);

    glBindBuffer(GL_ARRAY_BUFFER, normalArrayBufferID);
    glVertexAttribPointer(normalID, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(normalID);

    // Associate the texture coordinate array in the buffer object with the vertex attribute "vTextureCoord", 
    // which is identified by texCoordID. 
    glBindBuffer(GL_ARRAY_BUFFER, texCoordArrayBufferID);
    glVertexAttribPointer(textureCoordID, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(textureCoordID);

    // Start the shader program. Draw the object. The third parameter is the number of vertices. 
    glDrawArrays(GL_TRIANGLES, 0, numVertices);

    // Refresh the window
    glutSwapBuffers();

    checkOpenGLError();
}

//---------------------------------------------------------------
// Handles the reshape event
void reshape(int width, int height)
{
    // Specify the width and height of the picture within the window
    glViewport(0, 0, width, height);

    projMatrix = perspective(fieldOfView, (float)width / (float)height, nearPlane, farPlane);

    viewMatrix = lookAt(eyePosition, lookAtCenter, upVector);
}

//---------------------------------------------------------------
// Read mouse motion data and convert them to rotation angles. 
void passiveMotion(int x, int y) {

    rotateY = (float)x * -0.5f;
    rotateX = (float)y * 0.5f;

    // Generate a dislay event to force refreshing the window. 
    glutPostRedisplay();
}

//-----------------------------------------------------------------
void init() {
    prepareVBOs();

    prepareShaders();

    getShaderVariableLocations(program);

    setLightingParam();

    prepareTextureImage();

    // Specify the background color
    glClearColor(1, 1, 1, 1);

    glEnable(GL_DEPTH_TEST);

    // Most of the OpenGL API calls are made from this function.
    // So we need to check error here. 
    checkOpenGLError();
}

//---------------------------------------------------------------
void main(int argc, char *argv[])
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Projective texture mapping");

    glutReshapeWindow(800, 800);

    glewInit();

    initOpenGLDebugContext(true);

    init();

    // Register the display callback function
    glutDisplayFunc(display);

    // Register the reshape callback function
    glutReshapeFunc(reshape);

    // Register the passive mouse motion call back function
    // This function is called when the mouse moves within the window
    // while no mouse buttons are pressed. 
    glutPassiveMotionFunc(passiveMotion);

    // Start the event loop
    glutMainLoop();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值