将 Uniform 数据正确发送到 GPU

Posted

技术标签:

【中文标题】将 Uniform 数据正确发送到 GPU【英文标题】:Properly sending Uniform data to the GPU 【发布时间】:2016-06-15 00:02:19 【问题描述】:

我正在尝试通过制服将灯光数据发送到我的片段着色器。我在使用以下功能时遇到问题:

void glUniform3fv(GLint location, GLsizei count, const GLfloat *value);

下面是我写的一个函数,它的目的是把所有的光数据(作为一个固定大小的数组存储在'Shader'类中)发送到片段着色器: (注:Vector3F 类是我自己的,如果需要我可以提供它的源代码。)

void Shader::updateLights()

    // this->lights[x].getPosR() returns a Vector3F reference. Same with getLightDirectionR() and getColourR().
    glUniform3fv(this->uniforms[LIGHT1POS_U], 3, &(this->lights[0].getPosR().getXR()));
    glUniform3fv(this->uniforms[LIGHT1LD_U], 3, &(this->lights[0].getLightDirectionR().getXR()));
    glUniform3fv(this->uniforms[LIGHT1COLOUR_U], 3, &(this->lights[0].getColourR().getXR()));
    glUniform1f(this->uniforms[LIGHT1POW_U], this->lights[0].getPowerR());

    glUniform3fv(this->uniforms[LIGHT2POS_U], 3, &(this->lights[1].getPosR().getXR()));
    glUniform3fv(this->uniforms[LIGHT2LD_U], 3, &(this->lights[1].getLightDirectionR().getXR()));
    glUniform3fv(this->uniforms[LIGHT2COLOUR_U], 3, &(this->lights[1].getColourR().getXR()));
    glUniform1f(this->uniforms[LIGHT2POW_U], this->lights[1].getPowerR());

    glUniform3fv(this->uniforms[LIGHT3POS_U], 3, &(this->lights[2].getPosR().getXR()));
    glUniform3fv(this->uniforms[LIGHT3LD_U], 3, &(this->lights[2].getLightDirectionR().getXR()));
    glUniform3fv(this->uniforms[LIGHT3COLOUR_U], 3, &(this->lights[2].getColourR().getXR()));
    glUniform1f(this->uniforms[LIGHT3POW_U], this->lights[2].getPowerR());

    glUniform3fv(this->uniforms[LIGHT3POS_U], 3, &(this->lights[3].getPosR().getXR()));
    glUniform3fv(this->uniforms[LIGHT3LD_U], 3, &(this->lights[3].getLightDirectionR().getXR()));
    glUniform3fv(this->uniforms[LIGHT3COLOUR_U], 3, &(this->lights[3].getColourR().getXR()));
    glUniform1f(this->uniforms[LIGHT3POW_U], this->lights[3].getPowerR());

    // Print out all the information to ensure that data is correct.
    std::cout << "Lights Info:\n";
    for(unsigned int i = 0; i < Shader::MAX_LIGHTS; i++)
    
        Light* l = &(this->lights[i]);
        std::cout << "Light Id " << i << ": ";
        std::cout << "Position = [" << l->getPosR().getX() << ", " << l->getPosR().getY() << ", " << l->getPosR().getZ() << "], ";
        std::cout << "Light Direction = [" << l->getLightDirectionR().getX() << ", " << l->getLightDirectionR().getY() << ", " << l->getLightDirectionR().getZ() << "], ";
        std::cout << "Light Colour = [" << l->getColourR().getX() << ", " << l->getColourR().getY() << ", " << l->getColourR().getZ() << "], ";
        std::cout << "Light Power = " << l->getPowerR() << " Watts.\n";
    

但是,制服是空的!我确信我的问题在于我尝试const GLfloat *value。灯光数据存储在类体中,所以我认为范围不是问题。

在运行时打印以下文本块:

Light Id 0: Position = [0, 15, 0], Light Direction = [0, -1, 1], Light Colour = [1, 1, 1], Light Power = 200 Watts.
Light Id 1: Position = [5, 15, 10], Light Direction = [0, -1, 1], Light Colour = [1, 1, 1], Light Power = 200 Watts
Light Id 2: Position = [10, 15, 20], Light Direction = [0, -1, 1], Light Colour = [1, 1, 1], Light Power = 200 Watts.
Light Id 3: Position = [15, 15, 30], Light Direction = [0, -1, 1], Light Colour = [1, 1, 1], Light Power = 200 Watts.

我只见过这个函数是通过 glm::vec3 对象调用的,所以我不确定我是否在第三个参数中提供了足够的信息(我似乎只是发送了 Vector3F 的 X 值XYZ)。我试图在函数中构建一个浮点列表,以确保所有数据都被发送,但是一旦我超出范围,数据就会丢失,导致运行时崩溃。在这种情况下,我真的很想避免堆分配。什么是格式化我的数据以便正确发送数据的好方法?我的片段着色器工作并且光照数据有效(所以我应该看到它),但场景是漆黑的。

【问题讨论】:

"我试图在函数中构建一个浮点列表以确保所有数据都被发送,但是一旦我超出范围,数据就会丢失,导致运行时崩溃." OpenGL will finish accessing this data by the time the function returns. 所以这个内存没有必要在你的调用之后持续存在。 @NicolBolas 我不知道是这样的,谢谢! 【参考方案1】:
glUniform3fv(this->uniforms[LIGHT1POS_U], 3, &(this->lights[0].getPosR().getXR()));

count 参数是要写入的 uniform 中数组元素的数量,而不是向量中的元素数量。它已经知道向量中元素的数量:这就是3f 在函数名中的含义。

所以除非this-&gt;uniforms[LIGHT1POS_U] 定义为uniform vec3 name[3];,否则这段代码将无法正常工作。您应该从每个此类调用中收到 GL_INVALID_OPERATION 错误。

当然,所有这些都假设getXR 返回的任何东西都相当于一个包含 3 个浮点数的数组。由于您没有费心向我们展示代码,因此对此无话可说。

【讨论】:

啊,我的假设很糟糕。谢谢你。此外,getXR() 只是一个非常量函数,它返回向量的 X 值,这当然是错误的。我现在将每个三个值放入自己的浮点数组中,它可以工作。

以上是关于将 Uniform 数据正确发送到 GPU的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 openGL 将数据发送到 GPU

将大图像时间发送到 GPU

WebGL - 发送数组缓冲区 VS 将图像/画布/位图从 CPU 发送到 GPU

如何将数据从 PC 发送到手机 c#

GLSL 变量属性

GLSL Uniform