1. 程式人生 > >Unity相機潛入水面下的螢幕特效shader

Unity相機潛入水面下的螢幕特效shader

由於最近找相關程式碼或者三維裡兩個平面交線的演算法都沒找到合理的,便自己花了兩個小時想了想,下邊先上演算法,再上程式碼

下邊上演算法:

主要問題是需要計算當相機半潛入水面時,即相機的近平面一部分在水面上,一部分在水面下,因此需要計算相機近平面和水面的交線。

下面說說兩個平面的交線計算方法:

1,  兩個平面的法線叉乘,取得交線的向量,此時再需要找到一個點,就可以用點和向量確定一條直線

2,  因為直線的方程式:P=P0+tu;P0為已知的直線上的一個點,u為已知的向量

       平面的方程式:(P-P1)●normal=0;P1為已知的一個平面上的點,normal為已知的平面的法線向量

       然後將直線方程代入平面方程

        即 (P0-P1+tu)●normal=0;

        即(P0-P1)●normal=-tu●normal;

        即t=-(P0-P1)●normal/u●normal;

下邊上程式碼:

//這個指令碼掛在相機上

using UnityEngine;

public class imageeffect : MonoBehaviour {

    //水面的位置

    public Transform water;

    //螢幕特效的材質

    public Material mat;

    //相機平面的法線和水面的法線

    private Vector3 nor_came, nor_water;

    //相機

    private Camera main;
    Vector3 pos;
void Start () {
        main = transform.GetComponent<Camera>();
}


void Update () {
        nor_came = transform.forward;
        nor_water = water.up;
        //兩個平面的交線向量
        Vector3 nor1 = Vector3.Cross(nor_came, nor_water);
        //相機平面的法線向量和交線向量叉乘
        Vector3 nor2 = Vector3.Cross(nor_came, nor1);
        //相機近平面的上的中心點
        Vector3 cam_plane_pos = transform.position + transform.forward * main.nearClipPlane;
        Vector3 p = cam_plane_pos - water.position;
        float d = -Vector3.Dot(p, water.up) / Vector3.Dot(nor2, water.up);
        pos = main.WorldToScreenPoint(cam_plane_pos + nor2 * d);
}
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        mat.SetFloat("_Posy", pos.y);
        Graphics.Blit(source, destination, mat);
    }

}

下面上shader程式碼

Shader "Hidden/effectshader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always


Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"


struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};


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


v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}

sampler2D _MainTex;
float _Posy;


fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
if(_ScreenParams.y-i.vertex.y<_Posy){
col.rgb=col.rgb*0.7+float3(0,0.3,0.3);
}
return col;
}
ENDCG
}
}

}

下面上圖


水下效果我這裡暫時混合了一個顏色,可以用一個氣泡紋理,將uv的Y根據_Time變數取樣,就可以獲得氣泡向上浮起的動畫,由於沒有美工,自己找的氣泡紋理太醜,就不上圖了哈。

水面暫時用一個綠色的面片代替,水面的shader後邊再寫。

第一次寫部落格,如果有什麼不對的地方歡迎指出

轉載請註明連結