首页 > 其他分享 >WebGL之二维矩阵变换(高级)

WebGL之二维矩阵变换(高级)

时间:2024-01-25 23:32:39浏览次数:24  
标签:return WebGL 矩阵 shader 二维 program const gl image

一, index.html

<body>
	<script src="js/common/shaderUtil.js"></script>
	<script id="vertex-shader-2d" type="notjs">
		attribute vec2 a_position;
		attribute vec2 a_texCoord;
		uniform mat3 u_matrix;//2D变换矩阵
		varying vec2 v_texCoord;
		
		void main(){
			v_texCoord = a_texCoord;
			gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
		}


</script>
	<script id="fragment-shader-2d" type="notjs">
		precision mediump float;
		uniform sampler2D u_image;
		varying vec2 v_texCoord;
		void main(){
			gl_FragColor = texture2D(u_image, v_texCoord);
		}
</script>
	
	<script src="js/shader6.js"></script>
</body>

二, shaderUtil.js

window.angle2Radian = (angle) => {
	const angleInRadians = angle * Math.PI / 180;
	return angleInRadians;
}

window.radian2Angle = (radian) => {
	const angle = radian * 180 / Math.PI;
	return angle;
}

window.getCS = (radian) => {
	return {
		cos: Math.cos(radian),
		sin: Math.sin(radian)
	};
}

/**
 * 2D变换
 */
window.m3 = {
	projection: (width, height) => {
		// 注意:这个矩阵翻转了 Y 轴,所以 0 在上方
		return [
			2 / width, 0, 0,
			0, -2 / height, 0,
			-1, 1, 1
		];
	},
	translation: (tx, ty) => {
		return [
			1, 0, 0,
			0, 1, 0,
			tx, ty, 1,
		];
	},

	rotation: (angle) => {
		const data = getCS(angle2Radian(angle));
		return [
			data.cos, -data.sin, 0,
			data.sin, data.cos, 0,
			0, 0, 1,
		];
	},

	scaling: (sx, sy) => {
		return [
			sx, 0, 0,
			0, sy, 0,
			0, 0, 1,
		];
	},

	translate: (m, tx, ty) => {
		return m3.multiply(m, m3.translation(tx, ty));
	},
	rotate: (m, angle) => {
		return m3.multiply(m, m3.rotation(angle));
	},
	scale: (m, sx, sy) => {
		return m3.multiply(m, m3.scaling(sx, sy));
	},

	multiply: (a, b) => {
		const a00 = a[0 * 3 + 0];
		const a01 = a[0 * 3 + 1];
		const a02 = a[0 * 3 + 2];
		const a10 = a[1 * 3 + 0];
		const a11 = a[1 * 3 + 1];
		const a12 = a[1 * 3 + 2];
		const a20 = a[2 * 3 + 0];
		const a21 = a[2 * 3 + 1];
		const a22 = a[2 * 3 + 2];
		const b00 = b[0 * 3 + 0];
		const b01 = b[0 * 3 + 1];
		const b02 = b[0 * 3 + 2];
		const b10 = b[1 * 3 + 0];
		const b11 = b[1 * 3 + 1];
		const b12 = b[1 * 3 + 2];
		const b20 = b[2 * 3 + 0];
		const b21 = b[2 * 3 + 1];
		const b22 = b[2 * 3 + 2];
		return [
			b00 * a00 + b01 * a10 + b02 * a20,
			b00 * a01 + b01 * a11 + b02 * a21,
			b00 * a02 + b01 * a12 + b02 * a22,
			b10 * a00 + b11 * a10 + b12 * a20,
			b10 * a01 + b11 * a11 + b12 * a21,
			b10 * a02 + b11 * a12 + b12 * a22,
			b20 * a00 + b21 * a10 + b22 * a20,
			b20 * a01 + b21 * a11 + b22 * a21,
			b20 * a02 + b21 * a12 + b22 * a22,
		];
	},
};

三, shader.js

/**
 * 加载图片
 * @param imageName
 * @param pork
 * @param callback
 */
function loadImage(imageName, pork, callback) {
    const image = new Image();
    image.src = "http://127.0.0.1:" + pork + "/WebGLDemo/textures/" + imageName;
    image.onload = () => {
        callback(image);
    };
}


function setTexture(gl, image) {
    const texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); //gl.LINEAR
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); //gl.NEAREST
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
}

function setRectangle(gl, x, y, width, height) {
    const x1 = x;
    const x2 = x + width;
    const y1 = y;
    const y2 = y + height;
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2,
    ]), gl.STATIC_DRAW);
}


/**
 * 获得绘图上下文gl WebGLRenderingContext
 * @param {Object} width
 * @param {Object} height
 */
function getWebGLRenderingContext(width, height) {
    const canvas = document.createElement("canvas");
    document.getElementsByTagName("body")[0].appendChild(canvas);

    canvas.width = width;
    canvas.height = height;

    const gl = canvas.getContext("webgl");
    if (!gl) {
        console.log("%c不支持webgl", "color:#F00");
        return null;
    }
    return gl;
}

function getShaderSource(isVertex) {
    let source;
    if (isVertex) {
        source = document.querySelector("#vertex-shader-2d").text;
    } else {
        source = document.querySelector("#fragment-shader-2d").text;
    }
    return source;
}

/**
 * @param {Object} gl WebGLReanderingContext
 * @param {Object} type gl.VERTEX_SHADER/gl.FRAGMENT_SHADER
 * @param {Object} source source string
 */
function createShader(gl, type, source) {
    const shader = gl.createShader(type); //创建相关类型的shader
    gl.shaderSource(shader, source); //提供shader的资源
    gl.compileShader(shader); //编译shader
    const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (success) {
        return shader;
    }
    console.log(gl.getShaderInfoLog(shader));
    gl.deleteShader(shader);
}

/**
 * 链接(link)2个shader,得到着色程序program
 * @param {Object} gl WebGLReanderingContext
 * @param {Object} vertexShader 顶点着色器
 * @param {Object} fragmentShader 片段着色器
 */
function createProgram(gl, vertexShader, fragmentShader) {
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    const success = gl.getProgramParameter(program, gl.LINK_STATUS);
    if (success) {
        return program;
    }
    console.log(gl.getProgramInfoLog(program));
    gl.deleteProgram(program);
}

function render(gl, program, image) {
    const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
    const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
    const matrixUniformLocation = gl.getUniformLocation(program, "u_matrix");

    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    setRectangle(gl, 0, 0, image.width, image.height); //矩形(2个三角形)


    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        0.0, 0.0,
        1.0, 0.0,
        0.0, 1.0,
        0.0, 1.0,
        1.0, 0.0,
        1.0, 1.0
    ]), gl.STATIC_DRAW);

    //开始渲染
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.useProgram(program);


    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const size = 2; //每次迭代运行提取2个单位数据
    const type = gl.FLOAT; //每个单位数据是32位的浮点数
    const normaliza = false; //不需要归一化数据
    const stride = 0; //0 = 移动单位数量 * 每个单位占用的内存(sizeof(type))
    const offset = 0; //每次迭代运行运动多少内存到下一个数据开始点,从缓冲起始位置开始读取
    gl.vertexAttribPointer(positionAttributeLocation, size, type, normaliza, stride, offset);

    gl.enableVertexAttribArray(texCoordAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.vertexAttribPointer(texCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0);


    setTexture(gl, image);//设置贴图


    const primitiveType = gl.TRIANGLES; //绘制三角形
    const pOffset = 0; //从第一个点开始绘制
    const count = 6; //绘制6个点(运行6次)
    let matrix;
    let scale = 0.7;
    let angle = 0;
    let isScaleAdd = true;
    setInterval(() => {
        matrix = m3.projection(gl.canvas.clientWidth, gl.canvas.clientHeight);
        matrix = m3.translate(matrix, 150, 200);
        angle += 10;
        if (angle >= 360) {
            angle = 360 - angle;
        }
        matrix = m3.rotate(matrix, angle);
        if (isScaleAdd) {
            scale += 0.01;
            if (scale >= 1.4) {
                isScaleAdd = false;
            }
        } else {
            scale -= 0.01;
            if (scale <= 0.7) {
                isScaleAdd = true;
            }
        }
        matrix = m3.scale(matrix, scale, scale);
        matrix = m3.translate(matrix, -image.width / 2, -image.height / 2);
        gl.uniformMatrix3fv(matrixUniformLocation, false, matrix);
        gl.drawArrays(primitiveType, pOffset, count);
    }, 15);
}

function main() {
    const WIDTH = 400;
    const HEIGHT = 300;
    const gl = getWebGLRenderingContext(WIDTH, HEIGHT);
    if (!gl) return;
    //#region 构建2个shader
    const vertexShader = createShader(gl, gl.VERTEX_SHADER, getShaderSource(true));
    const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, getShaderSource(false));
    //#endregion

    //#region link2个shader
    const program = createProgram(gl, vertexShader, fragmentShader);
    //#endregiopn
    loadImage("cocos.png", 8848, (image) => {
        render(gl, program, image);
    });
}

main();

matrix = m3.translate(matrix, -image.width / 2, -image.height / 2);  设置锚点:图片中间

四,效果

WebGL之二维矩阵变换(高级)_2D

标签:return,WebGL,矩阵,shader,二维,program,const,gl,image
From: https://blog.51cto.com/aonaufly/9421625

相关文章

  • 算法随记_1 蛇形矩阵(偏移量法)
    蛇形矩阵title:(在线学习平台)link:(https://www.acwing.com/)cover:(https://cdn.acwing.com/media/activity/surface/log.png)输入两个整数n和m,输出一个n行m列的矩阵,将数字1到n×m按照回字蛇形填充至矩阵中。具体矩阵形式可参考样例。输入样例33输出样例12......
  • (2/60)有序数组平方、长度最小子数组、螺旋矩阵
    有序数组的平方leetcode:977.有序数组的平方给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。暴力法思路遍历数组,元素原地替换为自身平方值。将数组进行排序。复杂度分析时间复杂度:O(N+logN)空间复杂度:O(1)注......
  • 代码随想录算法训练营第二天|977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
    977.有序数组的平方给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/错误的vector遍历方式,这会导致访问越界!!!while(nums[flag]<0)flag++;倒也不难,我......
  • 矩阵号:日入100+,八大提示词(Prompt)使用技巧
    最近在搞头条矩阵,发现自己的指令写的太烂了,一个指令将会决定你的写作质量。收益比较拉垮,50个号收益好的,也就这么几个号。于是我扒了一些提示词的操作技巧,分享一下自己的学习心得。先说理论知识,实操放文章最后。我们与GPT沟通交流时,可以用到乔哈里()沟通视窗模型,它分为......
  • 【每日GIS算法】(1)二维矢量的运算
    二维向量的基础运算主要有以下几种矢量的加法矢量的减法矢量的乘法矢量的除法矢量的模矢量的点乘矢量的叉乘矢量的归一化针对不同的场景,我们为二维矢量类提供对应的实例方法,但是由于这些实例方法会修改对象内部的数值,因此还提供对应的静态方法,在不改变原来的向量的情况......
  • P1962 斐波那契数列(矩阵快速幂)
    #include<bits/stdc++.h> #defineintlonglong usingnamespacestd; intn,a[3],m=1e9+7,c[3][3],b[3][3],x[3][3],a1[3]; voidfirst() { for(inti=1;i<=2;i++) for(intj=1;j<=2;j++)x[i][j]=0; for(inti=1;i<=2;i++) ......
  • WebGL之缩放(基础)
    一,index.html<body> <scriptid="vertex-shader-2d"type="notjs"> attributevec2a_position; attributevec2a_texCoord; uniformvec2u_resolution; uniformvec2u_translation; uniformvec2u_rotation;//旋转全局变量 unif......
  • jax框架为例:求hession矩阵时前后向模式的自动求导的性能差别
    注意:本文相关基础知识不介绍。给出代码:fromjaximportjacfwd,jacrevimportjax.numpyasjnpdefhessian_1(f):returnjacfwd(jacrev(f))defhessian_2(f):returnjacfwd(jacfwd(f))defhessian_3(f):returnjacrev(jacfwd(f))defhessian_4(f):......
  • 【动态规划】矩阵
    目录1.题目列表2.应用2.1.Leetcode64.最小路径和2.1.1.题目2.1.2.分析2.1.2.1.边界条件2.1.2.2.状态转移2.1.3.代码实现2.2.Leetcode174.地下城游戏2.2.1.题目2.2.2.分析2.2.2.1.初始条件2.2.2.2.状态转移2.2.3.代码实现1.题目列表序号题目难度16......
  • MarkDown基础及表格、KaTeX公式、矩阵、流程图、UML图、甘特图语法
    概述最多可设置6级标题技巧列表有序列表MD语法:1.你好2.我也好呈现效果:你好我也好无序列表MD语法:-a-b*aa*bb+aaa+bbb效果:abaabbaaabbb结论,支持三种方式:-、*、+TODO列表MD语法:-[x]后端接口开发-[]与前端联调呈现效果:后端......