glsl着色器学习(五)

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

javascript 复制代码
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缓冲区
javascript 复制代码
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. 绑定数据

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

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

创建并设置纹理
javascript 复制代码
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,表示一个包涵红、绿、蓝和透明通达的纹理。
    javascript 复制代码
    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)。多级渐远纹理可以提高纹理在不同距离下的渲染质量和性能。

  • 图片上的内容只是辅助理解
  • 到这里,我们就完成了所有的初始化代码。
相关推荐
Charles Ray25 分钟前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
我要吐泡泡了哦1 小时前
GAMES104:15 游戏引擎的玩法系统基础-学习笔记
笔记·学习·游戏引擎
骑鱼过海的猫1231 小时前
【tomcat】tomcat学习笔记
笔记·学习·tomcat
贾saisai3 小时前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发
北岛寒沫4 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
铁匠匠匠5 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
架构文摘JGWZ6 小时前
Java 23 的12 个新特性!!
java·开发语言·学习
小齿轮lsl7 小时前
PFC理论基础与Matlab仿真模型学习笔记(1)--PFC电路概述
笔记·学习·matlab
Aic山鱼7 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法
qq11561487077 小时前
Java学习第八天
学习