一種火焰shader的實現

2021-08-18 10:02:39 字數 3569 閱讀 1724

火焰在我們的日常生活中十分常見,我們都知道火焰有內外焰之分,在現實世界中內外焰的顏色區別並不是十分明顯,而在大多數遊戲尤其是**渲染風格的遊戲中火焰的內外焰顏色有明顯的區別(我十分喜愛的一款國產遊戲:蠟燭人)

接下來我們來實現乙個簡易的火焰shader

先上最終效果圖

整體思路:分別渲染火焰的內焰和外焰,疊加後得到最終效果

首先我們來實現火焰的主體也就是內焰的效果,為了表現出火焰扭曲且流動的特性,我們需要使用一張噪音紋理和一張控制扭曲的紋理,關鍵步驟是使用扭曲紋理來取樣這張流動的噪音紋理,我們這裡選擇使用扭曲紋理的rgb通道中的兩個通道來對噪音紋理進行取樣:

fixed4 distort = tex2d(_distorttex, i.uv2) * _distort;

fixed4 noise = tex2d(_noisetex,fixed2((i.uv.x + _time.x * _speedx) + distort.g ,(i.uv.y + _time.x * _speedy) + distort.r));

這裡為防止偏移速度過快使用_time.x控制流動速度,_distort控制扭曲的強度

我們同樣可以用兩張噪音紋理完成這種效果,先取樣一張噪音紋理,對其加上偏移和強度控制後在用於取樣第二張噪音紋理,可以達成類似效果此處不再演示

得到的效果如下:

好的,已經初步有擾亂和流動的感覺了,但是火焰不可能是全屏的,應當還有漸變效果,這裡我們自然可以想到使用一張從上到下由黑變白的漸變紋理與其疊加從而產生一種漸變的效果

float4 gradientblend = lerp(float4(1,1,1,1), float4(0, 0, 0, 0), (i.uv2.y + _height));

noise += gradientblend;

float4 flame = float4(noise.rgb, saturate(noise.a * _mainalphacontrol));

注意,這裡的疊加次數越多,得到的效果就更加平滑,這裡我選擇疊加兩次,由於多次疊加,疊加後用saturate將alpha鉗制,使用_height來控制漸變的範圍,_alphacontrol用於控制邊緣

得到效果如下:

恩不錯,現在乘上我們的顏色就能得到內焰的效果了,現在考慮外焰效果,我們可以將外焰考慮為只是在內焰的邊緣向外延伸一段距離的火焰,所以可以將flame的alpha值加上乙個閾值後再減去原本的而得到

這樣我們就得到了外焰的效果,乘上外焰顏色再和內焰相加即可得到最終的效果了,由於疊加的漸變紋理alpha自身就是漸變的,所以我們最終得到的顏色也帶有漸變的效果

完整的shader如下:

shader "myshader/firetest"

_distorttex("distort texture", 2d) = "white" {}

//控制整體的alpha值

_mainalphacontrol("mainalphacontrol", range(1,20)) = 1

_edgealphacontrol("edgealphacontrol", range(1,50)) = 1

//控制漸變紋理

_height("height", range(-4,10)) = 1

//火焰邊緣大小

_edge("edge", range(0.02,0.3)) = 0.1

//控制扭曲強度

_distort("distort", range(0,1)) = 0.2

_maincolor("maincolor",color) = (1,1,1,1)

_edgecolor("edgecolor",color) = (1,1,1,1)

} subshader

lod 100

zwrite off cull off

blend srcalpha oneminussrcalpha

pass

; struct v2f

; float _speedx, _speedy;

sampler2d _noisetex, _distorttex;

float4 _distorttex_st, _noisetex_st;

float _height, _edge, _distort, _mainalphacontrol, _edgealphacontrol;

float4 _maincolor;

float4 _edgecolor;

fixed4 frag(v2f i) : sv_target

endcg}}}

學生黨一枚,文章中的錯誤,不足誠請各位指點!!

參考:更新:最近在學ue4,這裡也提供一種類似火焰實現的效果

同樣先上最終效果圖

這裡選擇用溶解的方法實現火焰效果,原理和之前提到的類似。混合模式為translucent,無光照。

首先是uv處理部分,簡單的實現uv流動。

其次我們來實現火焰的主體,這裡我們使用減法實現溶解。貼圖首先乘上給定的edgesharp變數,用於控制外焰邊緣的軟硬程度,從上圖看即其值越大火焰邊緣的值越白。然後用減法減去變數值,並由mask過通道的uv來控制。最左邊減edgesharp保證其小於等於0。最右邊則減去-1,這是因為我們要保證最右邊都為白色,所以減-1可以保證右側原本為0值的黑色部分都變白。然後再通過add乙個變數值用來控制火焰整體的移動,就和之前unity中實現的height控制一樣。最後的影象有小於0的部分也有大於1的部分所以再通過clamp鉗制。

最後再加上折射效果,最左側的折射率為1即不折射,靠近右側的折射率由引數控制即可。然後再加上法線貼圖和顏色控制即可完成火焰效果。

一種分頁的實現

以下 是一種分頁的實現。分別是檔案page.php和page.css。分頁的糾結點在於分頁條中省略號的顯示。實現的基本邏輯是 1,接收瀏覽器端傳過來的想要顯示的頁碼數 page。page get p 2,根據頁碼數 page 以及固定的每頁顯示數 pagesize 從資料庫中取資料。sql sele...

記憶體池的一種實現

include include include include include const.h include utilityfunc.h include hashtable.h include logmsg.h define system page size 4096 define default...

快速排序的一種實現

閒來沒事,寫了乙個程式玩玩,省的到時候會了shell,又不會c的程式設計了 手動痛哭 本著簡明的原則,選取的標準數是在陣列的 開頭 或者 結尾處 這裡需要注意,如果你選擇的基準數是在左側,那麼就需要從右側開始遍歷陣列 從右側選取的基準數也是同理。include include include usi...