GLSL索引绘图并设置纹理案例
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GLSL索引绘图并设置纹理案例相关的知识,希望对你有一定的参考价值。
参考技术A索引绘图就是将图形中肉眼可见的定点,通过索引的方式建立定点之间的连接,绘制过程中将顶点重复利用
案例效果
本文主要讲解绘制图形相关, 自定义着色器及着色器的加载
一、 准备工作
二、 绘制
顶点数据的创建及传递流程如下:
构建矩阵
1、获取顶点着色器中uniform修饰的投影矩阵、模型视图矩阵的入口,方便后续将对应矩阵传入顶点着色器中,入口的获取与attribute入口获取类似,其中的name都需要与着色器中一模一样
2、获取屏幕的纵横比,用于设置透视投影
3、创建投影矩阵
索引绘图
glDrawElements方法的mode参数:设置要呈现的画图的模式
完整demo
在以上内容的基础上,做如下操作
setupTexture函数
主要是将png/jpg图片解压成位图,然后进行绑定、加载
设置纹理demo
GLSL 纹理函数只为天空盒返回黑色
【中文标题】GLSL 纹理函数只为天空盒返回黑色【英文标题】:GLSL Texture Function Returning Only Black For Sky Box 【发布时间】:2015-05-04 00:50:46 【问题描述】:我正在尝试通过使用 GLSL 对四边形进行纹理化来为我的 OpenGL 场景生成天空盒。但是,当我尝试使用纹理生成天空盒颜色时,天空盒会变成黑色。天空框在我手动设置颜色时起作用,所以我基本上将问题缩小到我设置纹理的方式有问题。我还为纹理函数处理了一堆不同的 eyeDirection 向量值,但我仍然只得到一个黑色方块。
这是我的片段着色器:
#version 450 compatibility
layout(binding=0) uniform samplerCube currTexture;
smooth in vec3 eyeDirection;
out vec4 fragmentColor;
void main()
fragmentColor = texture(currTexture, eyeDirection);
//fragmentColor = vec4(eyeDirection, 1.0);
这是我的顶点着色器:
#version 450
uniform mat4 projection;
uniform mat4 modelView;
in vec4 aPosition;
smooth out vec3 eyeDirection;
void main()
mat3 inverseModelView = inverse(mat3(modelView));
vec3 unprojected = (inverse(projection) * aPosition).xyz;
eyeDirection = inverseModelView * unprojected;
// eyeDirection = aPosition.xyz;
//gl_Position = aPosition.xyww;
gl_Position = new vec4(aPosition.x, aPosition.y, 1.0, aPosition.w );
这里是我初始化纹理的地方:
// initializes all the necessary texture values
void TrainView::initTextures()
// loading in texture maps
SDL_Surface* xPos = IMG_Load("SkyBoxXpos.png");
SDL_Surface* xNeg = IMG_Load("SkyBoxXneg.png");
SDL_Surface* yPos = IMG_Load("SkyBoxYpos.png");
SDL_Surface* yNeg = IMG_Load("SkyBoxYneg.png");
SDL_Surface* zPos = IMG_Load("SkyBoxZpos.png");
SDL_Surface* zNeg = IMG_Load("SkyBoxZneg.png");
if (!xPos)
printf("IMG_Load: %s\n", IMG_GetError());
if (!xNeg)
printf("IMG_Load: %s\n", IMG_GetError());
if (!yPos)
printf("IMG_Load: %s\n", IMG_GetError());
if (!yNeg)
printf("IMG_Load: %s\n", IMG_GetError());
if (!zPos)
printf("IMG_Load: %s\n", IMG_GetError());
if (!zNeg)
printf("IMG_Load: %s\n", IMG_GetError());
// handle error
glGenTextures(1, &skyBoxTexture);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyBoxTexture);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
// files are 24-bit bmp files
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, xPos->w, xPos->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, xPos->pixels);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, xNeg->w, xNeg->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, xNeg->pixels);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, yPos->w, yPos->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, yPos->pixels);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, yNeg->w, yNeg->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, yNeg->pixels);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, zPos->w, zPos->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, zPos->pixels);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, zNeg->w, zNeg->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, zNeg->pixels);
glBindTexture(GL_TEXTURE_CUBE_MAP, NULL);
这是我尝试绘制/渲染天空盒的地方:
// handles everything for drawing the sky box
void TrainView::drawSkyBox()
glUseProgram(skyBoxShader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyBoxTexture);
int loc = glGetUniformLocation(skyBoxShader, "modelView");
GLfloat mvFl[16], projFl[16];
glGetFloatv(GL_MODELVIEW_MATRIX, mvFl);
glUniformMatrix4fv(loc, 1, GL_FALSE, mvFl);
loc = glGetUniformLocation(skyBoxShader, "projection");
glGetFloatv(GL_PROJECTION_MATRIX, projFl);
glUniformMatrix4fv(loc, 1, GL_FALSE, projFl);
loc = glGetUniformLocation(skyBoxTexture, "currTexture");
glUniform1i(loc, 0);
// not sure if this is necessary or done as intended by opengl
GLuint sampler;
glGenSamplers(1, &sampler);
glBindSampler(0, sampler);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
glVertex3f(-1.0, -1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glVertex3f(1.0, 1.0, 0.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd();
glUseProgram(NULL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
【问题讨论】:
您正在设置纹理参数以使用 mipmap 进行采样,但您没有生成 mipmap。你可能想要一个glGenerateMipmap()
在那里。您尝试添加的采样器对象可能弊大于利。
Reto 你说的完全正确,谢谢一百万!
【参考方案1】:
您在此处为立方体纹理启用 mipmaped 采样:
glTexParameteri(GL_TEXTURE_CUBE_MAP,
GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
但是,您并没有为纹理创建 mipmap。在规范语言中,这意味着您的纹理不是“mipmap 完整”,这反过来又使其不是“纹理完整”。对不完整纹理进行采样的结果是BLACK。
创建 mipmap 最简单的方法是调用 glGenerateMipmap()
在指定纹理数据之后,即在所有 glTexImage2D()
调用 6 面之后:
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
如果你不需要mipmaps,你可以简单地设置filter参数的值不使用mipmaps:
glTexParameteri(GL_TEXTURE_CUBE_MAP,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
您尝试创建采样器对象的操作在这里没有帮助。如果您想用多个不同的采样属性对相同的纹理进行采样,采样器对象非常有用。假设您想在同一着色器中使用GL_LINEAR
和GL_NEAREST
对同一纹理进行采样,您可以通过为此纹理创建两个采样器对象来实现。我不认为这是一个很常见的用例,但在某些情况下它会派上用场,而且在引入采样器对象之前是不可能做到的。
【讨论】:
感谢您的深入解释。 mipmap 是不必要的,所以我最终摆脱了它。现在,天空盒一切正常。以上是关于GLSL索引绘图并设置纹理案例的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL和GLSL中的glTexParameter和过滤?