gpt4 book ai didi

c++ - OpenGL 4,错误的缓冲区偏移值

转载 作者:太空宇宙 更新时间:2023-11-04 12:02:03 25 4
gpt4 key购买 nike

我正在使用带有 C++ 的 OpenGL 4.0 开发粒子系统。

目前,我的程序中的一个粒子由 12 个浮点组件组成:

[vec4 位置,vec4 颜色,vec3 速度,生命周期] = [xPos,yPos,zPos,wPos,r,g,b,a,xVel,yVel,zVel,生命周期]

我目前的方法是用所有粒子填充一个数组(称为 vertexData),这样数组的结构将是:[粒子,粒子,粒子,...],其中每个粒子都具有上述布局。

我的计划是简单地将这个初始信息提供给顶点着色器,然后让它根据初始信息计算位置偏移和颜色。我希望大部分计算都在 GPU 上完成。

我想通过将所有数据放在单个缓冲区对象中来将数据传递给着色器,然后使用偏移量来获取正确的值以传递给顶点着色器。

问题:我似乎无法获得正确的数据。我觉得我误解了整个缓冲区偏移量,并且程序从我的数据中获取随机值......我得到了着色器属性的工作句柄,但数据绝对不正确。使用示例粒子,您将在下面的第一个代码块中看到,只有位置似乎正确。颜色为紫色(应为白色),生命周期为 0(应为 5)。很难调试着色器代码。如果生命周期不是应该的,我刚刚做了一个检查,将点涂成另一种颜色。

我是否需要将数据排列成这样:[(所有粒子位置),(所有粒子颜色),(所有粒子速度),(所有粒子生命周期)]? (就像这里所做的: http://arcsynthesis.org/gltut/Basics/Tut02%20Vertex%20Attributes.html )

或者我可能需要为每种类型的粒子数据创建一个不同的缓冲区,一个用于位置,一个用于颜色等?

代码:
现在了解我如何填充数据、创建缓冲区对象、渲染和着色器代码的一些代码。
数组初始化和填充是这样完成的:

const int PARTICLE_COUNT = 1;
const int PARTICLE_COMPONENTS_COUNT = 12;
...
GLfloat* vertexData;
...

void InitVertexData(){

vertexData = new GLfloat[PARTICLE_COUNT * PARTICLE_COMPONENTS_COUNT];

for (int i = 0; i < PARTICLE_COUNT; i++)
{
vertexData[i * PARTICLE_COMPONENTS_COUNT + 0] = 0.5f; //0: posX
vertexData[i * PARTICLE_COMPONENTS_COUNT + 1] = 0.5f; //1: posY
vertexData[i * PARTICLE_COMPONENTS_COUNT + 2] = 0.0f; //2: posZ
vertexData[i * PARTICLE_COMPONENTS_COUNT + 3] = 1.0f; //3: posW

vertexData[i * PARTICLE_COMPONENTS_COUNT + 4] = 1.0f; //4: red
vertexData[i * PARTICLE_COMPONENTS_COUNT + 5] = 1.0f; //5: green
vertexData[i * PARTICLE_COMPONENTS_COUNT + 6] = 1.0f; //6: blue
vertexData[i * PARTICLE_COMPONENTS_COUNT + 7] = 1.0f; //7: alpha

vertexData[i * PARTICLE_COMPONENTS_COUNT + 8] = 0.0f; //8: velX
vertexData[i * PARTICLE_COMPONENTS_COUNT + 9] = 0.0f; //9: velY
vertexData[i * PARTICLE_COMPONENTS_COUNT + 10] = 0.0f; //10: velZ

vertexData[i * PARTICLE_COMPONENTS_COUNT + 11] = 5.0f; //11: lifetime
}
}

注意:粒子的值现在只是硬编码。我还没有实现计算初始值的函数。

然后,我生成一个缓冲区,我想保存所有粒子的所有数据。初始化时调用一次以下函数:
bool CreateBufferObject()
{
//VertexShader attribute variable handles.
GLint positionLocation = glGetAttribLocation(programId, "position");
GLint colorLocation = glGetAttribLocation(programId, "color");
GLint velocityLocation = glGetAttribLocation(programId, "velocity");
GLint lifetimeLocation = glGetAttribLocation(programId, "lifetime");

//Number of components (floats) in a particle element (such as position, color etc).
GLint positionComponentCount = 4; //posX, posY, posZ, posW
GLint colorComponentCount = 4; //r, g, b, a
GLint velocityComponentCount = 3; //velX, velY, velZ
GLint lifetimeComponentCount = 1; //lifetime (in seconds)

//Size (in bytes) of the vertexData array and the elements inside.
GLsizeiptr sizeofVertexDataArray = sizeof(GLfloat) * PARTICLE_COUNT * PARTICLE_COMPONENTS_COUNT; //4 * 2 * 12 = 96
GLsizeiptr sizeofPosition = sizeof(GLfloat) * positionComponentCount; //4*4 = 16
GLsizeiptr sizeofColor = sizeof(GLfloat) * colorComponentCount; //4*4 = 16
GLsizeiptr sizeofVelocity = sizeof(GLfloat) * velocityComponentCount; //4*3 = 12
GLsizeiptr sizeofLifetime = sizeof(GLfloat) * lifetimeComponentCount; //4*1 = 4

//Generate one buffer in GPU memory and get handle.
glGenBuffers(1, &vertexDataBufferId);

//Generate VAO, a descriptor of vertex data (not the actual object), and get handle.
glGenVertexArrays(1, &vaoId);
glBindVertexArray(vaoId);

//Bind the generated buffer to VAO as the current target.
glBindBuffer(GL_ARRAY_BUFFER, vertexDataBufferId);

//Copy the actual data from the vertexData array to GPU memory. TODO: Not sure what to pick instead of GL_STREAM_DRAW
glBufferData(GL_ARRAY_BUFFER, sizeofVertexDataArray, vertexData, GL_STREAM_DRAW);

//Guide Vertex Shader to where attributes are at in the memory, giving size and offset (in bytes) of the different elements of a particle.
glVertexAttribPointer(positionLocation, positionComponentCount, GL_FLOAT, GL_FALSE, sizeofPosition, 0); //offset 0
glVertexAttribPointer(colorLocation, colorComponentCount, GL_FLOAT, GL_FALSE, sizeofColor, (void*)positionComponentCount); //ofset 4
glVertexAttribPointer(velocityLocation, velocityComponentCount, GL_FLOAT, GL_FALSE, sizeofVelocity, (void*)(positionComponentCount + colorComponentCount)); //offset 8
glVertexAttribPointer(lifetimeLocation, lifetimeComponentCount, GL_FLOAT, GL_FALSE, sizeofLifetime, (void*)(positionComponentCount + colorComponentCount + velocityComponentCount)); //offset 11

glEnableVertexAttribArray(positionLocation);
glEnableVertexAttribArray(colorLocation);
glEnableVertexAttribArray(velocityLocation);
glEnableVertexAttribArray(lifetimeLocation);
//Error checks and debug prints omitted
}

我的理解如下:在glBufferData中,我指定了整个数据集(所有粒子)的大小,并将数据复制到GPU显存中。

使用 glVertexAttribPointer,我指定 OpenGL 应该使用哪些偏移量和计数来填充顶点着色器的属性变量。

然后在我的 Render 函数中调用(这也是我认为我可能出错的地方):
void Render()
{
...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

GLuint elapsedTimeUniformLoc = glGetUniformLocation(programId, "time");

glUniform1f(elapsedTimeUniformLoc, glutGet(GLUT_ELAPSED_TIME) / 1000.0f); //Divide by 1000 to get time in seconds.
glDrawArrays(GL_POINTS, 0, PARTICLE_COUNT)

glutSwapBuffers();
glutPostRedisplay();
}

由于一个点由 1 个顶点组成,我要求它绘制与 PARTICLE_COUNT 一样多的点(当前为 1)

着色器
const GLchar* VertexShader2 =
{
"#version 400\n"\

"uniform float time;\n"\
"in vec4 position;\n"\
"in vec4 color;\n"\
"in vec3 velocity;\n"\
"in float lifetime;\n"\

"out vec4 myColor;\n"\

"void main()\n"\
"{\n"\
" float dummy = velocity.x;\n"
" float timeScale = 0.1f;\n"\
" float currentAge = mod(time, lifetime);\n"\
" vec4 accumulatedOffset = vec4(timeScale*currentAge, 0.0f, 0.0f, 0.0f);\n"
" gl_Position = position + accumulatedOffset;\n"\


" if(lifetime ==0) { color.y = 1.0f; }\n"\
" //color.w = 1.0f - ((1.0f/lifetime) * currentAge)\n"\
" color.w = 1.0f - (0.2f * currentAge);\n"\
" myColor = color;\n"\
"}\n"\
};

const GLchar* FragmentShader =
{
"#version 400\n"\

"in vec4 myColor;\n"\
"out vec4 outColor;\n"\

"void main()\n"\
"{\n"\
" outColor = myColor;\n"\
"}\n"\
};

注意:由于速度值不正确,我使用虚拟变量只是为了确保着色器编译器不会丢弃该属性。

如果您需要查看更多代码,我会更新帖子。我希望我把我的问题和我的情况弄清楚了。

回复@Ben Voight
好的,所以从您的评论中,我认为 stride 参数表示该属性下一个值的数据偏移量。所以它必须是
PARTICLE_COMPONENTS_COUNT * sizeof(GLfloat)为所有 glVertexAttribPointer
但是,它仍然给我错误的数据。一个由以下组成的粒子

[-0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0],

我希望位置为 (-0.5, 0.5, 0.5),颜色为白色,生命周期为 5。(像以前一样忽略速度)

如果生命周期 == 0,我的顶点着色器会更改颜色,并且它报告生命周期确实为 0。我不明白它从哪里得到 0,它甚至不在数据中。颜色也错了。只有位置似乎是正确的。
事实上,它的工作原理和以前完全一样。

已解决
结果我在 glVertexAttribPointer 中传递了错误的步幅和偏移值。

可能重复:
Opengl Vertex attribute stride

最佳答案

glVertexAttribPointer 的 stride 参数需要PARTICLE_COMPONENTS_COUNT * sizeof (GLfloat) .

offset 参数以字节为单位。你所有的值都偏离了sizeof (GLfloat) .

您有什么理由使用花哨的索引而不是具有所有正确字段的结构数组?

关于c++ - OpenGL 4,错误的缓冲区偏移值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13736359/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com