使用 WebGL 创建 3D 对象
WebGL Demo
https://mdn.github.io/dom-examples/webgl-examples/tutorial/sample5/index.html
现在让我们给之前的正方形添加五个面从而可以创建一个三维的立方体。最简单的方式就是通过调用方法 gl.drawElements() 使用顶点数组列表来替换之前的通过方法gl.drawArrays() 直接使用顶点数组。而顶点数组列表里保存着将会被引用到一个个独立的顶点。
其实现在会存在这样一个问题:每个面需要 4 个顶点,而每个顶点会被 3 个面共享。我们会创建一个包含 24 个顶点的数组列表,通过使用数组下标来索引顶点,然后把这些用于索引的下标传递给渲染程序而不是直接把整个顶点数据传递过去,这样来减少数据传递。那么也许你就会问:那么使用 8 个顶点就好了,为什么要使用 24 个顶点呢?这是因为每个顶点虽然被 3 个面共享但是它在每个面上需要使用不同的颜色信息。24 个顶点中的每一个都会有独立的颜色信息,这就会造成每个顶点位置都会有 3 份副本。
定义立方体顶点位置
首先,更新 initBuffers() 函数中代码来创建立方体的顶点位置缓存区。现在的代码看起来和渲染正方形时的代码很相似,只是比之前的代码更长因为现在有了 24 个顶点(每个面使用 4 个顶点):
备注: 在“init-buffers.js”文件 initPositionBuffer() 函数中,用下面代码替换 positions:
JSCopy to Clipboard
const positions = [// Front face-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,// Back face-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,// Top face-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,// Bottom face-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,// Right face1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,// Left face-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
];
由于我们给顶点添加了 Z 分量,因此我们需要将 vertexPosition 属性的 numComponents 更新为 3。
备注: 在“draw-scene.js”文件 setPositionAttribute() 函数中,将 numComponents 从 2 改为 3:
JSCopy to Clipboard
const numComponents = 3;
定义顶点颜色
然后我们还要为每个顶点定义颜色。下面的代码首先为每个面定义颜色,然后用一个循环语句为每个顶点定义颜色信息。
备注: 在“init-buffers.js”文件 initColorBuffer() 函数中,用下面代码替换 colors 定义:
JSCopy to Clipboard
const faceColors = [[1.0, 1.0, 1.0, 1.0], // Front face: white[1.0, 0.0, 0.0, 1.0], // Back face: red[0.0, 1.0, 0.0, 1.0], // Top face: green[0.0, 0.0, 1.0, 1.0], // Bottom face: blue[1.0, 1.0, 0.0, 1.0], // Right face: yellow[1.0, 0.0, 1.0, 1.0], // Left face: purple
];// Convert the array of colors into a table for all the vertices.var colors = [];for (var j = 0; j < faceColors.length; ++j) {const c = faceColors[j];// Repeat each color four times for the four vertices of the facecolors = colors.concat(c, c, c, c);
}
定义元素(三角形)数组
既然已经创建好了顶点数组,接下来就要创建元素(三角形)数组了。
备注: 在“init-buffer.js”文件中添加下面的函数:
JSCopy to Clipboard
function initIndexBuffer(gl) {const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);// This array defines each face as two triangles, using the// indices into the vertex array to specify each triangle's// position.const indices = [0,1,2,0,2,3, // front4,5,6,4,6,7, // back8,9,10,8,10,11, // top12,13,14,12,14,15, // bottom16,17,18,16,18,19, // right20,21,22,20,22,23, // left];// Now send the element array to GLgl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(indices),gl.STATIC_DRAW,);return indexBuffer;
}
indices 数组声明每一个面都使用两个三角形来渲染。通过立方体顶点数组的索引指定每个三角形的顶点。那么这个立方体就是由 12 个三角形组成的了。
备注: 在“init-buffers.js”文件 initBuffers()函数中,添加下面的代码替换之前的 return 代码片段:
JSCopy to Clipboard
const indexBuffer = initIndexBuffer(gl);return {position: positionBuffer,color: colorBuffer,indices: indexBuffer,
};
渲染立方体
接下来就需要在 drawScene() 函数里添加代码使用立方体顶点索引数据来渲染这个立方体了。代码里添加了对 gl.bindBuffer() 和 gl.drawElements()的调用:
备注: 在 drawScene() 函数中,gl.useProgram 代码前添加如下代码:
JSCopy to Clipboard
// Tell WebGL which indices to use to index the vertices
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
备注: 在“draw-scene.js”文件 drawScene() 函数中,用下面这段代码替换之前 gl.drawArrays():
JSCopy to Clipboard
{const vertexCount = 36;const type = gl.UNSIGNED_SHORT;const offset = 0;gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
}
立方体的每个面都由 2 个三角形组成,那就是每个面需要 6 个顶点,或者说总共 36 个顶点,尽管有许多重复的。然而,因为索引数组的每个元素都是简单的整数类型,所以每一帧动画需要传递给渲染程序的数据也不是很多。
最后,让我们把变量 squareRotation 替换成 cubeRotation 并添加 X 轴的第二个旋转。
备注: 在“webgl-demo.js”文件的头部,把变量 squareRotation 替换成 cubeRotation:
JSCopy to Clipboard
let cubeRotation = 0.0;
备注: 在 drawScene() 函数声明中,将变量 squareRotation 替换成 cubeRotation:
JSCopy to Clipboard
function drawScene(gl, programInfo, buffers, cubeRotation) {
备注: 在 drawScene() 函数中,用下面代码替换之前的 mat4.rotate 函数:
JSCopy to Clipboard
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation, // amount to rotate in radians[0, 0, 1],
); // axis to rotate around (Z)
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.7, // amount to rotate in radians[0, 1, 0],
); // axis to rotate around (Y)
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.3, // amount to rotate in radians[1, 0, 0],
); // axis to rotate around (X)
备注: 在 main() 函数中,替换 drawScene() 函数调用参数中的 squareRotation 为 cubeRotation:
JSCopy to Clipboard
drawScene(gl, programInfo, buffers, cubeRotation);
cubeRotation += deltaTime;
到现在为止,我们已经创建了一个颜色生动的并且会在场景中移动和旋转的立方体,这一定很酷吧。
相关文章:
使用 WebGL 创建 3D 对象
WebGL Demohttps://mdn.github.io/dom-examples/webgl-examples/tutorial/sample5/index.html 现在让我们给之前的正方形添加五个面从而可以创建一个三维的立方体。最简单的方式就是通过调用方法 gl.drawElements() 使用顶点数组列表来替换之前的通过方法gl.drawArrays() 直接…...
百度地图3d区域掩膜,最常见通用的大屏地图展现形式
需求及效果 原本项目使用的是百度地图3.0,也就是2d版本的那个地图,客户不满意觉得不够好看,让把地图改成3d的,但是我们因为另外的系统用的都是百度地图,为了保持统一只能用百度地图做 经过3天的努力,最后我终于把这个…...
小区物业管理收费系统源码小程序
便捷、透明、智能化的新体验 一款基于FastAdminUniApp开发的一款物业收费管理小程序。包含房产管理、收费标准、家属管理、抄表管理、在线缴费、业主公告、统计报表、业主投票、可视化大屏等功能。为物业量身打造的小区收费管理系统,贴合物业工作场景,轻…...
C++实现一个简单的Qt信号槽机制
昨天写这个文章《深入探讨C的高级反射机制(2):写个能用的反射库》的时候就在想,是不是也能在这套反射逻辑的基础上,实现一个类似Qt的信号槽机制? Qt信号槽机制简介 所谓的Qt的信号槽(Signals …...
微信小程序常用的传值
1.通过 URL 传参 在页面跳转时,可以在 URL 中携带参数进行传递,然后在目标页面的 onLoad 生命周期中获取参数。 // 在页面 A 中跳转到页面 B 并传递参数 wx.navigateTo({url: /pages/detail/index?id123 });// 在页面 B 的 onLoad 生命周期中获取参数…...
SQL面试真题解答 数据统计分析,求“同比、环比”等(SQL窗口函数使用)
SQL面试真题解答 数据统计分析,求“同比、环比”等(SQL窗口函数使用) 环比、环比增长率、同比、同比增长率,根据百度百科上的 说明: 环比增长率 环比增长率,一般是指和上期相比较的增长率。 环比增长率&a…...
【递归、搜索与回溯】floodfill算法二
floodfill算法二 1.被围绕的区域2.太平洋大西洋水流问题3.扫雷游戏4.衣橱整理 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.被围绕的区域…...
Dataease安装,配置Jenkins自动部署
Dataease安装,配置Jenkins自动部署 一.安装Dataease 安装前准备:1.Ubuntu20.04 LTS国内源安装指定版本Docker 2.docker-compose安装 下载离线安装的安装包,下载地址:https://community.fit2cloud.com/#/download/dataease/v1-…...
关于IDEA启动报错 【JAVA_HOME does not point to a valid JM installation】
希望文章能给到你启发和灵感~ 感谢支持和关注~ 阅读指南 一、基础环境说明1.1 硬件环境1.2 软件环境 二、起因 一、基础环境说明 考虑环境因素不同,大家适当的对比自己的软硬件环境情况分析~ 1.1 硬件环境 MacOS Monterey 版本 1…...
设置小蓝熊的CPU亲和性、CPU优先级再设置法环的CPU亲和性
# 适用于Windows系统 # 时间 : 2024-06-28 # 作者 : 三巧(https://blog.csdn.net/qq_39124701) # 文件名 : 设置小蓝熊的CPU亲和性、CPU优先级再设置法环的CPU亲和性.ps1 # 使用方法: 打开记事本,将所有代码复制到记事本中,保存文件时候修改文件后…...
Oracle中的序列(Sequence)是一种数据库对象
Oracle中的序列(Sequence)是一种数据库对象,用于生成数字序列,通常用于为主键列生成唯一、连续的数值。以下是一些使用序列的案例: 1. **为主键生成唯一值**: 在Oracle中,序列最常用的场景是…...
热点观察 | 《姜饼人王国》新作来袭、《Monopoly GO!》荣登5月全球畅销榜榜首
本周出海热点: 1. 中国品牌借欧洲杯打响知名度 2. 米哈游玩家切割二次元 3. 6月27日,Steam游戏《六月衷曲》上线TapTap 4. 《Monopoly GO!》荣登5月全球畅销榜榜首 5. 《地下城与勇士》拿下本周亚洲T1市场畅销榜冠军 6. 《姜饼人王国》新作强势登顶…...
智能网络构建:探索大模型在网络领域的应用
网络领域以其高度复杂性和快速迭代为特点,完成从网络设计、配置、诊断到安全的网络任务需要广泛的专业知识。这些任务的固有复杂性,加上网络技术和协议不断变化的格局,为传统基于机器学习的方法带来了显著的障碍。这些方法在泛化和自动化网络…...
C++编程逻辑讲解step by step:定义一个Person类,它的每个对象表示一个人。
题目 定义一个Person类,它的每个对象表示一个人。数据成员必须包含姓名、出生年份、死亡年份,一个构造函数,一析构函数,读取数据的成员函数,一个print()成员函数显示所有数据。 #include <iostream> using namespace std;…...
DBdoctor产品介绍
基本信息 DBdoctor是一款企业级数据库监控、巡检、性能诊断、SQL审核与优化平台,致力于解决一切数据库性能问题。采用eBPF技术可对数据库做细粒度的扫描,帮助您一分钟内找到数据库性能问题,实现性能诊断百倍提效。针对数据库性能诊断门槛高、…...
一加Ace3 刷机救砖简化说明
注意:工具使用英文目录,支持救砖和降级。PJE110国行版,CPH2609国际版。目前国行版不能完美转换国际版,每次升级都需要刷oplusstanvbk,不建议使用。跨国转换或ROOT一定先解锁Bootloader,可以使用“一加全能工…...
【服务器05】之【登录/注册账号成功转至游戏场景】
Unity登录注册数据库 打开【服务器01】的文章项目 导入新UI系统 点击2D 双击输入栏位置 修改输入框尺寸及位置 放大字体 修改默认输入文字 发现中文字变成了口口口口 原因是新UI系统不支持中文,解决这个问题需要更换字体 并且修改输入时字体大小 我们取电脑中找Fon…...
平价蓝牙耳机推荐性价比高,性价比高的蓝牙耳机学生党推荐
市场上的蓝牙耳机价格从几十元到几百甚至上千不等,性能与价格也呈现多样化,对于学生党来说,一个理想的选择是那些性价比高的平价蓝牙耳机,它们在不牺牲必要功能的同时,提供了可接受的音质和足够的便利性,接…...
【华为战报】5月、6月HCIP考试战报!
华为认证:HCIA-HCIP-HCIE 点击查看: 【华为战报】4月 HCIP考试战报! 【华为战报】2月、3月HCIP考试战报! 【华为战报】11月份HCIP考试战报! 【HCIE喜报】HCIE备考2个月丝滑通关,考试心得分享ÿ…...
OBD诊断
文章目录 OBD 参考标准OBD 服务OBD服务中的DTCOBD服务中0x03和0x07的区别参考 OBD 参考标准 OBD的标准: ISO 15031 Road Vehicles-Communication between vehicle and external equipment for emission-related diagnostics OBD 服务 序号ID服务说明服务详解10x0…...
2024年最值得关注的AI工具盘点:从ChatGPT到Stable Diffusion的完整指南
2024年AI工具实战指南:从智能对话到创意生成 在咖啡馆遇见一位自由编剧时,她向我展示手机里刚用AI生成的剧本分镜——角色表情、场景光线、甚至运镜角度都标注得专业细致。"三年前这些工作要团队协作一周,现在十分钟搞定。"她滑动屏…...
人脸识别OOD模型在酒店行业的应用:客户识别系统
人脸识别OOD模型在酒店行业的应用:客户识别系统 1. 引言 酒店行业正面临着前所未有的服务升级压力。想象一下这样的场景:一位客人拖着行李箱走进酒店大堂,前台工作人员立即叫出他的名字:"王先生,欢迎再次光临&a…...
RVC语音转换保姆级教程:3分钟训练专属AI歌手,零基础也能玩
RVC语音转换保姆级教程:3分钟训练专属AI歌手,零基础也能玩 1. 前言:为什么选择RVC? 想象一下,你只需要3分钟的训练时间,就能让AI完美模仿任何人的声音唱歌。这不是科幻电影,而是RVC࿰…...
Pytorch实战:用torchvision.utils.save_image一键保存tensor图片(附常见问题解决)
PyTorch实战:高效保存Tensor图片的终极指南 在深度学习项目开发过程中,我们经常需要将中间结果或最终输出以图片形式保存下来进行分析和展示。传统方法需要先将Tensor转换为NumPy数组,再通过OpenCV或PIL等库保存,这个过程不仅繁琐…...
Qwen3-VL-8B轻量部署全攻略:从环境搭建到API调用,一步到位
Qwen3-VL-8B轻量部署全攻略:从环境搭建到API调用,一步到位 在当今AI技术快速发展的时代,多模态模型正成为行业新宠。然而,大多数高性能视觉语言模型对硬件要求极高,让许多开发者和中小企业望而却步。Qwen3-VL-8B-Inst…...
PasteMD剪贴板美化工具:5分钟本地部署,一键整理杂乱文本
PasteMD剪贴板美化工具:5分钟本地部署,一键整理杂乱文本 你有没有过这样的体验?开会时手忙脚乱记下的笔记,事后看就像一堆乱码;从网页复制过来的内容,格式全乱套了;写文档时,想把一…...
【Java从入门到入土】06:String的72变:从字符串拼接到底层优化
【Java从入门到入土】06:String的72变:从字符串拼接到底层优化 String是Java开发中使用率Top1的类,几乎所有项目都绕不开字符串操作——但多数人只停留在“能用”的层面:用拼接字符串、不知道常量池的存在、正则验证写得漏洞百出&…...
ESP32 WiFi-AP 模式实战:从零搭建智能设备热点连接方案
1. ESP32 WiFi-AP模式入门指南 第一次接触ESP32的WiFi功能时,我被它的灵活性惊艳到了。这块小小的开发板不仅能连接现有WiFi网络,还能自己创建热点,就像个迷你无线路由器。今天我要分享的是如何让ESP32变身热点,让你的手机、电脑直…...
Phi-3-mini-128k-instruct实战教程:Chainlit集成企业微信/钉钉机器人通知链路
Phi-3-mini-128k-instruct实战教程:Chainlit集成企业微信/钉钉机器人通知链路 1. 模型介绍与环境准备 Phi-3-Mini-128K-Instruct是一个38亿参数的轻量级开放模型,在Phi-3数据集上训练而成。这个模型特别适合需要长文本处理能力的场景,支持1…...
Windows 10/11动态壁纸终极指南:从Lively Wallpaper安装到4K资源下载
Windows 10/11动态壁纸终极指南:从Lively Wallpaper安装到4K资源下载 想让你的Windows桌面焕发生机吗?动态壁纸早已不再是Mac用户的专属福利。从会随天气变化的实景视频到交互式粒子效果,Windows平台上的动态壁纸体验正在迎来革命性升级。不同…...
