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)。多级渐远纹理可以提高纹理在不同距离下的渲染质量和性能。

  • 图片上的内容只是辅助理解
  • 到这里,我们就完成了所有的初始化代码。
相关推荐
虾球xz32 分钟前
游戏引擎学习第276天:调整身体动画
c++·学习·游戏引擎
虾球xz33 分钟前
游戏引擎学习第275天:将旋转和剪切传递给渲染器
c++·学习·游戏引擎
qq_386322692 小时前
华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)
前端·网络·学习
J先生x2 小时前
【IP101】图像处理进阶:从直方图均衡化到伽马变换,全面掌握图像增强技术
图像处理·人工智能·学习·算法·计算机视觉
虾球xz6 小时前
游戏引擎学习第268天:合并调试链表与分组
c++·学习·链表·游戏引擎
Y3174296 小时前
Python Day23 学习
python·学习
song_ly0017 小时前
深入理解软件测试覆盖率:从概念到实践
笔记·学习·测试
DIY机器人工房7 小时前
[6-2] 定时器定时中断&定时器外部时钟 江协科技学习笔记(41个知识点)
笔记·stm32·单片机·学习·江协科技
海尔辛8 小时前
学习黑客5 分钟小白弄懂Windows Desktop GUI
windows·学习
烟雨迷10 小时前
Linux环境基础开发工具的使用(yum、vim、gcc、g++、gdb、make/Makefile)
linux·服务器·学习·编辑器·vim