webgl-原生纹理贴图

踩坑:

1、图片不显示:图片分辨率为非2的幂次方,图片不能被渲染。图形变成黑方块
2的N次幂:1 2 4 8 16 32 64 128 256 512 1024 2048 4096……
2、几何图形配置映射方式,顶点坐标和纹理坐标对应需要注意,构建顺序与新增顶点的奇偶性相关。
如果新增顶点时奇数,顶点排列顺序为:T = [n-1 n-2 n];
如果新增顶点为偶数,顶点排列顺序为:T = [n-2 n-1 n];

 

图片素材:

链接: https://pan.baidu.com/s/1CQ2fZ36Ke8QfGFDytFkyQw

提取码: 3dh4

关键代码:

function initTexture(ctx) {

    let texture = ctx.createTexture()

    let u_sampler = ctx.getUniformLocation(ctx.program, "u_sampler")

    let image = new Image()

    image.crossOrigin = "anonymous"

    image.src = "http://localhost:8080/upload/dog.webp"

    //异步加载,图片加载完成之后执行这个函数里的任务

    image.onload = () => {

        //对纹理图像进行y轴反转,是否翻转

        ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, true);

        //默认可以贴8张图片,从索引0开始,这里激活第一个

        ctx.activeTexture(ctx.TEXTURE0)

        //以TEXTURE_2D方式绑定贴图

        ctx.bindTexture(ctx.TEXTURE_2D, texture)

        //对贴图的参数进行设置texParameteri(贴图的种类,参数的名称,具体值)

        ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR)

        //设置纹理贴图填充方式(纹理贴图像素尺寸小于顶点绘制区域像素尺寸)

        ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR)

        console.log(image)

        //贴图用那种图片进行贴图

        ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image)

        //将第0张贴图贴到u_sampler

        ctx.uniform1i(u_sampler, 0)

        draw(ctx)

    }

}

html

<!DOCTYPE html>

<head>

    <style>

        *{

            margin: 0px;

            padding: 0px;

        }

    </style>

</head>

<body>

    <canvas id = 'webgl'>

        您的浏览器不支持HTML5,请更换浏览器

    </canvas>

    <script src="./main.js"></script>

</body>

main.js

let canvas = document.getElementById('webgl')

canvas.width = window.innerWidth

canvas.height = window.innerHeight

let radio = window.innerWidth / window.innerHeight;

let ctx = canvas.getContext('webgl')

//创建顶点资源和像素资源(颜色)

let vertexSource = `

attribute vec2 a_position;

attribute vec2 a_uv;

varying vec2 v_uv;

void main() {

  v_uv = a_uv;

  gl_Position = vec4(a_position, 0.0, 1.0);

  gl_PointSize = 10.0;

}

`

let fragmentSource = `

precision mediump float;

varying vec2 v_uv;

uniform sampler2D u_sampler;

void main (){

  vec4 color = texture2D(u_sampler, v_uv);

  gl_FragColor = color;

}

`

//gl_FragColor = vec4(v_uv, 0.0, 1.0);

if (initShader(ctx, vertexSource, fragmentSource)) {

    let box = [

        -0.5, -0.5,

        0.5, -0.5,

        0.5, 0.5,

        -0.5, 0.5

    ]

    let boxFloat32Array = new Float32Array(box)

    //创建buffer

    let buffer = ctx.createBuffer()

    //绑定buffer

    ctx.bindBuffer(ctx.ARRAY_BUFFER, buffer)

    //往buffer中填充值,并指定数据用途

    ctx.bufferData(ctx.ARRAY_BUFFER, boxFloat32Array, ctx.STATIC_DRAW)

    //获取vertexShader指定变量内存

    let a_Position = ctx.getAttribLocation(ctx.program, "a_position")

    //指定每两个数组元素为一个点

    /*

     * 当数组元素不需进行分割拆分的时候最后两位可以指定为0,0

     *

     *

     */

    ctx.vertexAttribPointer(

        a_Position, //location: vertex Shader里面的attributes变量的location

        2, ctx.FLOAT, //size: attribute变量的长度 vec2长度2 vec3长度3

        false, //normalized: 正交化 true或false  , [1, 2] => [1/根号5, 2/根号5]

        2 * boxFloat32Array.BYTES_PER_ELEMENT, //stride: 每个点的信息所占的BYTES

        0 //offset: 每个点的信息,从第几个BYTES开始数

    )

    ctx.enableVertexAttribArray(a_Position);

    let color = [

        0.0, 0.0,

        1.0, 0.0,

        1.0, 1.0,

        0.0, 1.0

    ]

    let colorFloat32Array = new Float32Array(color)

    let colorBuffer = ctx.createBuffer()

    ctx.bindBuffer(ctx.ARRAY_BUFFER, colorBuffer)

    ctx.bufferData(ctx.ARRAY_BUFFER, colorFloat32Array, ctx.STATIC_DRAW)

    let a_uv = ctx.getAttribLocation(ctx.program, "a_uv")

    ctx.vertexAttribPointer(a_uv, 2, ctx.FLOAT, false, 2 * colorFloat32Array.BYTES_PER_ELEMENT, 0)

    ctx.enableVertexAttribArray(a_uv)

    initTexture(ctx)

}


 

function draw(ctx) {

    ctx.clearColor(0.0, 0.0, 0.0, 1.0)

    ctx.clear(ctx.COLOR_BUFFER_BIT)

    ctx.drawArrays(ctx.TRIANGLE_FAN,

        0,//从第几个点开始

        4 //画几个点)

    )

    // ctx.drawArrays(ctx.TRIANGLE_FAN,

    //     0,//从第几个点开始

    //     4 //画几个点)

    // )

}

function initTexture(ctx) {

    let texture = ctx.createTexture()

    let u_sampler = ctx.getUniformLocation(ctx.program, "u_sampler")

    let image = new Image()

    image.crossOrigin = "anonymous"

    image.src = "http://localhost:8080/upload/dog.webp"//需要更改资源地址

    //异步加载,图片加载完成之后执行这个函数里的任务

    image.onload = () => {

        //对纹理图像进行y轴反转

        ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, 1);

        //默认可以贴8张图片,从索引0开始,这里激活第一个

        ctx.activeTexture(ctx.TEXTURE0)

        //以TEXTURE_2D方式绑定贴图

        ctx.bindTexture(ctx.TEXTURE_2D, texture)

        //对贴图的参数进行设置texParameteri(贴图的种类,参数的名称,具体值)

        ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR)

        //设置纹理贴图填充方式(纹理贴图像素尺寸小于顶点绘制区域像素尺寸)

        ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR)

        console.log(image)

        //贴图用那种图片进行贴图

        ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image)

        //将第0张贴图贴到u_sampler

        ctx.uniform1i(u_sampler, 0)

        draw(ctx)

    }

}


 

//创建顶点阴影和像素阴影

function createShader(ctx, type, source) {

    //创建shader

    let shader = ctx.createShader(type)

    //绑定

    ctx.shaderSource(shader, source)

    //编译shader

    ctx.compileShader(shader)

    //获取编译结果

    let compiler = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)

    if (compiler) {

        return shader

    } else {

        let log = ctx.getShaderInfoLog(shader)

        console.log("compile shaders error", log)

        //删除异常的shader,防止内存泄露

        ctx.deleteShader(shader)

        return null

    }

}

function createProgram(ctx, vertexShader, fragmentShader) {

    //创建program

    let program = ctx.createProgram()

    if (!program) {

        return null

    }

    //点资源和像素资源合并

    ctx.attachShader(program, vertexShader)

    ctx.attachShader(program, fragmentShader)

    ctx.linkProgram(program)

    //获取linked的结果

    let linked = ctx.getProgramParameter(program, ctx.LINK_STATUS)

    if (linked) {

        return program

    } else {

        //获取link错误信息

        let log = ctx.getProgramInfoLog(program)

        console.log("link program error", log)

        //删除防止内存泄漏

        ctx.delete(program)

        ctx.deleteShader(vertexShader)

        ctx.deleteShader(fragmentShader)

        return null

    }

}

function initShader(ctx, vertexSource, fragmentSource) {

    let vertexShader = createShader(ctx, ctx.VERTEX_SHADER, vertexSource)

    let fragmentShader = createShader(ctx, ctx.FRAGMENT_SHADER, fragmentSource)

    let program = createProgram(ctx, vertexShader, fragmentShader)

    if (program) {

        ctx.useProgram(program)

        //挂载到ctx

        ctx.program = program

        return true

    } else {

        return false

    }

}

效果图

猜你喜欢

转载自blog.csdn.net/sunboylife/article/details/130113520