在Unity5

时间:2016-02-05 13:11:20

标签: unity3d shader alpha

我正在Unity制作一个太空探索游戏,我有两个半透明问题。

每个行星由两个球体组成:一个是组合的表面和云层,另一个(半径略大)通过剔除前面和褪色α朝向球体的外边缘描绘地平线“发光” 。这一切工作正常,但有以下两个问题:

1)在我的自定义表面着色器中,当我在#pragma定义中使用alpha关键字时,alpha会被渲染到渲染球体中,但“发光”球体会在几千个单位的距离内消失。如果我不包含alpha关键字,则球体不会向边缘渐变,但会在距离处呈现。

2)尽管尝试了所有RenderType,Queue,ZWrite和ZDepth选项,表面球体和'发光'球体都是z-fighting;游戏似乎无法决定哪个多边形更接近 - 尽管事实上应该剔除发光球体上的近面。我甚至尝试将发光球推离播放器相机,并以相同的比例扩大其半径,但我仍然莫名其妙地在球体之间进行z战斗!

是否有任何我缺少的设置将使'glow'球体始终被绘制在表面球体之后(假设我已经尝试了ZWrite的所有组合,ZDepth如上所述)并且有一种方法可以有一个启用alpha的对象不会在距离消失吗?

我似乎无法弄清楚这一点,所以任何帮助都会受到赞赏!

修改
这是我的'发光球'的着色器代码。正面被剔除。我甚至尝试使用Offset关键字从相机中“推”任何绘制的多边形。我已经尝试了所有我能找到的Tag,ZWrite和ZTest选项。着色器通过色调颜色,大气密度浮动和太阳方向矢量......

Shader "Custom/planet glow" {
    Properties {
        _glowTint ("Glow Tint", Color) = (0.5,0.8,1,1)
        _atmosphereMix ("Atmosphere Mix", float) = 0
        _sunDirection ("Sun Direction", Vector) = (0, 0, 0, 0)
    }
    SubShader {
        Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }
        Cull Front // I want only the far faces to render (behind the actual planet surface)
        Offset 10000, 10000
        ZWrite On // Off also tried
        ZTest LEqual // I have tried various other options here, incombination with changing this setting in the planet surface shader

        CGPROGRAM
        #pragma surface surf Lambert alpha
        #pragma target 4.0

        struct Input {
            float3 viewDir;
        };

        fixed4 _glowTint;
        float _atmosphereMix;
        float4 _sunDirection;   

        void surf (Input IN, inout SurfaceOutput o) {
            _sunDirection = normalize(_sunDirection);
            o.Albedo = _glowTint;
            float cameraNormalDP = saturate(dot( normalize(IN.viewDir), -o.Normal ) * 4.5);
            float sunNormalDP = saturate(dot( normalize(-_sunDirection), -o.Normal ) * 2);
            o.Alpha = _atmosphereMix * sunNormalDP * (cameraNormalDP * cameraNormalDP * cameraNormalDP); // makes the edge fade 'faster'            
            o.Emission = _glowTint;
        }

        ENDCG
    } 
    FallBack "Diffuse"
}

3 个答案:

答案 0 :(得分:1)

您是否考虑过在另一台相机中以不同比例渲染大型物体以创建动态天空盒?这肯定会解决z战斗问题。 例如,您可以拥有两个摄像头 - 一个可以渲染范围为0.1-1000的对象,另一个可以渲染1000到100000的对象。

额外的优化可以包括从远处渲染环境到立方体天空盒,并且不是每一帧(除非你从远处摧毁一颗行星的特殊场合)。

还有另一个优化问题 - 你可以在行星周围渲染一个扁平环,旋转到面对摄像机,以避免在实际行星表面上过度绘制。但显然,这需要更复杂的照明计算。

另外,您是否在没有Skybox标志的相机上尝试过透明着色器?检查this answer有关如何使用自定义天空盒的信息。

答案 1 :(得分:0)

在试图解决世界空间'抖动'时,我似乎偶然发现了这个问题的解决方案...... 我正在开发的游戏使用了很远的距离。我改变了长距离物体的定位方式(距离越远,物体离相机越远),这解决了z战斗和α消失。 整个太阳系通过使用距离的平方根除以距离并乘以相对的Vector3和物体的比例来拟合30万公里。希望这些信息对某人有用。

答案 2 :(得分:0)

如果您使用的是alpha,则需要更改标签以在透明度通道中渲染Alpha。同时关闭ZWrite。并删除偏移量。

我在一个包含Forward和Deferred渲染的空项目中测试了着色器。这些调整很好。

首先绘制所有不透明几何体,然后完成Alpha通道并渲染场景中所有对象的TOP透明度的所有对象。它需要这样做,否则它将无法混合alpha的颜色。

Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
ZWrite Off