Unity投影器细节整理
抽了个空整理下投影器
一般投影器需要两张贴图,一张Cookie,一张FallOff。
Unity提供Light和Multiple两种自带shader,和粒子类似。
Cookie需要非alpha贴图,FallOff用带Alpha的贴图
当不使用FallOff贴图时会有侧背面穿透的问题,不管是正交还是透视投影器(Cookie边缘干净时也会)
实际上使用FallOff贴图也不能解决,但可以避免大部分情况
FallOff贴图,从左往右对应+Z至-Z范围
另外写了一个快速生成FallOff渐变贴图的工具脚本
点击创建后,会自动在Assets目录下生成一张名为Gradient的临时贴图
丢Editor目录下即可使用
using UnityEditor; using UnityEngine; using System.IO; using System.Linq; using System.Collections; public class GradientCreator : EditorWindow { public enum OrderModeEnum { H, V }; Color mBeginColor = new Color(1, 1, 1, 1); Color mEndColor = new Color(0, 0, 0, 0); float mOffset = 1f; int mExpectWidth = 256; int mExpectHeight = 256; bool mIsHardEdge = true; bool mIsInvert = false; OrderModeEnum mOrderMode; [MenuItem("Hont Tools/Gradient Creator")] public static void Setup() { GetWindow<GradientCreator>(); } void OnGUI() { mBeginColor = EditorGUILayout.ColorField("Begin Color", mBeginColor); mEndColor = EditorGUILayout.ColorField("End Color", mEndColor); mOffset = EditorGUILayout.Slider("Offset", mOffset, -1, 1); mIsInvert = EditorGUILayout.Toggle("Invert", mIsInvert); mExpectWidth = EditorGUILayout.IntField("Expect Width", mExpectWidth); mExpectHeight = EditorGUILayout.IntField("Expect Height", mExpectHeight); mIsHardEdge = EditorGUILayout.Toggle("Hard Edge", mIsHardEdge); mOrderMode = (OrderModeEnum)EditorGUILayout.EnumPopup("Order Mode", mOrderMode); if (GUILayout.Button("Create!")) { var mainTexture = new Texture2D(mExpectWidth, mExpectHeight); if (mOrderMode == OrderModeEnum.V) { for (int x = 0; x < mainTexture.width; x++) { for (int y = 0; y < mainTexture.height; y++) { var g = GetG(y, mainTexture.height); var currentColor = Color.Lerp(mBeginColor, mEndColor, g); mainTexture.SetPixel(x, y, currentColor); } } } else { for (int y = 0; y < mainTexture.height; y++) { for (int x = 0; x < mainTexture.width; x++) { var g = GetG(x, mainTexture.width); var currentColor = Color.Lerp(mBeginColor, mEndColor, g); mainTexture.SetPixel(x, y, currentColor); } } } mainTexture.Apply(); var outputFile = System.IO.Directory.GetCurrentDirectory() + "/Assets/Gradient.png"; if (File.Exists(outputFile)) File.Delete(outputFile); var bytes = mainTexture.EncodeToPNG(); File.WriteAllBytes(outputFile, bytes); AssetDatabase.Refresh(); } } float GetG(float current, float max) { var g = Mathf.Clamp01((current / max) + mOffset); g = mIsHardEdge ? g < 1 ? 0f : 1f : g; g = mIsInvert ? 1 - g : g; return g; } }
关于投影器的实现,我觉得如下:
1.Unity先把投影器影响到的物体剔除出来,然后再对他们进行再次绘制,并且这个绘制是在绘制透明物体的管线阶段下进行的。
2.通过'投影纹理映射'的方法,似乎是tex2Dproj。最终得到映射的UV坐标。进行绘制
需要注意,如果影响到的物体越多,dc也就越高,因为都要多绘制一次