JavaScript技术

webgl 纹理

2021-07-13  本文已影响0人  Viewwei

纹理的映射

纹理映射就是讲一张图形映射到一个几何矩形的表面上去.这样在矩形表面就能看到这样图片,这张图形又可以称为纹理图像或者纹理.纹理映射的作用就是根据纹理图像,为之前光栅化的每个片元涂上合适的颜色,组成纹理图像的像素又称为纹素.每个纹素有可以都是使用 RGB 或者 RGBA 格式编码

纹理映射的步骤

纹理坐标

纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色,webgl系统上的纹理坐标是二维的.webgl 中使用 s 和 t 命名纹理坐标
纹理坐标图像的四个角的坐标为左下角(0.0),右下角(1.0,0.0)右上角(1.0,1.0)和左上角(0.0,1.0).纹理坐标很通用,因为坐标值和图像自身的尺寸无关.


纹理坐标和 webgl 坐标系

示例程序把纹理图片添加到几个图形上

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body onload="main()">
        <canvas id="webgl" width="400" height="400"></canvas>
    </body>
    <script id="vertextShader" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        attribute vec2 a_TexCoord;
        varying vec2 v_texCoord;
        void main () {
            gl_Position = a_Position;
            v_texCoord = a_TexCoord;
        }
    </script>
    <script id="fragmentShader" type="x-shader/x-fragment">
        //  全局设置浮点数的精确度,其他类型都有默认的精度类型,浮点数需要单独的设置
        precision mediump float;
        uniform sampler2D u_Sampler;
        varying vec2 v_texCoord;
        void main () {
            // texture2D(u_Sampler,v_texCoord);  得到的是一个 vec4的向量,如果有多个纹理,也可以进行纹理的合并
            gl_FragColor = texture2D(u_Sampler,v_texCoord);
        }
    </script>
    <script src="./jsm/util.js"></script>
    <!-- <script src="tool/cuon-matrix.js"></script> -->
    <script>
        function main () {
            // function main() {
                const canvas = document.getElementById('webgl')
                const gl = canvas.getContext('webgl')
                const vertextShader = document.getElementById('vertextShader').innerText
                const fragmentShader = document.getElementById('fragmentShader').innerText
                if (!initShaders(gl, vertextShader, fragmentShader)) return
                if (!gl) return
                const a_Position = gl.getAttribLocation(gl.program, 'a_Position')
                const a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord')
                const u_Sampler = gl.getUniformLocation(gl.program,'u_Sampler')
                let n = initVertexBuffers(gl,a_Position,a_TexCoord) 
                initTextures(gl,n,u_Sampler)    
                // if (a_Position < 0) return
                gl.clearColor(0.0, 0.0, 0.0, 1.0)
                gl.clear(gl.COLOR_BUFFER_BIT) 
            // }
        }
        function initVertexBuffers (gl,a_Position,a_TexCoord) {
            var verticesTexCoords = 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
            ])
            var n = 4
            var vertexTexCoordBuffer = gl.createBuffer()
            gl.bindBuffer(gl.ARRAY_BUFFER,vertexTexCoordBuffer)
            gl.bufferData(gl.ARRAY_BUFFER,verticesTexCoords,gl.STATIC_DRAW)
            var fsize = verticesTexCoords.BYTES_PER_ELEMENT
            gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,fsize*4,0)
            gl.enableVertexAttribArray(a_Position)
            gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,fsize*4,fsize*2)
            gl.enableVertexAttribArray(a_TexCoord)
            return n
        }
        function initTextures(gl,n,u_Sampler) {
            var texture = gl.createTexture() //创建纹理对象
            var image = new Image()
            image.onload = function () {
                // 图片加载完成之后开始加载纹理
                loadTexture(gl,n,texture,u_Sampler,image)
            }
            image.src = './img/erha.jpg'
        }
        function  loadTexture(gl,n,texture,u_Sampler,image) {
            // 因为 st 坐标和 webgl  y坐标相反, 需要进行 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_MIN_FILTER,gl.LINEAR)
            gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR)         
            gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image)
            gl.uniform1i(u_Sampler,0)
            gl.drawArrays(gl.TRIANGLE_STRIP,0,n)
        } 
    </script>
</html>

添加纹理步骤

设置纹理坐标

将纹理坐标传入顶点着色器,与将其他顶点数据传入顶点着色器的方式相同.我们可以将纹理坐标和顶点坐标同一个缓冲器

var verticesTexCoords = 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
            ])
配置和加载纹理步骤
createTexture()

纹理对象是用来存储纹理图像的工具.创建一个纹理单元,使用 deleteTexture 可以删除指定的纹理对象

gl.activeTexture(a)
// a 代表纹理单元
gl.bindTexture(gl.TTEXTURE_2D,a)
//a 代表纹理对象
gl.pixelStorei(pname,param)
pname: 可选值为 gl.UNPACK_FLIP_Y_WEBGL 对图像记性 Y 轴的翻转
                            gl.UNPACK_PREMULTIPLY_ALPHA:将图像 RGB 颜色的每个分量x A
param: 指定非 0(true) 或 0(false).必须是整数
参数名称 参数值 参数说明
target gl.TEXTURE_2D或者 gl.TEXTURE_CUBE_MAP 绑定类型
pname 纹理参数 见表 2
param 纹理参数 值 见表 3

pname 可以指定 4 个纹理参数

纹理参数以及默认值表 2 如下
参数名称 描述 默认值
gl.TEXTURE_MAG_FILTER 纹理放大 gl.LINEAR
gl.TEXTURE_MIN_FILTER 纹理缩小,分子料理 gl.NEAREST_MIP_LINEAR
gl.TEXTURE_WRAP_S 纹理水平填充 gl.REPEAT
gl.TEXTURE_WRAP_T 纹理垂直填充 gl.REPEAT
纹理参数 gl.TEXTURE_MAG_FILTER gl.TEXTURE_MIN_FILTER 非金字塔纹理类常量
描述
gl.NEAREST 使用原纹理上距离映射后像素
gl.LINEAR 使用距离像素点中心最近的四个像素的颜色值的加权平均
gl.TEXTURE_WRAP_S 和 gl.TEXTURE_WRAP_T
描述
gl.REPEAT 平铺式的重复纹理
gl.MIRRORED_REPEAT 镜像对称的重复纹理
gl.CLAMP_TO_EDGE 使用纹理图像边缘值
纹理图像分配给纹理对象

gl.texImage2D(target,level, internalformat,format,type,image)

参数值 参数说明
target gl.TEXTURE_2D或者 gl.TEXTURE_CUBE_MAP
level 传入 0
internalformat 图像的内部格式
format 纹理数据的格式
type 纹理数据的类型
image 包含纹理图像的image对象

将纹理单元传递给片元着色器

一旦将纹理图像传入给 webgl 系统,就必须将其他片元着色器传入片元着色器并映射到图形的表面上去

    <script id="fragmentShader" type="x-shader/x-fragment">
        //  全局设置浮点数的精确度,其他类型都有默认的精度类型,浮点数需要单独的设置
        precision mediump float;
        uniform sampler2D u_Sampler;
        varying vec2 v_texCoord;
        void main () {
            // texture2D(u_Sampler,v_texCoord);  得到的是一个 vec4的向量,如果有多个纹理,也可以进行纹理的合并
            gl_FragColor = texture2D(u_Sampler,v_texCoord);
        }
    </script>

专用于纹理的数据类型

类型 描述
sampler2D 绑定gl. TEXTURE_2D 上的纹理数据类型
samperCube 绑定gl. TEXTURE_CUBE_MAP上的纹理数据类型

必须通过指定纹理单元编号,将纹理对象传递给u_ Sampler

gl.unifirmli(a,b)
//a表示片元着色器 sampler2D对象,b 表示纹理单元

从顶点着色器想片元着色器传输纹理坐标

顶点着色器向片元着色器传递数据通过 varying 进行传递

    <script id="vertextShader" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        attribute vec2 a_TexCoord;
        varying vec2 v_texCoord;
        void main () {
            gl_Position = a_Position;
            v_texCoord = a_TexCoord;
        }
    </script>
<script id="fragmentShader" type="x-shader/x-fragment">
        //  全局设置浮点数的精确度,其他类型都有默认的精度类型,浮点数需要单独的设置
        precision mediump float;
        uniform sampler2D u_Sampler;
                //传递顶点着色器
        varying vec2 v_texCoord;
        void main () {
            // texture2D(u_Sampler,v_texCoord);  得到的是一个 vec4的向量,如果有多个纹理,也可以进行纹理的合并
            gl_FragColor = texture2D(u_Sampler,v_texCoord);
        }
    </script>
在片元着色器中获取纹理像素颜色
    <script id="fragmentShader" type="x-shader/x-fragment">
        //  全局设置浮点数的精确度,其他类型都有默认的精度类型,浮点数需要单独的设置
        precision mediump float;
        uniform sampler2D u_Sampler;
        varying vec2 v_texCoord;
        void main () {
            // texture2D(u_Sampler,v_texCoord);  得到的是一个 vec4的向量,如果有多个纹理,也可以进行纹理的合并
            gl_FragColor = texture2D(u_Sampler,v_texCoord);
        }
    </script>
vec4 texture2D(sampler2D sampler,vec2 coord)
sampler:指定纹理单元
coord:指定纹理坐标
上一篇下一篇

猜你喜欢

热点阅读