Unity&Shader案例篇—声纳光波效果
来源:互联网 发布:sql server报价 编辑:程序博客网 时间:2024/05/06 04:21
原文:http://www.manew.com/thread-98405-1-1.html
一、前言
睡前再来一篇吧,明天周一了,加油吧!废话不多说了,先上效果图如图所示,前面两个的效果图是两种模式下的:
不同效果,最后一章图片是在其中一种模式下,场景进行了精心布置后的效果图。
看效果图会不自觉的认为实现这个效果是不是要在场景中的物体中进行绘制,如果真是要这样做的话那是在是太耗性能了(毕竟都工作了,本人毕业了就不想在搞那些不实用的)。
其实,这个是通过控制摄像机的最后渲染来实现的效果的,后面我会给出这个案例的工程文件下载地址。
读者在运行模式的Scene视图里将看到场景的物体(立方体)并没有被额外渲染,有了这个思路对于后面理解代码的实现原理会很有帮助。
二、原理
1、Shader部分—光照计算
这里用到的光照计算都比较简单,光照模式我使用了最简单的漫反射模式,代码如下:
//光照计算float4x4 modelMatrix = _Object2World;float4x4 modelMatrixInverse = _World2Object;float3 normalDirection = normalize( mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection));output.col = float4(diffuseReflection, 1.0);output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
如图所示为漫反射的示意图,它的计算公式为:
2、Shader部分—声纳光波的计算
Shader代码如下:
//声纳光波计算#ifdef SONAR_DIRECTIONAL float w = dot(output.pos.xyz, _SonarWaveVector);#else float w = length(output.pos.xyz - _SonarWaveVector);#endif // Moving wave. w -= _Time.y * _SonarWaveParams.w; // Get modulo (w % params.z / params.z) w /= _SonarWaveParams.z; w = w - floor(w); // Make the gradient steeper. float p = _SonarWaveParams.y; w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5; // Amplify. w *= _SonarWaveParams.x; fixed3 col = _SonarWaveColor * w + _SonarAddColor;
代码中使用了预编译命令,是考虑了前面说的效果图中的两种模式的切换。为此,还必须在前面添加预编译命令
#pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL
这个命令的大概意思就是说可以将这两个模式的Shader一起编译,然后就可以在C#代码里通过
Shader.DisableKeyword("SONAR_SPHERICAL");
或者
Shader.EnableKeyword("SONAR_SPHERICAL");
来进行切换。
完整顶点片段Shader代码如下:
Shader "CgInUnity/SonarFxVF"{ Properties { _SonarBaseColor("Base Color", Color) = (0.1, 0.1, 0.1, 0) _SonarWaveColor("Wave Color", Color) = (1.0, 0.1, 0.1, 0) _SonarWaveParams("Wave Params", Vector) = (1, 20, 20, 10) _SonarWaveVector("Wave Vector", Vector) = (0, 0, 1, 0) _SonarAddColor("Add Color", Color) = (0, 0, 0, 0) } SubShader { Tags{ "LightMode" = "ForwardBase" } // make sure that all uniforms are correctly set Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL #include "UnityCG.cginc" struct vertexInput { float4 vertex : POSITION; float3 normal:NORMAL; }; struct vertexOutput { float4 pos:SV_POSITION; float4 col:COLOR; }; float3 _SonarBaseColor; float3 _SonarWaveColor; float4 _SonarWaveParams; // Amp, Exp, Interval, Speed float3 _SonarWaveVector; float3 _SonarAddColor; uniform float4 _LightColor0; vertexOutput vert (vertexInput input) { vertexOutput output; //光照计算 float4x4 modelMatrix = _Object2World; float4x4 modelMatrixInverse = _World2Object; float3 normalDirection = normalize( mul(float4(input.normal, 0.0), modelMatrixInverse).xyz); float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz); float3 diffuseReflection = _LightColor0.rgb * max(0.0, dot(normalDirection, lightDirection)); output.col = float4(diffuseReflection, 1.0); output.pos = mul(UNITY_MATRIX_MVP, input.vertex); //声纳光波计算#ifdef SONAR_DIRECTIONAL float w = dot(output.pos.xyz, _SonarWaveVector);#else float w = length(output.pos.xyz - _SonarWaveVector);#endif // Moving wave. w -= _Time.y * _SonarWaveParams.w; // Get modulo (w % params.z / params.z) w /= _SonarWaveParams.z; w = w - floor(w); // Make the gradient steeper. float p = _SonarWaveParams.y; w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5; // Amplify. w *= _SonarWaveParams.x; fixed3 col = _SonarWaveColor * w + _SonarAddColor; output.col += float4(col, 1); return output; } float4 frag (vertexOutput input) : COLOR { return input.col; } ENDCG } }}
喜欢用简洁的Surface Shader代码的童鞋可以用如下代码替换:
Shader "CgInUnity/SonarFxSurf"{ Properties { _SonarBaseColor ("Base Color", Color) = (0.1, 0.1, 0.1, 0) _SonarWaveColor ("Wave Color", Color) = (1.0, 0.1, 0.1, 0) _SonarWaveParams ("Wave Params", Vector) = (1, 20, 20, 10) _SonarWaveVector ("Wave Vector", Vector) = (0, 0, 1, 0) _SonarAddColor ("Add Color", Color) = (0, 0, 0, 0) } SubShader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Lambert #pragma multi_compile SONAR_DIRECTIONAL SONAR_SPHERICAL struct Input { float3 worldPos; }; float3 _SonarBaseColor; float3 _SonarWaveColor; float4 _SonarWaveParams; // Amp, Exp, Interval, Speed float3 _SonarWaveVector; float3 _SonarAddColor; void surf(Input IN, inout SurfaceOutput o) {#ifdef SONAR_DIRECTIONAL float w = dot(IN.worldPos, _SonarWaveVector);#else float w = length(IN.worldPos - _SonarWaveVector);#endif // Moving wave. w -= _Time.y * _SonarWaveParams.w; // Get modulo (w % params.z / params.z) w /= _SonarWaveParams.z; w = w - floor(w); // Make the gradient steeper. float p = _SonarWaveParams.y; w = (pow(w, p) + pow(1 - w, p * 4)) * 0.5; // Amplify. w *= _SonarWaveParams.x; // Apply to the surface. o.Albedo = _SonarBaseColor; o.Emission = _SonarWaveColor * w + _SonarAddColor; } ENDCG } Fallback "Diffuse"}
这个代码看似简单,但是对于处在学习基础原理阶段的童鞋,我的建议还是多动手写写顶点片段Shader,实现简单的光照模式、顶点变换等等对于学习Shader会非常有帮助的。
3、C#脚本部分
脚本部分最关键的就是使用上述的Shader去渲染摄像机,这个需要通过如下的代码来实现吗,这段代码的意思是替换成这个Shader来渲染摄像机
GetComponent<Camera>().SetReplacementShader(shader, null);
其他的功能就是出传递参数给Shader来实现最终随时间变换的效果,完整的代码如下:
using UnityEngine;[RequireComponent(typeof(Camera))]public class SonarFxControl : MonoBehaviour{ // 声纳的模式 public enum SonarMode { Directional, Spherical } [SerializeField] SonarMode _mode = SonarMode.Directional; public SonarMode mode { get { return _mode; } set { _mode = value; } } // 声纳波的方向(仅仅在Directional模式下) [SerializeField] Vector3 _direction = Vector3.forward; public Vector3 direction { get { return _direction; } set { _direction = value; } } // 声纳波区域(仅仅在Spherical模式下) [SerializeField] Vector3 _origin = Vector3.zero; public Vector3 origin { get { return _origin; } set { _origin = value; } } // 背景颜色(Surfface Shader下有用) [SerializeField] Color _baseColor = new Color(0.2f, 0.2f, 0.2f, 0); public Color baseColor { get { return _baseColor; } set { _baseColor = value; } } // 声纳波的颜色 [SerializeField] Color _waveColor = new Color(1.0f, 0.2f, 0.2f, 0); public Color waveColor { get { return _waveColor; } set { _waveColor = value; } } // 波的高度\振幅 [SerializeField] float _waveAmplitude = 2.0f; public float waveAmplitude { get { return _waveAmplitude; } set { _waveAmplitude = value; } } // 波的颜色指数 [SerializeField] float _waveExponent = 22.0f; public float waveExponent { get { return _waveExponent; } set { _waveExponent = value; } } // 波的时间间隔 [SerializeField] float _waveInterval = 20.0f; public float waveInterval { get { return _waveInterval; } set { _waveInterval = value; } } // 波的速度 [SerializeField] float _waveSpeed = 10.0f; public float waveSpeed { get { return _waveSpeed; } set { _waveSpeed = value; } } // 额外的颜色 [SerializeField] Color _addColor = Color.black; public Color addColor { get { return _addColor; } set { _addColor = value; } } [SerializeField] Shader shader; int baseColorID; int waveColorID; int waveParamsID; int waveVectorID; int addColorID; void Awake() { baseColorID = Shader.PropertyToID("_SonarBaseColor"); waveColorID = Shader.PropertyToID("_SonarWaveColor"); waveParamsID = Shader.PropertyToID("_SonarWaveParams"); waveVectorID = Shader.PropertyToID("_SonarWaveVector"); addColorID = Shader.PropertyToID("_SonarAddColor"); } void OnEnable() { GetComponent<Camera>().SetReplacementShader(shader, null); Update(); } void OnDisable() { GetComponent<Camera>().ResetReplacementShader(); } void Update() { Shader.SetGlobalColor(baseColorID, _baseColor); Shader.SetGlobalColor(waveColorID, _waveColor); Shader.SetGlobalColor(addColorID, _addColor); var param = new Vector4(_waveAmplitude, _waveExponent, _waveInterval, _waveSpeed); Shader.SetGlobalVector(waveParamsID, param); if (_mode == SonarMode.Directional) { Shader.DisableKeyword("SONAR_SPHERICAL"); Shader.SetGlobalVector(waveVectorID, _direction.normalized); } else { Shader.EnableKeyword("SONAR_SPHERICAL"); Shader.SetGlobalVector(waveVectorID, _origin); } }}
三、结语
最后可以看看这种方式实现的声纳波效果的性能消耗如何,我们可以在运行的时候打开state看到如图所示的统计图,瞬间有没有觉得这个效果其实还蛮有实用价值的。
好了,感谢原作者的分享.
每天进步一点点!!!
- Unity&Shader案例篇—声纳光波效果
- Unity&Shader案例篇—声纳光波效果
- Unity&Shader案例篇—膨胀效果
- Unity&Shader案例篇—膨胀效果
- Unity&Shader案例篇—屏幕渐暗效果
- Unity&Shader案例篇—屏幕渐暗效果
- Unity&Shader案例篇—五子棋
- Unity&Shader案例篇—绘制雨滴
- Unity&Shader案例篇—火焰
- Unity&Shader案例篇—五子棋
- Unity&Shader案例篇—绘制雨滴
- Unity&Shader案例篇—绘制雪花
- Unity&Shader高级案例篇—图形命令缓冲
- Unity&Shader高级案例篇—图形命令缓冲
- Unity&Shader案例篇-镜子1
- Unity&Shader案例篇-镜子2
- Unity Shader ——人物穿越效果
- 【Unity Shader入门精要】— 透明效果
- 第三章——构建模块
- 仪表盘和图形编辑器 Grafana
- 安装WinXp时遇到蓝屏(BAD_POLL_CALLER)
- 递归问题深入到堆栈小结
- 自己写的一个超简单的伪登录。。。
- Unity&Shader案例篇—声纳光波效果
- STM32 AD参考及参照电压
- B-tree的构造及相关操作
- eclipse中的快捷键
- 微信JS接口 - 企业号开发者接口文档n
- 系统调用与内存管理(sbrk、brk、mmap、munmap)
- 微软远程桌面mac/ios/android客户端
- Tiled 读取翻转(Filpping)
- mybatis generator 生成代码时错误提示The specified target project directory src does not exist