簡體   English   中英

無法使用QGLShaderProgram在Qt 4.7應用程序中使用組數組編譯GLSL 3.30着色器

[英]Cannot compile GLSL 3.30 shader with group array in Qt 4.7 application using QGLShaderProgram

我正在開發一個使用Qt 4.7的應用程序,目的是創建一個簡單的3D OpenGL查看器。 我想使用GLSL 3.30着色器。 我使用Linux Ubutu 11.10,我的CG是具有NVS 3100M GPU的NVIDIA,NVIDIA驅動程序版本為280.13,OpenGL版本為3.3.0。

我有一個可以工作的基本着色器,它不會計算任何光照。 下一步需要這樣做,但是我遇到了問題。

這是我無法使用的修改后的頂點着色器。

#version 330

in vec3 inPosition;
in vec4 inColor;
in vec3 inNormal;
uniform mat4 inModelMatrix;
uniform mat4 inViewMatrix;
uniform mat4 inProjectionMatrix;
out vec4 exColor;

uniform Light {
    vec4 position;
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
} lights[4];

void main(void)
{
    gl_Position = inProjectionMatrix * inViewMatrix * inModelMatrix * vec4(inPosition, 1.0);
    exColor = lights[0].ambient;
}

GLSL 3.30的OpenGL着色語言參考指出:

uniform Transform { // API uses “Transform[2]” to refer to instance 2
    mat4 ModelViewMatrix;
    mat4 ModelViewProjectionMatrix;
    float Deformation;
} transforms[4];
...
... = transforms[2].ModelViewMatrix; // shader access of instance 2
// API uses “Transform.ModelViewMatrix” to query an offset or other query

因此,如果我沒記錯的話,代碼是正確的。 但是,它甚至不編譯。 引發以下錯誤:

QGLShader::link: "Vertex info
-----------
Internal error: assembly compile error for vertex shader at offset 1805:
-- error message --
line 38, column 15:  error: expected '='
line 82, column 36:  error: expected ';'
-- internal assembly text --
!!NVvp4.1
OPTION NV_parameter_buffer_object2;
# cgc version 3.1.0001, build date Jul 27 2011
# command line args: 
#vendor NVIDIA Corporation
#version 3.1.0.1
#profile gp4_1vp
#program main
#semantic Light.lights
#semantic inModelMatrix
#semantic inViewMatrix
#semantic inProjectionMatrix
#var float4 gl_Position : $vout.POSITION : HPOS : -1 : 1
#var float4 lights[0].position : BUFFER[0] : buffer[0][0] : -1 : 0
#var float4 lights[0].ambient : BUFFER[0] : buffer[0][16] : -1 : 1
#var float4 lights[0].diffuse : BUFFER[0] : buffer[0][32] : -1 : 0
#var float4 lights[0].specular : BUFFER[0] : buffer[0][48] : -1 : 0
#var float4 lights[1].position : BUFFER[1] : buffer[1][0] : -1 : 0
#var float4 lights[1].ambient : BUFFER[1] : buffer[1][16] : -1 : 0
#var float4 lights[1].diffuse : BUFFER[1] : buffer[1][32] : -1 : 0
#var float4 lights[1].specular : BUFFER[1] : buffer[1][48] : -1 : 0
#var float4 lights[2].position : BUFFER[2] : buffer[2][0] : -1 : 0
#var float4 lights[2].ambient : BUFFER[2] : buffer[2][16] : -1 : 0
#var float4 lights[2].diffuse : BUFFER[2] : buffer[2][32] : -1 : 0
#var float4 lights[2].specular : BUFFER[2] : buffer[2][48] : -1 : 0
#var float4 lights[3].position : BUFFER[3] : buffer[3][0] : -1 : 0
#var float4 lights[3].ambient : BUFFER[3] : buffer[3][16] : -1 : 0
#var float4 lights[3].diffuse : BUFFER[3] : buffer[3][32] : -1 : 0
#var float4 lights[3].specular : BUFFER[3] : buffer[3][48] : -1 : 0
#var float3 inPosition : $vin.ATTR0 : ATTR0 : -1 : 1
#var float4 inColor :  :  : -1 : 0
#var float3 inNormal :  :  : -1 : 0
#var float4x4 inModelMatrix :  : c[0], 4 : -1 : 1
#var float4x4 inViewMatrix :  : c[4], 4 : -1 : 1
#var float4x4 inProjectionMatrix :  : c[8], 4 : -1 : 1
#var float4 exColor : $vout.ATTR0 : ATTR0 : -1 : 1
PARAM c[12] = { program.local[0..11] };
CBUFFER buf0[][] = { program.buffer[0..3] };
ATTRIB vertex_attrib[] = { vertex.attrib[0..0] };
OUTPUT result_attrib[] = { result.attrib[0..0] };
TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8;
MOV.F R3, c[9];
MOV.F R2, c[8];
MUL.F R0, R3, c[5].y;
MOV.F R1, c[10];
MAD.F R0, R2, c[5].x, R0;
MAD.F R5, R1, c[5].z, R0;
MOV.F R0, c[11];
MAD.F R6, R0, c[5].w, R5;
MUL.F R4, R3, c[4].y;
MAD.F R5, R2, c[4].x, R4;
MAD.F R5, R1, c[4].z, R5;
MAD.F R5, R0, c[4].w, R5;
MUL.F R4, R6, c[1].y;
MAD.F R8, R5, c[1].x, R4;
MUL.F R4, R3, c[6].y;
M    UL.F R7, R6, c[0].y;
MAD.F R4, R2, c[6].x, R4;
MUL.F R3, R3, c[7].y;
MAD.F R2, R2, c[7].x, R3;
MAD.F R3, R1, c[6].z, R4;
MAD.F R1, R1, c[7].z, R2;
MAD.F R2, R0, c[6].w, R3;
MUL.F R4, R6, c[2].y;
MAD.F R0, R0, c[7].w, R1;
MAD.F R3, R2, c[1].z, R8;
MAD.F R1, R0, c[1].w, R3;
MAD.F R7, R5, c[0].x, R7;
MAD.F R3, R2, c[0].z, R7;
MAD.F R3, R0, c[0].w, R3;
MUL.F R1, vertex.attrib[0].y, R1;
MAD.F R1, vertex.attrib[0].x, R3, R1;
MUL.F R3, R6, c[3].y;
MAD.F R3, R5, c[3].x, R3;
MAD.F R3, R2, c[3].z, R3;
MAD.F R4, R5, c[2].x, R4;
MAD.F R3, R0, c[3].w, R3;
MAD.F R2, R2, c[2].z, R4;
MAD.F R0, R0, c[2].w, R2;
MAD.F R0, vertex.attrib[0].z, R0, R1;
ADD.F result.position, R0, R3;
LDC.F32X4 result.attrib[0], buf0[0][16];
END
# 41 instructions, 9 R-regs
" 

如果刪除對lights [0] .ambient的調用,則將編譯着色器,但是當我嘗試獲取統一位置時,它將無法正常工作:

int lightsLocation = shaderProgram.uniformLocation("Light[0]");

PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)(context()->getProcAddress("glGetUniformLocation"));

qDebug() << lightsLocation << glGetUniformLocation(shaderProgram.programId(), "Light[0]"); // -1 -1

我也嘗試使用“ Light”,“ lights”,“ lights [0]”,“ lights [0] .ambient”作為統一名稱,但均未成功。

經過一番搜索,我發現了這篇文章: 設置從JS到GLSL的結構數組的值,因此嘗試使用顯示的結構,但這也不起作用。

后續問題

如果我能通過一些回答使它生效,我不知道我應該使用哪種QGLShaderProgram方法來上傳數據。

tl; dr

1)為什么以下代碼無法編譯? 出vec4 exColor;

uniform Light {
     vec4 ambient;
} lights[4];

void main(void) {
    exColor = lights[0].ambient;
}

2)應該使用什么統一名稱作為QGLShaderProgam :: uniformLocation()的參數來獲得uniform Light { ... } lights[4]; struct Light { ... }; uniform Light lights[4]; struct Light { ... }; uniform Light lights[4];

3)一旦檢索到位置,應使用QGLShaderProgram的什么功能將數據上傳到GPU?

非常感謝你!

1)為了成為結構,您在Light之前缺少“結構”。

要么 ...

您的代碼是合法的,但會創建一個Uniform Block ,這是為了輕松在不同着色器之間共享大數據塊,並且不存儲在着色器統一塊中,而是存儲在緩沖區對象中。 如果您打算這樣做,則需要在着色器的開頭包括以下行:

#extension GL_ARB_uniform_buffer_object : enable

請注意,這不適用於較舊的NVIDIA GPU(驅動程序錯誤?也不適用於較舊的ATis),但是相同的代碼對我在GeForce GTX 560上也適用。

另外,熟悉GL_ARB_uniform_buffer_object (有示例着色器和代碼來設置它)。

2)如果您不使用(參考)制服,編譯器會對其進行優化,這就是為什么您無法獲得制服的位置。 這可能會導致沮喪,因為即使使用正確的名稱也無法獲得統一的位置。

對於統一緩沖區,規范中給出了內存中數據的布局,然后創建緩沖區對象(glGenBuffers()),將其填充原始數據(glBufferData()),然后使用glGetUniformBlockIndex()將其綁定到統一塊和glUniformBlockBinding()。

如果要作為“結構”,則始終可以通過glGetActiveUniformName()找到活動制服的名稱,這樣您就可以看到要使用的名稱。 對於您的結構,您需要使用“ lights [0] .ambient”到“ lights [3] .ambient”來獲得統一的位置,然后四次調用glUniform4f()來指定數據(因為指向的變量是向量)。

3)上面已經說過了。 對於統一塊,可以使用glBufferData(),對於統一塊可以使用適當的glUniform *()。 如果在結構中,則需要分別上傳結構成員。 如果在結構數組中,仍然需要針對數組中的每個結構分別上傳結構成員。 如果數組是結構的成員,則只有使用glUniform * v()才能上載浮點數/向量/矩陣的數組。

為了以與Qt對“頂點緩沖區”對象和“索引緩沖區”對象類似的方式處理統一緩沖區對象,我創建了此類:

#ifndef UNIFORMBUFFEROBJECT_H
#define UNIFORMBUFFEROBJECT_H

#include <qgl.h>

struct UBOInfoStruct {
    QString uniformName;
    GLuint progId;
    GLuint blockIdx;
    GLint blockSize;
    GLuint bindingIdx;
};

typedef UBOInfoStruct UBOInfo;

class UniformBufferObject
{
public:
    UniformBufferObject();

    bool create();
    bool isCreated() const;

    void destroy();

    bool bind();
    bool bind(GLuint progId, QString uniformName);
    void release();

    GLuint bufferId() const;

//    bool read(int offset, void *data, int count);
    void write(int offset, const void *data, int count);

    void allocate(const void *data, int count);
    inline void allocate(int count) { allocate(0, count); }


protected:
    static GLuint bindingIndex();
    static QVector<GLuint> m_bindingIndices;

    bool initFunctionPointers(const QGLContext* m_glContext);

    GLuint m_bufferId;

    const QGLContext* m_glContext;

    bool m_inited;

    QVector<UBOInfo> m_UBOInfos;

    PFNGLBINDBUFFERPROC glBindBuffer;
    PFNGLBINDBUFFERBASEPROC glBindBufferBase;
    PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
    PFNGLBUFFERDATAPROC glBufferData;
    PFNGLBUFFERSUBDATAPROC glBufferSubData;
    PFNGLDELETEBUFFERSPROC glDeleteBuffers;
    PFNGLGENBUFFERSPROC glGenBuffers;
    PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv;
    PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv;
    PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
    PFNGLGETUNIFORMINDICESPROC glGetUniformIndices;
    PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
};

#endif // UNIFORMBUFFEROBJECT_H

CPP:

#include "uniformbufferobject.h"

#include <QGLContext>

#include <QDebug>

QVector<GLuint> UniformBufferObject::m_bindingIndices = QVector<GLuint>();

GLuint UniformBufferObject::bindingIndex() {
    for(GLuint i = 0, size = m_bindingIndices.size(); i < size; i++) {
        if(m_bindingIndices.at(i) != i) {
            m_bindingIndices.insert(i, i);
            return i;
        }
    }
    m_bindingIndices.append(m_bindingIndices.size());
    return m_bindingIndices.size();
}

UniformBufferObject::UniformBufferObject() :
    m_bufferId(0), m_glContext(NULL), m_inited(false),
    glBindBuffer(NULL), glBindBufferBase(NULL), glBindBufferRange(NULL), glBufferData(NULL), glDeleteBuffers(NULL), glGenBuffers(NULL),
    glGetActiveUniformBlockiv(NULL), glGetActiveUniformsiv(NULL), glGetUniformBlockIndex(NULL), glGetUniformIndices(NULL),
    glUniformBlockBinding(NULL)
{
}

bool UniformBufferObject::create() {
    const QGLContext* m_glContext = QGLContext::currentContext();

    if(m_glContext) {
        if(!m_inited && !initFunctionPointers(m_glContext)) {
            qDebug("Cannot find Uniform Buffer Objects related functions");
            return false;
        }

        GLuint tmpBufferId = 0;
        glGenBuffers(1, &tmpBufferId);

        if(tmpBufferId) {
                m_bufferId = tmpBufferId;
            this->m_glContext = m_glContext;

            return true;
        } else {
            qDebug("Invalid buffer Id");
        }
    }

    qDebug("Could not retrieve buffer");

    return false;
}

bool UniformBufferObject::isCreated() const {
    return (bool)(m_bufferId != 0);
}

void UniformBufferObject::destroy() {
    if(m_bufferId != 0) {
        glDeleteBuffers(1, &m_bufferId);
    }
    m_bufferId = 0;
    m_glContext = NULL;
}

bool UniformBufferObject::bind() {
    if(!isCreated()) {
        qDebug("Buffer not created");
        return false;
    }

    glBindBuffer(GL_UNIFORM_BUFFER, m_bufferId);

    return true;
}

bool UniformBufferObject::bind(GLuint progId, QString uniformName) {
    GLuint tmpBlockIdx = glGetUniformBlockIndex(progId, uniformName.toUtf8());

    if(tmpBlockIdx == GL_INVALID_INDEX) {
        qDebug() << QString("Could not find block index of block named: %1").arg(uniformName);

        return false;
    }

    GLint tmpBlockSize;
    glGetActiveUniformBlockiv(progId, tmpBlockIdx, GL_UNIFORM_BLOCK_DATA_SIZE, &tmpBlockSize);

    GLuint tmpBindingIdx = bindingIndex();
    glUniformBlockBinding(progId, tmpBlockIdx, tmpBindingIdx);

    glBindBufferBase(GL_UNIFORM_BUFFER, tmpBindingIdx, m_bufferId);

    if(glGetError() == GL_INVALID_VALUE || glGetError() == GL_INVALID_ENUM) {
        qDebug() << "ERROR";
    }

    UBOInfo info;
    info.progId = progId;
    info.uniformName = uniformName;
    info.blockIdx = tmpBlockIdx;
    info.blockSize = tmpBlockSize;
    info.bindingIdx = tmpBindingIdx;

    m_UBOInfos.append(info);

    return true;
}

void UniformBufferObject::release() {
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

GLuint UniformBufferObject::bufferId() const {
    return m_bufferId;
}

void UniformBufferObject::write(int offset, const void *data, int count) {
    if(!isCreated())
        return;

    bind();

    glBufferSubData(GL_UNIFORM_BUFFER, offset, count, data);
}

void UniformBufferObject::allocate(const void *data, int count) {
    if(!isCreated())
        return;

    bind();

    glBufferData(GL_UNIFORM_BUFFER, count, data, GL_DYNAMIC_DRAW);
}

bool UniformBufferObject::initFunctionPointers(const QGLContext* m_glContext) {
    glBindBuffer = (PFNGLBINDBUFFERPROC)m_glContext->getProcAddress("glBindBuffer");
    glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)m_glContext->getProcAddress("glBindBufferBase");
    glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)m_glContext->getProcAddress("glBindBufferRange");
    glBufferData = (PFNGLBUFFERDATAPROC)m_glContext->getProcAddress("glBufferData");
    glBufferSubData = (PFNGLBUFFERSUBDATAPROC)m_glContext->getProcAddress("glBufferSubData");
    glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)m_glContext->getProcAddress("glDeleteBuffers");
    glGenBuffers = (PFNGLGENBUFFERSPROC)m_glContext->getProcAddress("glGenBuffers");
    glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)m_glContext->getProcAddress("glGetActiveUniformBlockiv");
    glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)m_glContext->getProcAddress("glGetActiveUniformsiv");
    glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)m_glContext->getProcAddress("glGetUniformBlockIndex");
    glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)m_glContext->getProcAddress("glGetUniformIndices");
    glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)m_glContext->getProcAddress("glUniformBlockBinding");

    if(!glBindBuffer ||
            !glBindBufferBase ||
            !glBindBufferRange ||
            !glBufferData ||
            !glBufferSubData ||
            !glDeleteBuffers ||
            !glGenBuffers ||
            !glGetActiveUniformBlockiv ||
            !glGetActiveUniformsiv ||
            !glGetUniformBlockIndex ||
            !glGetUniformIndices ||
            !glUniformBlockBinding)
    {
        qDebug("Could not init function pointers");
        return false;
    }

    return true;
}

正如我接受的答案中突出顯示的那樣,統一緩沖區對象具有關聯的布局( http://www.opengl.org/wiki/Uniform_Buffer_Object ),並且“統一塊”必須鏈接“兩次”(在此處了解更多信息: http:/ /arcsynthesis.org/gltut/Positioning/Tut07%20Shared%20Uniforms.html )。

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM