glsl着色器学习(五)

接下来是创建buffer,设置顶点位置,法线,顶点索引等。

const cubeVertexPositions = new Float32Array([
    1, 1, -1,
    1, 1, 1, 
    1, -1, 1, 
    1, -1, -1,
    -1, 1, 1, 
    -1, 1, -1,
    -1, -1, -1,
    -1, -1, 1,
     -1, 1, 1,
     1, 1, 1,
     1, 1, -1,
     -1, 1, -1,
     -1, -1, -1,
     1, -1, -1,
     1, -1, 1,
     -1, -1, 1,
     1, 1, 1,
     -1, 1, 1,
     -1, -1, 1,
     1, -1, 1,
     -1, 1, -1,
     1, 1, -1,
     1, -1, -1,
     -1, -1, -1,
]);
const cubeVertexNormals = new Float32Array([
    1, 0, 0,
    1, 0, 0,
    1, 0, 0,
    1, 0, 0,
    -1, 0, 0,
    -1, 0, 0,
    -1, 0, 0,
    -1, 0, 0,
    0, 1, 0,
    0, 1, 0,
    0, 1, 0,
    0, 1, 0,
    0, -1, 0,
    0, -1, 0,
    0, -1, 0,
    0, -1, 0,
    0, 0, 1,
    0, 0, 1,
    0, 0, 1,
    0, 0, 1,
    0, 0, -1,
    0, 0, -1,
    0, 0, -1,
    0, 0, -1,
]);
const cubeVertexTexcoords = new Float32Array([
     1, 0,
     0, 0,
     0, 1,
     1, 1,
     1, 0,
     0, 0,
     0, 1,
     1, 1,
     1, 0,
     0, 0,
     0, 1,
     1, 1,
     1, 0,
     0, 0,
     0, 1,
     1, 1,
     1, 0,
     0, 0,
     0, 1,
     1, 1,
     1, 0,
     0, 0,
     0, 1,
     1, 1,
]);
const cubeVertexIndices = new Uint16Array([
     0, 1, 2,
     0, 2, 3,
     4, 5, 6,
     4, 6, 7,
     8, 9, 10,
     8, 10, 11,
     12, 13, 14,
     12, 14, 15,
     16, 17, 18, 
     16, 18, 19,
     20, 21, 22,
     20, 22, 23,
],);
 cubeVertexPositions
  1. const cubeVertexPositions = new Float32Array([])

    1. 创建一个 Float32Array 类型的数组,用于存储立方体的八个顶点在三维空间中的位置坐标。每个顶点由三个浮点数表示,分别对应 X、Y、Z 轴的坐标。这个数组中依次列出了立方体八个顶点的坐标,按照一定的顺序排列,以便在后续的渲染过程中能够正确地构建立方体的几何形状。例如1,1,-1 表示一个顶点的坐标为X轴为1,Y轴为1,Z轴为-1。通过这种方式,定义立方体的位置。

    2. 每个顶点坐标包涵X,Y,Z三个分量,每个面有4个顶点,立方体有6个面,因此需要3x4x6 = 72个分量

    3. 此图用于理解

cubeVertexNormals
  1. 创建一个 Float32Array 类型的数组,存储了立方体每个顶点的法线向量。
  2. 法线向量是垂直于物体表面的向量,对于光照计算非常重要。在这个数组中,每个顶点都有一个对应的法线向量,所以是有24个组成,每个分别由三个浮点数表示,分别对应 X、Y、Z 轴的方向分量。例如,1, 0, 0表示一个法线向量在 X 轴方向上为 1,Y 轴和 Z 轴方向为 0,即指向 X 轴正方向。

  3. 法线分量也是一样,每个顶点三个分量,一个面有4个顶点,总共6个面,也是3x4x6=72个分量

cubeVertexTexcoords
  1. 这是一个 Float32Array 类型的数组,用于存储立方体每个顶点的纹理坐标纹理坐标。用于确定如何从纹理图像中采样颜色值,并将其应用到对应的顶点上。每个顶点由两个浮点数表示,通常在范围 [0, 1] 之间,分别对应纹理图像的 U(水平方向)和 V(垂直方向)坐标。(我们通常理解的UV坐标)例如1, 0表示纹理坐标在纹理图像的右上角。

  2. 立方体有6个面,每个面由4个顶点,每个顶点需要2个纹理坐标分量,因此需要6 x 4 x 2 = 48个纹理坐标数据。

cubeVertexIndices
  1. 创建一个 Uint16Array 类型的数组,存储了绘制立方体所需的顶点索引。
  2. 由于立方体有八个顶点,但在绘制时通常使用三角形来构建表面,每个三角形需要三个顶点索引。这个数组中依次列出了构成立方体十二个面(每个面由两个三角形组成)的顶点索引。例如,0, 1, 2表示第一个三角形的三个顶点索引分别为 0、1、2,对应 cubeVertexPositions 数组中的三个顶点。通过这种方式,可以使用较少的数据量来定义复杂的几何形状,避免重复存储顶点数据。

  3. 立方体每个面由2个三角形绘制而成,每个三角形需要3个顶点索引,因此每个面需要6个索引,则总共需要2x3x6=36个分量

创建buffer缓冲区
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeVertexPositions, gl.STATIC_DRAW);

const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeVertexNormals, gl.STATIC_DRAW);

const texcoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeVertexTexcoords, gl.STATIC_DRAW);

const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndices, gl.STATIC_DRAW);
  1.  const positionBuffer = gl.createBuffer();
    1. 创建一个新的缓冲区对象,用于存储立方体顶点位置数据
    2. 创建的buffer缓冲区对象
  2. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    1. 将创建的缓冲区绑定到ARRAY_BUFFER上。后续对bufferData等方法的调用将操作这个特定的缓冲区
    2. 绑定到ARRAY_BUFFER上。
  3. gl.bufferData(gl.ARRAY_BUFFER, cubeVertexPositions, gl.STATIC_DRAW);
    1. 将存储在cubeVertexPositions数组中的立方体顶点位置数据上传到当前绑定的缓冲区。
    2. gl.STATIC_DRAW参数表示这些数据不会经常改变,适合一次性上传并多次绘制;
    3. 绑定数据

其他缓冲区也是一个道理,这里不做赘述

通过缓冲区,可以减少数据传输的开销,提高图形渲染的性能

创建并设置纹理
onst checkerTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, checkerTexture);
gl.texImage2D(
    gl.TEXTURE_2D,
    0,                // mip level
    gl.LUMINANCE,     // internal format
    4,                // width
    4,                // height
    0,                // border
    gl.LUMINANCE,     // format
    gl.UNSIGNED_BYTE, // type
    new Uint8Array([  // data
      192, 128, 192, 128,
      128, 192, 128, 192,
      192, 128, 192, 128,
      128, 192, 128, 192,
    ]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);

const decalTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, decalTexture);
gl.texImage2D(
    gl.TEXTURE_2D,
    0,                // mip level
    gl.RGBA,          // internal format
    gl.RGBA,          // format
    gl.UNSIGNED_BYTE, // type
    makeTextCanvas('F', 32, 32, 'red'));
gl.generateMipmap(gl.TEXTURE_2D); 
  1. const checkerTexture = gl.createTexture();
    1. 使用Webgl的createTexture方法创建一个纹理对象,用于存储纹理;
  2. gl.bindTexture(gl.TEXTURE_2D, checkerTexture);
    1. 将创建的纹理对象绑定到TEXTURE_2D目标上,以便后续对该纹理进行操作;
  3. gl.texImage2D(gl.TEXTURE_2D,0, gl.LUMINANCE,4, 4,0, gl.LUMINANCE, gl.UNSIGNED_BYTE,new Uint8Array([...]));
    1. 定义纹理的图形数据。创建一个4x4的灰度纹理,数据由一个Unit8Array提供,其中包涵了不同灰度值的像素数据,用于形成棋盘格图案;
    2. gl.LUMINANCE表示内部格式和外部格式都是灰度
    3. gl.UNSIGNED_BYTE表示数据类型为无符号字节
  4. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    1. 设置纹理的缩小过滤器为最近邻过滤。当纹理缩小显示时,会选择最接近的像素,不进行差值。
  5. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    1. 设置纹理的方法过滤器也为最近邻过滤,当纹理被放大显示时,同样选择最接近的像素。
  6. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    1. 设置纹理在水平方向(S轴)的环绕模式为CLAMP_TO_EDGE,当超出纹理范围的坐标会被截断到纹理边缘颜色;
  7. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    1. 设置纹理在垂直方向(T轴)的环绕模式也为CLAMP_TO_EDGE
创建并设置贴花纹理
  1. const decalTexture = gl.createTexture();
    1. 创建另一个纹理对象,用于存储贴花纹理
  2. gl.bindTexture(gl.TEXTURE_2D,decalTexture);
    1. 绑定贴花纹理对象
  3. gl.texImage2D(
        gl.TEXTURE_2D,
        0,               
        gl.RGBA,        
        gl.RGBA,         
        gl.UNSIGNED_BYTE,
        makeTextCanvas('F', 32, 32, 'red'));
    1. 定义贴花纹理的图像数据。自定义创建了一个包涵字符F的红色32x32的画布,并将其作为纹理数据。内部格式和外部格式以及数据类型分别为gl.RGBA和gl.UNSIGNED_BYTE,表示一个包涵红、绿、蓝和透明通达的纹理。
    2. const makeTextCanvas = (text, width, height, color) => {
        const ctx = document.createElement('canvas').getContext('2d')
        ctx.canvas.width = width
        ctx.canvas.height = height
        ctx.font = `bold ${height * 5 / 6 | 0}px sans-serif`
        ctx.textAlign = 'center'
        ctx.textBaseline = 'middle'
        ctx.fillStyle = color
        ctx.fillText(text, width / 2, height / 2)
        return ctx.canvas
      };
  4. gl.generateMipmap(gl.TEXTURE_2D);
    1. 生成纹理的多级渐远纹理(mipmap)。多级渐远纹理可以提高纹理在不同距离下的渲染质量和性能。

  •  图片上的内容只是辅助理解
  •  到这里,我们就完成了所有的初始化代码。
  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

superTiger_y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值