Unity三种物体溶解方法
Posted zczplus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity三种物体溶解方法相关的知识,希望对你有一定的参考价值。
Unity三种物体溶解方法
效果展示
Dissolve1-3
1. 利用Noise纹理进行溶解
该方法的效果好坏在于噪声纹理的分布。本例利用SD的Blend节点,将Noise贴图和渐变贴图进行正片叠底操作,并简单调整边缘边缘大小,得到如下所示的噪声贴图。
制作的遮罩为四周较暗,且对角线轴向向内亮度递增,使得最终的溶解效果从四周向内部溶解。
shader要点
- 通过一个噪声权重因子来控制Noise贴图的整体亮度;
- 利用saturate将其截断在0,1之间。通过改变噪声权重因子的大小影响Noise贴图的亮度,
- 将加权过的噪声图作为输出图片的alpha值,从而改变物体的透明度,结合Blend最终达到消融的目的。
- 通过判断透明度的值生成包边效果,通过改变透明度的阈值范围控制包边的宽度。
- 结合之前的Bloom后处理方法,通过包边所在的透明度范围对包边进行提取,达到局部bloom的效果。
shader代码
Shader "Custom/DissolveShader"
Properties
_MainTex ("Main Texture", 2D) = "white"
_DissolveMap ("Noise Map", 2D) = "white"
_DissolveFactor ("Dissolve Factor", Range(0, 18)) = 0.5
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_DissolveColor ("Dissolve Color", Color) = (1, 0, 0, 1)
_DissolveBoundaryBegin ("Dissolve Boundary Begin", Range(0.3, 1)) = 0.4
_DissolveBoundaryEnd ("Dissolve Boundary End", Range(0.3, 0.4)) = 0.3
_DissolveBoundaryAlpha ("Dissolve Boundary Alpha", Range(0, 1)) = 0.5
SubShader
Tags "Queue" = "Geometry+1" "RenderType" = "Opaque"
pass
Blend SrcAlpha OneMinusSrcAlpha
Tags "LightMode" = "ForwardBase"
CGPROGRAM
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DissolveMap;
float4 _DissoveMap_ST;
float _DissolveFactor;
fixed4 _DissolveColor;
float _DissolveBoundaryBegin;
float _DissolveBoundaryEnd;
float _DissolveBoundaryAlpha;
struct v2f
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD2;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
;
v2f vert(appdata_base v)
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.screenPos = ComputeGrabScreenPos(o.pos);
return o;
fixed4 frag(v2f i) : SV_Target
// 采样噪声贴图的值
fixed dissolveTex = tex2D(_DissolveMap, i.uv).r;
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 color = albedo * tex2D(_MainTex, i.uv).rgb;
// 利用时间实现一个简单的动态效果
fixed dissolveFactor = _DissolveFactor * abs(lerp(-1, 1, frac(_Time.y * 0.1)));
// 利用消融因子为消融贴图赋值,使其整体灰度值随着消融因子的变化而变化
fixed alpha = saturate(dissolveTex * dissolveFactor * dissolveFactor);
// 判断当前的透明度 若在设定范围内则更改颜色 并同时更改透明度方便后续bloom效果实现
if (alpha < _DissolveBoundaryBegin && alpha > _DissolveBoundaryEnd)
return fixed4(_DissolveColor.rgb, _DissolveBoundaryAlpha);
else if (alpha < _DissolveBoundaryEnd)
alpha = 0;
return fixed4(color, alpha);
ENDCG
FallBack "Diffuse"
2. 屏幕空间棋盘格
利用cllip方法强制中止当前渲染过程,达到透视效果。由于clip方法的使用,导致无法进行early-z等操作,在手机端会有较大的性能开销。
shader要点
- 该方法在屏幕空间进行操作,所以要得到屏幕空间中的具体坐标;
- 利用floor方法将x,y值乘以棋盘格控制因子的结果限制为整数;
- 通过乘以0.5再相加的方式使得结果带小数部分或者不带小鼠部分;
- 最后利用frac函数对小数部分进行提取,从而得到一系列值为0和0.5的数;
- 对这些值取负值并利用clip函数进行判断,当对应的值为-0.5时,渲染中断,当为0时,渲染继续;从而实现棋盘格效果。
shader代码
Shader "Custom/Dissolve2Shader"
Properties
_MainTex ("Albedo (RGB)", 2D) = "white"
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_Range ("Range", Range(0, 1)) = 0.1
SubShader
Tags "RenderType" = "Opaque"
pass
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
float _Range;
sampler2D _MainTex;
float4 _Diffuse;
struct v2f
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD2;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
;
v2f vert(appdata_base v)
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.screenPos = ComputeScreenPos(o.pos);
return o;
fixed4 frag(v2f i) : SV_Target
float2 wcoord = (i.screenPos.xy / i.screenPos.w);
// 记得再乘以屏幕的像素个数,才能最终得到屏幕位置
wcoord *= _ScreenParams.xy;
// 随时间变化 * _Time.y * 3
float changeRange = _Range;
// screenPos *0.5 是为了方便当两数相加时有奇偶的区分,
// 若和为奇数,则乘以0.5再取小数部分则小数部分必为0.5,若为偶数,再乘0.5则小数部分为0
float2 screenPos = floor(wcoord.xy * changeRange) * 0.5;
// 棋盘图案中 4x4 像素块的 checker 值为负
float checker = -frac(screenPos.r + screenPos.g);
// 如果clip函数中的值为负数,则停止渲染
clip(checker);
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
// 对于保留的像素,读取纹理并将其输出
fixed3 color = albedo * tex2D(_MainTex, i.uv).rgb;
return fixed4(color, 1);
ENDCG
FallBack "Diffuse"
3. 判断顶点距离摄像头的距离进行clip
该方法同样利用clip方法达到消融的目的,距离的运算在世界空间中完成,消融的实现在屏幕空间中完成。
这里最后一句话有点没看懂 再琢磨琢磨。
shader 代码
Shader "Custom/Dissolve3Shader"
Properties
_MainTex ("Albedo (RGB)", 2D) = "white"
_Diffuse ("Diffuse Color", Color) = (1, 1, 1, 1)
_FogNear ("Fog Near", float) = 1.0
_FogFar ("Fog Far", float) = 1.0
_Test ("Test", float) = 1.0
SubShader
Tags "RenderType" = "Opaque"
pass
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
sampler2D _MainTex;
float4 _Diffuse;
float _FogFar;
float _FogNear;
float _Test;
struct appdata
float4 vertex : POSITION;
float2 uv1 : TEXCOORD0;
float2 uv2 : TEXCOORD1;
float3 normal : NORMAL;
;
struct v2f
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
float4 screenPos : TEXCOORD2;
float3 worldNormal : TEXCOORD3;
;
v2f vert(appdata v)
v2f o;
// 裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = v.uv1;
o.uv.zw = v.uv2;
// 屏幕空间坐标
o.screenPos = ComputeScreenPos(o.vertex);
// 世界空间坐标
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
fixed4 frag(v2f i) : SV_Target
// 计算光照
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed4 color = fixed4(albedo * tex2D(_MainTex, i.uv).rgb,tex2D(_MainTex, i.uv).a);
// 物体顶点距离相机距离
float distanceRamp = distance(i.worldPos, _WorldSpaceCameraPos.xyz);
// 利用Smoothstep对距离进行约束
distanceRamp = smoothstep(_FogNear, _FogFar, distanceRamp);
// 构建抖动顺序矩阵
float4x4 thresholdMatrix =
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
;
// 获取屏幕空间坐标(归一化
float2 screenPos = i.screenPos.xy / i.screenPos.w;
// 0-1的坐标范围乘以画面像素总数
screenPos *= _ScreenParams.xy;
// 依据动态抖动计算透明度
half noise = distanceRamp - thresholdMatrix[fmod(screenPos.x, 4 * _Test)] * thresholdMatrix[fmod(screenPos.y, 4 * _Test)];
clip(noise);
return color;
ENDCG
FallBack "Diffuse"
unity深度查找某个子物体和遍历所有子物体方法
本文总结一下关于unity的查找子物体的方法
首先说明一下这里将讲三种查找子物体方法:
查找固定路径的某一个子物体的方法、通过名字深度查找某个子物体的方法、查找父物体下所有子物体的方法。
第一:查找固定路径的某一个子物体的方法
对于已知的路径可以直接用go.transform.FindChild方法来查找。
例如:在这样一个层级路径下,我们要找到最后那个plane物体。
1 using UnityEngine; 2 using System.Collections; 3 4 public class findchild : MonoBehaviour { 5 6 // Use this for initialization 7 void Start () { 8 9 } 10 11 // Update is called once per frame 12 void Update () { 13 if (Input.GetMouseButtonDown(1)) 14 { 15 //查找物体方法 16 GameObject go = GameObject.Find("Cube"); 17 //查找子物体,并且将得到的物体转换成gameobject 18 GameObject objname= go.transform.FindChild("Sphere/Cylinder/Plane").gameObject; 19 20 Debug.Log("得到最终子物体的名字是:"+ objname.name); 21 } 22 } 23 }
然后是执行结果:
==-------------------------------------------------------------------------------------------------------------
第二:通过名字深度查找某个子物体的方法
注意:要使用这个方法必须要满足两个条件:第一必须有你要查找的子物体的名字,第二必须要从一个父物体上开始查起
下面代码中,check代表从这个父物体开始查起,name为你要查找的目标子物体的名称。如return GetTransform(transform,"bone12");
该方法核心代码:
而下面是查找的具体方法:
1 Transform GetTransform(Transform check, string name) 2 { 3 Transform forreturn = null; 4 5 foreach (Transform t in check.GetComponentsInChildren<Transform>()) 6 { 7 if (t.name == name) 8 { 9 Debug.Log("得到最终子物体的名字是:" + t.name); 10 forreturn = t; 11 return t; 12 13 } 14 15 } 16 return forreturn; 17 }
再看完整的测试代码:还用上个的例子的,例如这次要查到Cylinder这个物体:
修改后的代码:
1 using UnityEngine; 2 using System.Collections; 3 4 public class findchild : MonoBehaviour { 5 6 // Use this for initialization 7 void Start () { 8 9 } 10 11 // Update is called once per frame 12 void Update () { 13 if (Input.GetMouseButtonDown(1)) 14 { 15 // //查找物体方法 16 GameObject go = GameObject.Find("Cube"); 17 // //查找子物体,并且将得到的物体转换成gameobject 18 //GameObject objname= go.transform.FindChild("Sphere/Cylinder/Plane").gameObject; 19 20 //Debug.Log("得到最终子物体的名字是:"+ objname.name); 21 22 23 GetTransform(go.transform, "Cylinder"); 24 25 } 26 } 27 28 Transform GetTransform(Transform check, string name) 29 { 30 Transform forreturn = null; 31 32 foreach (Transform t in check.GetComponentsInChildren<Transform>()) 33 { 34 if (t.name == name) 35 { 36 Debug.Log("得到最终子物体的名字是:" + t.name); 37 forreturn = t; 38 return t; 39 40 } 41 42 } 43 return forreturn; 44 } 45 }
测试结果:
-----------------------------------------------------------------------------------------------------
第三:接下来我们将获取一个父物体下的所有子物体,然后销毁其下所有子物体
注意:所有子物体都是同级关系,在同一层里。如图:
核心方法:
1 List<Transform> lst = new List<Transform>(); 2 foreach (Transform child in transform) 3 { 4 lst.Add(child); 5 Debug.Log(child.gameObject.name); 6 } 7 for (int i = 0; i < lst.Count; i++) 8 { 9 Destroy(lst[i].gameObject); 10 }
上面的transform就是该父物体的transform。具体案例代码:
1 using UnityEngine; 2 using System.Collections; 3 using System.Collections.Generic; 4 5 public class findchild : MonoBehaviour { 6 7 // Use this for initialization 8 void Start () { 9 10 } 11 12 // Update is called once per frame 13 void Update () { 14 if (Input.GetMouseButtonDown(1)) 15 { 16 // //查找物体方法 17 GameObject go = GameObject.Find("Cube"); 18 List<Transform> lst = new List<Transform>(); 19 foreach (Transform child in go.transform) 20 { 21 lst.Add(child); 22 Debug.Log(child.gameObject.name); 23 } 24 for (int i = 0; i < lst.Count; i++) 25 { 26 Debug.Log("销毁的物体是:"+ lst[i].gameObject); 27 Destroy(lst[i].gameObject); 28 } 29 30 } 31 } 32 33 34 }
测试结果,全被销毁了:
以上就是我总结的常用的三种查找子物体的方法。
以上是关于Unity三种物体溶解方法的主要内容,如果未能解决你的问题,请参考以下文章