c++ - OPENGL 如何正确渲染这两个具有不同纹理/贴图的对象?

标签 c++ visual-studio opengl textures render

我试图将法线贴图和立方体贴图合并到一个程序中,但我无法正确渲染它们。在进行更复杂的事情之前,我正在做一个简单的练习来帮助我解决这个问题。我试图将这两个对象渲染到一个程序中。它们都有不同的纹理,环面使用立方体贴图,而墙使用法线贴图。

这些是他们应该单独看起来的样子:

object 1

object 2

目前,这就是我所拥有的。环面渲染正确,但没有显示墙的纹理。

3

我为此使用了 2 个单独的着色器程序,这是我第一次为一个程序使用多个着色器程序。我怀疑我的问题可能与着色器变量的初始化有关,或者是我没有得到的非常明显的问题。我为对象使用了两种不同的顶点结构。

struct Vertex2
{
    GLfloat position[3];
    GLfloat normal[3];
    GLfloat tangent[3];
    GLfloat texCoord[2];
};

Vertex2 g_vertices[] = {
    // Front: triangle 1
    // vertex 1
    -1.0f, 1.0f, 0.0f,  // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    0.0f, 1.0f,         // texture coordinate
    // vertex 2
    -1.0f, -1.0f, 0.0f, // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    0.0f, 0.0f,         // texture coordinate
    // vertex 3
    1.0f, 1.0f, 0.0f,   // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    1.0f, 1.0f,         // texture coordinate

    // triangle 2
    // vertex 1
    1.0f, 1.0f, 0.0f,   // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    1.0f, 1.0f,         // texture coordinate
    // vertex 2
    -1.0f, -1.0f, 0.0f, // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    0.0f, 0.0f,         // texture coordinate
    // vertex 3
    1.0f, -1.0f, 0.0f,  // position
    0.0f, 0.0f, 1.0f,   // normal
    1.0f, 0.0f, 0.0f,   // tangent
    1.0f, 0.0f,         // texture coordinate
};

Main.cpp 初始化函数:

static void init(GLFWwindow* window)
{
    glEnable(GL_DEPTH_TEST);    // enable depth buffer test
    glEnable(GL_TEXTURE_2D);

    // read the image data
    GLint imageWidth[5];            //image width info
    GLint imageHeight[5];           //image height info

    g_texImage[FRONT] = readBitmapRGBImage("images/cm_front.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[BACK] = readBitmapRGBImage("images/cm_back.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[LEFT] = readBitmapRGBImage("images/cm_left.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[RIGHT] = readBitmapRGBImage("images/cm_right.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[TOP] = readBitmapRGBImage("images/cm_top.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[BOTTOM] = readBitmapRGBImage("images/cm_bottom.bmp", &imageWidth[0], &imageHeight[0]);
    g_texImage[6] = readBitmapRGBImage("images/Fieldstone.bmp", &imageWidth[1], &imageHeight[1]);
    g_texImage[7] = readBitmapRGBImage("images/FieldstoneBumpDOT3.bmp", &imageWidth[2], &imageHeight[2]);

    glGenTextures(10, g_textureID);                  

    // ...

    // create and compile our GLSL program from the shader files
    g_shaderProgramID[0] = loadShaders("CubeEnvMapVS.vert", "CubeEnvMapFS.frag");
    g_shaderProgramID[1] = loadShaders("NormalMappingVS.vert", "NormalMappingFS.frag");

    // find the location of shader variables
    for (int i = 0; i < 2; i++)
    {
        positionIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aPosition");
        normalIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aNormal");
        texCoordIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aTexCoord");

        g_MVP_Index[i] = glGetUniformLocation(g_shaderProgramID[i], "uModelViewProjectionMatrix");
        g_M_Index[i] = glGetUniformLocation(g_shaderProgramID[i], "uModelMatrix");
        g_viewPointIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uViewPoint");

        g_lightPositionIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.position");
        g_lightAmbientIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.ambient");
        g_lightDiffuseIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.diffuse");
        g_lightSpecularIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.specular");
        g_lightShininessIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.shininess");

        g_materialAmbientIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.ambient");
        g_materialDiffuseIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.diffuse");
        g_materialSpecularIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.specular");
    }

    g_envMapSamplerIndex = glGetUniformLocation(g_shaderProgramID[0], "uEnvironmentMap");
    tangentIndex = glGetAttribLocation(g_shaderProgramID[1], "aTangent");
    g_texSamplerIndex = glGetUniformLocation(g_shaderProgramID[1], "uTextureSampler");
    g_normalSamplerIndex = glGetUniformLocation(g_shaderProgramID[1], "uNormalSampler");

    // initialise model matrix to the identity matrix
    g_mm_torus = glm::mat4(1.0f);
    g_mm_wall = mat4(1.0f);

    // ...

    // load mesh
    //  load_mesh("models/sphere.obj");
    load_mesh("models/torus.obj");

    // ...

    // generate identifier for VBOs and copy data to GPU
    glGenBuffers(5, g_VBO);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*g_numberOfVertices, g_pMeshVertices, GL_STATIC_DRAW);

    // generate identifier for IBO and copy data to GPU
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 3 * g_numberOfFaces, g_pMeshIndices, GL_STATIC_DRAW);

    // generate identifiers for VAO
    glGenVertexArrays(5, g_VAO);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[0]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
    glVertexAttribPointer(positionIndex[0], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
    glVertexAttribPointer(normalIndex[0], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));

    glEnableVertexAttribArray(positionIndex[0]);    // enable vertex attributes
    glEnableVertexAttribArray(normalIndex[0]);

    // generate identifier for VBOs and copy data to GPU
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);

    // create VAO and specify VBO data
    glBindVertexArray(g_VAO[1]);
    glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
    glVertexAttribPointer(positionIndex[1], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, position)));
    glVertexAttribPointer(normalIndex[1], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, normal)));
    glVertexAttribPointer(tangentIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, tangent)));
    glVertexAttribPointer(texCoordIndex[0], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));

    // enable vertex attributes
    glEnableVertexAttribArray(positionIndex[1]);
    glEnableVertexAttribArray(normalIndex[1]);
    glEnableVertexAttribArray(tangentIndex);
    glEnableVertexAttribArray(texCoordIndex[0]);
}

渲染场景函数:

static void render_scene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer

    glUseProgram(g_shaderProgramID[0]); // use the shaders associated with the shader program

    glBindVertexArray(g_VAO[0]);        // make VAO active

    // set uniform shader variables
    glm::mat4 MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_mm_torus;
    glUniformMatrix4fv(g_MVP_Index[0], 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(g_M_Index[0], 1, GL_FALSE, &g_mm_torus[0][0]);

    glUniform3fv(g_viewPointIndex[0], 1, &g_camera.getPosition()[0]);
    glUniform4fv(g_lightPositionIndex[0], 1, &g_lightProperties.position[0]);
    glUniform4fv(g_lightAmbientIndex[0], 1, &g_lightProperties.ambient[0]);
    glUniform4fv(g_lightDiffuseIndex[0], 1, &g_lightProperties.diffuse[0]);
    glUniform4fv(g_lightSpecularIndex[0], 1, &g_lightProperties.specular[0]);
    glUniform1fv(g_lightShininessIndex[0], 1, &g_lightProperties.shininess);

    glUniform4fv(g_materialAmbientIndex[0], 1, &g_materialProperties.ambient[0]);
    glUniform4fv(g_materialDiffuseIndex[0], 1, &g_materialProperties.diffuse[0]);
    glUniform4fv(g_materialSpecularIndex[0], 1, &g_materialProperties.specular[0]);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, g_textureID[0]);
    glUniform1i(g_envMapSamplerIndex, 0);

    glDrawElements(GL_TRIANGLES, g_numberOfFaces * 3, GL_UNSIGNED_INT, 0);  // display the vertices based on their indices and primitive type

    glUseProgram(g_shaderProgramID[1]); // use the shaders associated with the shader program

    glBindVertexArray(g_VAO[1]);        // make VAO active

    // set uniform shader variables
    glClear(GL_DEPTH_BUFFER_BIT);
    MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_mm_wall;
    glUniformMatrix4fv(g_MVP_Index[1], 1, GL_FALSE, &MVP[0][0]);
    glUniformMatrix4fv(g_M_Index[1], 1, GL_FALSE, &g_mm_wall[0][0]);

    glUniform3fv(g_viewPointIndex[1], 1, &g_camera.getPosition()[0]);
    glUniform4fv(g_lightPositionIndex[1], 1, &g_lightProperties.position[0]);
    glUniform4fv(g_lightAmbientIndex[1], 1, &g_lightProperties.ambient[0]);
    glUniform4fv(g_lightDiffuseIndex[1], 1, &g_lightProperties.diffuse[0]);
    glUniform4fv(g_lightSpecularIndex[1], 1, &g_lightProperties.specular[0]);
    glUniform1fv(g_lightShininessIndex[1], 1, &g_lightProperties.shininess);

    glUniform4fv(g_materialAmbientIndex[1], 1, &g_materialProperties.ambient[0]);
    glUniform4fv(g_materialDiffuseIndex[1], 1, &g_materialProperties.diffuse[0]);
    glUniform4fv(g_materialSpecularIndex[1], 1, &g_materialProperties.specular[0]);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, g_textureID[6]);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, g_textureID[7]);

    glUniform1i(g_texSamplerIndex, 1);
    glUniform1i(g_normalSamplerIndex, 2);

    glDrawArrays(GL_TRIANGLES, 0, 36);

    glFlush();  // flush the pipeline
}

圆环的顶点着色器:

#version 330 core

// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aNormal;

// uniform input data
uniform mat4 uModelViewProjectionMatrix;
uniform mat4 uModelMatrix;

// output data (will be interpolated for each fragment)
out vec3 vNormal;
out vec3 vPosition;

void main()
{
    // set vertex position
    gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);

    // world space
    vPosition = (uModelMatrix * vec4(aPosition, 1.0)).xyz;
    vNormal = (uModelMatrix * vec4(aNormal, 0.0)).xyz;
}

圆环的片段着色器:

#version 330 core

// interpolated values from the vertex shaders
in vec3 vNormal;
in vec3 vPosition;

// uniform input data
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
};

struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

uniform LightProperties uLightingProperties;
uniform MaterialProperties uMaterialProperties;
uniform vec3 uViewPoint;

uniform samplerCube uEnvironmentMap;

// output data
out vec3 fColor;

void main()
{
    vec3 N = normalize(vNormal);
    vec3 L;

    // determine whether the light is a point light source or directional light
    if(uLightingProperties.position.w == 0.0f)
        L = normalize((uLightingProperties.position).xyz);
    else
        L = normalize((uLightingProperties.position).xyz - vPosition);

    vec3 V = normalize(uViewPoint - vPosition);
    vec3 R = reflect(-L, N);

    // calculate the ambient, diffuse and specular components
    vec4 ambient = uLightingProperties.ambient * uMaterialProperties.ambient;
    vec4 diffuse = uLightingProperties.diffuse * uMaterialProperties.diffuse * max(dot(L, N), 0.0);
    vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);

    if(dot(L, N) > 0.0f)
    {
        specular = uLightingProperties.specular * uMaterialProperties.specular 
            * pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
    }

    vec3 reflectEnvMap = reflect(-V, N);

    // set output color
    fColor = texture(uEnvironmentMap, reflectEnvMap).rgb;

    fColor *= (diffuse + specular + ambient).rgb;   
}

墙的顶点着色器:

#version 330 core

// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aNormal;
in vec3 aTangent;
in vec2 aTexCoord;

// uniform input data
uniform mat4 uModelViewProjectionMatrix;
uniform mat4 uModelMatrix;

// output data (will be interpolated for each fragment)
out vec3 vPosition;
out vec3 vNormal;
out vec3 vTangent;
out vec2 vTexCoord;

void main()
{
    // set vertex position
    gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);

    // world space
    vPosition = (uModelMatrix * vec4(aPosition, 1.0)).xyz;
    vNormal = (uModelMatrix * vec4(aNormal, 0.0)).xyz;
    vTangent = (uModelMatrix * vec4(aTangent, 0.0)).xyz;
    vTexCoord = aTexCoord;
}

墙的片段着色器:

#version 330 core

// interpolated values from the vertex shaders
in vec3 vPosition;
in vec3 vNormal;
in vec3 vTangent;
in vec2 vTexCoord;

// uniform input data
struct LightProperties
{
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    float shininess;
};

struct MaterialProperties
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
};

uniform LightProperties uLightingProperties;
uniform MaterialProperties uMaterialProperties;
uniform vec3 uViewPoint;

uniform sampler2D uTextureSampler;
uniform sampler2D uNormalSampler;

// output data
out vec3 fColor;

void main()
{
    // calculate normal map vectors
    vec3 normal = normalize(vNormal);
    vec3 tangent = normalize(vTangent);
    vec3 biTangent = normalize(cross(tangent, normal));

    vec3 normalMap = 2.0f * texture(uNormalSampler, vTexCoord).xyz - 1.0f;

    // calculate vectors for lighting
    vec3 N = normalize(mat3(tangent, biTangent, normal) * normalMap);
    vec3 L;

    // determine whether the light is a point light source or directional light
    if(uLightingProperties.position.w == 0.0f)
        L = normalize((uLightingProperties.position).xyz);
    else
        L = normalize((uLightingProperties.position).xyz - vPosition);

    vec3 V = normalize(uViewPoint - vPosition);
    vec3 R = reflect(-L, N);

    // calculate Phong lighting
    vec4 ambient = uLightingProperties.ambient * uMaterialProperties.ambient;
    vec4 diffuse = uLightingProperties.diffuse * uMaterialProperties.diffuse * max(dot(L, N), 0.0);
    vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);

    if(dot(L, N) > 0.0f)
    {
        specular = uLightingProperties.specular * uMaterialProperties.specular 
            * pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
    }

    // set output color
    fColor = (diffuse + specular + ambient).rgb;    
    fColor *= texture(uTextureSampler, vTexCoord).rgb;
}

PS:对不起,如果我昨天的问题有点太不负责任了。有些建议我就是看不懂所以没有回复。

最佳答案

当您绘制第二部分(墙)时,您会将纹理绑定(bind)到纹理单元 GL_TEXTURE1GL_TEXTURE2:

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, g_textureID[6]);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, g_textureID[7]);

但是您将纹理单元索引 0 和 1 设置为纹理采样器制服 uTextureSampleruNormalSampler:

glUniform1i(g_texSamplerIndex, 0);
glUniform1i(g_normalSamplerIndex, 1);`

像这样调整你的代码:

glUniform1i(g_texSamplerIndex, 1);    // GL_TEXTURE1
glUniform1i(g_normalSamplerIndex, 2); // GL_TEXTURE2


"aTexCoord" 的属性索引存储到 texCoordIndex[i] for g_shaderProgramID[i]:

for (int i = 0; i < 2; i++)
{
    ....
    texCoordIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aTexCoord");
    ..... 
}

设置顶点属性指针和启用顶点属性时必须注意这一点

改变这个:

glVertexAttribPointer(texCoordIndex[0], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));
.....
glEnableVertexAttribArray(texCoordIndex[0]);

对此:

glVertexAttribPointer(texCoordIndex[1], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));
.....
glEnableVertexAttribArray(texCoordIndex[1]);

关于c++ - OPENGL 如何正确渲染这两个具有不同纹理/贴图的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45784493/

相关文章:

c++ - 为什么建议使用多个像素缓冲区对象。肯定是多余的?

c++ - C++ 中的迭代 BST 插入

c++ - C++ 中的宏问题

c# - 无法检查用户是否已存在于我的数据库中

visual-studio - 为什么即使更改依赖项也不会构建 CMake 自定义目标

c - 使用 memset 初始化三值结构数组

c - OpenGL没有纹理

c++ - dynamic_cast 中的类型必须是指向完整类类型的指针或引用,或者 void *

c++ - 如何为进度条保留数据

macos - 如何在azure中访问我的项目的文件