我的webgl学习之路(六)变换矩阵

对一个三角形变换有:缩放,移动,旋转;如果每次都向上面那样单独设置变量,做变换操作是很麻烦的一件事,于是就有了矩阵,它能把变换的所有操作放到里面去,这样大大减少了我们的可读性及性能;

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>放大 - 矩阵</title>
    <script id="vs" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat4 u_xformMatrix;
        void main(void){
            gl_Position = u_xformMatrix * a_Position;

        }
    </
script>
    <script id="fs" type="x-shader/x-fragment">
        void main(void){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    </
script>
</head>
<body>
<canvas id="canvas" style=" background-color: black"></canvas>

<script>
    onload = function () {
       
var canvas = document.getElementById("canvas");
       
canvas.width = 500;
       
canvas.height = 500;
       
var gl = canvas.getContext("webgl");

       
/*清空画板上的颜色,并初始化颜色*/
       
gl.clearColor(0.0, 0.0, 0.0, 1.0);
       
//设定canvas初始化时候的深度
       
gl.clearDepth(1.0);
       
//清空画面上的颜色
       
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

       
//顶点着色器和片段着色器生成
       
var v_shader = create_shader("vs");
       
var f_shader = create_shader("fs");

       
// 程序对象的生成和连接
       
var program = create_program(v_shader, f_shader);
       
//获取a_Position变量的存储位置
       
var a_Position = gl.getAttribLocation(program,"a_Position");

       
//创建缓冲区
       
var vertices = new Float32Array([
           
0.0,0.5,-0.5,
            -
0.5,0.5,-0.5,
        ]);

       
var n = 3;//点的个数

        //创建缓冲区
       
var vertexBuffer = gl.createBuffer();
       
if(!vertexBuffer){
           
console.log("Failed to create the buffer object");//缓冲区创建失败
           
return -1;
        }

       
//将缓冲区绑定到目标对象
       
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);

       
//向缓冲区写入数据
       
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);

       
//将缓冲区对象分配给a_Position; 参数一:传入数据;参数二:指定每个顶点传入多少个数(2表示只取两个数传入,剩下的两个数0.0和1.0补上;1.0是透明度,跟vertexAttrib2f()类似)
       
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);

       
//连接a_Position变量与分配给它的缓冲区对象
       
gl.enableVertexAttribArray(a_Position);

        scale();
//执行放大
        
       
gl.clear(gl.COLOR_BUFFER_BIT);
       
//开始绘制,显示器显示结果;参数二:从哪个点开始绘制;参数三:绘制几个点
        //TRIANGLES:一系列单独的三角形;绘制方式:(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)
        //TRIANGLE_STRIP:一系列带状的三角形
        //TRIANGLE_FAN:扇形绘制方式
       
gl.drawArrays(gl.TRIANGLES, 0, n);

       
/*旋转*/
       
function scale() {
           
var sX = 1.5,sY = 1.5,sZ = 1.0;
           
var xformMatrix = new Float32Array([
               
sX, 0.0, 0.0, 0.0,
               
0.0,sY, 0.0, 0.0,
               
0.00.0, sZ, 0.0,
                
0.00.0, 0.0, 1.0
           
])

           
var u_xformMatrix = gl.getUniformLocation(program,"u_xformMatrix");
           
if (!u_xformMatrix) {
               
console.log('Failed to get the storage location of u_xformMatrix');
                
return;
            }
           
gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix);

        }
       
       
function create_program(v_shader, f_shader) {
           
var program = gl.createProgram();

           
gl.attachShader(program, v_shader);
           
gl.attachShader(program, f_shader);

           
gl.linkProgram(program);
           
gl.useProgram(program);
           
return program;
        }

       
function create_shader(id) {
           
// 用来保存着色器的变量
           
var shader;

            
// 根据id从HTML中获取指定的script标签
           
var scriptElement = document.getElementById(id);

           
// 如果指定的script标签不存在,则返回
           
if (!scriptElement) {
               
return;
            }

           
// 判断script标签的type属性
           
switch (scriptElement.type) {

               
// 顶点着色器的时候
               
case 'x-shader/x-vertex':
                   
shader = gl.createShader(gl.VERTEX_SHADER);//生成顶点着色器
                   
break;

               
// 片段着色器的时候
               
case 'x-shader/x-fragment':
                   
shader = gl.createShader(gl.FRAGMENT_SHADER);//生成片元着色器
                   
break;
               
default :
                   
return;
            }

           
// 将标签中的代码分配给生成的着色器
           
gl.shaderSource(shader, scriptElement.text);

           
// 编译着色器
           
gl.compileShader(shader);

           
// 判断一下着色器是否编译成功
           
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

               
// 编译成功,则返回着色器
               
return shader;
            }
else {

               
// 编译失败,弹出错误消息
               
alert(gl.getShaderInfoLog(shader));
            }
        }
       
function create_program(vs, fs) {
           
// 程序对象的生成
           
var program = gl.createProgram();

           
// 向程序对象里分配着色器
            
gl.attachShader(program, vs);
           
gl.attachShader(program, fs);

           
// 将着色器连接
           
gl.linkProgram(program);

           
// 判断着色器的连接是否成功
           
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {

               
// 成功的话,将程序对象设置为有效
               
gl.useProgram(program);

               
// 返回程序对象
               
return program;
            }
else {
               
// 如果失败,弹出错误信息
               
alert(gl.getProgramInfoLog(program));
            }
        }
    }
</
script>
</body>
</html>

 

 

主要代码在scale()方法里;

缩放的矩阵设置主要放在对角线上,如下:

var sX = 1.5,sY = 1.5,sZ = 1.0;
var xformMatrix = new Float32Array([
   
sX, 0.0, 0.0, 0.0,
   
0.0,sY, 0.0, 0.0,
   
0.00.0, sZ, 0.0,
   
0.00.0, 0.0, 1.0
])

最后的1.0是w分量,暂不考虑;这些大概记得就可以,一般设置变换矩阵数学库中都有方法的;

 

平移的代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>平移三角形 - 矩阵</title>
    <script id="vs" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat4 u_xformMatrix;
        void main(void){
            gl_Position = u_xformMatrix * a_Position;

        }
    </
script>
    <script id="fs" type="x-shader/x-fragment">
        void main(void){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    </
script>
</head>
<body>
<canvas id="canvas" style=" background-color: black"></canvas>

<script>
    onload = function () {
       
var canvas = document.getElementById("canvas");
       
canvas.width = 500;
       
canvas.height = 500;
       
var gl = canvas.getContext("webgl");

        
/*清空画板上的颜色,并初始化颜色*/
       
gl.clearColor(0.0, 0.0, 0.0, 1.0);
       
//设定canvas初始化时候的深度
       
gl.clearDepth(1.0);
       
//清空画面上的颜色
       
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

       
//顶点着色器和片段着色器生成
       
var v_shader = create_shader("vs");
       
var f_shader = create_shader("fs");

       
// 程序对象的生成和连接
       
var program = create_program(v_shader, f_shader);
       
//获取a_Position变量的存储位置
       
var a_Position = gl.getAttribLocation(program,"a_Position");

       
//创建缓冲区
       
var vertices = new Float32Array([
           
0.0,0.5,-0.5,
            -
0.5,0.5,-0.5,
        ]);

       
var n = 3;//点的个数

        //创建缓冲区
       
var vertexBuffer = gl.createBuffer();
       
if(!vertexBuffer){
           
console.log("Failed to create the buffer object");//缓冲区创建失败
           
return -1;
        }

       
//将缓冲区绑定到目标对象
       
gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);

       
//向缓冲区写入数据
       
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);

       
//将缓冲区对象分配给a_Position; 参数一:传入数据;参数二:指定每个顶点传入多少个数(2表示只取两个数传入,剩下的两个数0.0和1.0补上;1.0是透明度,跟vertexAttrib2f()类似)
       
gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);

       
//连接a_Position变量与分配给它的缓冲区对象
       
gl.enableVertexAttribArray(a_Position);

        translation();
//执行旋转
       
       
gl.clear(gl.COLOR_BUFFER_BIT);
       
//开始绘制,显示器显示结果;参数二:从哪个点开始绘制;参数三:绘制几个点
        //TRIANGLES:一系列单独的三角形;绘制方式:(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)
        //TRIANGLE_STRIP:一系列带状的三角形
        //TRIANGLE_FAN:扇形绘制方式
       
gl.drawArrays(gl.TRIANGLES, 0, n);

       
/*旋转*/
       
function translation() {
           
var tX = 0.5,tY = 0.5,tZ = 0.0;
           
var xformMatrix = new Float32Array([
               
1.0, 0.0, 0.0, 0.0,
               
0.0, 1.0, 0.0, 0.0,
                
0.00.0, 1.0, 0.0,
               
tXtY, tZ, 1.0
           
])

           
var u_xformMatrix = gl.getUniformLocation(program,"u_xformMatrix");
           
if (!u_xformMatrix) {
               
console.log('Failed to get the storage location of u_xformMatrix');
               
return;
            }
           
gl.uniformMatrix4fv(u_xformMatrix,false,xformMatrix);

        }
       
       
function create_program(v_shader, f_shader) {
           
var program = gl.createProgram();

           
gl.attachShader(program, v_shader);
           
gl.attachShader(program, f_shader);

           
gl.linkProgram(program);
           
gl.useProgram(program);
           
return program;
        }

       
function create_shader(id) {
           
// 用来保存着色器的变量
            
var shader;

           
// 根据id从HTML中获取指定的script标签
           
var scriptElement = document.getElementById(id);

           
// 如果指定的script标签不存在,则返回
           
if (!scriptElement) {
               
return;
            }

           
// 判断script标签的type属性
           
switch (scriptElement.type) {

               
// 顶点着色器的时候
               
case 'x-shader/x-vertex':
                   
shader = gl.createShader(gl.VERTEX_SHADER);//生成顶点着色器
                   
break;

               
// 片段着色器的时候
                
case 'x-shader/x-fragment':
                   
shader = gl.createShader(gl.FRAGMENT_SHADER);//生成片元着色器
                   
break;
               
default :
                   
return;
            }

           
// 将标签中的代码分配给生成的着色器
           
gl.shaderSource(shader, scriptElement.text);

           
// 编译着色器
           
gl.compileShader(shader);

           
// 判断一下着色器是否编译成功
           
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

               
// 编译成功,则返回着色器
               
return shader;
            }
else {

               
// 编译失败,弹出错误消息
               
alert(gl.getShaderInfoLog(shader));
            }
        }
       
function create_program(vs, fs) {
           
// 程序对象的生成
           
var program = gl.createProgram();

            
// 向程序对象里分配着色器
           
gl.attachShader(program, vs);
           
gl.attachShader(program, fs);

           
// 将着色器连接
           
gl.linkProgram(program);

           
// 判断着色器的连接是否成功
           
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {

               
// 成功的话,将程序对象设置为有效
               
gl.useProgram(program);

               
// 返回程序对象
               
return program;
            }
else {
               
// 如果失败,弹出错误信息
               
alert(gl.getProgramInfoLog(program));
            }
        }
    }
</
script>
</body>
</html>

主要改变的地方在translation()方法里
 

是不是跟上面差不多的,很简单的;只是设置矩阵的参数问题;

那么如果我即做平移,又做旋转呢?下面我用来第三方数学库

代码如下:

 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>旋转&平移三角形 - 引入矩阵</title>
    <script id="vs" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat4 u_xformMatrix;
        void main(void){
            gl_Position = u_xformMatrix * a_Position;

        }

    </
script>
    <script id="fs" type="x-shader/x-fragment">
        void main(void){
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }

    </
script>
    <script src="../lib/cuon-matrix.js"></script>
</head>
<body>
<canvas id="canvas" style=" background-color: black"></canvas>

<script>
    onload = function () {
       
var canvas = document.getElementById("canvas");
       
canvas.width = 500;
       
canvas.height = 500;
       
var gl = canvas.getContext("webgl");

       
/*清空画板上的颜色,并初始化颜色*/
       
gl.clearColor(0.0, 0.0, 0.0, 1.0);
       
//设定canvas初始化时候的深度
       
gl.clearDepth(1.0);
       
//清空画面上的颜色
       
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

       
//顶点着色器和片段着色器生成
       
var v_shader = create_shader("vs");
       
var f_shader = create_shader("fs");

       
// 程序对象的生成和连接
       
var program = create_program(v_shader, f_shader);
       
//获取a_Position变量的存储位置
        
var a_Position = gl.getAttribLocation(program, "a_Position");

       
//创建缓冲区
       
var vertices = new Float32Array([
           
0.0, 0.5, -0.5,
            -
0.5, 0.5, -0.5,
        ]);

       
var n = 3;//点的个数

        //创建缓冲区
       
var vertexBuffer = gl.createBuffer();
       
if (!vertexBuffer) {
           
console.log("Failed to create the buffer object");//缓冲区创建失败
           
return -1;
        }

       
//将缓冲区绑定到目标对象
       
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

       
//向缓冲区写入数据
       
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

       
//将缓冲区对象分配给a_Position; 参数一:传入数据;参数二:指定每个顶点传入多少个数(2表示只取两个数传入,剩下的两个数0.0和1.0补上;1.0是透明度,跟vertexAttrib2f()类似)
       
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

       
//连接a_Position变量与分配给它的缓冲区对象
       
gl.enableVertexAttribArray(a_Position);

        rotate();
//执行旋转

       
gl.clear(gl.COLOR_BUFFER_BIT);
       
//开始绘制,显示器显示结果;参数二:从哪个点开始绘制;参数三:绘制几个点
        //TRIANGLES:一系列单独的三角形;绘制方式:(v0,v1,v2),(v2,v1,v3),(v2,v3,v4)
        //TRIANGLE_STRIP:一系列带状的三角形
        //TRIANGLE_FAN:扇形绘制方式
       
gl.drawArrays(gl.TRIANGLES, 0, n);

       
/*旋转*/
       
function rotate() {
           
var ANGLE = 90;

           
var radian = Math.PI * ANGLE / 180.0;//转为弧度制;
           
var cosB = Math.cos(radian);
           
var sinB = Math.sin(radian);

           
var xformMatrix = new Matrix4();

//            xformMatrix.setRotate(ANGLE,0,0,1);
           
xformMatrix.setTranslate(0.5,0.5,0.0);

           
var u_xformMatrix = gl.getUniformLocation(program, "u_xformMatrix");
           
if (!u_xformMatrix) {
               
console.log('Failed to get the storage location of u_xformMatrix');
               
return;
            }
           
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements);
        }

       
function create_program(v_shader, f_shader) {
           
var program = gl.createProgram();

           
gl.attachShader(program, v_shader);
            
gl.attachShader(program, f_shader);

           
gl.linkProgram(program);
           
gl.useProgram(program);
           
return program;
        }

       
function create_shader(id) {
           
// 用来保存着色器的变量
           
var shader;

           
// 根据id从HTML中获取指定的script标签
           
var scriptElement = document.getElementById(id);

           
// 如果指定的script标签不存在,则返回
           
if (!scriptElement) {
               
return;
            }

           
// 判断script标签的type属性
           
switch (scriptElement.type) {

               
// 顶点着色器的时候
               
case 'x-shader/x-vertex':
                   
shader = gl.createShader(gl.VERTEX_SHADER);//生成顶点着色器
                   
break;

               
// 片段着色器的时候
               
case 'x-shader/x-fragment':
                   
shader = gl.createShader(gl.FRAGMENT_SHADER);//生成片元着色器
                   
break;
               
default :
                   
return;
            }

           
// 将标签中的代码分配给生成的着色器
           
gl.shaderSource(shader, scriptElement.text);

           
// 编译着色器
           
gl.compileShader(shader);

           
// 判断一下着色器是否编译成功
           
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {

               
// 编译成功,则返回着色器
               
return shader;
            }
else {

                
// 编译失败,弹出错误消息
               
alert(gl.getShaderInfoLog(shader));
            }
        }

       
function create_program(vs, fs) {
           
// 程序对象的生成
           
var program = gl.createProgram();

           
// 向程序对象里分配着色器
           
gl.attachShader(program, vs);
           
gl.attachShader(program, fs);

           
// 将着色器连接
           
gl.linkProgram(program);

           
// 判断着色器的连接是否成功
           
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {

               
// 成功的话,将程序对象设置为有效
               
gl.useProgram(program);

               
// 返回程序对象
               
return program;
            }
else {
               
// 如果失败,弹出错误信息
               
alert(gl.getProgramInfoLog(program));
            }
        }
    }
</
script>
</body>
</html>

 

学过矩阵应该知道,矩阵是不满足交互律的,那个先乘,那个后乘都有很大的区别,

你可以试试,为什么结果这样,

那是因为旋转是在中心位置,不是以物体的中心位置来旋转的;

 

猜你喜欢

转载自blog.csdn.net/qq_25909453/article/details/82470221