二十八课代码(WebGL课程代码专用)

555 阅读2分钟

index.html

<!doctype html>
<html>

<head>
    <style>
        canvas {
            border: 1px solid #000000;
        }
    </style>

</head>

<body>
    <p>
        <b>scale value:</b>
        <input id="scalex" type="range" min="-2" max="2" value="1" step="0.1" oninput="gl_draw()" />
        <b id="scalevaluex">0</b>
        <input id="scaley" type="range" min="-2" max="2" value="1" step="0.1" oninput="gl_draw()" />
        <b id="scalevaluey">0</b>
    </p>
    <p>
        <b>offset value:</b>
        <input id="offsetx" type="range" min="-1" max="1" value="0" step="0.1" oninput="gl_draw()" />
        <b id="offsetvaluex">0</b>
        <input id="offsety" type="range" min="-1" max="1" value="0" step="0.1" oninput="gl_draw()" />
        <b id="offsetvaluey">0</b>
    </p>

    <p>
        <b>rotate value:</b>
        <input id="rotate" type="range" min="0" max="6.28" value="0" step="0.01" oninput="gl_draw()" />
        <b id="rotatevalue">0</b>
    </p>

    <p>
        <b>cat value:</b>
        <input id="cat" type="range" min="0" max="1" value="0" step="0.1" oninput="gl_draw()" />
        <b id="catvalue">0</b>
    </p>


    <canvas id="tri" width="600" height="600" style="width:300px; height:300px">
    </canvas>
    <script id="vertex_shader" type="myshader">
        // Vertex Shader
        precision mediump int;
        precision mediump float;
        
        uniform mat3 u_all;

        attribute vec2 a_PointVertex; // 顶点坐标
        attribute vec2 a_PointUV;     // 顶点UV

        varying vec2 uv;


        void main() {
          vec3 coord = u_all * vec3(a_PointVertex, 1.0);
          gl_Position = vec4(coord.x, coord.y, 0.0, 1.0);
          uv = a_PointUV;
          uv.y = 1.0 - uv.y;
        }
    </script>
    <script id="fragment_shader" type="myshader">
        // Fragment shader
        precision mediump int;
        precision mediump float;

        uniform sampler2D u_funny_cat; // 有趣的猫的图片
        uniform sampler2D u_eye; // 眼睛图片
        uniform float u_t; // 猫的图片占比
        varying vec2 uv;

        void main() {
          vec4 sample_color_cat = texture2D(u_funny_cat, uv);
          vec4 sample_color_eye = texture2D(u_eye, sample_color_cat.xy);
          gl_FragColor = vec4(sample_color_cat.xyz * u_t + (1.0 - u_t) * sample_color_eye.xyz, 1.0);
        }
    </script>
    <script type="text/javascript" src="logic.js"></script>
</body>

</html>

logic.js

var pointCanvas = null;
var gl = null;
var data = null;
var dataArr = null;
var pointCount = null;

var u_all_loc = null;
var u_EyeLocation = null;
var u_FunnyCatLocation = null;
var u_t = null;


var scaleDomX = null;
var scaleValueDomX = null;
var scaleDomY = null;
var scaleValueDomY = null;
var offsetDomX = null;
var offsetValueDomX = null;
var offsetDomY = null;
var offsetValueDomY = null;

var rotateDom = null;
var rotateValueDom = null;

var catDom = null;
var catValueDom = null;


// 入口函数
function Main() {
    gl_init();
    CreateTextureAndLoadImage(); // 加载图片
}

function genMat3ForGL(a, b, alpha, A, B) {
    let mat3 = [
        a * Math.cos(alpha), a * Math.sin(alpha), 0,
        -b * Math.sin(alpha), b * Math.cos(alpha), 0,
        A, B, 1,
    ];
    return new Float32Array(mat3);
}

function gl_init() {
    pointCanvas = document.getElementById('tri'); // 我们的纸
    gl = pointCanvas.getContext('webgl', { preserveDrawingBuffer: true }); // 我们的笔
    data = [-1, -1, 0, 0,
        1, -1, 1, 0,
        0, 1, 0.5, 1
    ];

    dataArr = new Float32Array(data);
    pointCount = 3;

    buffer_point = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer_point);
    gl.bufferData(gl.ARRAY_BUFFER, dataArr, gl.STATIC_DRAW);

    //
    var vertex_shader_code = document.getElementById('vertex_shader').textContent;

    var vertex_shader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertex_shader, vertex_shader_code);
    gl.compileShader(vertex_shader);
    // 检查shader错误
    const v_compiled = gl.getShaderParameter(vertex_shader, gl.COMPILE_STATUS);
    if (!v_compiled) {
        const v_theError = gl.getShaderInfoLog(vertex_shader);
        console.error(v_theError);
        gl.deleteShader(vertex_shader);
    }

    //
    var fragment_shader_code = document.getElementById('fragment_shader').textContent;
    var fragment_shader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragment_shader, fragment_shader_code);
    gl.compileShader(fragment_shader);
    // 检查shader错误
    const f_compiled = gl.getShaderParameter(fragment_shader, gl.COMPILE_STATUS);
    if (!f_compiled) {
        const f_theError = gl.getShaderInfoLog(fragment_shader);
        console.error(f_theError);
        gl.deleteShader(fragment_shader);
    }
    //
    var program = gl.createProgram();
    gl.attachShader(program, vertex_shader);
    gl.attachShader(program, fragment_shader);
    gl.linkProgram(program);
    gl.useProgram(program);
    // attributes
    var a_PointVertex = gl.getAttribLocation(program, 'a_PointVertex');
    var a_PointUV = gl.getAttribLocation(program, 'a_PointUV');
    gl.vertexAttribPointer(a_PointVertex, 2, gl.FLOAT, false, 16, 0);
    gl.enableVertexAttribArray(a_PointVertex);
    gl.vertexAttribPointer(a_PointUV, 2, gl.FLOAT, false, 16, 8);
    gl.enableVertexAttribArray(a_PointUV);
    // uniforms
    u_all_loc = gl.getUniformLocation(program, "u_all");
    u_t = gl.getUniformLocation(program, "u_t");
    u_FunnyCatLocation = gl.getUniformLocation(program, "u_funny_cat");
    u_EyeLocation = gl.getUniformLocation(program, "u_eye");

    scaleDomX = document.getElementById("scalex");
    scaleValueDomX = document.getElementById("scalevaluex");
    scaleDomY = document.getElementById("scaley");
    scaleValueDomY = document.getElementById("scalevaluey");
    offsetDomX = document.getElementById("offsetx");
    offsetValueDomX = document.getElementById("offsetvaluex");
    offsetDomY = document.getElementById("offsety");
    offsetValueDomY = document.getElementById("offsetvaluey");

    rotateDom = document.getElementById("rotate");
    rotateValueDom = document.getElementById("rotatevalue");

    catDom = document.getElementById("cat");
    catValueDom = document.getElementById("catvalue");

}

// gl更新逻辑
function gl_draw() {

    gl.uniformMatrix3fv(u_all_loc, false, genMat3ForGL(scaleDomX.value,
        scaleDomY.value, rotateDom.value, offsetDomX.value, offsetDomY.value
    ));

    gl.uniform1f(u_t, catDom.value);

    gl.activeTexture(gl.TEXTURE0 + 0);
    gl.bindTexture(gl.TEXTURE_2D, textureList[0 + 0]);
    gl.uniform1i(u_EyeLocation, 0 + 0);

    gl.activeTexture(gl.TEXTURE0 + 1);
    gl.bindTexture(gl.TEXTURE_2D, textureList[0 + 1]);
    gl.uniform1i(u_FunnyCatLocation, 0 + 1);

    scaleValueDomX.innerText = scaleDomX.value;
    offsetValueDomX.innerText = offsetDomX.value;
    scaleValueDomY.innerText = scaleDomY.value;
    offsetValueDomY.innerText = offsetDomY.value;
    rotateValueDom.innerText = rotateDom.value;
    catValueDom.innerText = catDom.value;

    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);

    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, pointCount);
}

function isPowerOf2(value) {
    return (value & (value - 1)) === 0;
}

var imageUrlList = ["images/eye.png", "images/funny-cat.jpg",];
var images_progress = 0;
var textureList = [];

function CreateTextureAndLoadImage() {
    // 在 WebGL 里创建一个 texture
    if (images_progress == imageUrlList.length) {
        gl_draw();
        return;
    }
    let texture = gl.createTexture();
    textureList.push(texture);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    let image = new Image();
    image.src = imageUrlList[images_progress];
    console.log(image.src);
    image.addEventListener('load', function () {
        gl.activeTexture(gl.TEXTURE0 + images_progress);
        gl.bindTexture(gl.TEXTURE_2D, textureList[images_progress]);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
        if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
            gl.generateMipmap(gl.TEXTURE_2D);
        } else {
            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.LINEAR);
        }
        images_progress++;
        CreateTextureAndLoadImage();
    });
}

Main();

models_tri.js

// 拿到一个平面方块的坐标点数组
function GetQuad(xcenter, ycenter, length) {
    return [
        // 左下角 // 右上角 // 左上角
        -length / 2 + xcenter, -length / 2 + ycenter, 0,
        length / 2 + xcenter, length / 2 + ycenter, 0,
        -length / 2 + xcenter, length / 2 + ycenter, 0,
        // 右下角
        -length / 2 + xcenter, -length / 2 + ycenter, 0,
        length / 2 + xcenter, -length / 2 + ycenter, 0,
        length / 2 + xcenter, length / 2 + ycenter, 0,
    ]
}

function GetCube() {
    return [
        // front
        -0.5, 0.5, -0.5,
        -0.5, -0.5, -0.5,
        0.5, 0.5, -0.5,

        0.5, -0.5, -0.5,
        0.5, 0.5, -0.5,
        -0.5, -0.5, -0.5,

        // back
        -0.5, -0.5, 0.5,
        0.5, 0.5, 0.5,
        -0.5, 0.5, 0.5,

        0.5, 0.5, 0.5,
        -0.5, -0.5, 0.5,
        0.5, -0.5, 0.5,

        // left
        -0.5, -0.5, 0.5,
        -0.5, 0.5, -0.5,
        -0.5, 0.5, 0.5,

        -0.5, -0.5, 0.5,
        -0.5, -0.5, -0.5,
        -0.5, 0.5, 0.5,


    ];
}

function GetTri(A, B, C) {
    return [A[0], A[1], B[0], B[1], C[0], C[1]];
}

function GetPolyN(center, R, N) {
    // 1. 先在圆周上,均匀获取 N 个点
    let idx = 0;
    let x = 0;
    let y = 0;
    let rad = 0;
    let pointArr = [];
    for (; idx != N; idx++) {
        rad = ((2 * Math.PI) / N) * idx;
        x = R * Math.cos(rad) + center[0]; // 考虑 R 和 中心
        y = R * Math.sin(rad) + center[1]; // 考虑 R 和 中心
        pointArr.push([x, y]);
    }
    // 2. 将这N个点,每两个一组,与中心,正好是三个点,组成N个三角形
    let res = []; // 平坦化数组
    for (idx = 0; idx != N; idx++) {
        res.push(...GetTri(pointArr[idx], pointArr[(idx + 1) % N], center)); // 注意这里是逆时针排布的
    }
    return res;
}
// 获取随机颜色 RGB
function GetRandomColor(pointCount) {
    let res = [];
    let idx = 0;
    for (; idx != pointCount; idx++) {
        res.push(Math.random());//R
        res.push(Math.random());//G
        res.push(Math.random());//B
        // res.push(1);//R
        // res.push(1);//G
        // res.push(1);//B
    }
    return res;
}