【问题标题】:Rotate quad made in geometry shader在几何着色器中旋转四边形
【发布时间】:2015-03-23 08:33:23
【问题描述】:

我正在使用几何着色器绘制一个四边形,但不知道如何用角度旋转它。

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?我数学不太好。

【问题讨论】:

    标签: c++ opengl glsl


    【解决方案1】:

    您不必使用矩阵,但需要使用那些正弦函数。这是一种将 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-18
      • 2023-03-28
      • 2020-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多