【问题标题】:Making 2D water look like 3d使 2D 水看起来像 3d
【发布时间】:2019-12-26 10:08:14
【问题描述】:

我对着色器知之甚少:(如果有人可以提供帮助

我正在使用这个免费的 2d 水资产,它包含一个水着色器。我想编辑那个着色器,让它看起来更像 2.5d 或 3d。

目前,它看起来像这样

我想让它看起来像

在顶部添加一个泡沫类型的东西,使其几乎不反光

资产中用于制作二维水的着色器

Shader "Water2D/Metaballs_Simple" {
Properties {  
_MainTex ("Texture", 2D) = "white" { }  
_Color ("Main color", Color) = (1,1,1,1)
_Cutoff ("Alpha cutoff", Range(0,1)) = 0.5

_Stroke ("Stroke alpha", Range(0,1)) = 0.1
_StrokeColor ("Stroke color", Color) = (1,1,1,1)

}
/// <summary>
/// Multiple metaball shader.

/// </summary>
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
GrabPass{}
Pass {
Blend SrcAlpha OneMinusSrcAlpha  
// Blend One One // Additive
// Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag  
#include "UnityCG.cginc"  
float4 _Color;
sampler2D _MainTex;  
fixed _Cutoff;
fixed _Stroke;
half4 _StrokeColor;
float2 _screenPos;



float4 _CameraDepthTexture_TexelSize;


struct v2f {
    float4  pos : SV_POSITION;
    float2  uv : TEXCOORD0;
};  

float4 _MainTex_ST;      
v2f vert (appdata_base v){
    v2f o;
    o.pos = UnityObjectToClipPos (v.vertex);
    o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
    return o;
};




half4 frag (v2f i) : COLOR{      
    half4 texcol= tex2D (_MainTex, i.uv);
    //half4 finalColor = texcol;


    clip(texcol.a - _Cutoff);

    if (texcol.a < _Stroke) {
        texcol = _StrokeColor;
    } else {
        texcol = _Color;
    }



     return texcol;


}




ENDCG

}
}
Fallback "VertexLit"
}

【问题讨论】:

    标签: unity3d shader cg


    【解决方案1】:

    根据您的着色器判断,流体似乎具有包含基于到边缘距离的 alpha 渐变的纹理。如果这类似于距离场,那么您可以使用它根据导数重建屏幕空间法线。

    float3 normal;
    normal.x = ddx(texcol.a);
    normal.y = ddy(texcol.a);
    normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
    

    然后,您可以使用此值来计算一些基本的 blinn-phong 镜面反射光照。这涉及使用到光的向量和到相机的向量之和来获得一个中途向量。

    由于我们的法线在相机空间中,我们可能也希望在相机空间中进行所有其他计算。理想情况下,我们希望在顶点着色器中进行尽可能多的计算,然后将它们传递给片段着色器:

    struct v2f {
        float4  pos : SV_POSITION;
        float2  uv : TEXCOORD0;
        float3  viewDir : TEXCOORD1;
        float3  lightDir : TEXCOORD2;
    };  
    
    float4 _MainTex_ST;      
    v2f vert (appdata_base v){
        v2f o;
        o.pos = UnityObjectToClipPos (v.vertex);
        o.viewDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceViewDir(v.vertex));
        o.lightDir = mul((float3x3)UNITY_MATRIX_MVP, ObjSpaceLightDir (v.vertex));
        o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
        return o;
    };
    

    我假设 ObjSpaceLightDir 适用于 2D 灯光,但我不确定。 在片段着色器中,我们现在可以获得镜面高光:

    float3 lightDir = normalize(i.lightDir);
    float3 viewDir = normalize(i.viewDir);
    float3 halfDir = normalize(lightDir + viewDir);
    
    float spec = pow(saturate(dot(normal, halfDir)), _Glossiness * 128);
    
    return saturate(_BaseColor + spec);
    

    您还可以添加一些微妙的朗伯着色以在下方创建阴影:

    float diff = saturate(dot(normal, lightDir));
    // 20% diffuse contribution, because lots of light passes through the liquid.
    // Can be tweaked based on artistic needs.
    return saturate(_BaseColor * (0.8 + 0.2 * diff) + spec);
    

    请注意,这不会正确地给出您的参考所具有的厚度错觉。为此,您需要将流体的厚度模拟为高度图并基于此生成法线。您可以通过向其添加一些程序噪声来分解镜面反射的形状,尽管我还没有尝试过。编写着色器时的一大挑战是 GPU 对像素的上下文一无所知,除了您提供给它的内容外,因此必须预先计算到最近边缘的距离之类的信息并将其输入到材质中纹理。老实说,我不确定他们是如何在顶部产生泡沫的——它可能是水纹理的一部分,也可能是背景中渲染的单独精灵。

    【讨论】:

      猜你喜欢
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 2015-03-20
      相关资源
      最近更新 更多