矩阵的设置,例如着色器 [英] Setup of matrix for instance shader

查看:194
本文介绍了矩阵的设置,例如着色器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想提请实例化的立方体



我可以叫 GL.DrawArraysInstanced(PrimitiveType.Triangles,0,36,2); 成功。



我的问题是,所有的多维数据集在相同的位置,相同的旋转绘制。我怎样才能改变这种单独为每立方?



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

  Matrix4 [] =矩阵新Matrix4 [] {
Matrix4.Identity,//什么也不做
Matrix4.Identity * Matrix4.CreateTranslation(1,0,0)//移动一点点
};

GL.BindBuffer(BufferTarget.ArrayBuffer,matrixBuffer);
GL.BufferData(BufferTarget.ArrayBuffer,(IntPtr的)(的sizeof(浮动)* 16 * Matrices.Length),矩阵,BufferUsageHint.StaticDraw);

这应该创建一个缓冲区,我可以存储我的矩阵。 matrixBuffer 是指向我的缓冲区。 。林不知道如果尺寸是正确的,我把浮动* 4(为的Vector4)* 4(4矢量)*数组大小



绘制环路:

  GL.BindBuffer(BufferTarget.ArrayBuffer,matrixBuffer); 
GL.VertexAttribPointer(3,4,VertexAttribPointerType.Float,假,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核心
布局(位置= 0);在vec4颜色
布局(位置= 1);在VEC2 texCoord
布局(位置= 2);在mat4 instanceMatrix
布局(位置= 3);

均匀mat4 projMatrix;

OUT vec4 vColor;
OUT VEC2 texCoords [];

无效的主要(){
GL_POSITION = instanceMatrix * projMatrix * vec4(位置,1.0);
// GL_POSITION = projMatrix * vec4(位置,1.0);
texCoords [0] = texCoord;
vColor =颜色;
}



所以我的问题:




  • 什么是错我的代码?

  • 为什么可以VertexAttribPointer的大小参数设置为仅4?

  • 什么是VertexAttribDivisor正确的值






编辑:



根据安灯科尔曼先生的答案我做了这个变化:

  GL.BindBuffer(BufferTarget.UniformBuffer,matrixBuffer); 
GL.BufferData(BufferTarget.UniformBuffer,(IntPtr的)(的sizeof(浮动)* 16),IntPtr.Zero,BufferUsageHint.DynamicDraw);
//绑定缓冲到结合点
GL.BindBufferBase(BufferRangeTarget.UniformBuffer,matrixUniform,matrixBuffer);

matrixUniform = GL.GetUniformBlockIndex(shaderPrograminstanceMatrix);
//绑定统一模块来结合点
GL.UniformBlockBinding(shaderProgram,matrixUniform,0);

GL.BufferSubData(BufferTarget.UniformBuffer,IntPtr.Zero,(IntPtr的)(的sizeof(浮动)* 16 * Matrices.Length),矩阵);

和着色器:

 的#Version 330芯vec4位置
布局(位置= 0); //得到VEC3,填写W和在vec4色1.0
布局(位置= 1);在VEC2 texCoord
布局(位置= 2);

均匀mat4 projMatrix;
均匀UniformBlock
{mat4 instanceMatrix []; };

OUT vec4 vColor;
OUT VEC2 texCoords [];

无效的主要(){
GL_POSITION = projMatrix * instanceMatrix [0] *位置;
texCoords [0] = texCoord;
vColor =颜色;
}


解决方案

您已经发现了艰辛的道路顶点属性的位置始终四部分。



做一个4x4矩阵每个顶点属性的唯一方法是,如果你承认, mat4 为4x为 vec4 一样大。



考虑你的<$ C的声明$ C> mat4 顶点属性:



 在mat4 instanceMatrix布局(位置= 3); 

您可能自然而然地想到那个位置的 3 存储16个浮点值,但你就错了。在GLSL的位置始终四部分。因此, mat4 instanceMatrix 竟占据4个不同的位置。



这实质上是如何 instanceMatrix 实际工作:



 布局(位置= 3)vec4 instanceMatrix_Column0;在vec4 instanceMatrix_Column1 
布局(位置= 4);在vec4 instanceMatrix_Column2
布局(位置= 5);在vec4 instanceMatrix_Column3
布局(位置= 6);



幸运的是,你不必写你的着色器的方式,这是非常有效的有 mat4 顶点属性。



不过,您有写C#代码的行为是那样:



  GL.BindBuffer(BufferTarget.ArrayBuffer,matrixBuffer); 
GL.VertexAttribPointer(3,4,VertexAttribPointerType.Float,假,64,0); // C0
GL.VertexAttribPointer(4,4,VertexAttribPointerType.Float,假,64,16); // C1
GL.VertexAttribPointer(5,4,VertexAttribPointerType.Float,假,64,32); // C2
GL.VertexAttribPointer(6,4,VertexAttribPointerType.Float,假,64,48); // C3



同样的,你必须设置你的顶点属性除数为所有4个地点:



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






顺便说一下,因为顶点属性始终是4组分,实际上你可以声明:



 在vec4位置布局(位置= 0); 



别再写这样丑陋的代码:



  GL_POSITION = instanceMatrix * projMatrix * vec4(位置,1.0); 

这是因为在一个顶点属性缺少的组件会自动的OpenGL扩展。



&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP; (0.0,0.0,0.0,1.0)



如果您声明>的GLSL着色器XYZ顶点属性作为 vec4 是W 自动分配的 1.0






值实际上,你不想来存储您的矩阵每个顶点。即多个顶点属性的地点的浪费。你可能考虑的是制服,或更好的数组没有一个统一的缓冲区。您可以使用索引顶点着色器预先定义的变量数组: gl_InstanceID 。这确实是解决这个最明智的办法,因为你可以使用每个实例的详细性能比你有顶点属性的位置(发现自己的的最小值的在GL 3.3 16,只有少数的GPU真正支持多考虑到16)。



请有到顶点着色器可以使用 vec4 制服的数量限制在一个单一的调用,并在 mat4 算作4X的 vec4 的大小。使用统一的缓冲区将可以绘制更多的情况下,比普通的旧数组将制服。


I want to draw instanced cubes.

I can call GL.DrawArraysInstanced(PrimitiveType.Triangles, 0, 36, 2); successfully.

My problem is that all the cubes are drawn at the same position and same rotation. How can i change that individually for every cube?

To create different positions and so on, i need a matrix for each cube, right? I created this:

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

This should create a buffer where i can store my matrices. matrixBuffer is the pointer to my buffer. Im not sure if the size is correct, i took float * 4 (for Vector4) * 4 (for 4 vectors) * array-size.

Draw Loop:

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

Any higher number than 4 in VertexAttribPointer(..., 4, VertexattribPointerType.Float, ...); causes a crash. I tought i have to set that value to 16?

Im not sure if i need a VertexAttribDivisor, probably i need this every 36th vertex so i call GL.VertexAttribDivisor(3, 36);? But when i do that, i can't see any cube.

My vertex shader:

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

So my questions:

  • What is wrong with my code?
  • Why can i set the size-parameter of VertexAttribPointer only to 4?
  • What is the correct value for VertexAttribDivisor?

Edit:

Based on the answer of Andon M. Coleman i made this changes:

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

And shader:

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

解决方案

You have discovered the hard way that vertex attribute locations are always 4-component.

The only way to make a 4x4 matrix a per-vertex attribute is if you concede that mat4 is 4x as large as vec4.

Consider the declaration of your mat4 vertex attribute:

layout(location = 3) in mat4 instanceMatrix;

You might naturally think that location 3 stores 16 floating-point values, but you would be wrong. Locations in GLSL are always 4-component. Thus, mat4 instanceMatrix actually occupies 4 different locations.

This is essentially how instanceMatrix actually works:

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;

Fortunately, you do not have to write your shader that way, it is perfectly valid to have a mat4 vertex attribute.

However, you do have to write your C# code to behave that way:

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

Likewise, you must setup your vertex attribute divisor for all 4 locations:

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


Incidentally, because vertex attributes are always 4-component, you can actually declare:

layout(location = 0) in vec4 position;

And stop writing ugly code like this:

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

This is because missing components in a vertex attribute are automatically expanded by OpenGL.

      (0.0, 0.0, 0.0, 1.0)

If you declare a vertex attribute as vec4 in the GLSL shader, but only supply data for XYZ, then W is automatically assigned a value of 1.0.


In actuality, you do not want to store your matrices per-vertex. That is a waste of multiple vertex attribute locations. What you may consider is an array of uniforms, or better yet a uniform buffer. You can index this array using the Vertex Shader pre-declared variable: gl_InstanceID. That is really the most sensible way to approach this, because you may find yourself using more properties per-instance than you have vertex attribute locations (mininum 16 in GL 3.3, only a few GPUs actually support more than 16).

Keep in mind that there is a limit to the number of vec4 uniforms a vertex shader can use in a single invocation, and that a mat4 counts as 4x the size of a vec4. Using a uniform buffer will allow you to draw many more instances than a plain old array of uniforms would.

这篇关于矩阵的设置,例如着色器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆