带有 VBO 的 OpenGL 多重纹理

发布于 2024-10-16 12:17:19 字数 3351 浏览 1 评论 0原文

我试图弄清楚如何为每个面渲染具有不同纹理的对象(立方体)。为了简单起见,我有 2 个纹理,分别应用于立方体的 3 个面。我知道我应该使用具有 3 个坐标的纹理数组来表示要使用的相关纹理。我只是不确定如何做到这一点以及如何编写我的片段着色器。

这是我的 init() 函数的相关部分:

final String textureName = model.getTextures().get(i).textureName;
final FileTexture textureGenerator = new FileTexture(this.getClass().getResourceAsStream(textureName),
                true, context);
textureId = textureGenerator.getTextureId();
width = textureGenerator.getWidth();
height = textureGenerator.getHeight();
textureMap.put(model.getTextures().get(i).matName, textureId);
context.getGL().glActiveTexture(GL.GL_TEXTURE0 + i);
context.getGL().glBindTexture(GL.GL_TEXTURE_2D, textureId);

但是,我在这里有点困惑,因为 Orange Book(OpenGL 着色语言)给出了示例,其中 glActiveTextureglBindTexture 已使用,但 GLSL 常见错误 表示您不应该这样做。

从那里,我的 display() 函数如下所示:

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getVertexBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 3 * 4, getVertices(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getTexCoordBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 2 * 4, getTexCoords(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, getIndicesBufferObject());
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, getNoOfIndices() * 4, getIndices(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getColorBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 4 * 4, getColors(), GL.GL_STREAM_DRAW);

layerTextureShader.use(gl);

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getVertexBufferObject());
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);

gl.glEnableClientState(GL.GL_COLOR_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, mask ? getMaskColorBufferObject() : getColorBufferObject());
gl.glColorPointer(4, GL.GL_FLOAT, 0, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE0);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(3, GL.GL_FLOAT, 0, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE1);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(3, GL.GL_FLOAT, 0, 0);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, getIndicesBufferObject());

final int count = getNoOfIndices();
gl.glDrawElements(GL.GL_TRIANGLES, count, GL.GL_UNSIGNED_INT, 0);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE0);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

gl.glClientActiveTexture(GL.GL_TEXTURE1);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL.GL_COLOR_ARRAY);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

layerTextureShader.release(gl);

我不确定要在我的 GLSL 着色器中放入什么。我的顶点着色器具有标准的 gl_TexCoord[0] = gl_MultiTexCoord0; 并且我的片段着色器如下所示:

uniform sampler2D texture;

void main()
{
    gl_FragColor = texture2D(texture, gl_TexCoord[0].st);
} 

How do I instruct thefragment Shader on which texture to use?我假设是在填充顶点、索引、纹理缓冲区等时,我通过为每个点传递第三个纹理坐标来实现这一点?这个第三个坐标的值是相关纹理坐标的值吗? 我希望我的问题有意义并感谢您的帮助。 克里斯

I'm trying to figure out how to render an object (a cube) with different textures for each face. For simplicities sake, I have 2 textures that are applied to 3 faces of the cube each. I understand that I should be using texture arrays with 3 coordinates to represent the relevant texture to be used. I'm just unsure of how to do this and how to code my fragment shader.

Here is the relevant part of my init() function:

final String textureName = model.getTextures().get(i).textureName;
final FileTexture textureGenerator = new FileTexture(this.getClass().getResourceAsStream(textureName),
                true, context);
textureId = textureGenerator.getTextureId();
width = textureGenerator.getWidth();
height = textureGenerator.getHeight();
textureMap.put(model.getTextures().get(i).matName, textureId);
context.getGL().glActiveTexture(GL.GL_TEXTURE0 + i);
context.getGL().glBindTexture(GL.GL_TEXTURE_2D, textureId);

I am slightly confused here however because the Orange Book (OpenGL Shading Language) gives examples in which the glActiveTexture and glBindTexture is used but the GLSL common mistakes says you shouldn't do this.

From there, my display() function looks like this:

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getVertexBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 3 * 4, getVertices(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getTexCoordBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 2 * 4, getTexCoords(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, getIndicesBufferObject());
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, getNoOfIndices() * 4, getIndices(), GL.GL_STREAM_DRAW);

gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getColorBufferObject());
gl.glBufferData(GL.GL_ARRAY_BUFFER, getNoOfVertices() * 4 * 4, getColors(), GL.GL_STREAM_DRAW);

layerTextureShader.use(gl);

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getVertexBufferObject());
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);

gl.glEnableClientState(GL.GL_COLOR_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, mask ? getMaskColorBufferObject() : getColorBufferObject());
gl.glColorPointer(4, GL.GL_FLOAT, 0, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE0);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(3, GL.GL_FLOAT, 0, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE1);
gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(3, GL.GL_FLOAT, 0, 0);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, getIndicesBufferObject());

final int count = getNoOfIndices();
gl.glDrawElements(GL.GL_TRIANGLES, count, GL.GL_UNSIGNED_INT, 0);

gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);

gl.glClientActiveTexture(GL.GL_TEXTURE0);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

gl.glClientActiveTexture(GL.GL_TEXTURE1);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL.GL_COLOR_ARRAY);
gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);

layerTextureShader.release(gl);

I am unsure of what to put in my GLSL shaders. My vertex shader has the standard gl_TexCoord[0] = gl_MultiTexCoord0; and my fragment shader looks like:

uniform sampler2D texture;

void main()
{
    gl_FragColor = texture2D(texture, gl_TexCoord[0].st);
} 

How do I instruct the fragment shader on which texture to use? I assume it's when I'm populating the vertex, index, textures buffers etc and I do it by passing in this 3rd texture coordinate for each point? Is the value of this 3rd coordinate the value of the relevant texture coordinate?
I hope my question makes sense and thanks for any help.
Chris

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌辣 2024-10-23 12:17:19

您正在寻找的是立方体贴图。在 OpenGL 中,您可以一次定义六个纹理(代表立方体的大小边)并使用 3D 纹理坐标而不是常见的 2D 纹理坐标来映射它们。对于简单的立方体,纹理坐标将与顶点各自的法线相同。 (如果您仅以这种方式对平面立方体进行纹理化,则也可以在顶点着色器中合并法线和纹理坐标!)立方体贴图比尝试同时绑定六个不同的纹理要简单得多,就像您现在所做的那样。

GLuint mHandle;
glGenTextures(1, &mHandle); // create your texture normally

// Note the target being used instead of GL_TEXTURE_2D!
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glBindTexture(GL_TEXTURE_CUBE_MAP, mHandle);

// Now, load in your six distinct images. They need to be the same dimensions!
// Notice the targets being specified: the six sides of the cube map.
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data1);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data2);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data3);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data4);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data5);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data6);

glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

// And of course, after you are all done using the textures...
glDeleteTextures(1, &mHandle);

现在,在执行着色器时,您需要顶点着色器接受和/或传递 3D 坐标 (vec3),而不是 2D 坐标 (vec2)。

// old GLSL style
attribute vec3 inTextureCoordinate;
varying vec3 vTextureCoordinate;

// more recent GLSL
in vec3 inTextureCoordinate;
out vec3 vTextureCoordinate;

在此示例中,您的顶点着色器将简单地指定 vTextureCooperative = inTextureCooperative。然后,您的片段着色器需要接受该纹理坐标并对立方体贴图统一进行采样。

uniform samplerCube cubeMap;
...
gl_FragColor = textureCube(cubeMap, vTextureCoordinate);

哇!那是很多。我遗漏了什么吗?

What you are looking for is a cube map. In OpenGL, you can define six textures at once (representing the size sides of a cube) and map them using 3D texture coordinates instead of the common 2D texture coordinates. For a simple cube, the texture coordinates would be the same as the vertices' respective normals. (If you will only be texturing plane cubes in this manner, you can consolidate normals and texture coordinates in your vertex shader, too!) Cube maps are much simpler than trying to bind six distinct textures simultaneously the way you are doing right now.

GLuint mHandle;
glGenTextures(1, &mHandle); // create your texture normally

// Note the target being used instead of GL_TEXTURE_2D!
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glBindTexture(GL_TEXTURE_CUBE_MAP, mHandle);

// Now, load in your six distinct images. They need to be the same dimensions!
// Notice the targets being specified: the six sides of the cube map.
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data1);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data2);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data3);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data4);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data5);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, width, height, 0,
    format, GL_UNSIGNED_BYTE, data6);

glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glTextParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

// And of course, after you are all done using the textures...
glDeleteTextures(1, &mHandle);

Now, when doing your shaders, you need the vertex shader to accept and/or pass 3D coordinates (vec3) instead of 2D coordinates (vec2).

// old GLSL style
attribute vec3 inTextureCoordinate;
varying vec3 vTextureCoordinate;

// more recent GLSL
in vec3 inTextureCoordinate;
out vec3 vTextureCoordinate;

In this example, your vertex shader would simply assign vTextureCoordinate = inTextureCoordinate. Your fragment shader then needs to accept that texture coordinate and sample the cube map uniform.

uniform samplerCube cubeMap;
...
gl_FragColor = textureCube(cubeMap, vTextureCoordinate);

Whew! That was a lot. Did I leave anything out?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文