旋转几何着色器中制作的四边形

时间:2015-01-24 10:32:51

标签: c++ opengl glsl

我正在使用几何着色器绘制四边形,但无法弄清楚如何用角度旋转它。

void main(void)
{
float scaleX = 2.0f / u_resolution.x;
float scaleY = 2.0f / u_resolution.y;

float nx = (u_position.x * scaleX) - 1.0f;
float ny = -(u_position.y * scaleY) + 1.0f;

float nw = u_size.x * scaleX;
float nh = u_size.y * scaleY;


gl_Position = vec4( nx+nw, ny, 0.0, 1.0 );
texcoord = vec2( 1.0, 0.0 );
EmitVertex();

gl_Position = vec4(nx, ny, 0.0, 1.0 );
texcoord = vec2( 0.0, 0.0 ); 
EmitVertex();

gl_Position = vec4( nx+nw, ny-nh, 0.0, 1.0 );
texcoord = vec2( 1.0, 1.0 ); 
EmitVertex();

gl_Position = vec4(nx, ny-nh, 0.0, 1.0 );
texcoord = vec2( 0.0, 1.0 ); 
EmitVertex();


EndPrimitive(); 
}

我应该使用旋转矩阵还是sin和cos?我的数学不太好。

1 个答案:

答案 0 :(得分:0)

您不必使用矩阵,但您需要使用这些正弦函数。这是一种将3D位置围绕某个任意轴旋转某个角度的方法:

// This is the 3D position that we want to rotate:
vec3 p = position.xyz;

// Specify the axis to rotate about:
float x = 0.0;
float y = 0.0;
float z = 1.0;

// Specify the angle in radians:
float angle = 90.0 * 3.14 / 180.0; // 90 degrees, CCW

vec3 q;
q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
    + p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
    + p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));

q.y = p.x * (y*x * (1.0 - cos(angle)) - z * sin(angle))
    + p.y * (y*y * (1.0 - cos(angle)) + cos(angle))
    + p.z * (y*z * (1.0 - cos(angle)) + x * sin(angle));

q.z = p.x * (z*x * (1.0 - cos(angle)) + y * sin(angle))
    + p.y * (z*y * (1.0 - cos(angle)) - x * sin(angle))
    + p.z * (z*z * (1.0 - cos(angle)) + cos(angle));

gl_Position = vec4(q, 1.0);

如果你知道你正在转动一些标准的x轴,y轴或z轴,你可以简化"算法"通过为该标准轴明确定义它。

注意我们如何围绕上面代码中的z轴旋转。例如,围绕x轴的旋转将是(x,y,z) = (1,0,0)。您可以将变量设置为任何值,但这些值应该导致轴为单位向量(如果这甚至很重要。)

然后,你也可以使用矩阵:

vec3 n = vec3(0.0, 0.0, 1.0); // the axis to rotate about

// Specify the rotation transformation matrix:
mat3 m = mat3(
  n.x*n.x * (1.0f - cos(angle)) + cos(angle),       // column 1 of row 1
  n.x*n.y * (1.0f - cos(angle)) + n.z * sin(angle), // column 2 of row 1
  n.x*n.z * (1.0f - cos(angle)) - n.y * sin(angle), // column 3 of row 1

  n.y*n.x * (1.0f - cos(angle)) - n.z * sin(angle), // column 1 of row 2
  n.y*n.y * (1.0f - cos(angle)) + cos(angle),       // ...
  n.y*n.z * (1.0f - cos(angle)) + n.x * sin(angle), // ...

  n.z*n.x * (1.0f - cos(angle)) + n.y * sin(angle), // column 1 of row 3
  n.z*n.y * (1.0f - cos(angle)) - n.x * sin(angle), // ...
  n.z*n.z * (1.0f - cos(angle)) + cos(angle)        // ...
);

// Apply the rotation to our 3D position:
vec3 q = m * p;
gl_Position = vec4(q, 1.0);

注意矩阵的元素是如何布局的,这样我们首先完成第一列,然后是第二列,依此类推;矩阵按列主要顺序排列。当您尝试将用数学符号编写的矩阵转换为代码中的数据类型时,这很重要。你基本上需要转置它(以对角方式翻转元素),以便在你的代码中使用它。此外,我们基本上将左侧的矩阵与右侧的列向量相乘。

如果您需要一个4乘4的齐次矩阵,那么您只需在上面的矩阵中添加一个额外的列和一行,这样新的最右列和最下面的行都将包含[0 0 0 1]

vec4 p = position.xyzw; // new dimension
vec3 n = ...; // same

mat4 m = mat4( // new dimension
  ...
  0.0,

  ...
  0.0,

  ...
  0.0,

  0.0,
  0.0,
  0.0,
  1.0
);

vec4 q = m * p;
gl_Position = q;

再次注意应用旋转时乘法的顺序,这很重要,因为它会影响最终结果。在乘法中发生的事情基本上是通过计算矩阵中位置矢量和每列的点积来形成新的矢量;结果向量中的每个坐标是原始向量和矩阵中单个列的点积(参见第一个代码示例。)

q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
    + p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
    + p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));

与:

相同
q.x = dot(p, m[0]);

甚至可以用自己组成矩阵:m = m*m;这将导致180度逆时针旋转矩阵,具体取决于所使用的angle