[英]Passing custom type (struct) uniform from Qt to GLSL using QGLShaderProgram
[英]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.