目前我正在将我们的OpenGL-Engine升级到一个新的着色和属性系统,它更具动态性,并且在使用和编程方面不是静态的。
为此,我将旧的VertexBuffer
课程替换为分配了多个BufferRenderer
(DataBuffer
,RenderDataBuffer
)对象的新RenderIndexBuffer
课程,那些拿着我的渲染数据。这个新系统允许使用glDrawElementsInstanced
进行实例化,并使用glDrawElements
进行静态渲染。
看起来属性会破坏现有的位置属性并导致意外的结果。我用不同的设置测试了这个
此代码设置测试数据:
_Shader = new Shader(ShaderSource.FromFile("InstancingShader.xml"));
_VertexBuffer = new BufferRenderer();
RenderDataBuffer positionBuffer = new RenderDataBuffer(ArrayBufferTarget.ARRAY_BUFFER, ArrayBufferUsage.STATIC_DRAW,
new VertexDeclaration(DeclarationType.Float, DeclarationSize.Three, AttributeBindingType.Position));
// Set the position data of the quad
positionBuffer.BufferData(new[] { new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0), new Vector3(1, 0, 1) });
RenderDataBuffer instanceBuffer = new RenderDataBuffer(ArrayBufferTarget.ARRAY_BUFFER, ArrayBufferUsage.DYNAMIC_DRAW,
new VertexDeclaration(DeclarationType.Float, DeclarationSize.Four, AttributeBindingType.Instancing),
new VertexDeclaration(DeclarationType.Float, DeclarationSize.Four, AttributeBindingType.Color));
// Buffer the instance data
instanceBuffer.BufferData<InstanceTestData>(new[] {
new InstanceTestData() { Color = Colors.Red, PRS = new Color(0.1f, 1f, 0.5f, 1) },
new InstanceTestData() { Color = Colors.Blue, PRS = new Color(1f, 1f, 0.5f, 1) },
new InstanceTestData() { Color = Colors.Green, PRS = new Color(0.1f, 1f, 1f, 1) },
new InstanceTestData() { Color = Colors.Yellow, PRS = new Color(1f, 1f, 1f, 1) }
});
// Set up a index buffer for indexed rendering
RenderIndexBuffer indiciesBuffer = new RenderIndexBuffer(type: IndiciesType.UNSIGNED_BYTE);
indiciesBuffer.BufferData(new Byte[] { 2, 1, 0, 1, 2, 3 });
// Register the buffers ( second parameter is used for glVertexAttribDivisor )
_VertexBuffer.AddBuffer(positionBuffer);
_VertexBuffer.AddBuffer(instanceBuffer, 1);
_VertexBuffer.IndexBuffer = indiciesBuffer;
顶点着色器(像素只输出颜色):
uniform mat4 uModelViewProjection;
varying vec4 vColor;
attribute vec3 aPosition; // POSITION0
attribute vec4 aColor; // COLOR 0
attribute vec4 aInstancePosition; // INSTANCING0
void main()
{
gl_Position = uModelViewProjection * vec4(vec2((aPosition.x * 20) + (gl_InstanceID * 20), aPosition.z * 20), -3, 1);
vColor = aColor;
}
glUseProgram
foreach (parameter in shader_parameters)
glUniformX
foreach (buffer in render_buffers)
glBindBuffer
foreach (declaration in buffer.vertex_declarations)
if (shader.Exists(declaration)) // Check if declaration exists in shader
glEnableVertexAttribArray(shader.attributeLocation(declaration))
glVertexAttribPointer
if (instanceDivisor != null)
glVertexAttribDivisor
glBindBuffer(index_buffer)
glDrawElementsInstanced
着色器属性绑定在初始化时完成,如下所示:
_VertexAttributes = source.Attributes.ToArray();
for (uint i = 0; i < _VertexAttributes.Length; i++)
{
ShaderAttribute attribute = _VertexAttributes[i];
GLShaders.BindAttribLocation(_ShaderHandle, i, attribute.Name);
}
因此,着色器中应该没有属性别名,每个都有一个唯一的数字(矩阵尚未实现,我知道它们需要多个索引,但我现在也没有使用它们作为顶点属性)。正如评论中所提到的,我在链接着色器之后过滤了属性,因此没有绑定不存在的位置。
这是属性绑定的代码:
Bind();
Int32 offset = 0;
for (UInt32 i = 0; i < _Declarations.Length; i++)
{
VertexDeclaration data = _Declarations[i];
ShaderAttributeLocation location;
if (shader.GetAttributeLocation(data.Binding, out location))
{
GLVertexBuffer.EnableVertexAttribArray(location);
GLVertexBuffer.VertexAttribPointer(location, (AttributeSize)data.Size, (AttributeType)data.Type, data.Normalized, _StrideSize, new IntPtr(offset));
if (instanceDivisor != null)
GLVertexBuffer.VertexAttribDivisor(location, instanceDivisor.Value);
}
offset += data.ComponentSize;
}
结果如下所示:
现在,如果我更改代码端的绑定(AttributeBindingType.Color
&lt; - &gt; AttributeBindingType.Instancing
),它看起来像这样:
如果我现在将vColor = aColor;
更改为vColor = aInstancePosition;
,结果很简单:我没有多个带有颜色的小四边形,而是有一个大的全屏四边形,它是红色的。每个属性的位置与其他属性不同,因此从技术上讲,这些值应该是正确的,但它们似乎不是。在着色器中同时使用这两个属性也无法解决问题。
我正在寻找解决这个问题的想法或解决方案。
我已经开始越来越多地跟踪它了,这个复杂的代码花了我几个小时但我发现了一些东西:我正在使用的着色器只在我调用{{1时省略属性索引0时才工作}}。换句话说,这是一种仅适用于指定着色器的解决方法:
BindAttribLocation
我想它与实例化或我用于实例化的多个VBO有关。这是与普通着色器的唯一区别。正常的只有在我将属性位置索引设置为0时才起作用,它们在从1开始时不起作用。
答案 0 :(得分:0)
我找到了问题的解决方案,而且非常简单。
在使用实例进行渲染之后,我需要在之前启用了除数的属性上调用glVertexAttribDivisor(location, 0);
。