设置着色器的矩阵

 懿切瀡纟彖_639 发布于 2023-01-15 13:44

我想绘制实例多维数据集.

我可以GL.DrawArraysInstanced(PrimitiveType.Triangles, 0, 36, 2);成功打电话.

我的问题是所有的立方体都是在相同的位置和相同的旋转绘制的.我怎样才能为每个立方体单独更改?

要创建不同的位置等,我需要每个立方体的矩阵,对吧?我创造了这个:

Matrix4[] Matrices = new Matrix4[]{
  Matrix4.Identity, //do nothing
  Matrix4.Identity * Matrix4.CreateTranslation(1,0,0) //move a little bit
};

GL.BindBuffer(BufferTarget.ArrayBuffer, matrixBuffer);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(sizeof(float) * 16 * Matrices.Length), Matrices, BufferUsageHint.StaticDraw);

这应该创建一个缓冲区,我可以存储我的矩阵.matrixBuffer是指向我的缓冲区的指针.我不确定大小是否正确,我采用浮动*4(对于Vector4)*4(对于4个向量)*数组大小.

绘制循环:

GL.BindBuffer(BufferTarget.ArrayBuffer, matrixBuffer);
GL.VertexAttribPointer(3, 4, VertexAttribPointerType.Float, false, 0, 0);
//GL.VertexAttribDivisor(3, ?);
GL.EnableVertexAttribArray(3);

GL.DrawArraysInstanced(PrimitiveType.Triangles, 0, 36, 2);

任何高于4的数字VertexAttribPointer(..., 4, VertexattribPointerType.Float, ...);都会导致崩溃.我认为我必须将该值设置为16?

我不确定我是否需要一个VertexAttribDivisor,可能我需要这个每36个顶点所以我打电话GL.VertexAttribDivisor(3, 36);?但是当我这样做时,我看不到任何立方体.

我的顶点着色器:

#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 texCoord;
layout(location = 3) in mat4 instanceMatrix;

uniform mat4 projMatrix;

out vec4 vColor;
out vec2 texCoords[];

void main(){
  gl_Position = instanceMatrix * projMatrix * vec4(position, 1.0);
  //gl_Position = projMatrix * vec4(position, 1.0);
  texCoords[0] = texCoord;
  vColor = color;
}

所以我的问题:

我的代码出了什么问题?

为什么我只能将VertexAttribPointer的size-parameter设置为4?

VertexAttribDivisor的正确值是多少?


编辑:

根据Andon M. Coleman的回答,我做了这些改变:

GL.BindBuffer(BufferTarget.UniformBuffer, matrixBuffer);
GL.BufferData(BufferTarget.UniformBuffer, (IntPtr)(sizeof(float) * 16), IntPtr.Zero, BufferUsageHint.DynamicDraw);
//Bind Buffer to Binding Point
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, matrixUniform, matrixBuffer);

matrixUniform = GL.GetUniformBlockIndex(shaderProgram, "instanceMatrix");
//Bind Uniform Block to Binding Point
GL.UniformBlockBinding(shaderProgram, matrixUniform, 0);

GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, (IntPtr)(sizeof(float) * 16 * Matrices.Length), Matrices);

着色器:

#version 330 core
layout(location = 0) in vec4 position; //gets vec3, fills w with 1.0
layout(location = 1) in vec4 color;
layout(location = 2) in vec2 texCoord;

uniform mat4 projMatrix;
uniform UniformBlock
{ mat4 instanceMatrix[]; };

out vec4 vColor;
out vec2 texCoords[];

void main(){
  gl_Position = projMatrix * instanceMatrix[0] * position;
  texCoords[0] = texCoord;
  vColor = color;
}

Andon M. Col.. 8

您已经发现顶点属性位置始终是4分量的困难方式.

使4x4矩阵成为每顶点属性的唯一方法是,如果你承认它mat4是4倍大的vec4.

考虑您的mat4顶点属性的声明:

layout(location = 3) in mat4 instanceMatrix;

您可能自然会认为位置3存储了16个浮点值,但您会错.GLSL中的位置始终为4个组件.因此,mat4 instanceMatrix实际上占据了4个不同的位置.

这基本上是如何instanceMatrix工作的:

layout(location = 3) in vec4 instanceMatrix_Column0;
layout(location = 4) in vec4 instanceMatrix_Column1;
layout(location = 5) in vec4 instanceMatrix_Column2;
layout(location = 6) in vec4 instanceMatrix_Column3;

幸运的是,您不必以这种方式编写着色器,具有mat4顶点属性是完全有效的.

但是,你必须写C#代码的行为是那样:

GL.BindBuffer(BufferTarget.ArrayBuffer, matrixBuffer);
GL.VertexAttribPointer(3, 4, VertexAttribPointerType.Float, false, 64,  0); // c0
GL.VertexAttribPointer(4, 4, VertexAttribPointerType.Float, false, 64, 16); // c1
GL.VertexAttribPointer(5, 4, VertexAttribPointerType.Float, false, 64, 32); // c2
GL.VertexAttribPointer(6, 4, VertexAttribPointerType.Float, false, 64, 48); // c3

同样,您必须为所有4个位置设置顶点属性除数:

GL.VertexAttribDivisor (3, 1);
GL.VertexAttribDivisor (4, 1);
GL.VertexAttribDivisor (5, 1);
GL.VertexAttribDivisor (6, 1);

顺便说一下,因为顶点属性总是4个组件,所以你可以实际声明:

layout(location = 0) in vec4 position;

并停止编写丑陋的代码,如下所示:

gl_Position = instanceMatrix * projMatrix * vec4(position, 1.0);

这是因为OpenGL会自动扩展顶点属性中缺少的组件.

      (0.0,0.0,0.0,1.0)

如果vec4在GLSL着色器中声明顶点属性,但仅为XYZ提供数据,则会W自动为其指定值1.0.


实际上,您不希望存储每个顶点的矩阵.这浪费了多个顶点属性位置.您可以考虑的是一系列制服,或者更好的统一缓冲区.您可以使用Vertex Shader预先声明的变量索引此数组:gl_InstanceID.这是解决此问题的最明智的方法,因为您可能会发现每个实例使用的属性多于顶点属性位置(GL 3.3中的mininum 16,只有少数GPU实际支持16个以上).

请记住,vec4顶点着色器可以在单个调用中使用的制服数量有限制,并且mat4计数为a的4倍vec4.使用统一缓冲区将允许您绘制比普通旧制服阵列更多的实例.

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有