简单的webgl学习 颜色和纹理

30 阅读7分钟

varying变量

    //创建着色器源码
    const VERTEX_SHADER_SOURCE = `
    //varying变量在使用时需要在顶点着色器和片元着色器中一起声明
    varying vec4 vColor;
    attribute vec4 aPosition;
    void main(){
        vColor = aPosition;
        gl_Position = aPosition;

    }
    ` //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `
    //需要声明精度
    precision lowp float;
    //varying变量的作用是从顶点着色器向片元着色器传递数据
    varying vec4 vColor;

    void main(){
        gl_FragColor = vColor;

    }
    `//片元着色器

执行过程

image.png

webgl渲染流程介绍

image.png 图元装配:将独立的顶点坐标装配成几何图形,图形的类别由gl.drawArrays()的第一个参数确定 光栅化:将装配好的图形转换为片元 剔除:对于不透明的物体,背面对于观察者来说是不可见的,在渲染过程中就会将不可见的部分剔除,不参与绘制,节省渲染开销 裁剪:在可视范围外的物体是看不到的,图形生成后有的部分位于可视范围外,这一部分会被裁剪掉,不参与绘制

给图形添加背景图

image.png 着色器

    const VERTEX_SHADER_SOURCE = `

    attribute vec4 aPosition;
    //接收纹理坐标
    attribute vec4 aTex;
    //传递纹理坐标(vec2类型)
    varying vec2 vTex;

    void main(){
        gl_Position = aPosition;
        vTex = vec2(aTex.x,aTex.y);

    }
    ` //顶点着色器
    const FRAGMENT_SHADER_SOURCE = `

    precision lowp float;
    varying vec2 vTex;

    //声明一些变量接收 sampler2D(2d纹理) samplerCube(立方体纹理)
    uniform sampler2D uSampler;


    void main(){
        //                               纹理坐标(手动指定)
        gl_FragColor = texture2D(uSampler, vTex);

    }
    `//片元着色器

修改点的信息

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


    //创建一组顶点数据
    //Float32Array是类型化数组
    const points = new Float32Array([
        //手动指定纹理坐标(4个顶点)
        -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
    ])

    const buffer = gl.createBuffer()

    gl.bindBuffer(gl.ARRAY_BUFFER,buffer)

    gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)

    const BYTES = points.BYTES_PER_ELEMENT

    gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES*4,0);

    gl.enableVertexAttribArray(aPosition)

    gl.vertexAttribPointer(aTex,1,gl.FLOAT,false,BYTES*4,BYTES*2);

    gl.enableVertexAttribArray(aTex)

script中

    //创建img对象
    const img = new Image()
    //添加onload函数,保证使用时图片已经加载
    img.onload = function(){
        //创建纹理对象,用于存储图像数据 gl.deleteTexture() 删除纹理对象
        const texture = gl.createTexture()
        //反转图片y轴
        //pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
        //开启纹理单元
        gl.activeTexture(gl.TEXTURE0)
        //webGL通过纹理单元管理纹理对象,每个纹理单元管理一张纹理图像

        //绑定纹理对象
        //bindTexture(type,texture)type有两种:gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
        gl.bindTexture(gl.TEXTURE_2D,texture);

        //texParameteri(type,pname,param)
        //pname分为四种:gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小,gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充)
        //param :对于gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小 有:gl.NEAREST使用最近像素颜色值,gl.LINEAR使用四周的加权平均值
        //param :对于gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充) 有:gl.REPEAT平铺重复,gl.MIRRORED_REPEAT镜像对称,gl.CLAMP_TO_EDGE 边缘延伸
        //处理放大缩小的逻辑
        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)

        //配置纹理对象
        //texImage2D(type,level,internalformat,format,dataType,image)level为0即可 image图片对象
        //internalformat图像的内部格式,如png图片内部格式为rgba,jpg图片内部格式为rgb:gl.RGB,gl.RGBA,gl.ALPHA,gl.LUMINANCE 使用物体表面的红绿蓝,分量的加权平均值来计算,gl.LUMINANCE_ALPHA
        //format纹理的内部格式,必须和internalformat相同
        //dataType纹理数据的数据类型 gl.UNISIGNED_BYTE无符号整形,每个颜色分类占一字节,gl.UNSIGNED_SHORT_5_6_5 rgb分量分别占据565比特,gl.UNSIGNED_SHORT_4_4_4_4 rgba分量分别占据4 4 4 4比特,gl.UNSIGNED_SHORT_5_5_5_1 rgba分量分别占据5 5 5 1比特
        gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)

        //                  当前开启的纹理单元的编号
        // i 代表int f代表float
        gl.uniform1i(uSampler,0)

    gl.drawArrays(gl.TRIANGLE_STRIP,0,4);

    }
    img.src = './assets/img2.png'

其中还遇到了访问本地资源跨域的问题,解决方案是下载了liveserver插件,使用http请求

但是最后的效果还是不尽人意 实际效果图:

image.png

原图: image.png 未找到原因,未能解决

多重纹理(将多个图片填充到同一个图形上)

多重纹理需要多个变量接收数据

    const FRAGMENT_SHADER_SOURCE = `

    precision lowp float;
    varying vec2 vTex;

    //声明一些变量接收 sampler2D(2d纹理) samplerCube(立方体纹理)
    uniform sampler2D uSampler;
    uniform sampler2D uSampler1;


    void main(){
        //                               纹理坐标(手动指定)
        vec4 c1 = texture2D(uSampler, vTex);
        vec4 c2 = texture2D(uSampler1, vTex);

        gl_FragColor = c1*c2;

    }
    `//片元着色器

创建promise对象,获取图像函数执行完成后进行操作

function getImage(){
    return new Promise(resolve =>{
        //创建img对象
        const img = new Image()
        //添加onload函数,保证使用时图片已经加载
        img.onload = function(){
            //创建纹理对象,用于存储图像数据 gl.deleteTexture() 删除纹理对象
            const texture = gl.createTexture()
            //反转图片y轴
            //pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            //开启纹理单元
            gl.activeTexture(gl.TEXTURE0)
            //webGL通过纹理单元管理纹理对象,每个纹理单元管理一张纹理图像
    
            //绑定纹理对象
            //bindTexture(type,texture)type有两种:gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
            gl.bindTexture(gl.TEXTURE_2D,texture);
    
            //texParameteri(type,pname,param)
            //pname分为四种:gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小,gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充)
            //param :对于gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小 有:gl.NEAREST使用最近像素颜色值,gl.LINEAR使用四周的加权平均值
            //param :对于gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充) 有:gl.REPEAT平铺重复,gl.MIRRORED_REPEAT镜像对称,gl.CLAMP_TO_EDGE 边缘延伸
            //处理放大缩小的逻辑
            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)
    
            //配置纹理对象
            //texImage2D(type,level,internalformat,format,dataType,image)level为0即可 image图片对象
            //internalformat图像的内部格式,如png图片内部格式为rgba,jpg图片内部格式为rgb:gl.RGB,gl.RGBA,gl.ALPHA,gl.LUMINANCE 使用物体表面的红绿蓝,分量的加权平均值来计算,gl.LUMINANCE_ALPHA
            //format纹理的内部格式,必须和internalformat相同
            //dataType纹理数据的数据类型 gl.UNISIGNED_BYTE无符号整形,每个颜色分类占一字节,gl.UNSIGNED_SHORT_5_6_5 rgb分量分别占据565比特,gl.UNSIGNED_SHORT_4_4_4_4 rgba分量分别占据4 4 4 4比特,gl.UNSIGNED_SHORT_5_5_5_1 rgba分量分别占据5 5 5 1比特
            gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)
    
            //                  当前开启的纹理单元的编号
            // i 代表int f代表float
            gl.uniform1i(uSampler,0)
    
            resolve()
    
        }
        img.src = './assets/img1.png'
        
    })
}

function getImage1(){
    return new Promise(resolve =>{
        //创建img对象
        const img = new Image()
        //添加onload函数,保证使用时图片已经加载
        img.onload = function(){
            //创建纹理对象,用于存储图像数据 gl.deleteTexture() 删除纹理对象
            const texture = gl.createTexture()
            //反转图片y轴
            //pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            //开启纹理单元
            gl.activeTexture(gl.TEXTURE1)
            //webGL通过纹理单元管理纹理对象,每个纹理单元管理一张纹理图像
    
            //绑定纹理对象
            //bindTexture(type,texture)type有两种:gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
            gl.bindTexture(gl.TEXTURE_2D,texture);
    
            //texParameteri(type,pname,param)
            //pname分为四种:gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小,gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充)
            //param :对于gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小 有:gl.NEAREST使用最近像素颜色值,gl.LINEAR使用四周的加权平均值
            //param :对于gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充) 有:gl.REPEAT平铺重复,gl.MIRRORED_REPEAT镜像对称,gl.CLAMP_TO_EDGE 边缘延伸
            //处理放大缩小的逻辑
            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)
    
            //配置纹理对象
            //texImage2D(type,level,internalformat,format,dataType,image)level为0即可 image图片对象
            //internalformat图像的内部格式,如png图片内部格式为rgba,jpg图片内部格式为rgb:gl.RGB,gl.RGBA,gl.ALPHA,gl.LUMINANCE 使用物体表面的红绿蓝,分量的加权平均值来计算,gl.LUMINANCE_ALPHA
            //format纹理的内部格式,必须和internalformat相同
            //dataType纹理数据的数据类型 gl.UNISIGNED_BYTE无符号整形,每个颜色分类占一字节,gl.UNSIGNED_SHORT_5_6_5 rgb分量分别占据565比特,gl.UNSIGNED_SHORT_4_4_4_4 rgba分量分别占据4 4 4 4比特,gl.UNSIGNED_SHORT_5_5_5_1 rgba分量分别占据5 5 5 1比特
            gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)
    
            //                  当前开启的纹理单元的编号
            // i 代表int f代表float
            gl.uniform1i(uSampler1,1)
    
            resolve()
    
        }
        img.src = './assets/img2.png'
        
    })
}

Promise.all([getImage(),getImage1()]).then(()=>{
    gl.drawArrays(gl.TRIANGLE_STRIP,0,4);

})

减少重复代码后

function getImage(url,location,index){
    return new Promise(resolve =>{
        //创建img对象
        const img = new Image()
        //添加onload函数,保证使用时图片已经加载
        img.onload = function(){
            //创建纹理对象,用于存储图像数据 gl.deleteTexture() 删除纹理对象
            const texture = gl.createTexture()
            //反转图片y轴
            //pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
            //开启纹理单元
            gl.activeTexture(gl[`TEXTURE${index}`])
            //webGL通过纹理单元管理纹理对象,每个纹理单元管理一张纹理图像
    
            //绑定纹理对象
            //bindTexture(type,texture)type有两种:gl.TEXTURE_2D二维纹理,gl.TEXTURE_CUBE_MAP立方体纹理
            gl.bindTexture(gl.TEXTURE_2D,texture);
    
            //texParameteri(type,pname,param)
            //pname分为四种:gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小,gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充)
            //param :对于gl.TEXTURE_MAG_FILTER放大,gl.TEXTURE_MIN_FILTER缩小 有:gl.NEAREST使用最近像素颜色值,gl.LINEAR使用四周的加权平均值
            //param :对于gl.TEXTURE_WRAP_S横向(水平填充),gl.TEXTURE_WRAP_T纵向(垂直填充) 有:gl.REPEAT平铺重复,gl.MIRRORED_REPEAT镜像对称,gl.CLAMP_TO_EDGE 边缘延伸
            //处理放大缩小的逻辑
            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);
    
            //配置纹理对象
            //texImage2D(type,level,internalformat,format,dataType,image)level为0即可 image图片对象
            //internalformat图像的内部格式,如png图片内部格式为rgba,jpg图片内部格式为rgb:gl.RGB,gl.RGBA,gl.ALPHA,gl.LUMINANCE 使用物体表面的红绿蓝,分量的加权平均值来计算,gl.LUMINANCE_ALPHA
            //format纹理的内部格式,必须和internalformat相同
            //dataType纹理数据的数据类型 gl.UNISIGNED_BYTE无符号整形,每个颜色分类占一字节,gl.UNSIGNED_SHORT_5_6_5 rgb分量分别占据565比特,gl.UNSIGNED_SHORT_4_4_4_4 rgba分量分别占据4 4 4 4比特,gl.UNSIGNED_SHORT_5_5_5_1 rgba分量分别占据5 5 5 1比特
            gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img)
    
            //                  当前开启的纹理单元的编号
            // i 代表int f代表float
            gl.uniform1i(location,index)
    
            resolve()
    
        }
        img.src = url
        console.log(img);
    })
}

Promise.all([getImage('./assets/img1.png',uSampler,0),getImage('./assets/img2.png',uSampler1,1)]).then(()=>{
    gl.drawArrays(gl.TRIANGLE_STRIP,0,4);

})

同上,也不能完整显示图片,未能找到原因