我试图弄清楚为什么我无法使用(现在内置的)shader_image_load_store扩展写入 3D 纹理。
我创建了两个简单的示例(在python中使其更容易):一个用于写入有效的2D纹理,另一个用于写入不起作用的3D纹理
(工作)2D版本如下:
#! /usr/bin/env python
from PyQt4 import QtGui, QtCore
from PyQt4.QtOpenGL import *
from OpenGL.GL import *
from OpenGL.GLU import *
import sys
iTexSize = 256
_vsClearSource = """
#version 440 compatibility
void main() {
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}
"""
_fsClearSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) coherent uniform image2D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec2 ivecVolumeCoordinate = ivec2(gl_FragCoord.x, gl_FragCoord.y ); //, iSliceIndex);
vec4 vecVolumeValue = vec4(0,1,0,1); // vec4( float(iSlabIndex)/float(iPrimitiveCount)); //,0.0,0.0,0.0);
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
gl_FragData[0] = vec4(1,0,1,1);
}
"""
_fsFillSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) coherent uniform image2D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec2 ivecVolumeCoordinate = ivec2(gl_FragCoord.x, gl_FragCoord.y );
vec4 vecVolumeValue = vec4( float(gl_FragCoord.x) / float(iMaxTexSize) , float(gl_FragCoord.y) / float(iMaxTexSize) , 0 , 1 );
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
gl_FragData[0] = vec4(1,0,1,1);
}
"""
class Viewer3DWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.uWidth = 0
self.uHeight = 0
self.texColorTexture = None
self.fboRendering = None
self.texColorVolume = None
self.vecBackgroundColor = (1.,1.,1.)
self.vecDrawBuffers = [ GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 ]
self.fSurfacesSpacing = 1.0
self.fSurfacesTransparency = 1.0
def initializeGL(self):
self.shaShaderFill = QGLShaderProgram(self.context())
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Fragment, _fsFillSource)
self.shaShaderFill.link()
self.shaShaderClear = QGLShaderProgram(self.context())
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Fragment, _fsClearSource)
self.shaShaderClear.link()
glClearColor(1.0, 1.0, 1.0, 1.0)
glClearDepth(1.0)
def initRenderTargets(self):
global iTexSize
if (self.texColorTexture is None):
self.texColorTexture = glGenTextures( 1 )
if (self.fboRendering is None):
self.fboRendering = glGenFramebuffers(1)
glBindTexture( GL_TEXTURE_RECTANGLE, self.texColorTexture )
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None)
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, self.texColorTexture, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def deleteRenderTargets(self):
if (self.fboAccumulation is not None):
glDeleteFramebuffers(1,self.fboRendering)
self.fboAccumulation = None
if (self.texColorTexture is not None):
glDeleteTextures( self.texColorTexture )
self.texColorTexture = None
def initColorVolume(self):
if (self.texColorVolume is None):
self.texColorVolume = glGenTextures( 1 )
glBindTexture( GL_TEXTURE_2D, self.texColorVolume )
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
#glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None);
glBindTexture(GL_TEXTURE_2D, 0);
def fillVolume(self, bClear):
global iTexSize
shaShader = self.shaShaderClear
if(not bClear):
shaShader = self.shaShaderFill
if (not self.fboRendering):
self.initRenderTargets()
if (not self.texColorVolume):
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_READ_WRITE,GL_RGBA32F);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering);
glDrawBuffers(1, self.vecDrawBuffers);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
shaShader.bind()
shaShader.setUniformValue("iPrimitiveCount", iTexSize)
shaShader.setUniformValue("volColorVolume", 0)
for i in range(iTexSize):
shaShader.setUniformValue("iSliceIndex", i)
glBegin(GL_QUADS);
glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
#sync
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glBindImageTexture(0,0,0,GL_FALSE,0,GL_READ_WRITE,GL_RGBA32F);
shaShader.release()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
def paintGL(self):
if (self.uWidth is 0):
return
if (not self.fboRendering):
self.initRenderTargets()
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.fillVolume(True)
#draw into the volume
self.fillVolume(False)
#slice the volume
self.displayTexture()
glFlush()
def displayTexture(self): #essentially not useable here
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glDisable(GL_BLEND)
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor(1.0, 1.0,1.0)
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, self.texColorVolume )
glBegin(GL_QUADS);
glTexCoord2f(0,0) #,0.5)
glVertex2f(-1.0, -1.0);
glTexCoord2f(1,0) #,0.5)
glVertex2f(1.0, -1.0);
glTexCoord2f(1,1) #,0.5)
glVertex2f(1.0, 1.0);
glTexCoord2f(0,1) #,0.5)
glVertex2f(-1.0, 1.0);
glEnd();
glBindTexture( GL_TEXTURE_2D, 0 )
def resizeGL(self, widthInPixels, heightInPixels):
if ((widthInPixels is not self.uWidth) or (heightInPixels is not self.uHeight)):
self.uWidth = widthInPixels
self.uHeight = heightInPixels
glViewport(0, 0, widthInPixels, heightInPixels)
self.update()
class TestImageLoadStore2D(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('TestImageLoadStore2D')
self.statusBar().showMessage("Hello there")
exit = QtGui.QAction("Exit", self)
exit.setShortcut("Ctrl+Q")
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
self.viewer3D = Viewer3DWidget(self)
self.setCentralWidget(self.viewer3D)
self.resize(500,500)
def closeEvent(self, event):
event.accept()
if __name__ == '__main__':
# app = QtGui.QApplication(['Python Qt OpenGL Demo'])
app = QtGui.QApplication(sys.argv)
window = TestImageLoadStore2D()
window.show()
sys.exit(app.exec_())
而非工作3D版本如下:
#! /usr/bin/env python
from PyQt4 import QtGui, QtCore
from PyQt4.QtOpenGL import *
from OpenGL.GL import *
from OpenGL.GLU import *
import sys
iTexSize = 256
_vsClearSource = """
#version 440 compatibility
void main() {
gl_Position = ftransform();
gl_FrontColor = gl_Color;
}
"""
_fsClearSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
//layout(rgba32f, binding=0) writeonly uniform image3D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec3 ivecVolumeCoordinate = ivec3(gl_FragCoord.x, gl_FragCoord.y, 0); //iSliceIndex);
vec4 vecVolumeValue = vec4(0,1,0,1); // vec4( float(iSlabIndex)/float(iPrimitiveCount)); //,0.0,0.0,0.0);
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
memoryBarrier();
gl_FragData[0] = vec4(1,0,1,1);
}
"""
_fsFillSource = """
#version 440 compatibility
uniform int iPrimitiveCount;
uniform int iSliceIndex;
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
const int iMaxTexSize = 255;
void main() {
ivec3 ivecVolumeCoordinate = ivec3(gl_FragCoord.x, gl_FragCoord.y, 0); //iSliceIndex);
vec4 vecVolumeValue = vec4( float(gl_FragCoord.x) / float(iMaxTexSize) , float(gl_FragCoord.y) / float(iMaxTexSize) , float(iSliceIndex)/float(iPrimitiveCount) , 1 );
imageStore(volColorVolume, ivecVolumeCoordinate, vecVolumeValue);
memoryBarrier();
gl_FragData[0] = vec4(1,0,1,1);
}
"""
class Viewer3DWidget(QGLWidget):
def __init__(self, parent):
QGLWidget.__init__(self, parent)
self.uWidth = 0
self.uHeight = 0
self.texColorTexture = None
self.fboRendering = None
self.texColorVolume = None
self.vecBackgroundColor = (1.,1.,1.)
self.vecDrawBuffers = [ GL_COLOR_ATTACHMENT0 , GL_COLOR_ATTACHMENT1 , GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 ]
self.fSurfacesSpacing = 1.0
self.fSurfacesTransparency = 1.0
self.fZCoord = 0.0
def setZCoordinate(self, fZCoordinate):
self.fZCoord = fZCoordinate
self.update()
def initializeGL(self):
self.shaShaderFill = QGLShaderProgram(self.context())
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderFill.addShaderFromSourceCode(QGLShader.Fragment, _fsFillSource)
self.shaShaderFill.link()
self.shaShaderClear = QGLShaderProgram(self.context())
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Vertex, _vsClearSource)
self.shaShaderClear.addShaderFromSourceCode(QGLShader.Fragment, _fsClearSource)
self.shaShaderClear.link()
glClearColor(1.0, 1.0, 1.0, 1.0)
glClearDepth(1.0)
def initRenderTargets(self):
global iTexSize
if (self.texColorTexture is None):
self.texColorTexture = glGenTextures( 1 )
if (self.fboRendering is None):
self.fboRendering = glGenFramebuffers(1)
glBindTexture( GL_TEXTURE_RECTANGLE, self.texColorTexture )
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA32F, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None)
glBindTexture(GL_TEXTURE_RECTANGLE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, self.texColorTexture, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def deleteRenderTargets(self):
if (self.fboAccumulation is not None):
glDeleteFramebuffers(1,self.fboRendering)
self.fboAccumulation = None
if (self.texColorTexture is not None):
glDeleteTextures( self.texColorTexture )
self.texColorTexture = None
def initColorVolume(self):
if (self.texColorVolume is None):
self.texColorVolume = glGenTextures( 1 )
glBindTexture( GL_TEXTURE_3D, self.texColorVolume )
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, iTexSize, iTexSize, iTexSize, 0, GL_RGBA, GL_FLOAT, None);
glBindTexture(GL_TEXTURE_3D, 0);
def fillVolume(self, bClear):
global iTexSize
shaShader = self.shaShaderClear
if(not bClear):
shaShader = self.shaShaderFill
if (not self.fboRendering):
self.initRenderTargets()
if (not self.texColorVolume):
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
glBindFramebuffer(GL_FRAMEBUFFER, self.fboRendering);
glDrawBuffers(1, self.vecDrawBuffers);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
shaShader.bind()
shaShader.setUniformValue("iPrimitiveCount", iTexSize)
shaShader.setUniformValue("volColorVolume", 0)
for i in range(iTexSize):
shaShader.setUniformValue("iSliceIndex", i)
glBegin(GL_QUADS);
glVertex2f(-1.0, -1.0);
glVertex2f(1.0, -1.0);
glVertex2f(1.0, 1.0);
glVertex2f(-1.0, 1.0);
glEnd();
#sync
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
glBindImageTexture(0,0,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
shaShader.release()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
def paintGL(self):
if (self.uWidth is 0):
return
if (not self.fboRendering):
self.initRenderTargets()
self.initColorVolume()
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.fillVolume(True)
#draw into the volume
#self.fillVolume(False)
#slice the volume
self.displayTexture()
glFlush()
def displayTexture(self): #essentially not useable here
glMatrixMode( GL_PROJECTION )
glLoadIdentity()
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glDisable(GL_BLEND)
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor(1.0, 1.0,1.0)
glEnable(GL_TEXTURE_3D);
glBindTexture( GL_TEXTURE_3D, self.texColorVolume )
fZCoord = self.fZCoord
glBegin(GL_QUADS);
glTexCoord3f(0,0,fZCoord)
glVertex2f(-1.0, -1.0);
glTexCoord3f(1,0,fZCoord)
glVertex2f(1.0, -1.0);
glTexCoord3f(1,1,fZCoord)
glVertex2f(1.0, 1.0);
glTexCoord3f(0,1,fZCoord)
glVertex2f(-1.0, 1.0);
glEnd();
glBindTexture( GL_TEXTURE_3D, 0 )
def resizeGL(self, widthInPixels, heightInPixels):
if ((widthInPixels is not self.uWidth) or (heightInPixels is not self.uHeight)):
self.uWidth = widthInPixels
self.uHeight = heightInPixels
glViewport(0, 0, widthInPixels, heightInPixels)
self.update()
class TestImageLoadStore3D(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setWindowTitle('TestImageLoadStore3D')
self.statusBar().showMessage("Hello there")
exit = QtGui.QAction("Exit", self)
exit.setShortcut("Ctrl+Q")
exit.setStatusTip('Exit application')
self.connect(exit, QtCore.SIGNAL('triggered()'), QtCore.SLOT('close()'))
self.setToolTip('This is a window, or <b>something</b>')
self.viewer3D = Viewer3DWidget(self)
parentWidget = QtGui.QWidget()
slider1 = QtGui.QSlider(QtCore.Qt.Horizontal, None)
slider1.setRange(0,10000)
slider1.setValue(5000)
slider1.setMaximumWidth(120)
slider1.valueChanged.connect(self.slider1Handler)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(slider1)
vbox.addStretch(1)
self.viewer3D.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )
hbox = QtGui.QHBoxLayout()
hbox.addLayout(vbox)
hbox.addWidget(self.viewer3D)
parentWidget.setLayout(hbox)
self.setCentralWidget(parentWidget)
self.resize(500,500)
def closeEvent(self, event):
event.accept()
def slider1Handler(self, iVal):
fVal = iVal / 10000.0
#print "zcoord: ",fVal
self.viewer3D.setZCoordinate(fVal)
if __name__ == '__main__':
# app = QtGui.QApplication(['Python Qt OpenGL Demo'])
app = QtGui.QApplication(sys.argv)
window = TestImageLoadStore3D()
window.show()
sys.exit(app.exec_())
代码不是特别整洁,也是因为我复制/粘贴/修改了一些较旧的 pyopengl 代码。问题是写在3D纹理中的值绝对没有意义。我使用最新版本的PyOpenGL(实验版本),Quadro K5000和最新的驱动程序(332.76)运行它,这些驱动程序也为OpenGL 4.4提供支持。
我不确定我可能做错了什么,也是因为我没有找到很多写入 3D 纹理的例子(实际上没有,我也查看了最新版本的红皮书)
有人可以开导我吗?
您的问题出在碎片着色器中:
layout(size4x32, binding=0) writeonly uniform image3D volColorVolume;
您正在通过以下方式绑定 3D 纹理
glBindImageTexture(0,self.texColorVolume,0,GL_FALSE,0,GL_WRITE_ONLY,GL_RGBA32F);
让我引用OpenGL 4.4规范第8.26节"纹理图像加载和存储"(强调我的):
如果由纹理标识的纹理是一维数组, 二维数组、三维、立方体贴图、立方体贴图数组或 二维多重采样数组纹理,可以绑定 整个纹理级别或单个图层或面 纹理级别。如果分层为 TRUE,则绑定整个关卡。如果 layered 为 FALSE,只有由 layer 标识的单个图层才会 绑定。当分层为 FALSE 时,单个绑定图层被视为 图像访问的不同纹理目标:
一维
- 数组纹理层被视为一维纹理;
二维阵列、三维、立方体- 贴图、立方体贴图阵列纹理层被视为二维纹理;和
二维多重采样- 数组纹理被视为二维多重采样纹理。
因此,如果您只是将 layered
参数设置为 GL_FALSE
的 3D 纹理的一层(就像您当前所做的那样),它将表现得好像它只是一个 2D 纹理,因此只需使用image2D
并使用 2D 坐标访问它,或者将其绑定为设置为 GL_TRUE
的layered
和您可以写入特定图层的有效图层范围/使用image3D
和三维图像坐标的纹理切片。
python中有60个分号。Python 不使用分号。事实上,我很确定python是唯一真正不使用分号的编程语言。