Unity实现水面shader

举报
心疼你的一切 发表于 2024/12/17 15:18:30 2024/12/17
【摘要】 unity中实现水材质

Shader在Unity中扮演着至关重要的角色,通过编写和优化Shader,开发者可以实现对图形渲染的精细控制,从而创造出丰富的视觉效果。理解Shader的工作原理和组成部分,以及如何在Unity中应用和优化Shader,是提高游戏和应用程序性能的关键。

一、效果如下:

二、创建shader文件如下图:

创建后起一个名字即可

三、shader代码如下:

Shader "Custom/WaterShader"
{
    Properties {
        _WaterTex ("Normal Map (RGB), Foam (A)", 2D) = "white" {}
        _WaterTex2 ("Normal Map (RGB), Foam (B)", 2D) = "white" {}
 
        _Tiling ("Wave Scale", Range(0.00025, 0.1)) = 0.25
        _WaveSpeed("Wave Speed", Float) = 0.4
 
        
        _SpecularRatio ("Specular Ratio", Range(10,500)) = 200
 
        _BottomColor("Bottom Color",Color) = (0,0,0,0)
        _TopColor("Top Color",Color) = (0,0,0,0)
        _Alpha("Alpha",Range(0,1)) = 1
 
        _ReflectionTex("_ReflectionTex", 2D) = "black" {}
        _ReflectionLight("ReflectionLight",Range(0,1)) = 0.3
 
        _LightColorSelf ("LightColorSelf",Color) = (1,1,1,1)
        _LightDir ("LightDir",vector) = (0,1,0,0)
 
        
        
    }
    
    SubShader {  
        Tags {
            "Queue"="Transparent-200"
            "RenderType"="Transparent" 
            "IgnoreProjector" = "True"
            "LightMode" = "ForwardBase"
        }
        LOD 250
        Pass{
            Lighting On
            ZWrite On
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
 
            #pragma vertex Vert
            #pragma fragment Frag
            #include "UnityCG.cginc"
            
             float _Tiling;
             float _WaveSpeed;
             float _SpecularRatio;
             sampler2D _WaterTex;
             sampler2D _WaterTex2;
             sampler2D _ReflectionTex;
             float4 _LightColorSelf;
             float4 _LightDir;
             float4 _BottomColor;
             float4 _TopColor;
             float _Alpha;
             float _ReflectionLight;
 
 
            struct v2f
            {
             float4 position  : POSITION;
             float3 worldPos  : TEXCOORD0;
             float3 tilingAndOffset:TEXCOORD2;
             float4 screen:TEXCOORD3;
             float4 VertColor :TEXCOORD4;
 
            };
 
    
 
 
 
 
 
            v2f Vert(appdata_full v)
            {
             v2f o;
             o.worldPos = mul(unity_ObjectToWorld, v.vertex);
             o.position = UnityObjectToClipPos(v.vertex);
             //uv动画
             o.tilingAndOffset.z =frac( _Time.x * _WaveSpeed);
             o.tilingAndOffset.xy = o.worldPos.xz*_Tiling;
             o.screen = ComputeScreenPos(o.position);
             o.VertColor = v.color;
             return o;
            }
 
 
 
            float4 Frag(v2f i):COLOR
            {
              float3 lightColor=_LightColorSelf.rgb*2;
              //世界视向量
              float3 worldView = -normalize(i.worldPos - _WorldSpaceCameraPos);
              float2 tiling = i.tilingAndOffset.xy;
              //法线采样
              float4 N1 = tex2D(_WaterTex, tiling.yx +float2(i.tilingAndOffset.z,0));
              float4 N2 = tex2D(_WaterTex2, tiling.yx -float2(i.tilingAndOffset.z,0));
              //两个法线相加,转世界空间,这里没有unpack,所以法线贴图不需要转normal  法线贴图为0-1 两张加起来为0-2 将其x2-2,转换为-2 --2然后将其normalize,变成-1到1
              //在遇到两张法线的情况下 ,一般将法线相加 再normalize
              float3 worldNormal  = normalize((N1.xyz+N2.xyz)*2-2);
              //以垂直的方向代替灯光 跟法线做点积 得到漫反射强度
              float LdotN = dot(worldNormal, float3(0,1,0));
              fixed2 uv = i.screen.xy/(i.screen.w+0.0001);
              uv.y = 1-uv.y;
 
 
              fixed4 refTex = tex2D (_ReflectionTex,uv + worldNormal.xy*0.02 );
 
 
 
 
 
 
              //这个变量一般在Forward渲染路径下使用,存储的是重要的pixel光源方向,没错,的确是使用w来判断这个光源的类型的,一般和_LightColor0配合使用
              //float3 LView=_WorldSpaceLightPos0.xyz;
              float3 LView = _LightDir.xyz;
 
                 //if(_WorldSpaceLightPos0.w == 0.0){ 
                    // L = normalize(_WorldSpaceLightPos0.xyz); 
                    // } 
                    // else{ 
                    // L = normalize(_WorldSpaceLightPos0.xyz - i.worldPos); 
                    // } 
 
            
              
              
                //根据世界法线 ,世界视向量+光向量  得出高光 系数
                float dotSpecular = dot(worldNormal,  normalize( worldView+LView));
                //控制高光的范围
                float3 specularReflection = pow(saturate(dotSpecular), _SpecularRatio);
                
                
  
 
              float4 col;
              float fresnel = 0.5*LdotN+0.5;
              //根据法线的强度 来确定两种颜色之间的混合 ????
              col.rgb  = lerp(_BottomColor.xyz, _TopColor.xyz, fresnel);
             
              col.rgb = saturate (LdotN) *col.rgb;
             
            
              //加上高光
              col.rgb += specularReflection;
              col.rgb = lerp (col.rgb,refTex.rgb*_ReflectionLight,0.7);
              //col.rgb +=refTex.rgb*_ReflectionLight;
              //加上灯光颜色
              col.rgb*=lightColor;
              col.rgb *= i.VertColor.rgb;
              //控制透明度
              
              col.a =i.VertColor.a * _Alpha;
              return col;
            }
 
        ENDCG    
        }  
 
    }
 
    FallBack "Diffuse"


}


四、新建材质球步骤如下:

然后更改材质球的渲染模式,改成我们刚刚写的shader即可

在网上找两张法线贴图,和水的照片贴到材质球上即可,其他参数自行调整

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。