【Unity3D】地面网格特效
1 前言
本文实现了地面网格特效,包含以下两种模式:
- 实时模式:网格线宽度和间距随相机的高度实时变化;
- 分段模式:将相机高度分段,网格线宽度和间距在每段中对应一个值。
本文完整资源见→Unity3D地面网格特效。
2 地面网格实现
SceneController.cs
using System;
using UnityEngine;
public class SceneController : MonoBehaviour {
private static SceneController instance; // 单例
private Action cameraChangedHandler; // 相机状态改变处理器
private Transform cam; // 相机
public static SceneController Instance() { // 获取实例
return instance;
}
public void AddHandler(Action handler) { // 添加处理器
cameraChangedHandler += handler;
}
private void Awake() {
instance = this;
cam = Camera.main.transform;
}
private void Update() { // 更新场景(Scroll: 缩放场景, Ctrl+Drag: 平移场景, Alt+Drag: 旋转场景)
float scroll = Input.GetAxis("Mouse ScrollWheel");
ScaleScene(scroll);
if ((Input.GetMouseButton(0))) {
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) {
float hor = Input.GetAxis("Mouse X");
float ver = Input.GetAxis("Mouse Y");
MoveScene(hor, ver);
}
if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) {
float hor = Input.GetAxis("Mouse X");
float ver = Input.GetAxis("Mouse Y");
RotateScene(hor, ver);
}
}
}
private void ScaleScene(float scroll) { // 缩放场景
if (Mathf.Abs(scroll) > Mathf.Epsilon) {
cam.position += cam.forward * scroll * 50;
cameraChangedHandler?.Invoke();
}
}
private void MoveScene(float hor, float ver) { // 平移场景
if (Mathf.Abs(hor) > Mathf.Epsilon || Mathf.Abs(ver) > Mathf.Epsilon) {
cam.position -= (cam.right * hor * 3 + cam.up * ver * 3);
cameraChangedHandler?.Invoke();
}
}
private void RotateScene(float hor, float ver) { // 旋转场景
if (Mathf.Abs(hor) > Mathf.Epsilon || Mathf.Abs(ver) > Mathf.Epsilon) {
cam.RotateAround(Vector3.zero, Vector3.up, hor * 3);
cam.RotateAround(Vector3.zero, -cam.right, ver * 3);
cameraChangedHandler?.Invoke();
}
}
}
说明:SceneController 脚本组件挂在相机对象上,这里旋转中心是固定的,如果想设置为随相机焦点自动变化,可以参考 缩放、平移、旋转场景。
GridPlane.cs
using UnityEngine;
public class GridPlane : MonoBehaviour {
public GridType gridType = GridType.REALTIME; // 网格类型
private const float lineGapFactor = 0.2f; // 线段间距因子(相机距离单位长度变化时线段间距的变化量)
private const float lineWidthFactor = 0.01f; // 线段宽度因子(相机距离单位长度变化时线段宽度的变化量)
private const int segmentFactor = 100; // 分段因子(每隔多远分一段)
private Transform cam; // 相机
private float camDist; // 相机距离
private float lineGap = 1; // 线段间距
private float lineWidth = 0.05f; // 线段宽度
private Vector4 planeCenter = Vector4.zero; // 地面中心
private Material material; // 网格材质
private void Start() {
SceneController.Instance().AddHandler(UpdateGrid);
cam = Camera.main.transform;
material = Resources.Load<Material>("GridPlaneMat");
material.SetVector("_PlaneCenter", planeCenter);
UpdateGrid();
}
private void UpdateGrid() { // 更新网格
camDist = Mathf.Abs(cam.position.y - planeCenter.y);
if (gridType == GridType.REALTIME) {
RealtimeUpdateGrid();
} else if (gridType == GridType.SEGMENTED) {
SegmentedUpdateGrid();
}
}
private void RealtimeUpdateGrid() { // 实时更新网格
lineGap = camDist * lineGapFactor;
lineWidth = camDist * lineWidthFactor;
UpdateMatProperties();
}
private void SegmentedUpdateGrid() { // 分段更新网格
int dist = (((int) camDist) / segmentFactor + 1) * segmentFactor;
lineGap = dist * lineGapFactor;
lineWidth = dist * lineWidthFactor;
UpdateMatProperties();
}
private void UpdateMatProperties() { // 更新材质属性
lineGap = Mathf.Max(lineGap, lineGapFactor);
lineWidth = Mathf.Max(lineWidth, lineWidthFactor);
material.SetFloat("_LineGap", lineGap);
material.SetFloat("_LineWidth", lineWidth);
}
}
public enum GridType { // 网格类型
REALTIME, // 实时模式(网格随相机高度实时变化)
SEGMENTED // 分段模式(网格随相机高度分段变化)
}
说明:GridPlane 脚本组件挂在地面对象上。
GridPlane.shader
Shader "MyShader/GridPlane" { // 路径上的节点移动特效
Properties {
_PlaneColor("Plane Color", Color) = (1, 1, 1, 1) // 地面颜色
_LineColor("Line Color", Color) = (1, 1, 1, 1) // 线条颜色
_LineGap("Line Gap", Int) = 1 // 线段间距
_LineWidth("Line Width", Range(0, 1)) = 0.1 // 线段宽度
_PlaneCenter("Plane Center", Vector) = (0, 0, 0, 0) // 地面中心
}
SubShader {
Pass {
cull off
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float4 _PlaneColor; // 地面颜色
float4 _LineColor; // 线条颜色
int _LineGap; // 线段间距
float _LineWidth; // 线段宽度
float4 _PlaneCenter; // 地面中心
struct v2f {
float4 pos : SV_POSITION; // 裁剪空间顶点坐标
float2 worldPos : TEXCOORD0; // 世界空间顶点坐标(只包含xz)
};
v2f vert(float4 vertex: POSITION) {
v2f o;
o.pos = UnityObjectToClipPos(vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, vertex)
o.worldPos = mul(unity_ObjectToWorld, vertex).xz; // 将模型空间顶点坐标变换到世界空间
return o;
}
fixed4 frag(v2f i) : SV_Target {
float2 vec = abs(i.worldPos - _PlaneCenter.xz);
float2 mod = fmod(vec, _LineGap);
float2 xz = min(mod, _LineGap - mod);
float dist = min(xz.x, xz.y);
float factor = 1 - smoothstep(0, _LineWidth, dist);
fixed4 color = lerp(_PlaneColor, _LineColor, factor);
return fixed4(color.xyz, 1);
}
ENDCG
}
}
}
说明:在 Assets 窗口新建 Resources 目录,接着在 Resources 目录下面创建材质,重命名为 GridPlaneMat,将 GridPlane.shader 与 GridPlaneMat 材质绑定。
3 运行效果
1)实时模式
2)分段模式
声明:本文转自【Unity3D】地面网格特效。
【Unity3D】地面网格特效的更多相关文章
- Unity3D 导航网格自动寻路(Navigation Mesh)
NavMesh(导航网格)是3D游戏世界中用于实现动态物体自动寻路的一种技术,将游戏中复杂的结构组织关系简化为带有一定信息的网格,在这些网格的基础上通过一系列的计算来实现自动寻路..导航时,只需要给导 ...
- unity3d 摄像机抖动特效
摄像机抖动特效 在须要的地方调用CameraShake.Shake()方法就能够
- Unity3D图像后处理特效——Depth of Field 3.4
Depth of Field 3.4 is a common postprocessing effect that simulates the properties of a camera lens. ...
- Unity3D特效-场景淡入淡出
最近公司开始搞Unity3D..整个游戏..特效需求还是比较多的.关于UI部分的特效淡入淡出.看网上用的方法都是用个黑东东遮挡然后设置alpha这么搞....本大神感觉非常的low.而且很渣.故奋笔疾 ...
- [Unity3D]Unity资料大全免费分享
都是网上找的连七八糟的资料了,整理好分享的,有学习资料,视频,源码,插件……等等 东西比较多,不是所有的都是你需要的,可以按 ctrl+F 来搜索你要的东西,如果有广告,不用理会,关掉就可以了,如 ...
- cocos2d-x 网格动画深入分析
转自:http://www.2cto.com/kf/201212/179828.html 在TestCpp中的EffectsTest示例中展示了一些屏幕特效,它是将屏幕划分为多个格子,并对这些格子进行 ...
- 24、Cocos2dx 3.0游戏开发找小三之网格动作:高炫酷的3D动作
重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/37596763 网格动作类似于动作特效,能够实现翻转. ...
- WebGL场景的两种地面构造方法
总述:大部分3D编程都涉及到地面元素,在场景中我们使用地面作为其他物体的承载基础,同时也用地面限制场景使用者的移动范围,还可以在通过设置地块的属性为场景的不同位置设置对应的计算规则.本文在WebGL平 ...
- Unity塔防游戏开发
Unity3D塔防开发流程 配置环境及场景搭建编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG More开发工具:Unity3D编辑器.Visual Studio编译器开发建议:了解Uni ...
- 手搓一个“七夕限定”,用3D Engine 5分钟实现烟花绽放效果
七夕来咯!又到了给重要的人送惊喜的时刻. 今年,除了将心意融入花和礼物,作为程序员,用自己的代码本事手搓一个技术感十足"七夕限定"惊喜,我觉得,这是不亚于车马慢时代手写信的古典主义 ...
随机推荐
- UPF - Power Intent Basic
Mainstream Low Power techniques Low Vth - 阈值电压比较低,翻转时间小,漏电流比较大,功耗大,速度快 High Vth - 阈值电压比较高,翻转时间长,漏电流比 ...
- Linux 查看office文件及pdf文件
1.查看pdf文件 evince PdfFile_name 查看office文件 openoffice.org 文件名 & // 打开或者编辑.doc.odt等文本文档命令 openoffic ...
- 【TouchGFX】代码结构
生成代码与用户代码 代码结构图示如下 据上图显示代码结构分为三层 引擎 这是TouchGFX提供的标准类,作为生成类的基类 生成 这是touchgfx designer生成的类,作为用户类的基类,这部 ...
- CSS : 使用 z-index 的前提
使用 z-index 前 , 需要将元素 定位设置为 position : relative .
- [转帖]TiDB BR 备份至 MinIO S3 实战
https://tidb.net/blog/3a31d41d#3.%E9%83%A8%E7%BD%B2%20MinIO%20S3%20%E5%8F%8A%E5%A4%87%E4%BB%BD%E6%81 ...
- [转帖]dd 自动压测与结果解析脚本
测试串行.并发.读.写 4类操作,每类操作又可以指定各种bs及count值,循环压测.每种场景一般执行3次,取平均值. 一. 串行写 #!/bin/sh bs_list=(256k 1024k 10M ...
- vue如何在render函数中使用判断(2)
h函数的三个参数 第一个参数是必须的. 类型:{String | Object | Function} 一个 HTML 标签名.一个组件.一个异步组件.或一个函数式组件. 是要渲染的html标签. 第 ...
- js 闭包详解一
闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面就是我的学习笔记,对于Javascript初学者应该是很有用的. 一.变量的作用域 要理解 ...
- TienChin 活动管理-搜索活动
ActivityController @PreAuthorize("hasPermission('tienchin:activity:list')") @GetMapping(&q ...
- 13.4 DirectX内部劫持绘制
相对于外部绘图技术的不稳定性,内部绘制则显得更加流程与稳定,在Dx9环境中,函数EndScene是在绘制3D场景后,用于完成将最终的图像渲染到屏幕的一系列操作的函数.它会将缓冲区中的图像清空,设置视口 ...