这是上学期的一次课程作业,难度不高但是也一并记录下来,偷懒地拿课程报告改改发上来。

课程要求:使用sketchUp建模,在Unity3D中实现场景漫游和场景互动。

知识点:建模、官方第一人称控制器、网格碰撞器、刚体、触发器、射线(触发)碰撞器。

实验题目

基于SketchUp和Unity 3D的虚拟场景漫游和场景互动(增强现实)

实验内容

实验要求

实验要求是实现虚拟场景漫游和增强显示效果。

模型实现

我们组的项目模型采用SketchUp的小作业房屋设计模型修改而来,最终通过两张房屋设计图分别设计了两套住房模型:图略。
增强现实效果实现

将模型导入Unity3d中后,进一步细化贴图和场景,导入官方package以加入第一人称角色控制器,对模型加入碰撞器,实现了场景漫游并结合第一人称角色控制器的camera加入射线碰撞器,实现注视特定目标可以显示出目标信息(左上角第一个显示栏,如“这是老韩家吃饭的地方”),对于特殊目标设定对应的Text 3D效果,实现类似增强现实的场景效果(如餐桌上方浮现的“Let’s Eat!”),加入触发器可以显示出当前所在位置(左上角第一个显示栏,如“welcome to 老韩家的客厅”)。

我们设立了多处地点触发显示和多处特定目标信息显示,对于餐桌、房屋、电视机和床加入了增强现实的Text 3D效果,具体实现将在设计过程中展示。

具体流程(重点)

创建SketchUp模型

生成fbx文件

将SketchUp中的模型导入Unity 3D中需要使用SketchUp 2016 pro并生成fbx文件及其贴图文件和文件夹,在实际操作中我们还注意到由于房顶等模型材质具有双面不同贴图的情况,结合网上博客了解到生成fbx文件时需要如下设置:

其中选项部分需要如下设置:

创建Unity场景

在Unity 3D中创建项目,生成Assert文件夹,创建场景在Assert文件夹下:

TerrianLightSkybox制作

在场景中加入第一个3D模型——Terrian,其中可以加入树木、草、地形和地面贴图,我们采用绿色草地的贴图效果

而Light我们使用,并在房屋中设置了,优点是可以使得漫游时照亮房屋,方便观察操作,缺点是不符合实际日照情况。

Skybox我们先后使用了Standard Assert自带的Skybox和Assert Store中的Skybox,效果均不理想,最后放弃加入Skybox,使用默认场景。

fbx移入场景中并贴图

将之前导出的fbx文件及其贴图文件夹移动到Assert文件夹中,由于Unity自身原因,并不能自动将贴图文件和模型完美结合,需要自行贴图,即在Albedo中拖入贴图文件夹下的对应图片,由于图片命名和模型命名不完全相同,有一些模型结果并不理想。(此过程及其繁琐)

加入第一人称角色控制器

如果要自行实现角色控制并漫游,难度过高,我们选择导入官方package即Standard Assert:

导入后效果如下:

而角色控制器分为:

我们选择了第一人称角色控制器,一方面是因为第三人称角色控制器为了实现摄像头跟踪要加入smooth follow而且并不理想,另一方面我们实现的增强现实效果,即注视物体显示信息和Text 3D效果通过第一人称角色控制器来实现射线碰撞器更为方面,需要注意的是,为了通过某些狭窄的通道,可能需要更改角色的XYZ大小,也应该同步更改offset步长,否则会报错。

模型加入碰撞器属性

碰撞器是极为重要的一环,因为为了实现增强现实效果(注视现实物体信息和Text 3D模型),所有物体都要选择是否作为碰撞体,在Unity中设置如下:

因为大多数模型,包括房屋家具等都是复杂的多面体模型,所以需要使用Mesh Colider(网格碰撞器),在网格碰撞器的具体实现中我们注意到了以下几个关键点:

  1. 如果一个父物体加入了Mesh Colider组件,那它的所有子物体都必须加入Mesh Colider组件,拥有子物体的物体模型有很多:
  2. Mesh Colider组件中有Convex(相互碰撞)的选项,大多数物体我们需要勾选,但是在具体实现中,我们将房屋的Convex选择不勾选,并将门的门框(仅仅是门框,不是整个门)不作为Mesh Colider碰撞体,可以使得角色方便进入,但是仍然会和门碰撞,不会穿过门板。
  3. 调试时候出现了部分模型Convex不通过的问题,原因是对应的Mesh超过了255个面,我们将这个模型(一盆花)不勾选Convex,即可。
  4. 大多数碰撞体结果如下:

加入trigger触发器物体并隐藏

我们另一个技术点是实现显示身处位置,即“welcome to 老韩家的客厅”,具体实现需要先设置触发器,我们在多个地点设置了cube模型的触发器,包括客厅、厕所、厨房、卧室、房屋外:

触发器的效果是隐藏物体:

并设置成可穿过的物体:

一一对应模型信息并加入Text 3D的文字模型

为了实现增强现实效果,即注视物体显示物体信息,我们将很多模型信息记录下来,Tag是模型的名称记录,方便脚本中对应实现:

为了实现Text 3D的模型效果,我们加入了Text 3D模型:

命名为对应的text+对应的模型tag,并设置为隐藏,只有观测到对应模型时才会显示:

编写RayTest2.cs脚本,实现射线碰撞器

做好了碰撞器和Text 3D模型,我们编写了对应的脚本:

在Start()函数中,进行字典的初始化,即将碰撞物体及其信息一一对应:

在Update()函数中,在每一帧进行以camera为射线起点,以camera方向为射线方向,长度为100的射线碰撞,并返回碰撞到的物体信息:

在OnGUI()函数中,输出射线碰撞到的物体对应的字典信息:

同时检测是否有对应的Text 3D模型,有则将其显示:
 

也会记录前一次的碰撞物体,如果不同,则说明视线转移了,之前的Text 3D继续隐藏:

编写TriggerTest2.cs脚本,实现触发器

比较简单,见附代码。

运行调试

完成之后可以在Unity
3D中运行查看,可以生成exe文件运行,在Console中可以显示Debug信息,通过调试的一点人生の经验

  1. 在室内向房顶看去,房顶显示为透明,是因为fbx导出时没有选择双面材质。
  2. Terrain加入草的元素时没有效果,是因为草的Height需要 > 0。
  3. 第一人称角色控制器不能移动,是因为模型大小更改以后,要同时更改offset步长。
  4. 显示模型Convex错误,是因为过于复杂的物体如一盆花的Mesh网格超过了255个,取消掉其Convex选项即可。
  5. 物体添加了Mesh Conlider之后仍然会直接穿过,原因是其子物体也要全部加上Mesh Conlider组件。
  6. 注意整个场景中只能包含一个监视器,一般将后加入的监视器去掉,即去掉第一人称角色控制器中的MainCamera。

参考

http://stephen830.iteye.com/blog/ Unity学习笔记

http://www.cnblogs.com/infly123/p/3920393.html 碰撞器和触发器的区别

http://www.ceeger.com/Components/ Unity圣典

http://www.cnblogs.com/slysky/p/4290803.html 碰撞器与触发器[Unity]

代码

RayTest2.cs

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Text;
public class RayTest2 : MonoBehaviour {
public string cur = "";
public string fro = "";
public Dictionary<string, string> dic = new Dictionary<string, string>();
// Use this for initialization
void Start () {
dic.Add("Mesh390","老张家的房子");
dic.Add("Mesh230", "老张家的书桌");
dic.Add("Mesh298", "老张家的书桌");
dic.Add("Mesh220", "老张家的电脑桌!");
dic.Add("Mesh249", "老张家的沙发");
dic.Add("Mesh253", "老张家的沙发");
dic.Add("Mesh250", "老张家的沙发");
dic.Add("Mesh252", "老张家的沙发");
dic.Add("Mesh389", "老张家的电视机");
dic.Add("Mesh239", "老张家的隔断");
dic.Add("Mesh231", "老张家的一盆花");
dic.Add("Mesh232", "老张家的一盆花");
dic.Add("Mesh290", "老张家的一盆花");
dic.Add("Mesh291", "老张家的一盆花");
dic.Add("Mesh13", "老张家的大床");
dic.Add("Mesh21", "老张家的大床");
dic.Add("Mesh29", "老张家的大床");
dic.Add("Mesh246", "老张家吃饭的地方");
dic.Add("Mesh198", "老张家的衣柜");
dic.Add("Mesh205", "老张家的衣柜");
dic.Add("Mesh305", "老张家的衣柜");
dic.Add("Mesh292", "老张家的马桶!");
dic.Add("Mesh293", "老张家的马桶!");
dic.Add("Mesh265", "老张家的厨房一套");
dic.Add("Mesh266", "老张家的厨房一套");
dic.Add("Mesh267", "老张家的厨房一套"); dic.Add("Mesh1812","老韩家的房子");
dic.Add("Mesh31", "老韩家吃饭的地方");
dic.Add("Mesh1327", "老韩家的大桌子");
dic.Add("Mesh121", "老韩家的衣柜");
dic.Add("Mesh126", "老韩家的衣柜");
dic.Add("Mesh131", "老韩家的衣柜");
dic.Add("Mesh136", "老韩家的衣柜");
dic.Add("Mesh141", "老韩家的衣柜");
dic.Add("Mesh103", "老韩家的沙发");
dic.Add("Mesh116", "老韩家的茶几"); dic.Add("Mesh1315", "老韩家的洗衣机");
dic.Add("Mesh1322", "老韩家的厨房一套");
dic.Add("Mesh40", "老韩家的环绕音响");
dic.Add("Mesh64", "老韩家的环绕音响");
} // Update is called once per frame
void Update ()
{
Ray ray=new Ray(Camera.main.transform.position,Camera.main.transform.forward*);
Debug.Log(ray);
RaycastHit hitcur;
if(Physics.Raycast(ray,out hitcur,))
{
cur = hitcur.collider.gameObject.name.ToString();
Debug.Log(cur);
}
}
void OnGUI()
{
try
{
GUI.Box(new Rect(, , , ), "这是" + dic[cur]);
}
catch (Exception e)
{
GUI.Box(new Rect(, , , ), "");
} if (fro == cur)
{
}
else
{
try
{
GameObject obj2 = GameObject.Find("text" + fro);
obj2.GetComponent<Renderer>().enabled = false;
}
catch (Exception e) { };
}
try
{
GameObject obj = GameObject.Find("text" + cur);
obj.GetComponent<Renderer>().enabled = true;
fro = cur;
}catch (Exception e) { };
}
}

TriggerTest2.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Text;
public class TriggerTest2 : MonoBehaviour {
public string cur_room = "outside1";
public Dictionary<string, string> dic = new Dictionary<string, string>();
// Use this for initialization
void Start () {
dic.Add("outside1","北京地下室群居房区");
dic.Add("house1room11","老张的客厅");
dic.Add("house1room12","老张的客厅");
dic.Add("house1room13","老张的客厅");
dic.Add("house1room21","老张的卧室A");
dic.Add("house1room31","老张的厕所");
dic.Add("house1room41","老张的厨房");
dic.Add("house1room51","老张的卧室B");
dic.Add("house1room61","老张的卧室C"); dic.Add("outside2","北京地下室群居房区");
dic.Add("house2room11","老韩的客厅");
dic.Add("house2room12","老韩的客厅");
dic.Add("house2room21","老韩的卧室A");
dic.Add("house2room31","老韩的卧室B");
dic.Add("house2room41","老韩的卧室C");
dic.Add("house2room51","老韩的厨房");
dic.Add("house2room61","老韩的厕所");
} // Update is called once per frame
void Update () {
//Debug.Log(cur_room);
}
void OnGUI()
{
try
{
GUI.Box(new Rect(, , , ), "welcome to " + dic[cur_room]);
}
catch (Exception e) { };
}
void OnTriggerEnter(Collider collider)
{ //进入触发器执行的代码
cur_room = collider.gameObject.name.ToString();
}
}

基于SketchUp和Unity3D的虚拟场景漫游和场景互动的更多相关文章

  1. Unity3d场景漫游---iTween实现

    接触U3D以来,我做过的场景漫游实现方式一般有以下几种: Unity3d中的Animation组件,通过设置摄像机的关键点实现场景漫游 第一人称或第三人称控制器 编写摄像机控制脚本 iTween iT ...

  2. 基于VRML的虚拟校园漫游系统

    最近学习VRML的开发,在CSDN网上搜索到一个基于VRML的虚拟校园漫游系统.感觉很不错. 浏览效果如下:

  3. Unity3d 简单的小球沿贝塞尔曲线运动(适合场景漫游使用)

        简单的小球沿贝塞尔曲线运动,适合场景漫游使用 贝塞尔曲线:(贝塞尔曲线的基本想法部分摘自http://blog.csdn.net/u010019717/article/details/4768 ...

  4. 放弃antd table,基于React手写一个虚拟滚动的表格

    缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...

  5. [Unity3D]Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 在<仙剑奇侠传>.<古剑奇谭>等游戏中,常常须要玩家在一个3D场景中 ...

  6. 【Unity入门】场景编辑与场景漫游快捷键

    版权声明:本文为博主原创文章,转载请注明出处. 打开Unity主窗口,选择顶部菜单栏的“GameObject”->“3D Object”->“Plane”在游戏场景里面添加一个面板对象.然 ...

  7. OSG实现场景漫游(转载)

    OSG实现场景漫游 下面的代码将可以实现场景模型的导入,然后在里面任意行走,于此同时还实现了碰撞检测. 源代码下载地址: /* * File : Travel.cpp * Description : ...

  8. [Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果

    大家好,我是秦元培.欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei.终于在各种无语的论文作业中解脱了,所以立即抓紧时间来这里更新博客.博主本来计划在Unity3 ...

  9. nginx篇最初级用法之三种虚拟主机基于域名\基于端口\基于IP地址端口的虚拟主机

    在nginx中虚拟主机的类型与apache一样也有三种 1.基于域名的虚拟主机 2.基于端口的虚拟主机 3.基于IP地址端口的虚拟主机 在nginx配置文件中每一个server为一个虚拟主机如果需要多 ...

随机推荐

  1. docker registry ui

    https://hub.docker.com/r/parabuzzle/docker-registry-ui/

  2. MySQL8 重置改root密码及开放远程访问

    1. 修改配置文件 先修改配置文件:vim /etc/my.conf 在 [mysqld] 下加上下面这行 skip-grant-tables 重启 mysql 服务: service mysqld ...

  3. spring jpa exists

    Subquery<A> subquery = criteriaQuery.subquery(A.class);Root<A> root1 = subquery.from(A.c ...

  4. 第五章 二叉树(e4)层次遍历

  5. spotlight

    spotlight - 必应词典 美['spɑt.laɪt]英['spɒt.laɪt] n.聚光灯:聚光灯照亮的地方:聚光灯照明圈:媒体和公众的注意 v.用聚光灯照:突出报道(以使公众注意) 网络射灯 ...

  6. 使用Sql分页方法给Repeater控件分页的方法

    页面代码 <div class="bookList"> <asp:Repeater ID="rpBooks" runat="serv ...

  7. 安装完CentOS可以不做的事

    添加用户到sudo. 打开/etc/sudoers 找到root ALL=(ALL) ALL这一行,在后面再加上一行就可以了(不用引号): username ALL=(ALL) ALL 注意,都用ta ...

  8. Spring框架的配置文件分开管理(了解)

    1. 例如:在src的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种! * 主配置文件中包含其他的配置文件: <import resource=&qu ...

  9. CentOS7下BIND配置主从服务器和缓存服务器

    系统环境:CentOS Linux release 7.4.1708 (Core)  3.10.0-693.el7.x86_64 软件版本:bind-chroot-9.9.4-51.el7_4.1.x ...

  10. python激活码