玩转 HTML5 下 WebGL 的 3D 模型交并补

2024-08-30 11:38

本文主要是介绍玩转 HTML5 下 WebGL 的 3D 模型交并补,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CSG 构造实体几何这个概念在工业水利水电施工上、游戏上已经有很多人使用了,最简单的实体表示叫作体元,通常是形状简单的物体,如立方体、圆柱体、棱柱、棱锥、球体、圆锥等。根据每个软件包的不同这些体元也有所不同,在一些软件包中可以使用弯曲的物体进行 CSG 处理,在另外一些软件包中则不支持这些功能。构造物体就是将体元根据集合论的布尔逻辑组合在一起,这些运算包括:并集、交集以及补集。我们一般可以用 CSG 来将简单的模型合在一起生成复杂的模型,这样在构造模型的时候会省很多力。
HT 中的 ht.CSGNode 图元类型就是参考 CSG 封装的一个函数,ht.CSGNode 继承于 ht.Node,当 style 的 shape3d 属性为空时显示为六面体效果,CSGNode如果通过 setHost 吸附到 宿主 CSGNode 或 CSGShape 后,宿主 CSGNode 或 CSGShape 可与吸附的CSGNode图元进行CSG的组合建模。详情请参考 HT for Web 建模手册 CSGNode 章节。这里我用 CSG 的概念写了一个例子,让大家能更好地理解这个概念。
本例 Demo 地址: http://hightopo.com/guide/guide/plugin/modeling/examples/example_bookshelf.html
先来看下效果图:
图片描述
从上面效果图可以看到,我们将界面分为三个部分,这三个部分先是右边部分上下分割,然后将整个界面左右分割,HT 用封装好的 ht.widget.SplitView 进行界面的分割,然后将分割组件添加进底层 div 中:

dm = new ht.DataModel();// 数据模型            
treeView = new ht.widget.TreeView(dm); //树组件                                                                                                 
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件  
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, 'v', 0.6);//分割组件 
mainSplit = new ht.widget.SplitView(treeView, splitView, 'h', 0.27);   view = mainSplit.getView();  
view.className = 'main';
document.body.appendChild(view);    
window.addEventListener('resize', function (e) {mainSplit.invalidate();
}, false);                         

上面代码是一种非常常见的在 HTML 中添加 HT 组件的方法,详情可参考 HT for Web 入门手册组件章节。这种方法进行添加 HT 组件有一个需要注意的点,因为 HT 一般都以设置 position 为 absolute 的绝对定位方式,必须设置 left、right、top、bottom 等等基础 css 样式,像这样:

.main {margin: 0px;padding: 0px;position: absolute;top: 0px;bottom: 0px;left: 0px;right: 0px;
}

所以为了最外层组件加载填充满窗口的方便性,HT 的所有组件都有 addToDOM 函数,其思想逻辑如下,其中 iv 是 invalidate 的缩写:

addToDOM = function(){   var self = this,view = self.getView(),   style = view.style;document.body.appendChild(view);            style.left = '0';style.right = '0';style.top = '0';style.bottom = '0';      window.addEventListener('resize', function () { self.iv(); }, false);            
}  

以后我们在代码中就可以直接调用 addToDOM 函数,而不用写一大堆代码了,上面代码用 addToDOM 取代之后的代码如下,而且不用描绘 css 样式:
dm = new ht.DataModel();// 数据模型
treeView = new ht.widget.TreeView(dm); //树组件
gv1 = new ht.graph3d.Graph3dView(dm); //3D 组件
gv2 = new ht.graph3d.Graph3dView(dm);
splitView = new ht.widget.SplitView(gv1, gv2, ‘v’, 0.6);//分割组件
mainSplit = new ht.widget.SplitView(treeView, splitView, ‘h’, 0.27);
mainSplit.addToDOM();
界面分配好之后我们就要对其添加内容了,界面的左边部分是 HT 封装的树组件,我在之前的文章写到过,树组件是一个非常方便的绘制树形关系的组件,开发人员能够轻松地从数据模型 DataModel 中获取数据和节点之间的关系放到树上,只需要在树组件声明的过程中,将对应的数据模型 DataModel 放进树组件的参数即可,当然我们还扩展了很多跟树组件有关的函数,非常方便实用,这里我们只用了 expandAll 函数,将所有对象展开:

treeView = new ht.widget.TreeView(dm); //树组件   
treeView.expandAll();

右边部分上下分为两部分,都是 3D 场景,就是设置显示有点不同,其他完全相同,上面的 3D 场景重载了 getVisibleFunc 函数,如果元素的 showMe 属性为 true,则可视;如果节点为 ht.CSGNode 类型并且节点的 getHost 函数的参数为空,则不可视;其他情况均可视:

gv1.setVisibleFunc(function(data){if(data.showMe){return true;}if(data instanceof ht.CSGNode && data.getHost()){return false;}return true;
});

我们先向 3D 场景中添加元素对象,我们先解释中间的书架,对两边的书架有缺的再进行补充。首先我们添加了一个 ht.CSGNode 节点 shelf,作为书架的主节点,其他的节点都是依附于这个节点的,对这个节点设置了位置、大小、名称以及六个面的颜色,然后添加进数据模型 DataModel:

var shelf = new ht.CSGNode();
shelf.s3(500, 400, 120);
shelf.p3(0, 200, 0);
shelf.setName('shelf1');
shelf.s({'all.color': '#E5BB77'
});
dm.add(shelf);

接着向这个 shelf 中添加 10 个节点,做书架的格子效果,并设置依附关系和父子关系添加进数据模型中:

for(var i=0; i<2; i++){for(var j=0; j<5; j++){var clipNode = new ht.CSGNode();clipNode.setHost(shelf);clipNode.s3(80, 100, 120);clipNode.p3(-200+j*100, 340-i*120, 20);clipNode.setName('substract-'+i+'-'+j);clipNode.s('batch', 'tt');clipNode.setParent(shelf);dm.add(clipNode);}
}

为了让书架变得更美观一点,我们在书架的上下左右都加上了 ht.CSGNode,最后为了更加具象化,我们还添加了一本书,实现方式也差不多,都非常简单:

var book = new ht.Node();
book.setName('CSS3: The Missing Manual');
book.s3(60, 80, 8);
book.p3(-100, 210, 20);
book.r3(-Math.PI/6, Math.PI/5, 0);
book.setIcon('book');
book.s({'front.image': 'book','back.color': 'white','left.color': 'white','all.color': 'gray'
});
book.setHost(shelf);
book.setParent(shelf);
dm.add(book);  

接着左边的书架也是类似的构建方法,有一点不同的是,这边有一个 ht.CSGBox 类型,继承于 ht.CSGNode,其除具备父类 CSGNode 的挖空等功能外,还可对六个面进行旋转展开关闭的操作,这里我们的节点只设置了前面的能够旋转展开,并且设置了一系列的样式:

clipNode = new ht.CSGBox();
clipNode.setName('CSGBox-Expand-Left');
clipNode.s3(100, 100, 120);
clipNode.p3(0, 65, 0.1);
clipNode.setHost(shelf);
clipNode.showMe = true;
clipNode.s({'all.visible': false,//6面均不可见'front.visible': true,//前面可见'front.toggleable': true,//允许前面双击展开                    'front.reverse.flip': true,//前面的反面显示正面的内容'front.transparent': true,//前面透明'front.end': Math.PI * 0.7,//前面展开状态的结束旋转弧度'front.color': 'rgba(0, 50, 50, 0.7)'//前面颜色
});

图片描述

可能你们还想知道下面的地球是怎么做到的?还记得之前的文章写到过 HT 中设置了 shape3d 属性,设置这个属性实际上就是在操作 setShape3dModel(name, model) 和 getShape3dModel(name),可以通过这个属性设置为 box|sphere|cylinder|cone|torus|star|rect|roundRect|triangle|rightTriangle|parallelogram|trapezoid 等等模型,这些模型也都是 HT 封装好的,要使用时直接设置 shape3d 为其中的一个值即可,如这个例子中用到 “shape3d: sphere” 就是设置为球体。我们简单地用一张地图图片包裹在这个球体的外侧,当然,这张地图图片是先通过 ht.Default.setImage 注册过的,然后通过 shape3d.image 将图片附到这个节点上:

earth = new ht.Node();
earth.setName('earth');
earth.s3(70, 70, 70);
earth.p3(0, 50, 0);
earth.s({'shape3d': 'sphere','shape3d.image': 'earth'
});
earth.setHost(shelf);  
earth.setParent(shelf);
dm.add(earth);

右边的书架,同样也是有一个主节点,其他节点依附于它,但是我们看到这边换了一个新的节点类型 ht.DoorWindow,ht.DoorWindow继承于 ht.CSGNode,其除具备父类 CSGNode 的挖空等功能外,还可进行整体的旋转展开关闭的操作, 常用于作为门或窗的业务对象,吸附于 CSGNode 或 CSGShape 的 host 作为墙面的图元。这个节点类型就是 ht.CSGNode 的延展,相对来说就是区分了实际应用而添加了不同的 style 参数,更多的属性请到 HT for Web 建模手册 DoorWindow 章节 查看然后添加到节点中玩玩:

photos = new ht.DoorWindow();
photos.setName('DoorWindow-Photos');
photos.setIcon('ben12');
photos.s3(110, 100, 130);
photos.p3(5, 180, 0);                
photos.setHost(shelf);  
photos.showMe = true;
photos.s({                    'bottom.uv': [1,1, 1,0, 0,0, 0,1],'bottom.uv.scale': [1, 1],'left.uv.scale': [3, 3],'top.uv.scale': [2, 2],'dw.s3': [0.8, 0.9, 0.05],'dw.t3': [0, -5, 0],'dw.axis': 'v','dw.toggleable': false,'front.image': 'ben1','back.image': 'ben2','all.color': '#F8CE8B'
});
photos.setParent(shelf);
dm.add(photos);

最后,我们将左侧的地球 earth 和右侧的照片 photo 旋转起来:

var angle = 0;
setInterval(function(){angle += Math.PI/40;earth.r3(0, angle, 0);photos.s('dw.angle', angle);
}, 50);

我们看到,其实虽然 HT 封装了很多不同的 CSG 节点类型,但是实际应用都差不多,而且内容也没有差特别多,差别都是在 style 参数上,但是真的在实际开发中,这种区分就会很大程度上加快开发速度,毕竟名称一目了然,就知道要运用哪些 style 属性了。

这篇关于玩转 HTML5 下 WebGL 的 3D 模型交并补的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120719

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}