如何让Unity玻璃着色器仅折射背后的物体?
问题描述:
我正在寻找Unity的玻璃着色器,它只折射它背后的物体,或者想法如何修改现有的玻璃着色器来做到这一点。如何让Unity玻璃着色器仅折射背后的物体?
这个屏幕截图显示了当我在曲面网格上使用FX/Glass/Stained BumpDistort时会发生什么。
正如你可以看到,玻璃着色折射无论是在网前球和它背后的理由。我正在寻找一个着色器,它只会折射它背后的物体。
下面是该着色器的代码,以供参考:
// Per pixel bumped refraction.
// Uses a normal map to distort the image behind, and
// an additional texture to tint the color.
Shader "FX/Glass/Stained BumpDistort" {
Properties {
_BumpAmt ("Distortion", range (0,128)) = 10
_MainTex ("Tint Color (RGB)", 2D) = "white" {}
_BumpMap ("Normalmap", 2D) = "bump" {}
}
Category {
// We must be transparent, so other objects are drawn before this one.
Tags { "Queue"="Transparent" "RenderType"="Opaque" }
SubShader {
// This pass grabs the screen behind the object into a texture.
// We can access the result in the next pass as _GrabTexture
GrabPass {
Name "BASE"
Tags { "LightMode" = "Always" }
}
// Main pass: Take the texture grabbed above and use the bumpmap to perturb it
// on to the screen
Pass {
Name "BASE"
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata_t {
float4 vertex : POSITION;
float2 texcoord: TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
float4 uvgrab : TEXCOORD0;
float2 uvbump : TEXCOORD1;
float2 uvmain : TEXCOORD2;
UNITY_FOG_COORDS(3)
};
float _BumpAmt;
float4 _BumpMap_ST;
float4 _MainTex_ST;
v2f vert (appdata_t v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.uvbump = TRANSFORM_TEX(v.texcoord, _BumpMap);
o.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
sampler2D _BumpMap;
sampler2D _MainTex;
half4 frag (v2f i) : SV_Target
{
// calculate perturbed coordinates
half2 bump = UnpackNormal(tex2D(_BumpMap, i.uvbump)).rg; // we could optimize this by just reading the x & y without reconstructing the Z
float2 offset = bump * _BumpAmt * _GrabTexture_TexelSize.xy;
i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
half4 col = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
half4 tint = tex2D(_MainTex, i.uvmain);
col *= tint;
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
// ------------------------------------------------------------------
// Fallback for older cards and Unity non-Pro
SubShader {
Blend DstColor Zero
Pass {
Name "BASE"
SetTexture [_MainTex] { combine texture }
}
}
}
}
我的直觉是,它具有与_GrabTexture被捕获的方式做,但我不能完全肯定。我会很感激任何建议。谢谢!
答
没有简单的答案。 如果不以某种方式思考上下文,就不能考虑折射,所以让我们来看看:
基本上,定义对象何时在另一个“后面”并不容易。甚至可以有不同的方法,更不用说考虑整个几何体。有很多奇怪的情况,几何相交,中心和边界可能在任何地方。
折射通常很容易在raytracing algorithms中考虑(你只是进行射线并计算它如何反射/折射以获得颜色)。但是在raster graphics(用于99%的实时图形)中,这些对象将作为一个整体呈现,并轮流显示。
该图像正在发生的事情是,先渲染背景和球,然后再渲染玻璃。玻璃不会“折射”任何东西,它只是将之前渲染缓冲区中写入的任何内容变形。
“之前”是关键。你不会在光栅图形中“落后”,所有事情都是通过意识到渲染顺序来完成的。让我们看看如何一些折射创建:
- 手动设置render queue tags for the shaders,让你知道在流水线什么时候他们被吸引
- 手动设置each material's render queue
- 创建一个脚本,不断编组场景和每一帧根据位置或您想要的任何方法计算玻璃前后应绘制的内容,并在材质中设置渲染队列
- 创建一个脚本,用于渲染场景(through various methods)不应该是的对象折射,并将其用作纹理t Ø折射(根据场景的复杂程度,这有时是必要的)
这些只是从我的头顶一些选项,一切都取决于你的场景
我的建议是:
- 选择球的材料
- Inspector窗口上点击右键 - >勾选上“调试”模式
- 设置自定义渲染Q ueue到2200(该规则的几何形状绘制后)
- 选择玻璃材料
- 设置自定义渲染队列到2100(大多数几何后,但球之前)
感谢您彻底响应!我现在要试试你的建议。 – Miles
@Miles那是怎么回事? –