2

シンプルな3DOpenGLビューアを作成することを目的として、Qt4.7を使用するアプリケーションを開発しています。GLSL3.30シェーダーを使用したい。Linux Ubutu11.10を使用しています。CGはNVS3100M 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)次のコードがコンパイルされないのはなぜですか?vec4exColorを出力します。

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];

3)場所が取得されたら、データをGPUにアップロードするためにQGLShaderProgramのどの機能を使用する必要がありますか?

どうもありがとうございます!

4

2 に答える 2

0

1)構造体になるために、Lightの前に「構造体」がありません。

また ...

コードは合法ですが、Uniform Blockを作成します。これは、異なるシェーダー間でデータの大きなブロックを簡単に共有するためのものであり、ShaderのUniform Blockではなく、バッファーオブジェクトに格納されます。これを行う場合は、シェーダーの先頭に次の行を含める必要があります。

#extension GL_ARB_uniform_buffer_object : enable

これは古いNVIDIAGPUでは機能しないことに注意してください(ドライバーのバグ?古いATisでも機能しませんでした)が、GeForceGTX560でも同じコードが機能します。

また、GL_ARB_uniform_buffer_objectに慣れてください(シェーダーとそれを設定するコードの例があります)。

2)ユニフォームを使用(参照)していない場合、コンパイラはそれを最適化します。そのため、ユニフォームの場所を取得できません。正しい名前を使用しても均一な位置を取得できないため、フラストレーションにつながる可能性があります。

均一バッファの場合、メモリ内のデータのレイアウトは仕様によって指定されます。次に、バッファオブジェクトを作成し(glGenBuffers())、生データを入力し(glBufferData())、glGetUniformBlockIndex()を使用して均一ブロックにバインドします。およびglUniformBlockBinding()。

「構造体」であることが意図されている場合は、glGetActiveUniformName()を使用してアクティブなユニフォームの名前をいつでも見つけることができるため、使用する名前を確認できます。構造体では、「lights[0].ambient」から「lights[3].ambient」を使用して均一な位置を取得し、glUniform4f()を4回呼び出してデータを指定する必要があります(ベクトル)。

3)すでに上記のことを言った。ユニフォームブロックの場合はglBufferData()、ユニフォームの場合は適切なglUniform *()。構造体の場合は、構造体メンバーを個別にアップロードする必要があります。構造体の配列の場合でも、配列内の構造体ごとに、構造体メンバーを個別にアップロードする必要があります。配列が構造体のメンバーである場合にのみ、glUniform * v()を使用してfloat / vector/matricesの配列をアップロードします。

于 2012-01-11T17:01:42.023 に答える
0

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;
}

私が受け入れた回答で強調されているように、Uniform Buffer Objectsには関連するレイアウト(http://www.opengl.org/wiki/Uniform_Buffer_Object)があり、Uniform Blocksは「2回」リンクする必要があります(詳細はこちら:http:/ /arcsynthesis.org/gltut/Positioning/Tut07%20Shared%20Uniforms.html)。

お役に立てれば!

于 2012-01-15T22:10:09.733 に答える