现代 OpenGL,在对象上获得白色纹理

Posted

技术标签:

【中文标题】现代 OpenGL,在对象上获得白色纹理【英文标题】:Modern OpenGL , getting a white texture on an object 【发布时间】:2018-02-22 15:07:30 【问题描述】:

我正在尝试将纹理加载到现代 NVIDIA openGL 中的对象

我有一个要加载纹理的正方形,我使用 stb_image 作为我的加载器

这里是主要代码:

float position1[16]
    0.0f , 0.0f, 0.0f , 0.0f,
    0.8f , 0.0f, 1.0f , 0.0f,
    0.0f , 0.8f, 0.0f , 1.0f,
    0.8f , 0.8f, 1.0f , 1.0f ,
;

unsigned int Indexs[6]
    0 , 1 , 2 ,
    2 , 1 , 3

;
VertexBuffer buffer(position1, sizeof(position1));
IndexBuffer Index(Indexs, 6);
Texture Tex("Smile.png");
Tex.Bind();
buffer.Bind();
Index.Bind();
Shader BasicShader("basic.shader");

Renderer renderer; 
glfwSwapInterval(0);


//! MAIN LOOP !!!


BasicShader.Uniform1i("u_Texture ", 0);
BasicShader.Uniform4f("u_Color", 0.0f, 1.0f, 1.0f, 1.0f );
while (!glfwWindowShouldClose(window) )


    //! RENDER
    renderer.Clear();
    glEnable(GL_TEXTURE_2D);
    BasicShader.Uniform1i("u_Texture ", 0);
    BasicShader.Uniform4f("u_Color", 0.f, 1.0f, 1.0f, 1.0f);
    Tex.Bind();
    BasicShader.Bind();
    renderer.Draw(buffer, Index, Layout::D4Vertex, BasicShader);



    //! FRAME

    glfwSwapBuffers(window);

    //! EVENTS
    glfwPollEvents();


glfwTerminate();
return 0;
;

这是我的着色器,它当然是按预期正确编译的,没有错误:

#shader vertex
#version 410 core

layout(location = 0 ) in vec4 position;
layout(location = 1) in vec2 texCoord;

out vec2  v_TexCoord;

void main()

    gl_Position = position;
    v_TexCoord = texCoord;
;


#shader fragment
#version 410 core

layout(location = 0 ) out vec4 color;

uniform vec4 u_Color;
uniform sampler2D u_Texture;

in vec2 v_TexCoord;

void main()

    vec4 texColor = texture2D(u_Texture, v_TexCoord);
    color = texColor;
;

这是我的绘图调用:

void Renderer::Draw(VertexBuffer& vb,  IndexBuffer& iv, 
                    Layout layout,Shader& shader) 

    BufferLayout bufferLayout;
    shader.Bind();
    vb.Bind();
    iv.Bind();
    bufferLayout.SetLayout(layout);
    glDrawElements(GL_TRIANGLES, iv.GetCount(), GL_UNSIGNED_INT, nullptr);

这就是我设置缓冲区布局的方式:

void BufferLayout::SetLayout(Layout l)

    switch (l) 
        case Layout::NONE :
            glEnableVertexAttribArray(0);
        case Layout::D2Vertex :
            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 
         2,0);
        case Layout::D4Vertex:
            glEnableVertexAttribArray(0);
            glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 
        4,0);
    

这是我的纹理类(处理加载参数和绑定):

#include "Texture.h"
#include "stb_image.h";
#include "Renderer.h"

Texture::Texture(string  path)
    : m_RendererID(0) , m_BPP(0) , m_Height (0) , m_Width (0), 
      m_LocalBuffer(nullptr) , m_FilePath(path)

    stbi_set_flip_vertically_on_load(1);
    m_LocalBuffer = stbi_load(path.c_str(), &m_Width, &m_Height, &m_BPP, 4);
    //seems like the image is there
    glEnable(GL_TEXTURE_2D);

    glGenTextures(1, & m_RendererID);
    glBindTexture(GL_TEXTURE_2D, m_RendererID);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    GLenum temp = glGetError();
    if (temp != GL_NO_ERROR)  throw std::invalid_argument("OPENGL ERROR");
    // I Get  no erros
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, 
                 GL_UNSIGNED_BYTE, m_LocalBuffer);


Texture::~Texture()

    glDeleteTextures(1, &m_RendererID);


void Texture::Bind(unsigned int slot)

    glActiveTexture(GL_TEXTURE0 + slot);
    glBindTexture(GL_TEXTURE_2D, m_RendererID); 


void Texture::Unbind()

    glBindTexture(GL_TEXTURE_2D, 0);

还有我的 texture.h 文件:

#pragma once
#include "Renderer.h"

class Texture 
    private :
    unsigned int  m_RendererID;
    string m_FilePath;
    unsigned char * m_LocalBuffer;
    int m_Width, m_Height, m_BPP;

    public:
    Texture(string  path);
    ~Texture();

    void Bind(unsigned int slot = 0);
    void Unbind();

    inline int GetWidth()const  return m_Width; 
    inline int GetHeight()const  return m_Height; 

;

基本上我很确定问题一定出在我发布的代码中,并且所有其他代码都按预期工作。

谁能发现问题? 结果应该是一个带有纹理“Smile.png”的正方形,我得到一个白色纹理。我的项目目录中确实有文件“Smile.png”,在我看来,stb_image 可以找到并加载它。

*glGetError(); 没有错误

【问题讨论】:

我必须承认,很难在 OpenGL 上制作一个 small MCVE。但是,您至少可以正确格式化您的代码... 我没有看到任何将数据绑定到texCoord 属性的代码。 @BDL case Layout::D4Vertex: glEnableVertexAttribArray(0); glVertexAttribPointer(0,2,GL_FLOAT , GL_FALSE , sizeof(float)*4 , 0); 应该这样做......对吗?这段代码在渲染器中调用到 BufferLayout 类 这是属性 0 的设置。您缺少属性 1 的类似代码。 @BDL 谢谢! :) 你能用一个例子来做一个完整的答案吗?因为我不完全理解如何做到这一点...... 【参考方案1】:

在代码示例中,缺少属性 1 (texCoord) 的设置代码。对于着色器使用的每个属性,必须绑定一个缓冲区,必须启用该属性,并且必须指定属性和着色器之间的关系。

如前所述,这是针对属性 0 而不是针对属性 1。SetLayout 方法中的代码可能看起来像这样:

//Attribute 0: uses first two floats
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);

//Attribute 1: uses 3rd and 4th float
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void*)(2 * sizeof(float)));

【讨论】:

嗯,它不起作用,我将数组 position1 放入缓冲区中,您可以在问题顶部看到。前两个浮点数是顶点线,后两个浮点数是纹理线,依此类推在蚀刻线中……你确定这是我需要读取这个数组的缓冲区布局吗?我真的不明白这是如何工作的......但我得到了一个黑屏形式的布局。 是的,我 100% 确定这是您的布局所需要的。每个顶点的大小为4 * sizeof(float),uv 坐标在位置之后存储2 * sizeof(float) 字节。您的代码中可能还有更多问题,但老实说,在您修复格式问题之前,我拒绝再调试它。 另外:由于我们没有更改与属性 0 相关的任何内容,因此位置根本不应该更改。您确定您从纹理输出的颜色不仅仅是黑色吗? 忘记我说的对不起忘记复制一行,你解决了问题!谢谢你,我诚实地调试了两天。纹理现在正在屏幕上加载

以上是关于现代 OpenGL,在对象上获得白色纹理的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES 1.1 - alpha 蒙版

尝试在大位图上使用 OpenGL 纹理压缩 - 得到白色方块

纹理不填充图形 - OpenGL

如何在OpenGL中将像素作为纹理绘制到多边形?

使用现代 OpenGL 渲染纹理

OpenGL渲染白色纹理错误