文章目录

  • 一、前言
  • 二、实现思路
  • 三、具体实现过程
    • 1、场景建模
    • 2、一些小物件模型
    • 3、制作RenderTexture
    • 4、制作小场景
    • 5、小场景摄像机渲染到RenderTexture
    • 6、制作材质球
    • 7、shader实现透视立体效果
    • 8、触发机关动画
    • 9、GamePlay脚本
    • 10、运行测试
  • 四、工程源码
  • 五、完毕

一、前言

嗨,大家好,我是新发。
最近去面大厂了,一直在充电,然后,前天,有同学私信我,问我笼中窥梦的效果用Unity如何实现,

如下是笼中窥梦的游戏画面

不错,然后,我就用Unity实现了一下比较基础的效果,如下,



下面我就来讲一下我的制作思路和过程吧~

二、实现思路

我先讲一下实现思路。
需求一:
在一个盒子的每个面上可以看到多个场景的画面,并且具有透视效果
思路:
在盒子的每个面上通过RenderTexture来显示画面,每张RenderTexture对应一个小场景的摄像机的渲染画面,然后RenderTexture的材质球的shader需要实现3D透视效果

需求二:
盒子在某个视觉角度下,多个场景之间的物体会在视觉上联系起来,触发机关
思路:
触发条件可以理解为主摄像机的一个角度和距离,党摄像机与这个条件很接近时就触发多场景机关动画

三、具体实现过程

1、场景建模

我用Blender简单制作了场景模型,主要是盒子的框架和面,

2、一些小物件模型

我之前在AssetStore上买过一个Low Poly模型包,

里面有很多小零件模型和低模人形模型,

喜欢Low Poly风格的同学可自行去AssetStore上下载:https://assetstore.unity.com/packages/3d/props/exterior/polygon-prototype-low-poly-3d-art-by-synty-137126

3、制作RenderTexture

Project视图中右键菜单,点击Create / Render Texture即可创建RenderTexture

盒子的前后左右,再加上顶部,总共5个面,需要5RenderTexture,如下

4、制作小场景

事实上,我是在一个Unity场景中制作了多个小场景,每个小场景都带一个独立摄像机进行渲染,他们相互之间在空间距离上错开,如下


小场景一:

小场景二:

小场景三:

小场景四:

小场景五:

5、小场景摄像机渲染到RenderTexture

把刚刚我们创建的5RenderTexture分别赋值给小场景中的摄像机的TargetTexture,如下,

这样子,摄像机就不会直接渲染到屏幕上了,而会渲染到我们设置的这张RenderTexture上,如下,

6、制作材质球

盒子的面是网格(Mesh),网格要渲染需要材质球(Material),我们分别创建5个材质球,如下,

把材质球分别赋值给盒子的面,如下

7、shader实现透视立体效果

如果上面的材质球使用普通的Unlit/Texture作为shader,效果是这个鬼样,从侧面看的时候,它失去了立体效果,你可以想象你从侧面看电视机的那个样子,而实际上,我们需要的是从侧面看窗外的那种效果,

这里我的思路是先在顶点着色器阶段计算齐次裁剪坐标系下的屏幕坐标,缓存起来,然后到片元着色器阶段的时候先去齐次(即除以w分量),然后换算成uv,再对纹理进行采样,这样子得出来的结果就等价于小场景的画面是平铺在整个屏幕上的,然后经过了盒子网格的裁切,就有了那种透过窗户看世界的效果了,我写的shader代码如下,我写了注释,比较简单,大家如果有shader基础的话应该能看懂,

Shader "linxinfa/BoxWorld"
{Properties{_MainTex ("Texture", 2D) = "white" {}// 屏幕高与宽的比值,默认720/1280,即0.5625_ScreenHW ("ScreenHW", Float) = 0.5625}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;};struct v2f{float4 vertex : SV_POSITION;float4 screenPos : TEXCOORD1;};sampler2D _MainTex;float _ScreenHW;v2f vert (appdata v){v2f o;// 把顶点坐标从局部坐标转化到齐次裁剪空间o.vertex = UnityObjectToClipPos(v.vertex);// 计算屏幕坐标,注意这时的坐标是齐次空间下的屏幕坐标o.screenPos = ComputeScreenPos(o.vertex);return o;}fixed4 frag (v2f i) : SV_Target{// 去齐次float2 screenPos = i.screenPos.xy / i.screenPos.w;// 根据屏幕坐标来算uvfloat2 uv = screenPos.xy * float2(1, _ScreenHW);// 采样float4 col = tex2D(_MainTex, uv);return col;}ENDCG}}
}

把材质球的shader设置为linxinfa/BoxWorld,如下

现在就是透过窗户看世界的效果了,

8、触发机关动画

机关条件就是主摄像机的某个坐标和角度,这个我们可以做一个配置表,简单的机关可以做成一个动画,触发了机关就播放动画即可,当然也有复杂一点的机关,可以根据具体需求去实现。
我做的机关动画状态机如下,

其中level1动画如下,

9、GamePlay脚本

最后就是写C#脚本来驱动游戏了,我只写了一个脚本GamePlay.cs
脚本的逻辑就是根据鼠标控制摄像头的移动和旋转,判断主摄像头的坐标和角度是否达到触发机关的条件,然后触发机关,播放机关动画,逻辑不复杂,可以看我写的注释,代码如下,

using System;
using System.Collections;
using UnityEngine;public class GamePlay : MonoBehaviour
{// 小场景摄像机[SerializeField] private Transform[] littleSceneCams;// 小场景中心(相机围绕次中心旋转)[SerializeField] private Transform[] littleSceneCenters;// 盒子[SerializeField] private Transform box;// 主摄像机[SerializeField] private Transform camMain;private float m_deltaX;private float m_deltaY;[SerializeField] private float m_rotateSpeed;[SerializeField] private Vector3 lookOffset = new Vector3(0, 1, 0);[SerializeField] private Vector3 lookFaceOffset = new Vector3(0, -0.5f, 0);[SerializeField] private float moveYSpeed = 0.05f;[SerializeField] private float moveZSpeed = 0.1f;private int level = 0;[SerializeField] private Animator ani;private bool canRotate = true;void Update(){if (!canRotate || !Input.GetMouseButton(0)) return;m_deltaX = Input.GetAxis("Mouse X");m_deltaY = Input.GetAxis("Mouse Y");if (m_deltaX == 0 && m_deltaY == 0){return;}// 左右旋转盒子box.Rotate(Vector3.up, -m_deltaX);// 左右旋转每个小场景for (int i = 0, len = littleSceneCenters.Length; i < len; ++i){littleSceneCenters[i].Rotate(Vector3.up, -m_deltaX * m_rotateSpeed);}// 移动主摄像机camMain.localPosition += new Vector3(0, m_deltaY * moveYSpeed, m_deltaY * moveZSpeed);// 限制主摄像机的移动区域if (LimitCamPos()) return;// 移动小场景摄像机for (int i = 0, len = littleSceneCams.Length; i < len; ++i){var cam = littleSceneCams[i];cam.localPosition += new Vector3(0, m_deltaY * moveYSpeed, m_deltaY * moveZSpeed);cam.LookAt(littleSceneCenters[i].position + lookFaceOffset);}// 检查是否触发了机关CheckLevelCondition();}// 限制主摄像机的移动区域 private bool LimitCamPos(){var curPos = camMain.position;var isOut = false;if (curPos.z < -5f){curPos.z = -5f; isOut = true;}if (curPos.z > 1.2f){curPos.z = 1.2f; isOut = true;}if (curPos.y > 4.8f){curPos.y = 4.8f; isOut = true;}if (curPos.y < 1.3f){curPos.y = 1.3f; isOut = true;}camMain.position = curPos;camMain.LookAt(box.position + lookOffset);return isOut;}/// <summary>/// 检测是否触发了机关/// </summary>private void CheckLevelCondition(){if (Vector3.Distance(camMain.position, new Vector3(0, 2.242501f, -3.405001f)) <= 0.5f &&Math.Abs(camMain.localEulerAngles.x - 20.047f) <= 2 &&0 == level){Debug.Log("触发了机关");StartCoroutine(NextLevel());}}// 下一关private IEnumerator NextLevel(){canRotate = false;++level;ani.SetInteger("level", level);yield return null;ani.SetInteger("level", 0);// 四秒后才允许旋转yield return new WaitForSeconds(4);canRotate = true;}
}

在场景中创建一个空物体,重命名为GamePlay,并挂上GamePlay脚本,设置成员变量,如下,

10、运行测试

最终运行Unity,测试效果如下,



四、工程源码

本文Demo工程我已上传到CODE CHINA,感兴趣的同学可自行下载学习,
地址:https://codechina.csdn.net/linxinfa/UnityVisionDiffBox
注意:我使用的Unity版本为2021.1.7f1c1,如果你使用的Unity版本与我不同,可能打开工程时会有兼容问题

五、完毕

好啦,就到这里吧~
我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信~

【游戏开发实战】教你在Unity中实现笼中窥梦的效果(RenderTexture | 视觉差| 多相机 | 渲染 | shader | 多场景)相关推荐

  1. 三维游戏开发实战--狙击僵尸(unity开发)

    1.需求分析 地形设计,对游戏地形进行设计比如挖坑造河等. 场景设计,种树.种草.摆放房屋建筑等. 第一人称视角实现,WASD前后左右移动,空格键进行跳跃,按左Shift进行加速. 敌人的简单制作,敌 ...

  2. 【游戏开发实战】教你在Unity中实现模型消融化为灰烬飘散的效果(ShaderGraph | 消融 | 粒子系统 | 特效)

    文章目录 一.前言 二.ShaderGraph环境准备 三.模型准备:原神角色模型 四.实现思路 1.效果一的实现思路 2.效果二的实现思路 五.ShaderGraph具体实现 1.效果一 1.1.创 ...

  3. 【游戏开发实战】Unity手游第一人称视角,双摇杆控制,FPS射击游戏Demo(教程 | 含Demo工程源码)

    文章目录 一.前言 二.实现方案 1.无主之地,第一人称视角 2.我之前做的摇杆控制 3.第一人称视角 + 摇杆控制 三.开始实战 1.资源获取:Unity AssetStore 2.Low Poly ...

  4. 【游戏开发实战】用Go语言写一个服务器,实现与Unity客户端通信(Golang | Unity | Socket | 通信 | 教程 | 附工程源码)

    文章目录 一.前言 二.Go开发环境搭建(Windows系统) 1.安装Go命令行工具 2.创建GoWorkspace目录 3.配置GOPATH环境变量 4.配置GOPROXY代理 5.安装VSCod ...

  5. 《Unity 5.x游戏开发实战》一1.9 添加一个水平面

    本节书摘来异步社区<Unity 5.x游戏开发实战>一书中的第1章,第1.9节,作者: Alan Thorn 译者: 李华峰 责编: 胡俊英,更多章节内容可以访问云栖社区"异步社 ...

  6. 【Unity】动作游戏开发实战详细分析-07-连续技与组合技功能设计

    [Unity]动作游戏开发实战详细分析-07-连续技与组合技功能设计 基本思路 在一些动作游戏中,存在着连续技这一功能,具体来说就是连续按下规定的按键会触发能力的功能,或者是长按触发等等. 实现解析 ...

  7. 《Unity 2D与3D手机游戏开发实战》简介

    #好书推荐##好书奇遇季#<Unity 2D与3D手机游戏开发实战>,京东当当天猫都有发售.彩色印制,定价89元,网店打折销售更便宜.本书配套源码.PPT课件,适合Unity游戏开发初学者 ...

  8. 【Unity】动作游戏开发实战详细分析-16-敌人AI设计

    [Unity]动作游戏开发实战详细分析-16-敌人AI设计 基本思想 本文来实现简单的敌人AI,使用协程来开发AI.如果想要使用行为树插件可自行学习使用. 代码实现 敌人的目标信息结构 用于存储所有的 ...

  9. 【游戏开发实战】Unity从零开发多人视频聊天功能,无聊了就和自己视频聊天(附源码 | Mirror | 多人视频 | 详细教程)

    文章目录 一.前言 二.思考问题与解决方案 1.思考问题 2.解决方案 2.1.Unity中如何开启摄像头并对图像进行采样 2.2.图像如何中转给其他客户端 2.3.如何实现清晰度切换 2.4.客户端 ...

  10. 【Unity】动作游戏开发实战详细分析-06-技能系统设计

    [Unity]动作游戏开发实战详细分析-06-技能系统设计 基本思想 不同的技能可以设计为技能模版,当角色释放技能时,会通过模版ID将它进行实例化,这个实例技能类可以是一个挂载的MonoBehavio ...

最新文章

  1. java培训教程分享:Java编写软件代码自动提示功能
  2. 投票 | RONG奖学金最佳人气奖评选活动开始啦!
  3. 【Android 安全】DEX 加密 ( Proguard 混淆 | 混淆后的报错信息 | Proguard 混淆映射文件 mapping.txt )
  4. linux 网络设置
  5. python中系列的含义_python中四种组合数据类型的含义、声明、增删改查,遍历
  6. 操作系统开发系列—13.g.操作系统的系统调用 ●
  7. python中get函数作用_python get函数有什么作用?示例解析
  8. 多位博士毕业去了三四流高校,现在怎么样了?
  9. linux动态库查找路径以及依赖关系梳理
  10. stm32运行linux,新出的STM32F750成功运行Linux
  11. 有趣的编程代码_iPad amp; Mac 编程游戏推荐
  12. android 触摸事件 控制,Android笔记:触摸事件的分析与总结----TouchEvent处理机制
  13. HTML中的行内元素和框元素详解
  14. redis 性能监控和排查
  15. 按首字母排序(汉字、英文、数字)简单实现
  16. 1230v3配服务器内存性能提升,E3 1230 V3四核3.7G睿频福利教程及评测
  17. 百度地图根据经纬度获取实际地理位置Api接口
  18. Python实现psf2otf
  19. 王道程序员求职宝典 pdf
  20. java面向对象程序设计的六大基本原则

热门文章

  1. Unity 安装个人免费版步骤详解
  2. python实现 模糊C均值聚类算法(Fuzzy-C-Means)-基于iris数据集
  3. (课程笔记1)ENVI裁剪出Landsat8全色波段和其他波段的同一区域数据
  4. threejs特效:边缘暗角shader
  5. python 典型相关分析_CCA典型关联分析原理与Python案例
  6. DOSBOX的安装及ASM文件的编译
  7. 编译报错:无法打开包括文件 No such file or directory
  8. 专利挖掘和撰写(京东技术资质申请和创造专利挖掘)
  9. Arduino实现语音实时播报当前温湿度
  10. 基于LM2733升压电路设计