首页 > 其他分享 >WebGL之三维正射投影(高级)

WebGL之三维正射投影(高级)

时间:2024-01-26 21:01:18浏览次数:29  
标签:const 0.0 WebGL sideLength 投影 三维 return gl data

一,前言

1,绘制一个正方体的数据,我们以前,上,右逆时针绘制,对面的用顺时针绘制。

WebGL之三维正射投影(高级)_COCOS

    2, 数据准备 cubeModel.js

/**
 * 获得正方体所有顶点位置
 * @param sideLength 边长
 */
window.getCubeVertexesPosition = (sideLength) => {
    //前
    const FRONT = [
        0.0, 0.0, 0.0,
        sideLength, 0.0, 0.0,
        0.0, sideLength, 0.0,
        0.0, sideLength, 0.0,
        sideLength, 0.0, 0.0,
        sideLength, sideLength, 0.0
    ];
    //上
    const TOP = [
        0.0, sideLength, 0.0,
        sideLength, sideLength, 0.0,
        0.0, sideLength, sideLength,
        0.0, sideLength, sideLength,
        sideLength, sideLength, 0.0,
        sideLength, sideLength, sideLength
    ];
    //右
    const RIGHT = [
        sideLength, 0.0, 0.0,
        sideLength, 0.0, sideLength,
        sideLength, sideLength, 0.0,
        sideLength, sideLength, 0.0,
        sideLength, 0.0, sideLength,
        sideLength, sideLength, sideLength
    ];
    //后
    const REAR = [
        0.0, 0.0, sideLength,
        0.0, sideLength, sideLength,
        sideLength, 0.0, sideLength,
        sideLength, 0.0, sideLength,
        0.0, sideLength, sideLength,
        sideLength, sideLength, sideLength
    ];
    //左
    const LEFT = [
        0.0, 0.0, 0.0,
        0.0, sideLength, 0.0,
        0.0, 0.0, sideLength,
        0.0, 0.0, sideLength,
        0.0, sideLength, 0.0,
        0.0, sideLength, sideLength
    ];
    //下
    const BOTTOM = [
        0.0, 0.0, 0.0,
        0.0, 0.0, sideLength,
        sideLength, 0.0, 0.0,
        sideLength, 0.0, 0.0,
        0.0, 0.0, sideLength,
        sideLength, 0.0, sideLength
    ];
    let data = [];
    return data.concat(FRONT, TOP, RIGHT, REAR, BOTTOM, LEFT);
};
/**
 * 获得cube的纹理坐标
 */
window.getCubeTexcoord = () => {
    const TEXCOORD = [
        0.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 1.0, 0.0
    ];
    let data = [];
    return data.concat(TEXCOORD, TEXCOORD, TEXCOORD, TEXCOORD, TEXCOORD, TEXCOORD);//6x6个点的纹理贴图坐标
};
//红橙黄绿蓝靛 (每个面的颜色值) RGBA
window.getCubeColors = () => {
    const FRONT = [1.0, 0.0, 0.0, 0.9];//红
    const TOP = [1.0, 0.55, 0.0, 0.9];//橙
    const RIGHT = [1.0, 1.0, 0.0, 0.9];//黄
    const REAR = [0.0, 1.0, 0.0, 0.9];//绿
    const BOTTOM = [0.0, 0.0, 1.0, 0.9];//蓝
    const LEFT = [0.0, 1.0, 1.0, 0.9];//靛
    let data = [];
    data = data.concat(FRONT, FRONT, FRONT, FRONT, FRONT, FRONT);
    data = data.concat(TOP, TOP, TOP, TOP, TOP, TOP);
    data = data.concat(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT);
    data = data.concat(REAR, REAR, REAR, REAR, REAR, REAR);
    data = data.concat(BOTTOM, BOTTOM, BOTTOM, BOTTOM, BOTTOM, BOTTOM);
    data = data.concat(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT);
    return data;//6X6个点的颜色值
}

二, index.html

<body>
	<script src="js/model/cubeModel.js"></script>
	<script src="js/common/shaderUtil.js"></script>
	<script id="vertex-shader-2d" type="notjs">
		attribute vec4 a_position;
		attribute vec2 a_texCoord;
		attribute vec4 a_color;
		uniform mat4 u_matrix;//2D变换矩阵
		varying vec2 v_texCoord;
		varying vec4 v_color;//颜色值,每个面用不同的颜色值
		
		void main(){
			v_texCoord = a_texCoord;
			v_color = a_color;
			gl_Position = u_matrix * a_position;
		}
</script>
	<script id="fragment-shader-2d" type="notjs">
		precision mediump float;
		uniform sampler2D u_image;
		varying vec2 v_texCoord;
		varying vec4 v_color;
		void main(){
			gl_FragColor = texture2D(u_image, v_texCoord) * v_color;
		}
</script>
	
	<script src="js/shader7.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,
        ];
    },
};
/**
 * 3D变换
 */
window.m4 = {
    projection: (width, height, depth) => {
        // 注意:这个矩阵翻转了 Y 轴,所以 0 在上方
        return [
            2 / width, 0, 0, 0,
            0, -2 / height, 0, 0,
            0, 0, 2 / depth, 0,
            -1, 1, 0, 1,
        ];
    },
    translation: (tx, ty, tz) => {
        return [
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            tx, ty, tz, 1,

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

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

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

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

    translate: (m, tx, ty, tz) => {
        return m4.multiply(m, m4.translation(tx, ty, tz));
    },
    xRotate: (m, angle) => {
        return m4.multiply(m, m4.xRotation(angle));
    },
    yRotate: (m, angle) => {
        return m4.multiply(m, m4.yRotation(angle));
    },
    zRotate: (m, angle) => {
        return m4.multiply(m, m4.zRotation(angle));
    },
    scale: (m, sx, sy, sz) => {
        return m4.multiply(m, m4.scaling(sx, sy, sz));
    },

    multiply: (a, b) => {
        const a00 = a[0 * 4 + 0];
        const a01 = a[0 * 4 + 1];
        const a02 = a[0 * 4 + 2];
        const a03 = a[0 * 4 + 3];
        const a10 = a[1 * 4 + 0];
        const a11 = a[1 * 4 + 1];
        const a12 = a[1 * 4 + 2];
        const a13 = a[1 * 4 + 3];
        const a20 = a[2 * 4 + 0];
        const a21 = a[2 * 4 + 1];
        const a22 = a[2 * 4 + 2];
        const a23 = a[2 * 4 + 3];
        const a30 = a[3 * 4 + 0];
        const a31 = a[3 * 4 + 1];
        const a32 = a[3 * 4 + 2];
        const a33 = a[3 * 4 + 3];
        const b00 = b[0 * 4 + 0];
        const b01 = b[0 * 4 + 1];
        const b02 = b[0 * 4 + 2];
        const b03 = b[0 * 4 + 3];
        const b10 = b[1 * 4 + 0];
        const b11 = b[1 * 4 + 1];
        const b12 = b[1 * 4 + 2];
        const b13 = b[1 * 4 + 3];
        const b20 = b[2 * 4 + 0];
        const b21 = b[2 * 4 + 1];
        const b22 = b[2 * 4 + 2];
        const b23 = b[2 * 4 + 3];
        const b30 = b[3 * 4 + 0];
        const b31 = b[3 * 4 + 1];
        const b32 = b[3 * 4 + 2];
        const b33 = b[3 * 4 + 3];
        return [
            b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
            b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
            b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
            b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
            b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
            b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
            b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
            b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
            b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
            b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
            b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
            b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
            b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
            b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
            b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
            b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
        ];
    },
};

四, 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 setCube(gl, sideLength) {
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(getCubeVertexesPosition(sideLength)), 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 colorAttributeLocation = gl.getAttribLocation(program, "a_color");
    const matrixUniformLocation = gl.getUniformLocation(program, "u_matrix");

    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const MAX_SIDE_LENGTH = Math.max(image.width, image.height);
    setCube(gl, MAX_SIDE_LENGTH); //正方体


    const texCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(getCubeTexcoord()), gl.STATIC_DRAW);

    const colorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(getCubeColors()), gl.STATIC_DRAW);

    //开始渲染
    gl.viewport(0, 0, gl.canvas.clientWidth, gl.canvas.clientHeight);
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.enable(gl.CULL_FACE);//剔除背面
    gl.enable(gl.DEPTH_TEST);//开启深度测试
    gl.useProgram(program);


    gl.enableVertexAttribArray(positionAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    const size = 3; //每次迭代运行提取3个单位数据
    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, 3, gl.FLOAT, false, 0, 0);

    gl.enableVertexAttribArray(colorAttributeLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    gl.vertexAttribPointer(colorAttributeLocation, 4, gl.FLOAT, false, 0, 0);//RGBA 4个数据


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


    const primitiveType = gl.TRIANGLES; //绘制三角形
    const pOffset = 0; //从第一个点开始绘制
    const count = 6 * 6; //一个面绘制6次,总共有6个面 36个点
    let matrix;
    let scale = 0.7;
    let angle = 0;
    let isScaleAdd = true;
    setInterval(() => {
        matrix = m4.projection(gl.canvas.clientWidth, gl.canvas.clientHeight, 400);
        matrix = m4.translate(matrix, 150, 200, 0);
        angle += 1;
        if (angle >= 360) {
            angle = 360 - angle;
        }
        matrix = m4.yRotate(matrix, angle);
        matrix = m4.zRotate(matrix, angle);
        if (isScaleAdd) {
            scale += 0.01;
            if (scale >= 1.4) {
                isScaleAdd = false;
            }
        } else {
            scale -= 0.01;
            if (scale <= 0.7) {
                isScaleAdd = true;
            }
        }
        matrix = m4.scale(matrix, scale, scale, scale);
        matrix = m4.translate(matrix, -MAX_SIDE_LENGTH / 2, -MAX_SIDE_LENGTH / 2, -MAX_SIDE_LENGTH / 2);
        gl.uniformMatrix4fv(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("head.png", 8848, (image) => {
        render(gl, program, image);
    });
}

main();

五,效果

WebGL之三维正射投影(高级)_WebGL_02

标签:const,0.0,WebGL,sideLength,投影,三维,return,gl,data
From: https://blog.51cto.com/aonaufly/9438060

相关文章

  • WebGL之二维矩阵变换(高级)
    一,index.html<body> <scriptsrc="js/common/shaderUtil.js"></script> <scriptid="vertex-shader-2d"type="notjs"> attributevec2a_position; attributevec2a_texCoord; uniformmat3u_matrix;//2D变......
  • 高效、易用、精准 | 三维天地智能试剂管理平台在实验室中的应用
    在当前实验室管理阶段,关于试剂耗材管理方面,存在以下几个关键性问题:一是试剂耗材管理缺乏规范性,二是试剂耗材台账信息模糊不清,三是库存管理存在精确度不足,四是位置定位及查找困难。针对所述问题,致力于实验室数智化建设的北京三维天地科技股份有限公司为实验室提供了一款高效......
  • WebGL之缩放(基础)
    一,index.html<body> <scriptid="vertex-shader-2d"type="notjs"> attributevec2a_position; attributevec2a_texCoord; uniformvec2u_resolution; uniformvec2u_translation; uniformvec2u_rotation;//旋转全局变量 unif......
  • WebGL之旋转(基础)
    一,index.html<body> <scriptid="vertex-shader-2d"type="notjs"> attributevec2a_position; attributevec2a_texCoord; uniformvec2u_resolution; uniformvec2u_translation; uniformvec2u_rotation;//旋转全局变量 varyi......
  • WebGL之图片偏移(基础)
    一,index.html二,shader.js/***加载图片*@paramimageName*@parampork*@paramcallback*/functionloadImage(imageName,pork,callback){ constimage=newImage(); image.src="http://127.0.0.1:"+pork+"/WebGLDemo/textures/"......
  • WebGL之贴图处理(基础)
    一,index.html二,shader.js/***加载图片*@paramimageName*@parampork*@paramcallback*/functionloadImage(imageName,pork,callback){ constimage=newImage(); image.src="http://127.0.0.1:"+pork+"/WebGLDemo/textures/"+......
  • 电力能源三维可视化合集 | 图扑数字孪生
    电力能源是现代社会发展和运行的基石,渗透于工业、商业、农业、家庭生活等方方面面,它为经济、生活质量、环境保护和社会发展提供了巨大的机会和潜力。图扑软件应用自研HTforWeb强大的渲染引擎,助力现代化的电力能源数字孪生场景,在发电、变电、用电、管理等多种方面呈现出多元化......
  • 2024云渲染,渲染农场带给三维建模行业的影响
    在电影和电视的CG特效制作中,三维建模技术是核心组成部分,因为它们能够创造出既细致又引人注目的场景和角色。三维建模和渲染软件等功能的也在日益强大,建模艺术家们可以创作出更加逼真的环境、栩栩如生的人物发丝、动人心弦的光照效果和栩栩如生的纹理质感。那么云渲染与渲染农场给......
  • 应用案例 | 基于三维机器视觉的焊接件上料解决方案
    在制造业中,还有许多传统的焊接自动化设备主要是通过人工来进行上料。传统的上料过程中,主要是通过人工来进行的。上料过程中会收到人为因素的影响,如操作人员的技能水平、工作态度等,导致上料不准确,不稳定,影响工作效率。例如,操作人员无法准确地将焊接件放置在指定位置,或者放置的焊接件......
  • 应用案例 | 基于三维机器视觉的自动化无序分拣解决方案
    近年来,电商行业蓬勃发展,订单的海量化、订单类型的碎片化,使物流行业朝着“多品种、无边界、分类广”的方向迅速发展。根据许多研究机构的预测,电子商务销售额预计将以每年两位数的速度增长,推动整个行业的规模不断扩大。物流分拣一直是一项单调乏味的体力活,长期以来存在着招工难的问题......