我画了一个盒子。我添加了处理 vao 和 vbo 的基本类。
class BasicObject_V2
{
public:
BasicObject_V2(GLuint typeOfPrimitives = 0){
this->typeOfPrimitives = typeOfPrimitives;
switch (this->typeOfPrimitives){
case GL_QUADS: numVertsPerPrimitive = 4; break;
}}
void allocateMemory(){
glGenVertexArrays(1, &vaoID);
glBindVertexArray(vaoID);
glGenBuffers(1, &vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertexAttributes), &vertices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 48, (const void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 48, (const void*)12);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 48, (const void*)24);
glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 48, (const void*)40);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
}
GLuint vboID;
GLuint vaoID;
GLuint typeOfPrimitives;
GLuint numVertsPerPrimitive;
int getNumberOfVertices(){
return vertices.size();
}
struct vertexAttributes{
glm::vec3 pos;
glm::vec3 normal;
glm::vec4 color;
glm::vec2 texCoord;
};
std::vector<vertexAttributes> vertices;
};
Run Code Online (Sandbox Code Playgroud)
这是我的 Box 类。
class Box_V2 : public BasicObject_V2 {
public:
Box_V2(float width = 1, float height = 1, float length = 1) : BasicObject_V2(GL_QUADS) {
float wHalf = width / 2.0f;
float hHalf = height / 2.0f;
float lHalf = length / 2.0f;
vertexAttributes va;
glm::vec3 corners[8];
corners[0] = glm::vec3(-wHalf, -hHalf, lHalf);
corners[1] = (...)
glm::vec3 normals[6];
normals[0] = glm::vec3(0, 0, 1); // front
//(...)
// FRONT
va.pos = corners[0];
va.normal = normals[0];
va.texCoord = glm::vec2(0.0, 0.0);
vertices.push_back(va);
//...
allocateMemory();
}
};
Run Code Online (Sandbox Code Playgroud)
我还为其设置了纹理(根据 opengl superible 示例),但它确实有效。
static GLubyte checkImage[128][128][4];
void makeCheckImage(void)
{
int i, j, c;
for (i = 0; i<128; i++) {
for (j = 0; j<128; j++) {
c = ((((i & 0x8) == 0) ^ ((j & 0x8)) == 0)) * 255;
checkImage[i][j][0] = (GLubyte)c;
checkImage[i][j][1] = (GLubyte)c;
checkImage[i][j][2] = (GLubyte)c;
checkImage[i][j][3] = (GLubyte)255;
}}}
void init(){
glClearColor(0.7, 0.4, 0.6, 1);
//Create a Texture
makeCheckImage();
//Texure
glGenTextures(4, tex);
//glCreateTextures(GL_TEXTURE_2D, 4, tex);//4.5
glTextureStorage2D(tex[0], 0, GL_RGBA32F, 2, 2);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGBA, GL_FLOAT, checkImage);
//glTextureSubImage2D(tex[0], 0, 0, 0, 2, 2, GL_RGBA, GL_FLOAT, checkImage);//4.5
//load the shader
programID = loadShaders("vertex.vsh", "fragment.fsh");
glUseProgram(programID);
//create a box
box_v2 = new Box_V2();
glBindTexture(GL_TEXTURE_2D, tex[0]);
}}
void drawing(BasicObject* object){
glBindVertexArray(object->vaoID);
glDrawArrays(object->typeOfPrimitives, 0, object->getNumberOfVertices() * object->numVertsPerPrimitive);
glBindVertexArray(0);
}
Run Code Online (Sandbox Code Playgroud)
这是我的着色器:VS:
#version 450 core
layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec4 color;
layout(location = 3) in vec2 texCoord;
uniform mat4 rotate;(...)
out vec4 v_normal;
out vec4 v_color;
out vec4 v_pos;
out vec2 v_texCoord;
void main(){
v_normal = rotate*vec4(normal,1);//*model;
v_color=color;
v_texCoord=texCoord;
gl_Position = rotate*scale*trans*vec4(pos.xyz, 1);
}
Run Code Online (Sandbox Code Playgroud)
还有FS:
#version 450 core
in vec4 v_color;
in vec2 v_texCoord;
uniform sampler2D ourTexture;
out vec4 outColor;
void main(){
//outColor=texelFetch(ourTexture, ivec2(gl_FragCoord.xy), 0); //4.5
outColor=texture(ourTexture,v_texCoord*vec2(3.0, 1.0));
}
Run Code Online (Sandbox Code Playgroud)
现在它绘制了一个黑色的盒子,上面没有任何纹理。我是 OpenGL 新手,我找不到问题出在哪里。
您的代码有很多问题。看起来你试图以一种方式编写它,然后尝试以另一种方式编写它,导致某种弗兰肯斯坦的代码,它实际上不是一种方式或另一种方式。
glGenTextures(4, tex);
//glCreateTextures(GL_TEXTURE_2D, 4, tex);//4.5
glTextureStorage2D(tex[0], 0, GL_RGBA32F, 2, 2);
Run Code Online (Sandbox Code Playgroud)
这是一个完美的例子。您使用非 DSAglGenTextures呼叫,但您立即转身并使用DSA glTextureStorage2D呼叫就可以了。你不能这样做。为什么?因为tex[0]还没有创建。
glGenTextures只分配纹理的名称,而不分配其状态数据。只有绑定纹理才能获取内容。这就是 DSA 引入这些glCreate*功能的原因;他们为对象分配名称和状态。这也是为什么glCreateTextures要设定一个目标;该目标是纹理对象状态的一部分。
简而言之,注释掉的调用始终是正确的。查看编写的代码,glTextureStorage2D调用失败并出现 OpenGL 错误(仅供参考:打开 KHR_debug 以查看何时发生错误)。
那么,让我们看看如果我们去掉失败的部分,您的代码会是什么样子:
glGenTextures(4, tex);
glBindTexture(GL_TEXTURE_2D, tex[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGBA, GL_FLOAT, checkImage);
Run Code Online (Sandbox Code Playgroud)
这里有两个问题。首先,正如 BDL 提到的,您的数据描述不正确。你正在传递GLubytes,但你告诉 OpenGL 你正在传递GLfloats。不要对 OpenGL 撒谎。
其次,有内部格式。因为您使用了未调整大小的内部格式(并且因为您不在 OpenGL ES 领域),所以您的实现选择的格式将是unsigned normalized。它不会是 32 位浮点格式。如果您想要其中之一,则必须明确要求,并使用GL_RGBA32F.
此外,因为您为纹理分配了可变存储(即:因为glTextureStorage2D失败),所以现在遇到了问题。您只分配了一层 mipmap 级别,但默认过滤模式将尝试从多个 mipmap 中获取。并且您永远不会将纹理的mipmap 范围设置为仅从第一个开始采样。所以你的纹理不完整。不可变的存储纹理将使 mipmap 范围与您分配的范围相匹配,但可变的存储纹理就不太好了。
创建可变存储纹理时,您应该始终设置 mipmap 范围:
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE2D, GL_TEXTURE_MAX_LEVEL, 0); //It's a closed range.
Run Code Online (Sandbox Code Playgroud)
最后,您将纹理绑定到单元 0 进行渲染(主要是偶然的,因为您从未调用过glActiveTexture)。但你不必费心通过将ourTexture统一值设置为 0 来通知你的着色器。