基于HTML5的WebGL经典3D虚拟机房漫游动画

2024-08-30 11:38

本文主要是介绍基于HTML5的WebGL经典3D虚拟机房漫游动画,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第一人称在 3D 中的用法要参考第一人称在射击游戏中的使用,第一人称射击游戏(FPS)是以第一人称视角为中心围绕枪和其他武器为基础的视频游戏类型 ; 也就是说,玩家通过主角的眼睛来体验动作。自从流派开始以来,先进的 3D 和伪 3D 图形已经对硬件发展提出了挑战,而多人游戏已经不可或缺。

 

Doom 的截图,这个流派的突破游戏之一,展示了第一人称射击游戏的典型视角

 

现在博物馆或者公司也经常使用到 3D 动画做宣传片等等,3D 动画演绎最大的优势,便是在于内容与形式上给人的真实感受。它比平面作品更直观,比 2D 动画更真实,所以更能给观赏者以置身于广告环境当中的感受,大大增强广告的说服力。3D 技术的发展甚至挑战受众的分辨能力,使受众的判断游离于与虚拟和现实之间。
而且 3D 特效的应用为创意提供了更加广阔的思维空间,并成为创意执行的可靠保证,并丰富了创意的形式和风格手段。根据广告主题的表现诉求,可以营造出梦幻般的神奇氛围来刺激打动受众,从而起到与受众沟通的目的。
3D动画宣传片将 3D 动画、特效镜头、企业视频、照片、未来前景等内容通过后期合成、配音、解说形成一部直观、生动、喜闻乐见的高品位的企业广告宣传片,让社会不同层面的人士对企业产生正面的、积极的、良好的印象,从而建立对企业的好感与信任,并信赖该企业的产品或服务。

现在 3D 发展地如此迅速也要感谢人类对于“现实”的追求,所以学好用好 3D 是未来成功必不可少的一部分。

本文例子的思路是进入一个机房参观,打开门的动作是再生动不过了, 再加上适当地转弯,基本上完全模拟了人在机房中参观的效果。还有一个好处就是,如果要演示给领导看而又不用操作,这种炫酷的效果领导一定会很满意!

http://www.hightopo.com/demo/room-walkthrough/index.html

界面上的“reset”和“start”两个按钮是直接加在 body 体中的 button,并在这两个按钮上添加点击事件:

 

<div class="button" style="right: 50px;background-image: url(run.png);" οnclick="startAnim();"></div>
<div class="button" style="right: 100px;background-image: url(reset.png);" οnclick="reset();"></div>

整个场景由 HT 封装的 3D 组件搭建形成的,构造这么大的场景是需要一定量的代码的,为了简化,我把场景单独拿出来,并用 HT 封装的 ht.JSONSerializer 类将场景序列化为 json,代码中只引入了生成后的 json 文件,为了让大家更明确,我这边做个示例,假设已经搭建好 3D 场景了:

 

 

dm = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dm);
//.......构建好场景
dm.serialize();//可以填入number参数,作为空格缩进值

既然我们已经搭建好环境,转成了 json 文件,代码中不好控制,这种情况下我们会将 DataModel 数据模型再反序列化,这个函数的功能就是将 json 格式转成对象,并将反序列化的对象传入到 DataModel 数据模型中,详情请参考 HT for Web 序列化手册:

 

 

 var g3d = window.g3d = new ht.graph3d.Graph3dView(),dataModel = g3d.dm(),view = g3d.getView(),path = null;
g3d.setMovableFunc(function(data) {return false;
});
g3d.setVisibleFunc(function(data) {if (data.getName() === "path") {return false;}return true;
});
g3d.setEye([523, 5600, 8165]);
g3d.setFar(60000);
dataModel.deserialize(json);

我们目前需要操作场景中的“门”、以及我们将要走的路线“path”,遍历 DataModel 数据模型,获取这两个数据:

 

 

for (var i = 0; i < dataModel.size(); i++) {var data = dataModel.getDatas().get(i);if (data.getName() === "门") {//json中设置的名称window.door = data;}if (data.getName() === "path") {path = data;}if (window.door && path) {//获取到door 和 path 的data之后就跳出循环break;}
}

这个例子中简单来说就只有四个动作,“重置”回到原点、“开始动作”、“向前移动”,“停止”。点击“开始”按钮,在“开始动作”中我们只做了一个动作,“开门”动作,动作结束之后调用“forward”函数向前移动:

 

 

function startAnim() {if (window.isAnimationRunning) {return;}reset();window.isAnimationRunning = true;//动画是否正在进行ht.Default.startAnim({frames: 30, // 动画帧数,默认采用`ht.Default.animFrames`。interval: 20, // 动画帧间隔,默认采用`ht.Default.animInterval`。   finishFunc: function() {// 动画结束后调用的函数。forward();}, action: function(t){ // action函数必须提供,实现动画过程中的属性变化。door.setRotationY(-120 * Math.PI / 180 * t);}});
}

这边的“reset”函数就是“重置”回到原点的功能,我们通过这个函数将所有变化过的都恢复初始的位置,包括“门”的位置:

 

function reset() {if (window.isAnimationRunning) {return;}g3d.setCenter([0,0,0]);g3d.setEye([523, 5600, 8165]);window.forwardIndex = 0;door.setRotationY(0);
}

 

要“移动”,肯定需要走路的“路径”,也就是我们刚刚获取到的“path”,通过 window.points = path.getPoints()._as; 获取“path”中的所有元素,初始化  window.forwardIndex = 0; 通过控制“path”中前后两点来设置 3D 场景中的 Eye 和 Center,这样就能营造一个我们是第一人的效果:

 

 

var point1 = points[forwardIndex],point2 = points[forwardIndex + 1];
var distanceX = (point2.x - point1.x),distanceY = (point2.y - point1.y),distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY)-200;//两点之间的距离通过三角形勾股定理计算 怕碰墙所以-200
g3d.setEye([point1.x, 1600, point1.y]);//眼睛
g3d.setCenter([point2.x, 1600, point2.y]);//我

HT 中 3D 组件有一个 walk(step, anim, firstPersonMode) 方法,该函数同时改变eye和center的位置,也就是eye和center在两点建立的矢量方向上同时移动相同的偏移量。step为偏移的矢量长度值。firstPersonMode参数为空时则默认采用Graph3dView#isFirstPersonMode()当前值, 如果为第一人称模式调用walk操作,该函数会考虑Graph3dView#getBoundaries()边界限制。

 

 

g3d.walk(distance, {frames: 50,interval: 30,easing: function(t) {return t; },finishFunc: function() {forwardIndex += 1;if (points.length - 2 > forwardIndex) {//points.length = 5g3d.setCenter([point2.x, 1600, point2.y]);//把结束点变成起始点g3d.rotate(Math.PI / 2, 0, {frames: 30,interval: 30,easing: function(t) {return t;},finishFunc:function() { forward();}});} else {var lastPoint = points[points.length  - 1];//json 中path的points 的最后一个点g3d.setCenter([lastPoint.x, 1400, lastPoint.y]);g3d.rotate(-Math.PI / 2, 0, {frames: 30,interval: 30,finishFunc: function() {window.isAnimationRunning = false;}});}}
});

不管“path”的点有多少个,这个判断语句还是能运作,只在最后一个点是跳出 finishFunc 动画结束后调用的函数,并将 window.isAnimationRunning 值设为 false 停止 startAnim 函数。如果不是最后一个点,用户“旋转”之后,回调 forward 函数。至此,全部代码解释完毕,很短的代码量,却做出了这么大的工程!

 

这篇关于基于HTML5的WebGL经典3D虚拟机房漫游动画的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

css实现图片旋转功能

《css实现图片旋转功能》:本文主要介绍了四种CSS变换效果:图片旋转90度、水平翻转、垂直翻转,并附带了相应的代码示例,详细内容请阅读本文,希望能对你有所帮助... 一 css实现图片旋转90度.icon{ -moz-transform:rotate(-90deg); -webkit-transfo

vue基于ElementUI动态设置表格高度的3种方法

《vue基于ElementUI动态设置表格高度的3种方法》ElementUI+vue动态设置表格高度的几种方法,抛砖引玉,还有其它方法动态设置表格高度,大家可以开动脑筋... 方法一、css + js的形式这个方法需要在表格外层设置一个div,原理是将表格的高度设置成外层div的高度,所以外层的div需要

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代