当前位置: 首页 > article >正文

WebGL系列教程五(使用索引绘制彩色立方体)

目录

  • 1 前言
  • 2 立方体
  • 3 开始绘制
    • 3.1 声明顶点和颜色
    • 3.2 使用索引绘制
    • 3.3 效果
    • 3.4 完整代码
  • 4 总结

1 前言

  上一讲我们讲了如何绘制彩色的三角形,这一讲我们来说如何绘制立方体。为什么几乎所有的WebGL教程总是从开始绘制三角形开始,因为三角形是最小的面,其他的一切图形都可以用三角形来拼接。好了,废话不多说,我们直接开整。

2 立方体

  一个立方体有8个顶点,如下图所示
在这里插入图片描述
  现在我们要把立方体的重心放到坐标轴原点去,回忆一下WebGL中的坐标系,X轴向右,Y轴向上,Z轴向外,这八个顶点的坐标和对应的颜色为:

顶点XYZ坐标颜色(RGB)
v01.0,1.0,1.0,1.0,1.0,1.0
v1-1.0,1.0,1.0,1.0,0.0,1.0
v2-1.0,-1.0,1.0,1.0,0.0,1.0
v31.0,-1.0,1.0,1.0,1.0,0.0
v41.0,-1.0,-1.0,1.0,0.0,1.0
v5-1.0,-1.0,-1.0,1.0,1.0,1.0
v6-1.0,1.0,-1.0,0.0,0.0,1.0
v71.0,1.0,-1.0,0.0,1.0,1.0

3 开始绘制

3.1 声明顶点和颜色

 <script id="vertex-shader" type="x-shader/x-vertex">
     //声明一个点,vec3表示3维向量
     attribute vec3 aPosition;
     attribute vec4 a_Color;
     varying vec4 v_Color;
     void main(){
     	 //点的位置,将vec3补齐为vec4
         gl_Position = vec4(aPosition,1.0);
         //传递颜色
         v_Color = a_Color;
     }
 </script>
 <script id="fragment-shader" type="x-shader/x-fragment">
     precision highp float;
     varying vec4 v_Color;
     void main(){
         //点的颜色,rgba形式
         gl_FragColor = v_Color;
     }
 </script>

3.2 使用索引绘制

  因为现在我们要使用顶点索引,因此就不能使用DrawArrays方法进行绘制了,改为使用DrawElements。

//顶点和颜色
let verticesColors = new Float32Array([
     1.0, 1.0, 1.0,   1.0,1.0,1.0,//v0 近平面 右上 颜色
    -1.0, 1.0, 1.0,   1.0,0.0,1.0,//v1 近平面 左上 颜色
    -1.0,-1.0, 1.0,   1.0,0.0,1.0,//v2 近平面 左下 颜色
     1.0,-1.0, 1.0,   1.0,1.0,0.0,//v3 近平面 右下 颜色
     1.0,-1.0,-1.0,   1.0,0.0,1.0,//v4 远平面 右下 颜色
    -1.0,-1.0,-1.0,   1.0,1.0,1.0,//v5 远平面 左下 颜色
    -1.0, 1.0,-1.0,   0.0,0.0,1.0,//v6 远平面 左上 颜色
     1.0, 1.0,-1.0,   0.0,1.0,1.0 //v7 远平面 右上 颜色
]);
//顶点索引
let indices = new Uint8Array([
    0,1,2,  0,2,3,//近平面
    4,5,6,  4,6,7,//远平面
    1,2,5,  1,5,6,//左平面
    0,3,4,  0,4,7,//右平面
    3,4,2,  3,5,2,//下平面
    0,7,6,  0,1,6 //上平面
]);
//使webgl视口和canvas画板一样大
gl.viewport(0, 0, canvas.width, canvas.height);
//开启深度检测
gl.enable(gl.DEPTH_TEST);
//顶点
let vertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,verticesColors,gl.STATIC_DRAW);
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
let a_Position = gl.getAttribLocation(program,'a_Position');
gl.vertexAttribPointer(a_Position,3,gl.FLOAT,false,FSIZE*6,0);
gl.enableVertexAttribArray(a_Position);
//颜色
var a_Color = gl.getAttribLocation(program, 'a_Color');
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
//绑定索引缓冲
let indexBuffer =  gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);

3.3 效果

  为了使效果明显一点,我将立方体绕Y轴旋转了60度。虽然看起来效果还不错。但仍然能看到一些问题,比如左下角和右上角为什么有一条明显的连线?那是因为每个面都是由两个三角形组成的。每个三角形都有各自的颜色,当然在拼接的地方就能看到明显的颜色分隔了。我们在这里先留个问题,怎么样使每个面只保留一种颜色呢?
在这里插入图片描述

3.4 完整代码

let canvas = document.getElementById("canvas");
let gl = canvas.getContext("webgl");
let vertexSource = document.getElementById("vertex-shader").innerText;
let fragmentSource = document.getElementById("fragment-shader").innerText;
let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertexShader,vertexSource);
gl.shaderSource(fragmentShader,fragmentSource);
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
console.log(gl.getShaderInfoLog(vertexShader));
console.log(gl.getShaderInfoLog(fragmentShader));
let program = gl.createProgram();
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
console.log(gl.getProgramInfoLog(program));
//开始正常的逻辑,绘制立方体
// Create a cube

//   v6----- v7
//   /|      /|
//  v1------v0|
//  | |     | |
//  | |v5---|-|v4
//  |/      |/
//  v2------v3

//顶点和颜色
let verticesColors = new Float32Array([
     1.0, 1.0, 1.0,   1.0,1.0,1.0,//v0 近平面 右上 颜色
    -1.0, 1.0, 1.0,   1.0,0.0,1.0,//v1 近平面 左上 颜色
    -1.0,-1.0, 1.0,   1.0,0.0,1.0,//v2 近平面 左下 颜色
     1.0,-1.0, 1.0,   1.0,1.0,0.0,//v3 近平面 右下 颜色
     1.0,-1.0,-1.0,   1.0,0.0,1.0,//v4 远平面 右下 颜色
    -1.0,-1.0,-1.0,   1.0,1.0,1.0,//v5 远平面 左下 颜色
    -1.0, 1.0,-1.0,   0.0,0.0,1.0,//v6 远平面 左上 颜色
     1.0, 1.0,-1.0,   0.0,1.0,1.0 //v7 远平面 右上 颜色
]);
//顶点索引
let indices = new Uint8Array([
    0,1,2,  0,2,3,//近平面
    4,5,6,  4,6,7,//远平面
    1,2,5,  1,5,6,//左平面
    0,3,4,  0,4,7,//右平面
    3,4,2,  3,5,2,//下平面
    0,7,6,  0,1,6 //上平面
]);
//使webgl视口和canvas画板一样大
gl.viewport(0, 0, canvas.width, canvas.height);
//开启深度检测
gl.enable(gl.DEPTH_TEST);
//顶点
let vertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,verticesColors,gl.STATIC_DRAW);
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
let a_Position = gl.getAttribLocation(program,'a_Position');
gl.vertexAttribPointer(a_Position,3,gl.FLOAT,false,FSIZE*6,0);
gl.enableVertexAttribArray(a_Position);
//颜色
var a_Color = gl.getAttribLocation(program, 'a_Color');
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
//绑定索引缓冲
let indexBuffer =  gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);
//绘制三角形,36个点,立方体是6个面,每个面2个三角形,索引数组元素类型gl.UNSIGNED_BYTE,从第0个索引开始绘制
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);

4 总结

  本节我们通过梳理立方体的顶点坐标和对应的颜色关系,使用索引绘制的方式,绘制除了一个彩色的立方体,关于立方体是怎么旋转的,我们会在后面的博文中进行讲解。目前我们还遗留了一个思考问题,那就是如何使立方体的每个面都保持一个颜色,希望读者认真思考,我们留在下节进行解答。


http://www.kler.cn/a/301588.html

相关文章:

  • 计算机编程中的设计模式及其在简化复杂系统设计中的应用
  • 螺旋矩阵II(leetcode 59)
  • 使用Axios函数库进行网络请求的使用指南
  • 基于gradio+networkx库对图结构进行可视化展示
  • 推荐一个基于协程的C++(lua)游戏服务器
  • 智能化运维与AI/ML辅助决策:实现自动化与预测优化
  • C#中的装箱和拆箱是什么
  • 为拖延症量身定制的AI工具,让Kimi做我的《每日信息整理助手》
  • AI应用开发平台Dify本地Ubuntu环境部署结合内网穿透远程管理大模型
  • Linux环境基础开发工具使用(1)
  • 光器件 -- EDFA与Raman放大器
  • 什么是内存溢出,golang是如何解决内存溢出的
  • 深度学习速通系列:动态规划算法
  • [翻译] Vue 3.5 发布
  • 如何在 Linux 系统中禁用用户登录 ?
  • 杰发科技Bootloader(3)—— 基于7801的APP切到Boot
  • C++ vectorOJ练习题
  • 恒创科技:最小化服务器存储容量的技巧
  • Android JNI项目build时报告missing and no known rule to make it的原因
  • [001-03-007].第07节:Redis中的事务
  • ios免签H5
  • Docker Swarm 管理
  • 基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(六):Blender烘培和UE5导入
  • 深入探讨MySQL联表查询可能导致的问题及应对策略
  • Linux运维_Bash脚本_源码编译Moby(Docker-CE)-20240803
  • 嵌入式鸿蒙系统开发语言与开发方法分析