unity中的sun shafts(也称gay ray)的一种实现方法
来源:互联网 发布:数码宝贝物语 网络侦探 编辑:程序博客网 时间:2024/04/29 12:43
这个方法来自于圣典中一个大神的分享,链接:http://www.ceeger.com/forum/read.php?tid=12137#read_222385
上次ShadowGun中的做法是用一个可以伸缩的mesh来模拟,这次的则是用屏幕特效来模拟。
外加其实unity自己也提供了一个现成的,可以直接用的效果,圣典的说明链接:
http://www.ceeger.com/Components/script-SunShafts.html
pro版通过导入ImageEffect包,在里面找到 sun shafts 的.cs文件,然后跟其它屏幕特效一样,把它挂在摄像机上就可以使用了。
这种方法跟unity提供的那个应该是类似的。
首先这个实现最重要的是3个shader,分别是 Blend.shader GodRay.shader GodRayOptimize.shader
Blend:这是做RenderTexture混合用的shader
GodRay:第1种实现方法,主要逻辑在 fragment 里
GodRayOptimize:思路和第1个一样,在此原理基础上,把 uv 的计算挪到 vertex 里去做,提高了效率
思路:
这里的方法是,根据光源的方向和要发出 gay ray 的物体产生一个方向向量。
如:
half2 texCoord = i.uv;half2 deltaTexCoord = texCoord - ScreenLightPos.xy;deltaTexCoord *= 1.0f / NUM_SAMPLES * Density;
当前像素根据当前其在 RenderTexture 的 uv,沿着向量往光源方向有间隔的取样8次,每次取到的颜色都比上一次要衰减一次,最后取8次取样结果的平均值为当前像素的颜色。
如:
half4 color = tex2D(_MainTex, i.uv);half illuminationDecay = 1.0f;for (int i = 0; i < NUM_SAMPLES; i++){ texCoord -= deltaTexCoord; half4 sample = tex2D(_MainTex, texCoord); sample *= illuminationDecay; color += sample; illuminationDecay *= Decay;}color /= NUM_SAMPLES;return half4( color.xyz * Exposure, 1);
实际效果像下面一样:
cube是要产生gay ray的物体,Sphere是光线的起点
产生了重影的地方,就是沿着光源的方向采样8次后可以取到颜色的像素所产生的。因为每次采样的结果是会进行逐步衰减的,所以它们会有深浅之分。
没有重影的像素,实际上是因为它们沿向量采样8次,结果采样不到任何颜色所造成的。
但是我们应该注意到了,现在这不是我们想要的结果,因为这是重影,并不是gay ray,那要怎么办呢?
这个时候,我们只需要反复多来几次这种采样,衰减的过程就可以了。
因为我们是在第一次采样的结果基础上继续进行采样,衰减的,所以之前没有颜色的像素,这个时候也有颜色了。
代码如:
Graphics.Blit(sourceTexture, tempRtA, material);Graphics.Blit(tempRtA, tempRtB, material);Graphics.Blit(tempRtB, tempRtA, material);Graphics.Blit(tempRtA, tempRtB, material);Graphics.Blit(tempRtB, tempRtA, material);materialBlend.SetTexture("_GodRayTex", tempRtA);Graphics.Blit(sourceTexture, destTexture, materialBlend, 0);
可以看到,这里 Graphics.Blit 对 RenderTexture 进行了好几次的过滤。
外加缩小使用的 RenderTexture 的尺寸,也可以使重影的间隔变得不那么明显。
代码如:
void CreateBuffers() { int rt_width = Screen.width; // Screen.width / 4; int rt_height = Screen.height; // Screen.height / 4; if (!tempRtA) { tempRtA = new RenderTexture(rt_width, rt_height, 0); tempRtA.hideFlags = HideFlags.DontSave; } if (!tempRtB) { tempRtB = new RenderTexture(rt_width, rt_height, 0); tempRtB.hideFlags = HideFlags.DontSave; } }
效果如图:
我们可以看到径向光散射效果
更明显了。
外加作为光源的物体一定要比别的物体亮,差距越明显,效果越好,这在现实生活中也是一样的道理。
更好的表现需要对发光体和参数进行更进一步的调整,这就需要使用者自己去体验了。
GodRayOptimize 跟 GodRay 的原理是相同的,只是实现方式上略有区别而已。
下面是.shader和.cs文件的具体代码
Blend:
Shader "Z_TestShader/god ray 2 blend"{ Properties { _MainTex("Base (RGB)", 2D) = "" {} _GodRayTex ("God (RGB)", 2D) = ""{} _Alpha("_Alpha", Float) = 0.5 } CGINCLUDE #include "UnityCG.cginc" struct v2in { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; sampler2D _GodRayTex; uniform float _Alpha; v2f vert(v2in v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord; return o; } half4 frag(v2f i) : COLOR { half4 color = tex2D(_MainTex, i.uv) + tex2D(_GodRayTex, i.uv)*_Alpha; return color; } ENDCG Subshader { Tags{ "Queue" = "Transparent" } Pass { ZWrite Off // 绑定通道 BindChannels { Bind "Vertex", vertex Bind "texcoord", texcoord0 Bind "texcoord1", texcoord1 } Fog{ Mode off } CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag ENDCG } } Fallback off}
GodRay:
Shader "Z_TestShader/GodRay"{ Properties { _MainTex ("Base (RGB)", 2D) = "" {} // 光线的位置 ScreenLightPos ("ScreenLightPos", Vector) = (0,0,0,0) // 密度(从效果上讲,不要超过8这个采样数) Density ("Density", Float) = 0.01 // 衰减 Decay ("Decay", Float) = 0.5 // 曝光 Exposure ("Exposure", Float) = 0.5 } CGINCLUDE #include "UnityCG.cginc" // 采样数 #define NUM_SAMPLES 8 struct v2in { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; uniform float4 ScreenLightPos; uniform float Density; uniform float Decay; uniform float Exposure; v2f vert(v2in v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord; return o; } half4 frag(v2f i) : COLOR { half2 texCoord = i.uv; half2 deltaTexCoord = texCoord - ScreenLightPos.xy; deltaTexCoord *= 1.0f / NUM_SAMPLES * Density; half4 color = tex2D(_MainTex, i.uv); half illuminationDecay = 1.0f; for (int i = 0; i < NUM_SAMPLES; i++) { texCoord -= deltaTexCoord; half4 sample = tex2D(_MainTex, texCoord); sample *= illuminationDecay; color += sample; illuminationDecay *= Decay; } color /= NUM_SAMPLES; return half4( color.xyz * Exposure, 1); } ENDCG Subshader { Tags { "Queue" = "Transparent" } Pass { ZWrite Off BindChannels { Bind "Vertex", vertex Bind "texcoord", texcoord0 Bind "texcoord1", texcoord1 } Fog { Mode off } CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag ENDCG } } Fallback off}
GodRayOptimize:
Shader "Z_TestShader/GodRayOptimize"{ Properties { _MainTex ("Base (RGB)", 2D) = "" {} ScreenLightPos ("ScreenLightPos", Vector) = (0,0,0,0) Density ("Density", Float) = 0.01 Decay ("Decay", Float) = 0.5 Exposure ("Exposure", Float) = 0.5 } CGINCLUDE #include "UnityCG.cginc" struct v2in { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; }; struct v2f { float4 pos : POSITION; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; sampler2D _MainTex; uniform float4 ScreenLightPos; uniform float Density; uniform float Decay; uniform float Exposure; v2f vert(v2in v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); half2 texCoord = v.texcoord; half2 deltaTexCoord = texCoord - ScreenLightPos.xy; deltaTexCoord *= 1.0f / 8 * Density; o.uv0 = texCoord; texCoord -= deltaTexCoord; o.uv1 = texCoord; texCoord -= deltaTexCoord; o.uv2 = texCoord; texCoord -= deltaTexCoord; o.uv3 = texCoord; texCoord -= deltaTexCoord; o.uv4 = texCoord; texCoord -= deltaTexCoord; o.uv5 = texCoord; texCoord -= deltaTexCoord; o.uv6 = texCoord; texCoord -= deltaTexCoord; o.uv7 = texCoord; return o; } half4 frag(v2f i) : COLOR { half illuminationDecay = 1.0f; half4 color = tex2D(_MainTex, i.uv0)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv1)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv2)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv3)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv4)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv5)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv6)*illuminationDecay; illuminationDecay *= Decay; color += tex2D(_MainTex, i.uv7)*illuminationDecay; color /= 8; return half4( color.xyz * Exposure, 1); } ENDCG Subshader { Tags { "Queue" = "Transparent" } Pass { ZWrite Off BindChannels { Bind "Vertex", vertex Bind "texcoord", texcoord0 Bind "texcoord1", texcoord1 } Fog { Mode off } CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag ENDCG } } Fallback off}
cs:
using UnityEngine;using System.Collections;[ExecuteInEditMode]public class GodRayEffect : MonoBehaviour{ public Transform lightpos; public Shader curShader; public Shader curShaderblend; public float Density = 0.01f; public float Decay = 0.5f; public float Exposure = 0.5f; public float Alpha = 1; public RenderTexture tempRtA = null; public RenderTexture tempRtB = null; private Material m_material; private Material m_materiaBlend; Material material { get { if (m_material == null) { m_material = new Material(curShader); m_material.hideFlags = HideFlags.HideAndDontSave; } return m_material; } } Material materialBlend { get { if (m_materiaBlend == null) { m_materiaBlend = new Material(curShaderblend); m_materiaBlend.hideFlags = HideFlags.HideAndDontSave; } return m_materiaBlend; } } void Start() { if (!SystemInfo.supportsImageEffects) { enabled = false; return; } if (!curShader && !curShader.isSupported) { enabled = false; } } void OnDisable() { if (m_material != null) { DestroyImmediate(m_material); } if (m_materiaBlend != null) { DestroyImmediate(m_materiaBlend); } } void CreateBuffers() { int rt_width = Screen.width; // Screen.width / 4; int rt_height = Screen.height; // Screen.height / 4; if (!tempRtA) { tempRtA = new RenderTexture(rt_width, rt_height, 0); tempRtA.hideFlags = HideFlags.DontSave; } if (!tempRtB) { tempRtB = new RenderTexture(rt_width, rt_height, 0); tempRtB.hideFlags = HideFlags.DontSave; } } void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { if (curShader != null) { Vector3 lightScreenPos = Camera.main.WorldToScreenPoint(lightpos.position); if (lightScreenPos.z > 0 && lightScreenPos.x > 0 && lightScreenPos.x < GetComponent<Camera>().pixelWidth && lightScreenPos.y > 0 && lightScreenPos.y < GetComponent<Camera>().pixelHeight) { Vector4 screenLightPos = new Vector4(lightScreenPos.x / GetComponent<Camera>().pixelWidth, lightScreenPos.y / GetComponent<Camera>().pixelHeight, 0, 0); material.SetVector("ScreenLightPos", screenLightPos); Debug.Log(screenLightPos); material.SetFloat("Density", Density); material.SetFloat("Decay", Decay); material.SetFloat("Exposure", Exposure); materialBlend.SetFloat("Alpha", Alpha); CreateBuffers(); Graphics.Blit(sourceTexture, tempRtA, material); Graphics.Blit(tempRtA, tempRtB, material); Graphics.Blit(tempRtB, tempRtA, material); Graphics.Blit(tempRtA, tempRtB, material); Graphics.Blit(tempRtB, tempRtA, material); materialBlend.SetTexture("_GodRayTex", tempRtA); Graphics.Blit(sourceTexture, destTexture, materialBlend, 0); } else { Graphics.Blit(sourceTexture, destTexture); } } else { Graphics.Blit(sourceTexture, destTexture); } }}
- unity中的sun shafts(也称gay ray)的一种实现方法
- Unity 游戏中的 X-Ray
- webView 实现 与 javascript调用java方法(也称js调用native 方法) helloworld
- webView 实现 与 javascript调用java方法(也称js调用native 方法) helloworld
- unity ray射线说明, 及使用ray拾取物体的方法。
- unity 实现炸弹人放炸弹后只进不出的一种方法
- Unity 全局游戏脚本的一种实现方法
- ZOJ3963 【gay gay 的贪心】
- unity另外一种debug的方法
- Q78:规则网格(Regular Grids)——Ray Tracing中的一种加速技术
- Unity一种ObjectPool的实现------转自Unity Pattern
- WEB-INF中的jsp跳转方法(一种实现)
- Unity3D图像后处理特效——Sun Shafts
- Unity3D图像后处理特效——Sun Shafts
- simple ray tracer的实现
- 也一般入门的时候经常使用的一种方法
- atof的一种实现方法
- hash_map的一种实现方法
- Hadoop历史和简介
- Oracle数据库的备份方法
- Android 插件化 动态升级
- 前端数据之美
- Linux大文件分区
- unity中的sun shafts(也称gay ray)的一种实现方法
- webx 框架入门一
- 按键精灵,批量传包工具源码备份
- 编程语言 成员变量 命名前缀
- left join on 和where条件的放置
- RF+Jenkins构建持续集成
- 使用ShareSdk要注意的问题
- Activity启动模式singleInstance
- keepalived+redis 高可用redis主从解决方案