webgl入门学习

38 阅读4分钟

用canvas创建一个矩形

//获取canvas
const ctx = document.getElementById('canvas')
//获取2d的
const c = ctx.getContext('2d')
//绘制矩形X坐标Y坐标,宽度,高度,未指定颜色默认为黑色
//指定颜色为红色    
c.fillStyle = 'red'
c.fillRect(10,10,100,100)

创建webgl程序

const ctx = document.getElementById('canvas')
//获取webgl
const gl = ctx.getContext('webgl')
//gl.clearColor(r,g,b,a)清空指定canvas 的颜色,接受四个参数(取值区间为0.0-1.0)
gl.clearColor(1.0,0.0,0.0,1.0)
//gl.clear() 清空canvas
gl.clear(gl.COLOR_BUFFER_BIT)
//gl.COLOR_BUFFER_BIT 清空颜色缓存
//gl.COLOR_BUFFER_BIT清空深度缓存区
//gl.COLOR_BUFFER_BIT清空模板缓冲区

gl.COLOR_BUFFER_BIT与gl.clearColor(1.0,0.0,0.0,1.0)配合使用 gl.COLOR_BUFFER_BIT与gl.clearDepth(1.0) gl.COLOR_BUFFER_BIT与gl.clearStencil(0)

绘制一个点

着色器:开发者编写的一段程序,代替固定渲染管线 来处理图像的渲染 着色器的分类: 1.顶点着色器:用来描述顶点的特性,通过计算获取位置信息 顶点可以理解为一个点 2.片元着色器:进行逐片元处理程序,通过计算获取颜色信息 片元可以理解为一个像素

    const ctx = document.getElementById('canvas')
    const gl = ctx.getContext('webgl')
    //创建着色器源码,必须要有分号
    const VERTEX_SHADER_SOURCE = `
    //void表示无返回值,必须要存在main函数
    void main(){
        //要绘制的点的坐标
        //vec4(0.0,0.0,0.0,1.0); X Y Z W(齐次坐标(x/w,y/w,z/w))
        gl_Position = vec4(0.0,0.0,0.0,1.0);
        //点的大小,只接受浮点数类型
        gl_PointSize = 10.0;
    }
    ` //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
    void main(){
        //要绘制的点的颜色
        //vec4(1.0,0.0,0.0,1.0) r g b a
        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)
    //执行绘制
    //参数:要绘制的图形,从哪个开始,使用几个顶点
    gl.drawArrays(gl.POINTS,0,1);
        //线段,最少需要两个点
    // gl.drawArrays(gl.LINES,0,1);
    //三角形,最少需要三个点
    // gl.drawArrays(gl.TRIANGLES,0,1);

    //三个点
    //0.0 0.0 0.0 //一个点
    //0.2 0.0 0.0
    //0.4 0.0 0.0 //一个线段
    gl.drawArrays(gl.POINTS,0,1);
    // 从1点开始,需要两个点 
    gl.drawArrays(gl.LINES,1,2);

全部流程 image.png

webgl坐标系

image.png webgl的坐标点 image.png

image.png

使用attribute变量(修改位置)

    const VERTEX_SHADER_SOURCE = `
    //在main函数外声明变量
    //存储限定符 类型 变量名 分号
    attribute vec4 aPosition;
    //attribute变量只传递顶点数据,不能在片元着色器中使用
    //aPosition默认为vec4(0.0,0.0,0.0,1.0)
    void main(){

        gl_Position = aPosition;
        //点的大小,只接受浮点数类型
        gl_PointSize = 10.0;
    }
    ` //顶点着色器

给attribute变量赋值

    //获取attribute变量需要在initShader方法后,因为需要profram对象
    //getAttribLocation(program,name) program 程序对象, name 指定想要获取的attribute变量的名称 返回变量的储存地址
    const aPosition = gl.getAttribLocation(program,'aPosition')
    //几个用于给attribute变量赋值的同族函数
    //gl.vertexAttrib1f(location,v1) location 变量,v1 四个分量的值
    //gl.vertexAttrib2f(location,v1,v2) location 变量,v1 v2 四个分量的值
    //gl.vertexAttrib3f(location,v1,v2,v3) location 变量,v1 v2 v3 四个分量的值
    //gl.vertexAttrib4f(location,v1,v2,v3,v4) location 变量,v1 v2 v3 v4 四个分量的值

    //                          x,y坐标为0.5
    // gl.vertexAttrib4f(aPosition,0.5,0.5,0.0,1.0)

创建一个会动的点

    let x = 0;
    setInterval(()=>{
        x+= 0.1
        if(x>1){
            x = 0
        }
        //每次修改完attribute变量后需要重新绘制
        gl.vertexAttrib1f(aPosition,x)
        gl.drawArrays(gl.POINTS,0,1);
    },200)

通过鼠标控制绘制

也可以将click变成其他的事件,如mousemove

    ctx.addEventListener('click',(e)=>{
        let x = e.clientX
        let y = e.clientY
        //获取当前元素的left和top
        let domPosition = e.target.getBoundingClientRect();
        //获取鼠标点击的位置
        const domX = x-domPosition.left
        const domY = y-domPosition.top
        //转换为-1 到 1 的区间
        const halfwidth = ctx.offsetWidth/2
        const halfheight = ctx.offsetHeight /2
        const clickX = (domX - halfheight)/halfwidth
        const clickY = (-domY + halfwidth)/halfheight
        
        gl.vertexAttrib2f(aPosition,clickX,clickY)
        gl.drawArrays(gl.POINTS,0,1);
    })

使用uniform变量(修改颜色)

着色器中

    const FRAGMENT_SHADER_SOURCE = `
    //同attribute
    //片元着色器中没有指定默认精度
    //低精度lowp,高精度highp
    precision mediump float;
    uniform vec2 uColor;
    void main(){

        //gl_FragColor只接受vec4,故将vec123转换成vec4
        gl_FragColor = vec4(uColor.r,uColor.g,0.0,1.0;

    }
    `//片元着色器

js中

    ////////////////////////
    const uColor = gl.getUniformLocation(program,'uColor')
    gl.uniform2f(uColor,1.0,0.0)

    //着色器声明vec4,此处用uniform4f,着色器声明vec3,此处用uniform3f,其余同理
    //不可声明ucolor的类型为vec1,可以声明为uniform float uColor
    //gl.uniform1f(location,v1) location 变量,v1 四个分量的值
    //gl.uniform2f(location,v1,v2) location 变量,v1 v2 四个分量的值
    //gl.uniform3f(location,v1,v2,v3) location 变量,v1 v2 v3 四个分量的值
    //gl.uniform4f(location,v1,v2,v3,v4) location 变量,v1 v2 v3 v4 四个分量的值

    //uniform即可以用在顶点着色器,也可以用在片元着色器,
    //但是uniform不能传递顶点数据,因为每个顶点数据不同,uniform针对所有点生效