webgl

111 阅读3分钟

可以实现 地图,vr,物品展示,室内设计,城市规划

GLSL ES是以字符串的形式存在在JavaScript中的

webgl开源框架

three.js:js 3Dwebgl库

babylon.js: web3D图形引擎

kickjs: web的开源图形和游戏引擎

clayGl: 构建可扩展web3d应用程序

playCanvas: 网络游戏和3D图形引擎

webGlStudio.js和Litescene.js: 开源web 3D图形编辑器和创建器

luma: uber的3D Webgl 可视化库

A-Frame 是用于构建vr(虚拟现实) 体验的web框架

第一个程序


const ctx = document.getElementById('canvas')

const gl = ctx.getContext('webgl')
//clearColor(r,g,b,a)指定清空<canvas>的颜色 接收四个参数
gl.clearColor(1.0,0.0,0.0,1.0)
//gl.COLOR_BUFFER_BIT清空颜色缓存 gl.DEPTH_BUFFER_BIT 清空深度缓存区 gl.STENCIL_BUFFER_BIT 清空模版缓存区
gl.clear(gl.COLOR_BUFFER_BIT)


注意这两个要一起使用 gl.clearColor 和 gl.clear

着色器

着色器:就是让开发者自己去编写一段程序,用来代替固定渲染管线,来处理图像的渲染

顶点着色器:用来描述顶点的特性 =》通过计算获取位置信息

片元着色器:进行逐片远处理程序 =》通过计算获取颜色信息

流程介绍: 1.开始

2.获取元素

3.初始化顶点着色器源程序

  1. 初始化片元着色器源程序

    创建顶点着色器

    创建片元着色器

    关联着色器和着色器源码

    编译着色器

    创建program

    关联着色器 和 program

    使用program

<script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    console.log(gl)
    // 着色器 就是让开发者自己去编写一段程序,用来代替固定渲染管线,来处理图像的渲染
    const VERTEX_SHADER_SOURCE = `
        //必须要存在 main 函数 void里面必须有分号
        void main() {
            // 要绘制的点的坐标
            gl_Position = vec4(0.0,0.0,0.0,1.0);
            // 点的大小
            gl_PointSize = 10.0;
        }
    `; //顶点着色器
    //gl_Position  vec4(1.0,0.0,0.0,1.0) x,y,z,w 齐次坐标
    //gl_FraColor  vec4(1.0,0.0,0.0,1.0) r,g,b,a
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器

    //创建着色器
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) //指定顶点着色器的源码
    gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) //指定片元着色器的源码

    // 编译着色器
    gl.compileShader(vertexShader)
    gl.compileShader(fragmentShader)

    //创建一个程序对象
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader)
    gl.attachShader(program, fragmentShader)

    gl.linkProgram(program)

    gl.useProgram(program)

    // initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
    //执行绘制

    // 要绘制的图形是什么, 从哪个开始, 使用几个顶点
    gl.drawArrays(gl.POINTS, 0, 1)
</script>

attribute变量

1.获取attribute变量

   const aPosition = gl.getAttribLocation(program, 'aPositon')

获取attribute变量需要在initShader 函数之后,因为会用到program这个程序对象

2.赋值

    gl.vertexAttrib4f(aPosition, 0.5, 0.5, 0.0, 1.0)
    
    <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        void main() {
            gl_Position = aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    

    let x=0;
    setInterval(() => {
        x += 0.1;
        if(x>1.0){
            x=0
        }
        gl.vertexAttrib1f(aPosition, x)

        gl.drawArrays(gl.POINTS, 0, 1)
    },1000)
</script>

鼠标控制点

    <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        void main() {
            gl_Position = aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    
    const points = []
    ctx.onclick = function(ev) {
        // 坐标
        const x = ev.clientX
        const y = ev.clientY

        //ctx.offsetTop
        //ctx.offsetLeft
        const domPosition = ev.target.getBoundingClientRect();
        console.log(domPosition,ctx.offsetTop,ctx.offsetLeft)

        const domx = x - domPosition.left
        const domy = y - domPosition.top

        const halfWidth = ctx.offsetWidth / 2
        const halfHeight = ctx.offsetHeight / 2

        const clickX = (domx - halfWidth) /halfWidth
        const clickY = (halfHeight - domy)/halfHeight
        console.log(clickX,clickY)
        points.push({
            clickX,clickY
        })
        
        for(let i=0;i<points.length;i++){
            gl.vertexAttrib2f(aPosition,points[i].clickX,points[i].clickY)

            gl.drawArrays(gl.POINTS, 0, 1)
        }
    }

    
</script>

绘制不同颜色

     1.获取uColor变量
   const uColor = gl.getUniformLocation(program, 'uColor')

2.赋值

    gl.uniform4f(uColor,1.0,0.0,0.0,1.0)
    

缓冲区对象

缓冲区对象是webgl系统中的一块内存区域,可以一次性地向缓冲区对象中填充大量的顶点数据,然后将这些数据保存在其中,供顶点着色器使用

   <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        void main() {
            gl_Position = aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

           

    gl.drawArrays(gl.POINTS, 0, 3)


    
</script>
    const VERTEX_SHADER_SOURCE = `
    // 变量声明 vec4 类型 aPosition 变量名
    // 只传递顶点数据,不能在片元着色器使用
    attribute vec4 aPosition;
    attribute float aPointSize;
    void main() {
        gl_Position = aPosition;
        gl_PointSize = aPointSize;
    }
    `;
        
     const aPointSize = gl.getAttribLocation(program, 'aPointSize')
        
        
        //1创建顶点数据
    const size = new Float32Array([
        10.0,
        20.0,
        30.0,
    ])

    //2创建缓存对象
    const sizeBuffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,sizeBuffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,size,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPointSize,1,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPointSize)

    gl.drawArrays(gl.POINTS, 0, 3)

缓存区大小和位置写一起

        <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        attribute float aPointSize;
        void main() {
            gl_Position = aPosition;
            gl_PointSize = aPointSize;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    const aPointSize = gl.getAttribLocation(program, 'aPointSize')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,10.0,
        0.5,-0.5,20.0,
        0.0,0.5,30.0
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)

    const BYTES = points.BYTES_PER_ELEMENT; 

    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES*3,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    gl.vertexAttribPointer(aPointSize,1,gl.FLOAT,false,BYTES*3,BYTES*2);
    gl.enableVertexAttribArray(aPointSize)

    gl.drawArrays(gl.POINTS, 0, 3)


    
</script>

多种绘制的图形

image.png

通过着色器偏移

        <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        attribute float aTranslate;
        void main() {
            gl_Position = vec4(aPosition.x + aTranslate,aPosition.y,aPosition.z,1.0);
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')
    const aTranslate = gl.getAttribLocation(program, 'aTranslate')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

    let x=-1
    setInterval(()=>{
        x+=0.1;
        if(x>1){
            x=-1
        }
        gl.vertexAttrib1f(aTranslate,x)
        gl.drawArrays(gl.TRIANGLES, 0, 3)
    },60)  
</script>

通过着色器缩放

        
        <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        attribute float aTranslate;
        attribute float aScale;
        void main() {
            gl_Position = vec4(aPosition.x*aScale + aTranslate,aPosition.y,aPosition.z,1.0);
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')
    // const aTranslate = gl.getAttribLocation(program, 'aTranslate')

    const aScale = gl.getAttribLocation(program, 'aScale')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

    let x=-1
    setInterval(()=>{
        x+=0.1;
        if(x>2){
            x=1
        }
        gl.vertexAttrib1f(aScale,x)
        gl.drawArrays(gl.TRIANGLES, 0, 3)
    },60)  
</script>

图形旋转

        <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        attribute float deg;
        void main() {
            gl_Position.x = aPosition.x*cos(deg) - aPosition.y*sin(deg);
            gl_Position.y = aPosition.x*sin(deg) + aPosition.y*cos(deg);
            gl_Position.z = aPosition.z;
            gl_Position.w = aPosition.w;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    const deg = gl.getAttribLocation(program, 'deg')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

    let x=-1
    function animation(){
        x+=-0.01;
        gl.vertexAttrib1f(deg,x)
        gl.drawArrays(gl.TRIANGLES, 0, 3)
        requestAnimationFrame(animation)
    }
    animation()
</script>

平移矩阵

         const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        uniform mat4 mat;
        void main() {
            gl_Position = mat * aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')
    const mat = gl.getUniformLocation(program, 'mat')

    function getTranslateMatrix(x=0,y=0,z=0) {
        return new Float32Array([
            1.0,0.0,0.0,0.0,
            0.0,1.0,0.0,0.0,
            0.0,0.0,1.0,0.0,
            x,y,z,1,
    ])
    }

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

    let x=-1
    function animation(){
        x+=0.01;
        if(x>1){
            x=-1
        }
        const matrix =getTranslateMatrix(x,x)
        gl.uniformMatrix4fv(mat,false,matrix)
        gl.drawArrays(gl.TRIANGLES, 0, 3)
        requestAnimationFrame(animation)
    }
    animation();
</script>

缩放-缩放矩形

    <script>
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        uniform mat4 mat;
        void main() {
            gl_Position = mat * aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        void main() {
            gl_FragColor = vec4(1.0,0.0,0.0,1.0);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')
    const mat = gl.getUniformLocation(program, 'mat')

    function getScaleMatrix(x=1,y=1,z=1) {
        return new Float32Array([
            x,0.0,0.0,0.0,
            0.0,y,0.0,0.0,
            0.0,0.0,z,0.0,
            0.0,0.0,0.0,1,
    ])
    }

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,
        0.5,-0.5,
        0.0,0.5,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)

    // gl.vertexAttrib2f(aPosition,0.0,0.0)

    let x=0.1
    function animation(){
        x+=0.01;
        if(x>1.5){
            x=0.1
        }
        const matrix =getScaleMatrix(x,x)
        gl.uniformMatrix4fv(mat,false,matrix)
        gl.drawArrays(gl.TRIANGLES, 0, 3)
        requestAnimationFrame(animation)
    }
    animation();
</script>

图形旋转 矩形旋转

image.png

varing变量

顶点着色器向片元着色器传值

    const VERTEX_SHADER_SOURCE = `
        attribute vec4 aPosition;
        varying vec4 vColor;
        void main() {
            vColor = aPosition;
            gl_Position = aPosition;
            gl_PointSize = 10.0;
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        precision lowp float;
        varying vec4 vColor;

        void main() {
            gl_FragColor = vColor;
        }
    `;

从顶点到图形-webgl渲染流程介绍

image.png

1,图元装配过程:将独立的顶点坐标装配成几何图形,图形的类别由gl.drawArrays()第一个参数确定。 2.光栅化:将装配好的图形转换为片元

3.剔除:对于不透明物体,背面对于观察者来说是不可见的,那么在渲染过程中,就会将不可见的部分剔除,不参与绘制。节省渲染开销。

image.png

图形背景图

    <script>
    /*  */
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        attribute vec4 aTex;
        varying vec2 vTex;
        void main() {
            gl_Position = aPosition;
            vTex = vec2(aTex.x,aTex.y);
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        precision lowp float;
        uniform sampler2D uSampler;
        varying vec2 vTex;
        void main() {
            gl_FragColor = texture2D(uSampler,vTex);
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    const aTex = gl.getAttribLocation(program, 'aTex')
    const uSampler = gl.getUniformLocation(program, 'uSampler')

    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,0.0,1.0,
        0.5,-0.5,0.0,0.0,
        -0.5,0.5,1.0,1.0,
        0.5,0.5,1.0,0.0,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    const BYTES = points.BYTES_PER_ELEMENT
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES * 4,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)
    gl.vertexAttribPointer(aTex,2,gl.FLOAT,false,BYTES * 2,0);
    gl.enableVertexAttribArray(aTex)
    // gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
    
    const img = new Image()

    img.onload= function () {
        //创建文理对象
        const texture = gl.createTexture()

        //翻转图片 Y轴
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)

        //开启一个纹理单元
        gl.activeTexture(gl.TEXTURE0)

        //绑定纹理对象
        gl.bindTexture(gl.TEXTURE_2D,texture)

        //处理放大缩小的逻辑
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR)
        gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR)


        //横向 纵向 平铺的方式
        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.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)

        gl.uniform1i(uSampler,0)
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
    }

    img.src='../assets/2.png'
    console.log(img)

    
</script>

多重纹理

    
    <script>
    /*  */
    const ctx = document.getElementById('canvas')

    const gl = ctx.getContext('webgl')
    // 创建着色器源码
    const VERTEX_SHADER_SOURCE = `
        // 变量声明 vec4 类型 aPosition 变量名
        // 只传递顶点数据,不能在片元着色器使用
        attribute vec4 aPosition;
        attribute vec4 aTex;
        varying vec2 vTex;
        void main() {
            gl_Position = aPosition;
            vTex = vec2(aTex.x,aTex.y);
        }
    `;
    //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
        precision lowp float;
        uniform sampler2D uSampler;
        uniform sampler2D uSampler1;
        varying vec2 vTex;
        void main() {
            vec4 c1 = texture2D(uSampler,vTex);
            vec4 c2 = texture2D(uSampler1,vTex);
            gl_FragColor =c1 * c2;
        }
    `;
    //片元着色器


    const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

    const aPosition = gl.getAttribLocation(program, 'aPosition')

    const aTex = gl.getAttribLocation(program, 'aTex')
    const uSampler = gl.getUniformLocation(program, 'uSampler')
    const uSampler1 = gl.getUniformLocation(program, 'uSampler1')
    //1创建顶点数据
    const points = new Float32Array([
        -0.5,-0.5,0.0,1.0,
        0.5,-0.5,0.0,0.0,
        -0.5,0.5,1.0,1.0,
        0.5,0.5,1.0,0.0,
    ])

    //2创建缓存对象
    const buffer = gl.createBuffer()
    const BYTES = points.BYTES_PER_ELEMENT
    //3绑定缓存区对象
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    //4将数据写入缓存区 gl.bufferData(target,data,type)
    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
    //  5将缓存区对象分配给一个attribute对象
    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES * 4,0);
    //6开启attribute变量
    gl.enableVertexAttribArray(aPosition)
    gl.vertexAttribPointer(aTex,2,gl.FLOAT,false,BYTES * 2,0);
    gl.enableVertexAttribArray(aTex)
    // gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
    
    function getImage (url,location,index) {
        return new Promise(resolve => {
            const img = new Image()

            img.onload= function () {
                //创建文理对象
                const texture = gl.createTexture()

                //翻转图片 Y轴
                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)

                //开启一个纹理单元
                gl.activeTexture(gl[`TEXTURE${index}`])

                //绑定纹理对象
                gl.bindTexture(gl.TEXTURE_2D,texture)

                //处理放大缩小的逻辑
                gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR)
                gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR)


                //横向 纵向 平铺的方式
                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.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)

                gl.uniform1i(location,index)
                resolve()
            }
            img.src=url

        })
        

    }
    // function getImage1 () {
    //     return new Promise(resolve => {
    //         const img = new Image()

    //         img.onload= function () {
    //             //创建文理对象
    //             const texture = gl.createTexture()

    //             //翻转图片 Y轴
    //             gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)

    //             //开启一个纹理单元
    //             gl.activeTexture(gl.TEXTURE1)

    //             //绑定纹理对象
    //             gl.bindTexture(gl.TEXTURE_2D,texture)

    //             //处理放大缩小的逻辑
    //             gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR)
    //             gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR)


    //             //横向 纵向 平铺的方式
    //             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.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)

    //             gl.uniform1i(uSampler1,0)
    //             resolve()
    //         }
    //         img.src='../assets/1.png'

    //     })
        

    // }
    Promise.all([getImage('../assets/nice.png',uSampler,0), getImage('../assets/1.png',uSampler1,1)]).then(()=>{
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4)
    })
    
</script>