2016-02-19 16:19:48 liulong1567 阅读数 10597
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    12992 人正在学习 去看看 宋晓波
大众化的游戏引擎--Unity3D
    并不是所有VR应用都是游戏,然而现在做VR开发的几乎都会用专业游戏引擎来做,因为游戏引擎既满足了一个引擎的要求又可以方便地制作出高品质的VR应用。一个游戏引擎主要核心包括:高品质图像渲染、物理模拟引擎、实时光照、脚本驱动以及强大的可见即可得编辑器。

    目前市面上有许多非常好而且很成熟的游戏引擎,Unity3D是我们制作VR应用的首选解决方案。由于Unity3D不仅功能强大且容易掌握,受到了独立开发人员和学生的强烈拥护。下面是Unity3D一些亮点:

    功能强大:Unity引擎提供了许多非常重要的图形技术,比如,基于物理的材质渲染技术、实时光照技术、物理模拟技术、以及脚本驱动技术。

    容易拓展:Unity引擎是基于组件的架构,使得它非常容易拓展。用户可以通过脚本配置所有组件属性,甚至可以重新实现一些编辑器的功能,自定义一些编辑器的工具。

    可见即可得:对于一个新手来说也许Unity的编辑器有些复杂,但是一旦熟悉以后,就会发现它非常好用。这个编辑器作为开发来说非常高效,并且可以直接导入如Maya和3dsMax的模型。

    跨平台发布:游戏可以直接发布在OSX、Windows、Linux、XBox、PlayStation、IOS、Android以及Web上。其中,Web端通过一个基于WebGL的插件运行。这意味着,一旦使用者掌握了Unity他就可以开发多种平台上的应用了。

    价格便宜:Unity的免费版本已经具有全部功能,然而如果你使用Unity开发的应用盈利了,那么你只需要缴纳很少的月费和版权费。

    健全的生态:Unity有一个在线商店(Asset Store),里面有大量的3D模型、动画、代码包、工具等等。Asset Store使得Unity可以拥有全球最大的开发社区。

    支持VR:Unity结合Oculus的SDK提供了一整套的VR开发解决方案,其中还包括示例场景和入门教程。

    本章接下来会介绍如何构建这个示例场景,那么首先你需要下载安装Unity。下面是下载网址:http://unity3d.com/get-unity

 
图3-6

    安装完毕以后,启动Unity,然后建立一个空3D工程,我们现在来熟悉一下Unity的编辑器,图3-6就是编辑器的截图。中间的视图面板(Scene)可以实时观察和交互我们的场景;层级面板(Hierarchy)中有了一个包含了所有场景物体的树形图;工程面板(Project)中有工程文件夹中的所有资源(也包括场景中没有的资源);属性面板(Inspector)展示了当前选中的物体的所有属性,并且可以通过这个面板进行修改。
2017-05-06 12:14:51 a827443469 阅读数 7514
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    12992 人正在学习 去看看 宋晓波

超简单的引言

本教程介绍的是如何一个人制作出像模像样的VR全景动画。笔者没有去详细的研究过动画的制作方式,或者说根本就不了解啊,所以本文章只是门外汉的一次自嗨,请勿认真,作为一种参考即可。

一 总览

我们都知道,任何项目的开始都需要有策划的参与,没有完整的项目书,在项目的制作过程中你是会很痛苦的,不管是针对团队或者是个人开发,计划书都是必须的存在。
笔者认为,一个简单的动画项目,至少需要有角色、场景和故事,才能够进行下去,所以这三者的获取对于个人开发者而言就十分重要的。
故事即剧本,对于想单人开发VR动画的人而言,脑海里肯定是已经有了一定的想法了,那么,把他写下来,你就成功的获取了三要素中的故事了。
场景即故事发生的地点,如果你的动画不是那么要求的话,一个Plane就可以作为场景了,稍微讲究一点就可以自己使用Terrain慢慢刷吧,那么场景也就有了。
角色是比较难搞到的一个要素,想要一个机子逾期的模型和动画可没那么的简单,外包是不可能外包的,一辈子都不可能外包,原因自然是没钱啊,那么怎么获取符合自己故事的人物模型呢,请看下文。

二 角色模型

提到角色,制作VR全景动画,需要的是3D的模型,那么如何快速地获取自己想要的模型呢,答案当然是自己制作,这里笔者推荐个人开发这使用体素模型,何为体素模型,就是身体由一个个的方块、像素快组成的模型,好处自然是制作简单,快速成型,制作这种模型,几乎不要花费额外的学习成本,上手就来,下面说一下笔者自己的人物模型制作过程。
首先,你需要去下载一个软件MagicalVoxel,打开软件是这个样子的。
MagicalVoxel
这款软件使用特别的交单,几乎就是秒上手,网上也有很多的使用教程,这里就不重复造轮子了,给你们看看笔者花了5分钟制作出来的一个模型,推荐使用T Pose,有没有感觉很震撼,哈哈,现在是丑了点,等下动起来会好看一点,制作完成后记得将模型导出成obj格式的。
man

三 角色动画

有了角色模型,就需要让模型动起来,给模型添加动画,这里笔者使用的是一个在线的网站mixamo,可以在线为人形的模型添加骨骼和动画,使用前需要先注册帐号。
截至到2017年5月5日,使用这个网站需要注意两点,这两点开始没注意到,浪费了笔者很多的时间:(1)注册帐号,选择的地区不能选择中国,否则你将没有权限下载绑定好骨骼的模型和动画。(2)浏览器,使用的浏览器需要支持WEBGL功能,笔者之前使用的是360安全浏览器,不支持这个功能,导致无法上传模型,后面切换到360极速浏览器,通过简单的设置后就可以了,如果你使用的是其他的浏览器,需要支持这个功能,下面的图片是360极速浏览器的简单设置。
开启webgl
一切都搞定后,点击上传,具体流程直接看图
上传
选中上传的文件
选中上传的文件
绑定骨骼
绑定骨骼
点击Next生成完之后就可以在自己的库中见到你的模型,而且是绑定骨骼的,模型已经动起来了。

下一步是选择动画,这个网站上有很多的动画供你选择,而且全是免费的应该

选中一个动画,点击添加到包里即可

进入到你的库中,就可以看到你的模型和选择的动画文件了
这里写图片描述
接下来就是选中模型和动画,点击QUEUE DOWNLOAD,如果你的帐号选得是中国,这边的按钮是不可用的,模型和动画是分开下载的,模型下载选中FBX格式,可以直接导入Unity使用。

四 开发制作第一步

嗯,素材什么的都有了,接下来就是在Unity中的开发了,笔者使用的是Unity3D 5.6版本,新建一个项目,将模型导入到项目中,再将模型拉入场景中,你会发现模型是没有贴图的,下载的时候也是没有的。
别着急,别忘了之前从MagicaVoxel导出的时候是有一张的贴图的,我们将这张贴图一起拖入项目中,再将贴图的类型改成Sprite类型,为模型的材质球附上这张贴图即可。(下面的效果是我之前制作的模型)
这里写图片描述
这里写图片描述
接下来新建一个动画控制器,为模型指定上,再将需要的动画拉入控制器,点击运行,就会发现模型已经动起来了。
这里写图片描述
以上是很简单的方式,实际上,在动画的流程中,角色的动作和语音是很复杂的一个过程,需要使用脚本去精准的控制整个流程的进行。

五 开发制作第二步

第二步也是最重要的一步,即渲染VR全景视频,即下面这样的效果。
这里写图片描述
如果是自己写算法去渲染估计可以独立成一本书,我们自然要偷懒咯,这里推荐一款商店里的插件,如果是商业开发最好去支持一下作者,最新已经更新到了2.2.1。
这里写图片描述
下面介绍一下这个插件的简单使用,这款插件有几种渲染模式,笔者这边只介绍如何渲染出正常VR全景视频的方法,在使用前需要注意一点,这个插件必须放在Assets的第一层目录,这涉及到一些插件自带工具的路径问题。
这个插件的核心就是一个预制体,VRPanoramaCamera
这里写图片描述
想要渲染出正常的VR全景视频,需要注意VRCapture这个脚本的一些属性
(1)Capture Type:渲染的类型,我们需要选择最后一个EquidistantMono
(2)视频的分辨率设置
这里写图片描述
(3)Fps设置
这里写图片描述
(4)设置渲染的时长,这边和你设置的fps有关,如果是25fps那,这边就是25帧标识渲染1S
这里写图片描述
(5)这个是选择渲染视频还是音频,需要分开渲染,当然你也可以为你的视频进行后期配音也是可以的。
这里写图片描述
设置好这个脚本的参数,点击运行就可以开始渲染你的VR视频了,最后会渲染出一大堆的图片,一帧一张,存放在项目的跟目录位置,最下面的就是你的VR视频了。
这里写图片描述

总结语

这个教程其实就是多个工具插件的使用合集,虽说能够快速制作出一个VR全景视频,当真正想制作出优秀的作品,还是需要做很多的工作,如模型的细节、动画的类型、脚本控制流程的运行以及配音什么的,都是很重要的。这个教程只是抛砖引玉,希望有更多有兴趣的人可以加入到VR开发的行业中,为虚拟现实提供更多内容,同时也促进这个行业的良性发展。
咳咳!以上都是废话,好了,教程到此为止。还有什么疑问的地方可以留言,我有看到就会回复,谢谢。
最后放上一个我花了一天时间(建模,录音,选材,脚本什么地)做的一个demo视频的地址,因为选择的是最低画质(我电脑差点炸了,渣电脑渲染不起啊),而且最后合并视频和音频的时候没处理好,导致不同步,就将就看着吧。
http://pan.baidu.com/s/1eR8up3c
还有我控制流程的一个脚本,写的有点渣,纯粹为了实现而实现的,当做参考吧,制作动画的话感觉应该以时间线为事件的基准,嗯,我是这么认为的。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DanceManController : MonoBehaviour {


    public AudioSource BgmSource;
    public Transform DanceManAim;
    public float MoveSpeed = 0.5f;
    public float RotateSpeed = 0.5f;
    public float WaitTime = 5.0f;
    //Voice
    public AudioClip Voice01;
    public AudioClip Voice02;
    public AudioClip Voice03;
    public AudioClip Voice04;
    public AudioClip Bgm01;
    public AudioClip Bgm02;
    public AudioClip Bgm03;

    private Animator _animator;
    private GameObject _player;
    private Transform _danceManTransform;
    private AudioSource _audioSource;

    private bool _isWalk = false;
    private bool _isRotate = false;
    private float _bmgVolume = 0.15f;

    void Awake() {
        _animator = GetComponent<Animator>();
        _audioSource = GetComponent<AudioSource>();
        _player = GameObject.FindGameObjectWithTag("Player") as GameObject;
        _danceManTransform = transform;
    }
    void Start () {
        StartCoroutine("MoveMan");
        PlayAudio(Voice01);
        PlayBGM(Bgm01, _bmgVolume);
    }

    void Update () {
        if (_isWalk) {
            if (Vector3.Distance(_danceManTransform.localPosition, DanceManAim.localPosition) > 0.05f)
            {
                _animator.SetBool("Walk", true);
                _danceManTransform.localPosition += (DanceManAim.localPosition - _danceManTransform.localPosition).normalized * MoveSpeed * Time.deltaTime;
            }
            else {
                OnManIdle();
            }
        }
        if (_isRotate) {
            if (_danceManTransform.localEulerAngles.y < 180.0f)
            {
                _danceManTransform.Rotate(new Vector3(0, RotateSpeed, 0));
            }
            else {
                _isRotate = false;
                PlayAudio(Voice02);
                StartCoroutine("Dance01");
            }
        }
    }

    IEnumerator MoveMan() {
        yield return new WaitForSecondsRealtime(WaitTime);
        _isWalk = true;
        yield return 0;
    }

    IEnumerator Dance01() {
        yield return new WaitForSecondsRealtime(16.0f);
        PlayBGM(Bgm02, _bmgVolume);
        _animator.SetBool("Dance01", true);
        yield return 0;
    }
    IEnumerator Dance02()
    {
        yield return new WaitForSecondsRealtime(15.0f);
        PlayBGM(Bgm03, _bmgVolume);
        _animator.SetBool("Dance02", true);
        yield return 0;
    }
    IEnumerator EndVoice()
    {
        Debug.Log("结束语");
        yield return new WaitForSecondsRealtime(33.0f);
        BgmSource.volume = _bmgVolume;
        _audioSource.Stop();
        yield return 0;
    }

    public void OnManIdle()
    {
        _isWalk = false;
        _animator.SetBool("Walk", false);
        _isRotate = true;
    }

    public void PlayAudio(AudioClip clip) {
        _audioSource.volume = 1.0f;
        _audioSource.clip = clip;
        _audioSource.Play();
    }
    public void PlayBGM(AudioClip clip,float volume)
    {
        BgmSource.volume = volume;
        BgmSource.clip = clip;
        BgmSource.Play();
    }

    private int _dance01Size = 0;//Dance01的播放次数,三遍停止
    private bool _endVoice = false;//是否播放结束音

    public void OnDanceOver(int index) {
        if (index == 1) {
            if (_dance01Size == 2)
            {
                BgmSource.Stop();
                _animator.SetBool("Dance01", false);
                PlayAudio(Voice03);
                StartCoroutine("Dance02");
            }
            else {
                _dance01Size++;
            }
        }
        if (index == 2 && !_endVoice)
        {
            //_endVoice = true;
            //_bgmSource.volume = 0.05f;
            //PlayAudio(Voice04);
            //StartCoroutine("EndVoice");
        }
    }
}
2019-04-28 02:05:20 weixin_40754097 阅读数 413
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    12992 人正在学习 去看看 宋晓波

在许多漫游场景中,我们可能会遇到需要小地图的情况,这是为了进行重要地点标识以及指引方向。同样在VR中漫游中,如何处理方向导航仍然成为一个问题,这里给出一种将3D游戏中的小地图移植到VR相机中的思路。
以下是具体制作过程:

一、制作3D游戏的小地图:

1、首先创建一个简单的场景,使得我们在小地图中有物体可以观察。
场景中具体包括一个第一人称的控件和四个不同形状的物块(染成不同颜色仅仅是为了区分)。
在这里插入图片描述
导入第一人称控件的方法:选中Assets,右键选中Import Package,选择Characters,然后可以看到Standard Assets中有一个Characters文件夹,找到Prefabs中的RigidBodyFPSController(以下简称Controller)拖入场景即可,可以看到Controller自带一个Camera。
在这里插入图片描述
同时给它添加一个Quad,调整参数使它位于Controller的正上方,模拟小地图中主角的图标,同样染一个其他颜色以作区分。
在这里插入图片描述
添加方法:选中Controller,右键,选中3D Object,即可看到Quad。
2、创建3D下的小地图视角。
在这里插入图片描述
新建一个Camera,命名为Camera_Map以作区分,把Projection改成Orthography(正视投影),将它调整位于场景上方,大小正好可以包住场景,至此,可以在右下角的相机预览中看到小地图的雏形。
3、更改小地图形状。
新建一个Image和RawImage,其中RawImage是Image的子物体,两者位置重合,将Image命名为Image_Mask,用作遮罩层。
导入一张事先准备好的圆形图片mask_circle.png,用作遮罩层形状。
在这里插入图片描述
将Texture Type改为Sprite(2D and UI),点击Apply。
在这里插入图片描述
给Image_Mask添加一个Mask的组件,将mask_circle拖入Source Image中,即可看到效果:
在这里插入图片描述
在这里插入图片描述
4、将小地图视角投到画布上去。
新建一个Render Texture,选中Assets,右键,create选中Render Texture,命名为Render_tex,将Render_tex分别拖入Camera_Map中的Target Texture和RawImage中的Texture,即可看到中央的圆形小地图。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
到这一步3D视角下的小地图已经制作完成,只要将它放在画布的右上左上角就可以投入使用。

二、将小地图移植到VR中:

1、更改相机类型。
这是区分普通3D游戏和VR游戏最基本的一步,只有换成VR相机后,才能在头盔中观察到场景。这里我们将Controller向前的Camera删掉,重新添加进VR相机,只需将Steam VR包中的CameraRig直接拖入。
在这里插入图片描述
这里有一个细节,需要将Controller的控制脚本改成对应的Camera(eye),否则在后续移动时,方位可能会出错,有点“找不着北”。
在这里插入图片描述
2、更改画布类型。
然后将Canvas的Render Mode改成World Space,然后将Event Camera设置为CameraRig中的Camera(eye),这样才能在VR相机中观察到Canvas。
在这里插入图片描述
3、将画布附在手柄上。
最后一步将Canvas设置成VR手柄的子物体,可以跟随移动,同样调整Canvas和Image大小以及位置到合适为止。
在这里插入图片描述
4、为小地图添加“收起”和“打开”的控制。
在漫游时,并不是每时每刻都需要小地图的导航,有些时候小地图的存在反而遮挡了视线,影响漫游效果,所以很有必要让小地图在需要时出现,不需要时就隐藏起来。
在控制VR相机移动的脚本中加入以下代码:
在这里插入图片描述
这里的设定是利用扳机控制地图的隐藏和出现,当然你也可以使用其他交互方式。
在这里插入图片描述

三、效果。

最后的效果就是扣动扳机,屏幕中央出现小地图,再次扣动扳机,小地图消失。同时小地图上会显示“自己”与其他物体的相对距离,可以看到“自己”在小地图上移动。
一些效果截图:
在这里插入图片描述

2017-05-13 14:57:04 a514335188 阅读数 813
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    12992 人正在学习 去看看 宋晓波

有关Unity3D在VR领域的优化措施


VR应用由于其特殊性,帧数是一个十分关键的部分。如果帧数不够高,那么体验VR的人很容易就会感到头晕。研究显示,VR应用要想达到较好的效果,并且不会让人在体验时感到生理上的不适,那么至少要达到90fps以上的帧率。所以对于我们的VR应用来说,做好优化是十分关键的一步,这不同于制作其他非VR应用。

这里列出几项对我们的项目有帮助的优化技巧。

静态批处理

在我们的场景中将会存在大量的静态模型物体,比如墙面,地面,桌椅,柱子等。这些物体在运行过程中将不会移动,那么我们可以将这些不移动的物体标记为static,那么Unity在构建场景时将会自动进行烘焙,从而减少DrawCall的次数,一定程度上提高帧数。

使用贴图集

有于每一个不同的材质会引发一次DrawCall,为了减少DrawCall的次数,我们需要减少场景中的材质数量。我们使用不同材质的原因往往是这些材质需要不同的贴图,那么只要这些材质使用的Shader是相同的话,我们就可以使用贴图集来为这些不同的贴图创建相同的材质。贴图集中包含了许多小的贴图,我们可以在材质中使用不同的Offset来指定不同的贴图。

使用Pro Draw call Optimizer Light来生成贴图集(这个是免费版本)。

使用异步场景切换

当我们需要从一个房间移动到另一个房间时,可以把它们放到不同的场景中,在移动时使用Application.LoadLevelAsync()来异步加载场景,这样可以节省内存资源。

使用LightProbe

为了使动态物体在烘培好的场景中受到比较好的光照效果,我们可以使用LightProbe来给场景中可能移动的物体添加光照效果。

脚本优化

使用事件来代替Update的逐帧检测,尽量避免使用Update方法,可以一定程度提高性能。
缓存一些资源文件,来避免在每次调用的时候动态加载。

    private static GameObject _prefab;
    private static GameObject prefab
    {
        get
        {
            if (_prefab == null) {
                _prefab = Resources.Load<GameObject>("OverlayUI/Hand");
            }
            return _prefab;
        }
    }

使用自己编写的MonoBase类来代替MonoBehaviour类,其中使用协程和委托来代替原invoke方法,提高易用性和安全性。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;

public abstract class MonoBase : MonoBehaviour {

    public void Invoke(ThreadStart task,float delay) {
        StartCoroutine(startInvoke(task, delay));
    }

    private Dictionary<string, bool> _invokeRepeatingIds;
    private Dictionary<string, bool> invokeRepeatingIds
    {
        get
        {
            if (_invokeRepeatingIds == null) {
                _invokeRepeatingIds = new Dictionary<string, bool>();
            }
            return _invokeRepeatingIds;
        }
    }

    public void InvokeRepeating(ThreadStart task, string id, float rate) {
        if (invokeRepeatingIds.ContainsKey(id)) {
            throw new Exception("start a repeat invoke with reduplicate id '" + id + "'.");
        }
        invokeRepeatingIds.Add(id, true);
        StartCoroutine(startInvokeRepeating(task, id, rate));
    }

    public void CancelInvokeRepeating(string id) {
        if (invokeRepeatingIds.ContainsKey(id)) {
            invokeRepeatingIds[id] = false;
        }else {
            throw new Exception("repeat invoke with id '" + id + "' not found.");
        }
    }

    private IEnumerator startInvoke(ThreadStart task,float delay) {
        yield return new WaitForSeconds(delay);
        task();
    }

    private IEnumerator startInvokeRepeating(ThreadStart task, string id, float rate) {
        while (invokeRepeatingIds[id]) {
            task();
            yield return new WaitForSeconds(rate);
        }
        invokeRepeatingIds.Remove(id);
    }
}
2019-05-16 17:54:30 weixin_43778515 阅读数 1251
  • unity3D-游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    12992 人正在学习 去看看 宋晓波

在Unity3D中制作VR全景视频、图片

1.搭建SteamVR的场景
如果不会可以点击链接:SteamVR环境搭建教程链接

2.首先在Sence中创建一个Sphere
在这里插入图片描述
注意sphere中Scale的Z一定要是负数,因为我们是在球的内部观看视频的。

3.创建一个SurfaceShader,右键Assets–>Create–>Shader–>SandardSurfaceShader。
在这里插入图片描述
4.将此文件双击打开
在这里插入图片描述
在LOD 200下面加入cull off命令,以此可以在球的内部看到内容物。最后将此文件拖到Sphere上。
在这里插入图片描述
4.创建Render Texture文件,右键Assets–>Create–>Render Texture。同时更改分辨率参数也就是Size,改为:4960X2160。
在这里插入图片描述
5.将此文件拖到我们刚才新建材质球的Albedo中。
在这里插入图片描述
6.这是sphere已经设置完了,我们只需要在Sphere中添加Video Player组建,并把视频拖入到Video Clip上即可。(图片的话直接将图片拖到球上即可。)
在这里插入图片描述
7.那么我们如何才能用VR观看呢
只需要在Project栏中搜索:Player,将其拖入Sphere中,即可带上VR眼睛体验全景视频了。
在这里插入图片描述
在这里插入图片描述

Unity3D+VR的实现

阅读数 514

没有更多推荐了,返回首页