如何解决使用着色器绘制现代 OpenGL 球体
我正在尝试使用基本着色器绘制一个球体。但我无法绘制完整的球体。
球体计算
const float pi = 3.1414927f;
GLint layers = 100;
GLint circumferenceTiles = 100;
std::vector<float> va;
std::vector<int> ia;
// create the vertex attributes
va.reserve((layers + 1)* (circumferenceTiles + 1) * 5); // 5 floats: x,y,z,u,v
for (int il = 0; il <= layers; ++il)
{
float layer_rel = (float)il / (float)layers;
float layer_ang = (1.0f - 2.0f * layer_rel) * pi / 2.0f;
float layer_sin = std::sin(layer_ang);
float layer_cos = std::cos(layer_ang);
for (int ic = 0; ic <= circumferenceTiles; ic++)
{
float circum_rel = (float)ic / (float)circumferenceTiles;
float cricum_ang = circum_rel * 2.0f * pi - pi;
float circum_sin = std::sin(cricum_ang);
float circum_cos = std::cos(cricum_ang);
va.push_back(layer_cos * circum_cos); // x
va.push_back(layer_cos * circum_sin); // y
va.push_back(layer_sin); // z
va.push_back(circum_rel); // u
va.push_back(1.0f - layer_rel); // v
}
}
// create the face indices
ia.reserve(layers * circumferenceTiles * 6);
for (int il = 0; il < layers; ++il)
{
for (int ic = 0; ic < circumferenceTiles; ic++)
{
int i0 = il * (circumferenceTiles + 1) + ic;
int i1 = i0 + 1;
int i3 = i0 + circumferenceTiles + 1;
int i2 = i3 + 1;
int faces[]{ i0,i1,i2,i0,i3 };
ia.insert(ia.end(),faces + (il == 0 ? 3 : 0),faces + (il == layers - 1 ? 3 : 6));
}
}
绑定
// Vertex Array
gluint vao;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
// Vertex Buffer
gluint vbo;
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER,va.size() * sizeof(*va.data()),va.data(),GL_STATIC_DRAW);
// Index Buffer
gluint ibo;
glGenBuffers(1,&ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,ia.size() * sizeof(*ia.data()),ia.data(),GL_STATIC_DRAW);
gluint v_attr_inx = 0;
glVertexAttribPointer(v_attr_inx,3,GL_FLOAT,GL_FALSE,0);
glEnabLevertexAttribArray(v_attr_inx);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
绘图
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES,(GLsizei)ia.size(),GL_UNSIGNED_INT,0);
glBindVertexArray(0);
片段着色器
#version 330 core
// Interpolated values from the vertex shaders
in vec3 fragmentColor;
// Ouput data
layout(location = 0) out vec4 color;
uniform vec4 u_Color;
void main(){
// Output color = color specified in the vertex shader,// interpolated between all 3 surrounding vertices
color = u_Color;
}
顶点着色器
#version 330 core
// Input vertex data,different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
void main(){
// Output position of the vertex,in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
// The color of each vertex will be interpolated
// to produce the color of each fragment
fragmentColor = vertexColor;
}
我在这里做错了什么。是顶点的计算还是它的顺序。还是我的着色器有问题?愿意提供任何帮助。 提前致谢。
球体的种类:
解决方法
首先是一些小问题:
-
在着色器中输出着色器值应该是最后一行代码
所以在顶点线:
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
在片段中的行:
color = u_Color;
应该是最后一行代码(后面只跟着
main
函数的 } 终止)。这是一种安全措施,因为一些 GL 实现可能会优化它之后的任何代码!!! -
尽量忽略索引缓冲区,只将顶点渲染为点
通过这种方式,您可以快速确定问题是出在顶点和纹理坐标上,还是出在索引上。
现在的主要问题:
您在单个 VBO 中交错 x,y,z
和 u,v
,但我只看到单个 glVertexAttribPointer 调用。这意味着您将 2 个属性打包到单个 VBO 中,并告诉您的 OpenGL 中的一个。
此外,您传递给它的值与您的数据不匹配。当您没有设置步幅和每个顶点 3 个元素时。因此 OpenGL 不会为纹理设置任何 u,v
坐标,而是按如下方式传递顶点:
v0 = x0,y0,z0
v1 = u0,v0,x1
v2 = y1,z1,u1
v3 = v1,x2,y2
v4 = z2,u2,v2
v5 = x3,y3,z3
...
所以每 5 个点中只有 1 个顶点是正确的,所有其他顶点都通过混合该模式中的坐标和纹理坐标而扭曲。
您可以通过简单地注释掉两行代码来快速检查这一点:
// va.push_back(circum_rel);
// va.push_back(1.0f - layer_rel);
这会将您的数据转换为非交错数据,并且渲染正常(没有纹理)。
现在要解决您的问题(将上面的 2 行保留为未注释),我将对此进行更改:
GLuint v_attr_inx = 0;
glVertexAttribPointer(v_attr_inx,3,GL_FLOAT,GL_FALSE,0);
glEnableVertexAttribArray(v_attr_inx);
进入这个:
GLuint v_attr_inx = 0;
glVertexAttribPointer(v_attr_inx,5*sizeof(float),0);
glEnableVertexAttribArray(v_attr_inx);
GLuint t_attr_inx = 1;
glVertexAttribPointer(t_attr_inx,2,5 * sizeof(float),(GLvoid*)(3 * sizeof(float)));
glEnableVertexAttribArray(t_attr_inx);
匹配你的:
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
但是我会将 layout(location = 1) in vec3 vertexColor
更改为
layout(location = 1) in vec2 texcoord;
因为您没有传递任何 3D 颜色并且 u,v
代表 2D 纹理坐标...
希望我在 glVertexAttribPointer
调用中没有犯任何错误,因为我没有使用交错,因为我的所有 GL 引擎每个属性都有单独的 VBO。
注意第一个和最后两个参数。第一个应该与您要连接的布局位置相匹配。最后两个是 stride
和 offset
。 Doc 说 stride 以字节为单位,但是偏移量没有在那里声明,所以我只是假设它也是以字节为单位。所以步幅是你的 VBO 每个条目有多少字节......在你的情况下 (x,z,u,v)
是 5 个浮点数。偏移量告诉属性从哪里开始,因此顶点来自 0
并且纹理坐标跳过前 3 个浮点数 ...
此外,我会添加法线,因为一旦添加照明,这将比纹理更强调球体形状...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。