opengl学习整理

来源:互联网 发布:上海租房网站 知乎 编辑:程序博客网 时间:2024/06/01 18:12

本人opengl学习是基于https://learnopengl-cn.github.io/,这是一个非常好的学习OpenGL网站。本人碰到的学习问题会一点一点记录在这个博客里,希望能对后来学习OpenGL的人提供一点微小的帮助。

1.纹理图片颠倒问题
opengl里所规定的纹理图片原点位于左下角,而图片团点位于上方,这就导致了,生成的纹理图片上下颠倒的情况,解决办法有以下几种:
——在shader源码中进行修改,用1减去纹理t坐标,或者将顶点y坐标翻转,即加个负号。

void main(){    gl_Position = vec4(aPos, 1.0);    ourColor = aColor;    TexCoord = vec2(aTexCoord.x,1-aTexCoor;}

——在顶点数据里进行修改,和shader修改相同,用1减去纹理t坐标
——如果使用stbi_image.h,可以调用stbi_set_flip_vertically_on_load(true);来使纹理图片颠倒。

2.两个纹理图片合成
两个纹理图片合成,是基于纹理单元。参考https://learnopengl-cn.github.io/01%20Getting%20started/06%20Textures/。但是在编译结果中没有出现合成效果,只有单一的一张纹理图片。最后发现问题出现在着色器源码上,着色器源码和主程序中纹理的标识符需要保持一致,否则默认只显示第一个激活的纹理单元,具体的原因暂不清楚,以后深入学习后再来考虑这个问题。

#version 330 coreout vec4 FragColor;in vec3 ourColor;in vec2 TexCoord;uniform sampler2D texture1;uniform sampler2D texture2;void main(){    FragColor = mix(texture(texture1, TexCoord), texture(texture2,TexCoord),0.2);}

主程序纹理定义:unsigned int texture1,texture2

3.glTexImage2D中第七个参数设置的问题
编译过程中当导入jpg格式的图片,将第七个参数设置为GL_RGBA就会出错,错位为未找到atioglxx.pdb,究其原因应该为rgba有四个参数,最后一位为透明度,和只有RGB的jpg不匹配。而png的第七个参数需要设置为rgba,否则图形显示会崩坏。
着色器里导入纹理texture默认为vec4,如果导入的是jpg图像,则只有三个分量,猜测着色器里的texture会自动补位。猜测缘由下面代码

    FragColor = vec4(vec3(texture(texture1, TexCoords)), 1.0);//这里是只获得RGB分量    FragColor = texture(texture1, TexCoords);//这里将所有分量直接赋给vec4的fragcolor

4.矩阵旋转平移变换
glm库提供了丰富的矩阵运算,可以使用glm::translate和glm::rotate设置平移和旋转的大小和角度。平移和旋转设置的先后顺序,结果完全不一样。

5.一个窗口多次绘制图形
在一个窗口绘制多个图形,只需要更新顶点数组后,重新绑定VAO,然后再调用glDrawElements或者glDrawArrays。例如:

        glm::mat4 trans;        trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));        trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));        unsigned int transformLoc = glGetUniformLocation(ourShader.ID, "transform");        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));        glBindVertexArray(VAO);        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED0_IT,0);        ----------------------------------------------        trans=glm::mat4();        trans = glm::translate(trans, glm::vec3(-0.5f, 0.5f, 0.0f));        float scaleAmount = sin(glfwGetTime());        trans = glm::scale(trans, glm::vec3(scaleAmount,scaleAmount,scaleAmount));        glUniformMatrix4fv(transformLoc, 1, GL_FALSE, &trans[0][0]);        glBindVertexArray(VAO);        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

结果是在窗口左上角和右下角各显示一个贴图图片。

6.顶点着色器源码中数据的位置和主程序里的要保持一致
否则就会出现,纹理和颜色紊乱的错误。

#version 330 corelayout (location = 0) in vec3 aPos;//layout (location = 1) in vec3 aColor;layout (location = 1) in vec2 aTexCoord;//out vec3 ourColor;out vec2 TexCoord;uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main(){    gl_Position = projection * view * model * vec4(aPos.x, aPos.y,aPos.z,1.0);    //ourColor = aColor;    TexCoord = vec2(aTexCoord.x,aTexCoord.y);}

上面为着色器源码,下面是主程序,数据里因为只有纹理坐标没有颜色坐标,因此需要修改location,或者关联的时候直接设置为2。

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,5 * sizeof(float), (void*)0);    glEnableVertexAttribArray(0);    //glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));    //glEnableVertexAttribArray(1);    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));    glEnableVertexAttribArray(1);

7.每次使用变换矩阵,需要考虑矩阵的更新问题。
以下程序里,一开始没有将model矩阵的初始化放入循环中,导致每次循环的时候model没有初始化,而都是基于上次循环的model进行计算,从而导致结果与理想结果大相径庭。

        for (unsigned int i = 0; i < 10; i++)        {            glm::mat4 model;            float angle = 20.0f*i;            model = glm::translate(model, cubePositions[i]);            model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));            ourShader.setMat4("model", model);            glDrawArrays(GL_TRIANGLES, 0, 36);        }

8.OpenGL中Vec向量的问题
编译OpenGL程序的时候,发现一个问题:vec3颜色向量=vec3颜色向量1 * vec3颜色向量2 。这里我们可以发现一个问题,两个列向量相乘不合理(默认OpenGL中的vec为列向量),而结果为颜色向量的r=r1*r2,g=g1*g2,b=b1*b2。这里推测是vec独有的特性,编译了测试程序结果显示:vec2,vec3,vec4都是如此,左值向量的分量等于右边相乘向量的分量各自相乘。
纹理数据为vec4,所以我们直接把纹理texture直接赋值给vec3型的变量会报错。

9.模板测试的理解
一开始我在纠结与glStencilMask的问题,其实只需要简单的理解为设置成0x00就是禁止模板缓冲输入,0xFF就是启用模板缓冲输入。粘贴一下glStencilFunc函数和glStencilOp函数,这两个函数决定了如何更新模板缓冲。

glStencilFunc(GLenum func, GLint ref, GLuint mask)一共包含三个参数:
——func:设置模板测试函数(Stencil Test Function)。这个测试函数将会应用到已储存的模板值上和glStencilFunc函数的ref值上。可用的选项有:GL_NEVER、GL_LESS、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、GL_NOTEQUAL和GL_ALWAYS。它们的语义和深度缓冲的函数类似。
——ref:设置了模板测试的参考值(Reference Value)。模板缓冲的内容将会与这个值进行比较。
——mask:设置一个掩码,它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1。

glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)一共包含三个选项,我们能够设定每个选项应该采取的行为:
——sfail:模板测试失败时采取的行为。
——dpfail:模板测试通过,但深度测试失败时采取的行为。
——dppass:模板测试和深度测试都通过时采取的行为。

原创粉丝点击