您當前的位置:首頁 > 繪畫

Unity+FlowMap+薄膜干涉的泡泡渲染效果

作者:由 框Ko 發表于 繪畫時間:2022-03-23

首先看效果

Unity+FlowMap+薄膜干涉的泡泡渲染效果

https://www。zhihu。com/video/1489957292074704897

效果我覺得還是挺好的。。不過考慮到遊戲中應用場景還是太少了 ,所以作用不大。

看了看知乎上幾位博主的泡泡實現,總感覺要麼就是太高端了,要麼就是效果不好,最近剛好看到FlowMap。覺得拿來做泡泡正合適。

存在的問題

從結果大致一看 的確是個泡泡了 而且是有流動效果的泡泡,

跟真實的圖片對比一下,特別小的Noise還是沒有,可以考慮多采樣個NOise圖 或者是在繪製FlowMap的時候多講究講究

實現思路

薄膜干涉部分

使用FlowMap 取樣水面法線貼圖,作為泡泡表面法線 計算模擬法線,獲得干擾過後的入射角。

並且取FlowMap的一個值 作為頁面厚度的干擾值。

組合作為UV值取樣下面的貼圖。

這麼看來確實還真挺物理的,利用泡泡表面流動取樣真實計算出來的貼圖。

Unity+FlowMap+薄膜干涉的泡泡渲染效果

鏡面反射光部分

因為泡泡是雙層的,所以會生成兩個鏡面反轉的像。

只需要正常使用 ReflectDir和倒轉ReflectDir ,取樣兩次CubeMap後疊加即可實現。

有了思路之後,這個Shader我覺得最難的其實是中間的調參的過程,如果利用手頭的素材讓效果更好才是難點

正式開始計算

需要用到的貼圖資源

Unity+FlowMap+薄膜干涉的泡泡渲染效果

薄膜干涉貼圖、FLowmap、反射的CubeMap、水面的Normal

薄膜干涉貼圖下載剪下下就好

FlowMap 按照百人計劃中的使用方法 繪製出來,

Ball模型是按縱向展開的,繪製的時候特意保證從上往下流動的感覺,因為泡泡上面的水也受到重力的影響向下流。所以我就大概按照這個趨勢畫出來。

反射的QubeMap用個探針Bake出來就好,

Normal就拿隔壁Demo的水面效果,用起來感覺不錯。

計算薄膜干涉

第一步 計算取樣NormalMap的UV

因為我們要使用FLowMap 取樣Normal

同時為了避免FlowMap太重複 跟個岩漿的感覺一樣,所以也要給FlowMap加上Time 讓FlowMap的UV也有所變化。

實現流程可以參考FlowMap的使用方法

(這裡的程式碼可能不能複製過去直接執行,看個大概 最後有完整的Shader)

//取樣 FLowMap

float2

flowUV

=

i

uv

xy

+

_Time

*

0。1

*

_FlowUVDir

)*

_FlowTex_ST

xy

float3

flowDir

=

tex2D

_FlowTex

flowUV

*

2

-

1

flowDir

*=

_FlowSpeed

//控制時間週期

float

phase0

=

frac

_Time

*

0。1

*

_TimeSpeed

);

float

phase1

=

frac

_Time

*

0。1

*

_TimeSpeed

+

0。5

);

float4

tex0

=

tex2D

_NormalTex

i

uv

xy

-

flowDir

xy

*

phase0

);

float4

tex1

=

tex2D

_NormalTex

i

uv

xy

-

flowDir

xy

*

phase1

);

float

flowlerp

=

abs

((

0。5

-

phase0

/

0。5

);

float4

packedNormal

=

lerp

tex0

tex1

flowlerp

float3

normalTS

=

UnpackNormal

packedNormal

);

計算後 獲得使用FlowMap取樣出來的NormalMap

第二步,把取樣出來的NormalMap用TBN 套用到模型表面並計算nDotV

float3

tDirWS

TEXCOORD1

float3

nDirWS

TEXCOORD2

float3

bDirWS

TEXCOORD3

o

tDirWS

=

normalize

mul

unity_ObjectToWorld

float4

v

tangent

xyz

0。0

)。

xyz

);

o

nDirWS

=

UnityObjectToWorldNormal

v

normal

);

o

bDirWS

=

normalize

cross

o

nDirWS

o

tDirWS

*

v

tangent

w

);

//TBN

half3x3

TBN

=

float3x3

i

tDirWS

i

bDirWS

i

nDirWS

);

//計算Ndir

half3

nDirWS

=

normalize

mul

normalTS

TBN

));

float

nDotv

=

saturate

dot

nDirWS

vDirWS

));

讓我們看下帶有FlowMap的菲尼爾效果

Unity+FlowMap+薄膜干涉的泡泡渲染效果

https://www。zhihu。com/video/1490014719922991106

如果使用這個直接作為取樣薄膜干涉圖的UV 就會發現 會有一箇中心向周圍的整體顏色變化趨勢。

看真實泡泡圖的話,其實這種感覺沒那麼強烈。

所以下一步

就是使用 取樣出來的nDirWS dot vDirWS 減去 原生的模型的 nDirWS dot vDirWS

相當於減輕了菲尼爾效果 只保留了部分取樣的Noise效果。

(這裡可能不需要這麼麻煩,可能有其他更好的辦法 請大佬幫我指出)

//減弱菲尼爾效果 對泡泡影響

float

nDotv

=

saturate

dot

nDirWS

vDirWS

));

float

nDotv2

=

saturate

dot

i

nDirWS

vDirWS

));

float

RampYAxis

=

saturate

((

nDotv

-

nDotv2

*

0。95

)+

0。4

-

wave

*

0。8

);

Unity+FlowMap+薄膜干涉的泡泡渲染效果

不帶Wave 光使用nDotV相減的結果

可能有人注意到上面的這個Wave 了

Wave是我自己根據FlowMap取樣出來的一個數值,感覺最後結果中少了點大塊的顏色,

所以利用了上面FlowMap計算出來的過程量 ,繪製出個Wave波,參與運算。 讓效果好點

//引入波控制

float wave = lerp(flowDir。xy * phase0,flowDir。xy * phase1,flowlerp);

Unity+FlowMap+薄膜干涉的泡泡渲染效果

單wave的效果

Unity+FlowMap+薄膜干涉的泡泡渲染效果

把Wave納入計算後 得到的效果

將取樣出來的Wave值 作為取樣薄膜干涉圖的Y軸

取樣圖的X軸,並採樣圖片

X軸就利用NormalMap的X 作為模擬的厚度,並加入自定義的偏移量和權重來控制

取樣出來的顏色也乘以一個亮度方便控制。

float

RampXAxis

=

_RampXAxisOffset

+

packedNormal

r

*

_RampXAxisNoiseStrength

float2

rampTexUV

=

float2

RampXAxis

RampYAxis

);

float3

rampColor

=

tex2D

_RampTex

rampTexUV

)*

_ColorReflectIntensity

Unity+FlowMap+薄膜干涉的泡泡渲染效果

好像有點詭異

計算反射影象

因為泡泡是反射兩個顛倒的Cube

所以我們需要

1 計算反射方向

2計算反的反射方向

3利用這兩個方向分別取樣Cube

4將這兩個取樣出來的結果合併到一起

過程都很簡單 直接上程式碼

o

posWS

=

mul

unity_ObjectToWorld

v

vertex

);

o

rDirWS

=

reflect

(-

UnityWorldSpaceViewDir

o

posWS

),

o

nDirWS

);

//反射效果

float3

NegaReflectDir

=

float3

(-

i

rDirWS

x

,-

i

rDirWS

y

i

rDirWS

z

);

//計算兩個反射 然後混合

float3

reflectCol1

=

texCUBE

_EnvCube

i

rDirWS

)*

_ReflectAmount

float3

reflectCol2

=

texCUBE

_EnvCube

NegaReflectDir

)*

_ReflectAmount

float3

reflectCol

=

reflectCol1

+

reflectCol2

一樣加入了一些引數控制反射的亮度

Unity+FlowMap+薄膜干涉的泡泡渲染效果

效果還不錯

混合影象

其實我覺得這個最難的就是混合影象 調參

有幾個要點,

薄膜干涉計算出來的顏色 受到反射影象的明度影響很大,

明度高的地方反射出來的顏色也很明顯

(透明度也是這樣,越亮越不透明)

Unity+FlowMap+薄膜干涉的泡泡渲染效果

真實的影象

所以

首要,就是先計算反射影象的明度 然後作為權重來控制反射顏色

其次,反射影象的對比度也比我計算的結果更強一點 ,需要 平方一下增加下對比度

還有,泡泡的邊緣效果也強烈一些 可以計算出 fresnel 控制下強度。

大概思路就是這樣 剩下全是自己控制大小調參的過程了

//菲尼爾效果

float

fresnel

=

pow

1

-

nDotv2

_FresnelPow

);

//開始混合

//獲取明度

float

reflectLumin

=

dot

reflectCol

float3

0。22

0。707

0。071

));

//Ramp顏色受反射影象明度影響很大

float3

finalRampCol

=

rampColor

*(

pow

reflectLumin

1。5

)+

0。05

);

finalRampCol

=

pow

finalRampCol

1。4

);

float3

finalCol

=

finalRampCol

+

fresnel

*

_FresnelIntenisty

*

finalRampCol

*

reflectLumin

+

reflectCol

*

reflectCol

//透明度受反射影象明度 邊緣厚度影響

float

finalAlpha

=

_BubbleAlpha

*(

reflectLumin

*

0。5

+

0。5

)+

fresnel

*

0。2

//輸出

return

float4

finalCol

finalAlpha

);

所有Shader程式碼

Shader

“Unlit/Bubble”

{

Properties

{

_NormalTex

“NormalTex”

2D

=

“bump”

{}

_FlowTex

“_FlowTex”

2D

=

“white”

{}

_TimeSpeed

“_TimeSpeed”

float

=

1

_FlowSpeed

“_FlowSpeed”

float

=

1

_FlowUVDir

“flow UV Dir”

vector

=

1

1

1

1

_RampTex

“RampTex”

2D

=

“white”

{}

_RampXAxisOffset

“X Axis_Offset”

Range

0

1

))=

0。2

_RampXAxisNoiseStrength

“Ramp Tex X Axis Noise Strength”

float

=

2

_ColorReflectIntensity

“薄膜干涉亮度”

Range

0

20

))=

2

_EnvCube

“Reflection Cubemap”

Cube

)=

“_Skybox”

{}

_ReflectAmount

“反射的強度”

Range

0

1

))=

0。5

_BubbleAlpha

“泡泡透明度”

Range

0

2

))

=

1

_FresnelPow

“菲尼爾 對比度”

float

=

3

_FresnelIntenisty

“菲尼爾 亮度”

float

)=

0。2

}

SubShader

{

Tags

{

“RenderType”

=

“Transparent”

}

LOD

100

Pass

{

Tags

{

“LightMode”

=

“ForwardBase”

}

ZWrite

off

Blend

SrcAlpha

OneMinusSrcAlpha

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

#

include

“UnityCG。cginc”

struct

appdata

{

float4

vertex

POSITION

float2

uv

TEXCOORD0

float4

normal

NORMAL

float4

tangent

TANGENT

};

struct

v2f

{

float4

uv

TEXCOORD0

float4

vertex

SV_POSITION

float3

tDirWS

TEXCOORD1

float3

nDirWS

TEXCOORD2

float3

bDirWS

TEXCOORD3

float4

posWS

TEXCOORD4

float3

rDirWS

TEXCOORD5

};

sampler2D

_NormalTex

sampler2D

_FlowTex

float4

_FlowTex_ST

sampler2D

_RampTex

float

_FlowSpeed

float

_TimeSpeed

float2

_FlowUVDir

float

_RampXAxisOffset

float

_RampXAxisNoiseStrength

//反射

samplerCUBE

_EnvCube

float

_ReflectAmount

float

_BubbleAlpha

float

_ColorReflectIntensity

float

_FresnelPow

float

_FresnelIntenisty

v2f

vert

appdata

v

{

v2f

o

o

uv

xy

=

v

uv

o

posWS

=

mul

unity_ObjectToWorld

v

vertex

);

o

vertex

=

UnityObjectToClipPos

v

vertex

);

o

tDirWS

=

normalize

mul

unity_ObjectToWorld

float4

v

tangent

xyz

0。0

)。

xyz

);

o

nDirWS

=

UnityObjectToWorldNormal

v

normal

);

o

bDirWS

=

normalize

cross

o

nDirWS

o

tDirWS

*

v

tangent

w

);

o

rDirWS

=

reflect

(-

UnityWorldSpaceViewDir

o

posWS

),

o

nDirWS

);

return

o

}

fixed4

frag

v2f

i

SV_Target

{

//TBN

half3x3

TBN

=

float3x3

i

tDirWS

i

bDirWS

i

nDirWS

);

//取樣 FLowMap

float2

flowUV

=

i

uv

xy

+

_Time

*

0。1

*

_FlowUVDir

)*

_FlowTex_ST

xy

float3

flowDir

=

tex2D

_FlowTex

flowUV

*

2

-

1

flowDir

*=

_FlowSpeed

//控制時間週期

float

phase0

=

frac

_Time

*

0。1

*

_TimeSpeed

);

float

phase1

=

frac

_Time

*

0。1

*

_TimeSpeed

+

0。5

);

float4

tex0

=

tex2D

_NormalTex

i

uv

xy

-

flowDir

xy

*

phase0

);

float4

tex1

=

tex2D

_NormalTex

i

uv

xy

-

flowDir

xy

*

phase1

);

float

flowlerp

=

abs

((

0。5

-

phase0

/

0。5

);

float4

packedNormal

=

lerp

tex0

tex1

flowlerp

float3

normalTS

=

UnpackNormal

packedNormal

);

//計算Ndir

half3

nDirWS

=

normalize

mul

normalTS

TBN

));

half3

vDirWS

=

normalize

_WorldSpaceCameraPos

xyz

-

i

posWS

);

//引入波控制

float

wave

=

lerp

flowDir

xy

*

phase0

flowDir

xy

*

phase1

flowlerp

);

//減弱菲尼爾效果 對泡泡影響

float

nDotv

=

saturate

dot

nDirWS

vDirWS

));

float

nDotv2

=

saturate

dot

i

nDirWS

vDirWS

));

float

RampYAxis

=

saturate

((

nDotv

-

nDotv2

*

0。95

)+

0。4

-

wave

*

0。8

);

float

RampXAxis

=

_RampXAxisOffset

+

packedNormal

r

*

_RampXAxisNoiseStrength

float2

rampTexUV

=

float2

RampXAxis

RampYAxis

);

float3

rampColor

=

tex2D

_RampTex

rampTexUV

)*

_ColorReflectIntensity

//反射效果

float3

NegaReflectDir

=

float3

(-

i

rDirWS

x

,-

i

rDirWS

y

i

rDirWS

z

);

//計算兩個反射 然後混合

float3

reflectCol1

=

texCUBE

_EnvCube

i

rDirWS

)*

_ReflectAmount

float3

reflectCol2

=

texCUBE

_EnvCube

NegaReflectDir

)*

_ReflectAmount

float3

reflectCol

=

reflectCol1

+

reflectCol2

//菲尼爾效果

float

fresnel

=

pow

1

-

nDotv2

_FresnelPow

);

//開始混合

//獲取明度

float

reflectLumin

=

dot

reflectCol

float3

0。22

0。707

0。071

));

//Ramp顏色受反射影象明度影響很大

float3

finalRampCol

=

rampColor

*(

pow

reflectLumin

1。5

)+

0。05

);

finalRampCol

=

pow

finalRampCol

1。4

);

float3

finalCol

=

finalRampCol

+

fresnel

*

_FresnelIntenisty

*

finalRampCol

*

reflectLumin

+

reflectCol

*

reflectCol

//透明度受反射影象明度 邊緣厚度影響

float

finalAlpha

=

_BubbleAlpha

*(

reflectLumin

*

0。5

+

0。5

)+

fresnel

*

0。2

//輸出

return

float4

finalCol

finalAlpha

);

}

ENDCG

}

}

}

專案檔案

打包成UnityPackages的形式 上傳到百度雲

連結:

https://

pan。baidu。com/s/1n0ruUr

ebWFTYDuGw87MwBw

提取碼:54dw

——來自百度網盤超級會員V5的分享

標簽: 取樣  xy  nDirWS  float  反射