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

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补齐为vec4gl_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 总结

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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 云平台虚机卡顿问题分析
  • 恐怖类游戏智能体————孤岛惊魂
  • 禁忌搜索算法(TS算法)求解实例---旅行商问题 (TSP)
  • 图神经网络模型扩展5--3
  • java编程行业特点
  • OpenAI API key not working in my React App
  • 无人机 PX4 飞控 | EKF2简介与使用方法
  • pyinstaller打包python程序
  • 【LeetCode 算法笔记】155. 最小栈
  • JVM JMM 专题篇 ( 12000 字详解 )
  • 第159天:安全开发-Python-协议库爆破FTPSSHRedisSMTPMYSQL等
  • Redis 篇-初步了解 Redis 持久化、Redis 主从集群、Redis 哨兵集群、Redis 分片集群
  • k8s中的认证授权
  • kubeadm方式安装k8s+基础命令的使用
  • CentOS7更新YUM源
  • ES6核心特性
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • java取消线程实例
  • Linux CTF 逆向入门
  • 分享一份非常强势的Android面试题
  • 汉诺塔算法
  • 基于axios的vue插件,让http请求更简单
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 力扣(LeetCode)22
  • 盘点那些不知名却常用的 Git 操作
  • - 转 Ext2.0 form使用实例
  • ​ssh-keyscan命令--Linux命令应用大词典729个命令解读
  • ​一些不规范的GTID使用场景
  • ###C语言程序设计-----C语言学习(6)#
  • #APPINVENTOR学习记录
  • #define、const、typedef的差别
  • #ifdef 的技巧用法
  • #Js篇:单线程模式同步任务异步任务任务队列事件循环setTimeout() setInterval()
  • #pragam once 和 #ifndef 预编译头
  • (1)Nginx简介和安装教程
  • (1)svelte 教程:hello world
  • (4)Elastix图像配准:3D图像
  • (C++20) consteval立即函数
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (三)centos7案例实战—vmware虚拟机硬盘挂载与卸载
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (四) 虚拟摄像头vivi体验
  • (一)VirtualBox安装增强功能
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • *** 2003
  • .gitignore文件—git忽略文件
  • .htaccess 强制https 单独排除某个目录
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net mvc部分视图
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET开源快速、强大、免费的电子表格组件
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • .Net中wcf服务生成及调用
  • .sh 的运行