在Unity5中正确呈现半透明球体

14

我正在使用Unity制作太空探索游戏,但是在半透明方面遇到了两个问题。

每个星球由两个球体组成:一个是表面和云层的结合体,另一个(半径略大)通过剔除前面的面并向球体外缘淡化alpha来描绘地平线“光晕”。这基本上还算正常,但以下两个问题:

1)在我的自定义表面着色器中,当我在#pragma定义中使用alpha关键字时,alpha会计入渲染的球体中,但是“光晕”球体在几千个单位的距离处消失。如果我不包含alpha关键字,则球体不会朝边缘褪色,但是它会在远处渲染。

2)尽管尝试了所有RenderType、Queue、ZWrite和ZDepth选项,表面球体和“光晕”球体仍然存在z-fighting;游戏似乎无法确定哪些多边形更接近-尽管“光晕”球体上的近面应该被剔除。我甚至尝试将“光晕”球体从玩家相机推开,并以相同比例扩展其半径,但是我仍然无法解释为什么球体之间发生z-fighting!

是否有任何设置我错过了,可以使“光晕”球体始终在表面球体的后面绘制(假设我已尝试所有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"
}

你使用LOD吗?像LOD 250这样的?如果是,请将其删除。 - Jerry Switalski
不包括 LOD。感谢您的指引。 - moosefetcher
你能在这里包含你的着色器代码吗?我想不出任何会导致这种效果的原因。此外,关闭ZTest是一个有效的选项,尽管它没有列在官方Unity手册中。 - HalpPlz
即使添加了悬赏,也没有得到答案。有人有想法吗?我能提供更多信息吗? - moosefetcher
3个回答

1
你有没有考虑在另一个相机中以不同比例渲染大型物体,以创建动态天空盒?这肯定可以解决z-fighting问题。 例如,您可以拥有两个相机-一个渲染0.1-1000范围内的对象,另一个渲染1000到100000范围内的对象。

额外的优化可以包括从远处渲染环境到立方体天空盒中,并且不要每帧都这样做(除非也许是特殊情况,例如从远处摧毁星球)。

还有另一个优化问题-您可以绕行行星周围旋转,以面向相机渲染平坦的环形,以避免在实际行星表面上过度绘制。但是,这将需要更复杂的照明计算。

此外,您是否尝试在没有Skybox作为清晰标志的相机上使用透明着色器?请参见this answer了解如何使用自定义天空盒。

欢迎来到StackOverflow!下次请尝试将一些示例代码发布为您的答案,因为链接可能会失效。 - cdomination

0

在尝试解决世界空间“抖动”问题时,我似乎偶然发现了一个解决方案...... 我正在开发的游戏使用大距离。我改变了远距离物体的定位方式(距离越远,距离会收缩),这解决了z-fighting和alpha消失的问题。 通过使用距离的平方根除以距离,并将对象的相对Vector3和比例乘以该值,整个太阳系可以适应约300000公里。希望这些信息对某人有用。


0

如果您正在使用alpha,则需要更改标签以在透明通道中呈现alpha。还要关闭ZWrite并删除偏移量。

我在一个空项目中测试了您的着色器,使用正向和延迟渲染都可以正常工作。通过这些调整,所有不透明几何体首先被绘制,然后进行alpha通道处理,并将所有具有透明度的对象渲染在场景中所有对象的顶部。必须这样做,否则无法混合alpha的颜色。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接