GLSL——旋转、平移和缩放

6 篇文章 4 订阅
4 篇文章 2 订阅

hello 兄弟们,好久不见撒,我又回来啦!,今天主要讲解如何在顶点着色器中进行旋转、平移和缩放,涉及到矩阵和向量方面的知识哦,忘记的可以翻一下高中数学啦,在讲之前,先回顾一下矩阵和向量点积的知识,矩阵点乘向量,等于矩阵的每一行分别和向量相乘的和,如图1所示,单位矩阵和向量(x,y,z,w)的点乘:

图1

 一、旋转

图2所示,x轴上一点,绕z轴先转α角度后到B点的位置,求B点的坐标:

图2

 利用和角公式可得B点的坐标:

                        f(x) = x*cos(α) - y*sin(α);

                        f(y) = x*sin(α) + y*cos(α);

结合图1的矩阵,若要f(x) = x*cos(α) - y*sin(α),则矩阵的第一行元素为(cos(α), -sin(α), 0, 0),若要f(y) = x*sin(α) + y*cos(α),则矩阵的第二行元素为(sin(α), cos(α), 0, 0),所以矩阵为图3所示,因为我们计算矩阵用的是行主序,而shader中用的是列主序,需要将行主序转换成列主序:

                                                     图3

了解了原理后,就可以在shader中进行旋转了。我画了一个正方形(具体画法看我前几篇文章,这里不做介绍,直接在顶点shader里进行旋转),让正方形旋转30°,代码如下:

attribute vec3 kzPosition;
uniform highp mat4 kzProjectionCameraWorldMatrix;
void main()
{
    precision mediump float;
    //度数转为弧度制
    float angle = radians(30.);

    //旋转矩阵
    mat4 m4 = mat4(
    cos(angle), sin(angle), 0.0, 0.0,
    -sin(angle), cos(angle), 0.0, 0.0,
    0.0,        0.0,         1.0, 0.0,
    0.0,        0.0,         0.0, 1.0
    );
    
    vec4 pos = m4 * vec4(kzPosition, 1.0);
    gl_Position = kzProjectionCameraWorldMatrix * pos;
}

 效果图如图4所示:

图4

 二、平移

让图形沿x轴平移100,沿y平移200,也就是让图1中的x为x+100,让y为y+200,那么和什么矩阵点乘会得到想要的结果呢?我们可以看到,图1的矩阵出了(x,y,z),还有个w的元素,这个w也就是矩阵的齐次坐标(自行补习知识,这里不做赘述),我们可以通过w来改变图形的位移,得到的平移矩阵如图5所示:(记得在shader中使用的是列主席哦)

 平移代码:

attribute vec3 kzPosition;
uniform highp mat4 kzProjectionCameraWorldMatrix;
void main()
{
    precision mediump float;
    float tx = 100.;
    float ty = 200.;
    float tz = 0.;
    //x,y移动100,200
    mat4 m = mat4(
        1.0, 0.0, 0.0, 0.0,
        0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 1.0, 0.0,
        tx,  ty,  tz,  1.0
    );
    
    vec4 pos = m * vec4(kzPosition, 1.);
    gl_Position = kzProjectionCameraWorldMatrix * pos;
}

 三、缩放

如果使图片的x和y各缩放0.5倍,那么图1中的x应该为0.5x,y应为0.5y,即矩阵的第一行的结果为0.5x,第二行为0.5y,则矩阵第一行的x的元素就应该是0.5,第二行的y元素也应该是0.5,得到的矩阵如图6:

代码:

attribute vec3 kzPosition;
uniform highp mat4 kzProjectionCameraWorldMatrix;
void main()
{
    precision mediump float;
    float sx = 0.5;
    float sy = 0.5;
    float sz = 1.;
    mat4 m = mat4(
        sx,  0.0, 0.0, 0.0,
        0.0, sy,  0.0, 0.0,
        0.0, 0.0, sz, 0.0,
        0.0, 0.0, 0.0, 1.0
    );
    
    vec4 pos = vec4(kzPosition, 1.) * m;
    gl_Position = kzProjectionCameraWorldMatrix * pos;
}

 效果图如图7所示:(相较于图4,缩小了0.5倍)

图7

可以使用 QOpenGLWidget 类来创建一个 OpenGL 窗口,并使用 QMatrix4x4 类来实现旋转平移缩放。以下是一个简单的示例代码: ```python from PyQt5.QtWidgets import QApplication, QOpenGLWidget from PyQt5.QtGui import QOpenGLShader, QOpenGLShaderProgram, QMatrix4x4 from PyQt5.QtCore import Qt class OpenGLWidget(QOpenGLWidget): def initializeGL(self): self.shaderProgram = QOpenGLShaderProgram() self.shaderProgram.addShaderFromSourceFile(QOpenGLShader.Vertex, "vertexShader.glsl") self.shaderProgram.addShaderFromSourceFile(QOpenGLShader.Fragment, "fragmentShader.glsl") self.shaderProgram.link() self.vertices = [ -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0 ] self.vbo = self.createBuffer(self.vertices) self.projectionMatrix = QMatrix4x4() self.projectionMatrix.perspective(60, self.width() / self.height(), 0.1, 100.0) self.viewMatrix = QMatrix4x4() self.viewMatrix.translate(0.0, 0.0, -3.0) self.modelMatrix = QMatrix4x4() def paintGL(self): self.shaderProgram.bind() self.shaderProgram.setUniformValue("projectionMatrix", self.projectionMatrix) self.shaderProgram.setUniformValue("viewMatrix", self.viewMatrix) self.shaderProgram.setUniformValue("modelMatrix", self.modelMatrix) self.vbo.bind() self.shaderProgram.setAttributeBuffer("vertexPosition", Qt.GL_FLOAT, 0, 3) self.shaderProgram.enableAttributeArray("vertexPosition") self.glDrawArrays(Qt.GL_TRIANGLES, 0, 3) self.vbo.release() self.shaderProgram.release() def resizeGL(self, width, height): self.projectionMatrix.setToIdentity() self.projectionMatrix.perspective(60, width / height, 0.1, 100.0) def createBuffer(self, data): vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer) vbo.create() vbo.bind() vbo.allocate(data, len(data) * 4) vbo.release() return vbo ``` 这个示例代码使用了一个简单的三角形作为渲染对象,使用了一个顶点着色器和一个片段着色器来实现 OpenGL 渲染。可以通过修改顶点着色器和片段着色器来实现不同的效果。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值