【问题标题】:How to make Unity glass shader only refract objects behind it?如何让 Unity 玻璃着色器只折射它后面的物体?
【发布时间】:2017-03-19 07:08:31
【问题描述】:

我正在为 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 的方式有关,但我并不完全确定。我会很感激任何建议。谢谢!

【问题讨论】:

    标签: unity3d shader hlsl fragment-shader


    【解决方案1】:

    对此没有简单的答案。 如果不以某种方式考虑上下文,就无法考虑折射,所以让我们看看:

    基本上,定义一个对象何时“落后于”另一个对象并不容易。甚至meassure a point's distance to the camera 也有不同的方法,更不用说考虑整个几何图形了。几何相交有很多奇怪的情况,中心和边界可能在任何地方。

    raytracing algorithms 中通常很容易考虑折射(您只需行进一条射线并计算它如何反弹/折射以获得颜色)。但是在raster graphics(用于 99% 的实时图形)中,对象是作为一个整体渲染的,并且是轮流渲染的。

    该图像的情况是首先渲染背景和球,然后渲染玻璃。玻璃不会“折射”任何东西,它只是将自己绘制为之前写入渲染缓冲区中的任何内容的扭曲。

    “之前”是这里的关键。您不会在光栅图形中“落后”,一切都是通过意识到渲染顺序来完成的。让我们看看如何创建一些折射:

    • 手动设置render queue tags for the shaders,这样您就知道它们是在管道中的哪个点绘制的
    • 手动设置each material's render queue
    • 创建一个脚本,不断编组场景,每一帧根据位置或您想要的任何方法计算应该在玻璃之前或之后绘制的内容,并在材质中设置渲染队列
    • 创建一个渲染场景的脚本,过滤掉 (through various methods) 不应折射的对象,并将其用作要折射的纹理(取决于场景的复杂性,有时这是必要的)李>

    这些只是我脑海中的一些选项,一切都取决于你的场景

    我的建议:

    • 选择球的材料
    • 右键单击 Inspector 窗口 --> 勾选“调试”模式
    • 将自定义渲染队列设置为 2200(在绘制常规几何图形之后)
    • 选择玻璃材质
    • 将自定义渲染队列设置为 2100(在大多数几何体之后,但在球之前)

    【讨论】:

    • 感谢您的详尽回复!我现在就试试你的建议。
    • @Miles 怎么样?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多