
宣告:本文涉及圖文和模型素材僅用于個人學習、研究和欣賞,請勿二次修改、非法傳播、轉載、出版、商用、及進行其他獲利行為,
背景
如果你有玩過 ?? 《王者榮耀》、《陰陽師》 等手游,一定注意到過它的啟動影片、皮膚立繪卡片等場景,經常采用靜態底圖加區域液態流動效果的簡單影片,這些流動影片可能出現在緩緩流動的水流 ??、迎風飄動的旗幟 ??、游戲角色衣袖 ???♀?、隨著時間緩動的云、雨、霧天氣效果 ? 等,這種過渡效果不僅節省了開發全量影片的成本,而且使得游戲畫面更加熱血、冒險、奧德賽、高級,也更加容易吸引玩家氪金 ??,
本文使用前端開發技術,結合 SVG 和 CSS 來實作類似的液化流動效果,本文包含的知識點主要包括:mask-image 遮罩、feTurbulence 和 feDisplacementMap 濾鏡、filter 屬性、canvas 繪制方法、TimelineMax 影片以及input[type=file] 本地圖片資源加載等,
效果
先來看看實作效果,下面幾個示例以及 ?? 文章 Banner 圖都是應用了由本文內容生成的液態流動影片效果,由于GIF 圖壓縮比較嚴重,影片效果看起來不是很流暢 ??,大家不妨通過以下演示頁面鏈接,親自體驗一下效果,生成自己的 傳說、典藏 皮膚立繪吧 ??,
?????在線體驗:https://dragonir.github.io/paint-heat-map/?????在線體驗:https://codepen.io/dragonir/full/qBoxQKW
?? 霧氣擴散 塞爾達傳說:曠野之息

?? 衣袖飄動 貂蟬:貓影幻舞

?? 湖光波動

?? 文字液化

??ps:體驗頁面部署在Gitpage上傳圖片功能不是真正上傳到服務器,而是只會加載到瀏覽器本地,頁面不會獲取任何資訊,大家可以放心體驗,不用擔心隱私泄漏問題,
實作
頁面主要由 2 部分構成,頂部用于加載圖片 ,并且可以通過按住 ?? 滑鼠劃動的方式繪制熱點路徑,給圖片添加流動效果;底部是控制區域,點擊按鈕 ?? 清除畫布,可以清除繪制的流動影片效果、點擊按鈕 ?? 切換圖片可以加載本地的圖片,

??注意,還有一個隱形的功能,當你繪制完成時,可以點擊??滑鼠右鍵,然后選擇保存圖片,保存的這張圖片就是我們繪制流體影片路徑的熱點圖,利用這張熱點圖,使用本文的CSS知識,就能把靜態圖片轉化成動態圖啦!
HTML 頁面結構
#sketch 元素主要是用于繪制和加載流動效果熱點圖的畫板;#button_container 是頁面底部的按鈕控制區域;svg 元素用于利用其 filter 濾鏡實作液態流動影片效果,包括 feTurbulence 和 feDisplacementMap 濾鏡,
<main id="sketch">
<canvas id="canvas" data-img=""></canvas>
<div >
<div id="maskInner" ></div>
</div>
</main>
<section >
<button >清除畫布</button>
<button ><input type="file" id="upload">上傳圖片</button>
</section>
<svg>
<filter id="heat" filterUnits="objectBoundingBox" x="0" y="0" height="100%">
<feTurbulence id="heatturb" type="fractalNoise" numOctaves="1" seed="2" />
<feDisplacementMap xChannelSelector="G" yChannelSelector="B" scale="22" in="SourceGraphic" />
</filter>
</svg>
?? feTurbulence 和 feDisplacementMap
feTurbulence:濾鏡利用Perlin噪聲函式創建了一個影像,利用它可以實作人造紋理比如說云紋、大理石紋等模擬濾鏡效果,feDisplacementMap:映射置換濾鏡,該濾鏡用來自影像中從in2到空間的像素值置換影像從in到空間的像素值,即它可以改變元素和圖形的像素位置,通過遍歷原圖形的所有像素點,feDisplacementMap重新映射替換一個新的位置,形成一個新的圖形,該濾鏡在業界的主流應用是對圖形進行形變,扭曲,液化,
CSS 樣式
接著看看樣式的實作,main 元素作為主容器并將主圖案作為背景圖片;canvas 作為畫布占據 100% 的空間位置;.mask 和 .mask-inner 用于生成如下圖所示熱點路徑與背景圖相溶的效果,這種效果是借助 mask-image 實作的,最后,為了生成動態流動效果,.mask-inner 通過 filter: url(#heat) 將前面生成的 svg 作為濾鏡來源,后續即將在 JavaScript 中通過不間斷修改 svg 濾鏡的屬性,來生成液態流動影片,
main {
position: relative;
background-image: url('bg.jpg');
background-size: cover;
background-position: 100% 50%;
}
canvas {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.mask {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
mask-mode: luminance;
mask-size: 100% 100%;
backdrop-filter: hard-light;
mask-image: url('mask.png');
}
.mask-inner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: url('bg.jpg') 0% 0% repeat;
background-size: cover;
background-position: 100% 50%;
filter: url(#heat);
mask-image: url('mask.png')
}

?? mask-image
mask-image CSS 屬性用于設定元素上遮罩層的影像,
語法:
// 默認值,透明的黑色影像層,也就是沒有遮罩層,
mask-image: none;
// <mask-source><mask>或CSS影像的url的值
mask-image: url(masks.svg#mask1);
// <image> 圖片作為遮罩層
mask-image: linear-gradient(rgba(0, 0, 0, 1.0), transparent);
mask-image: image(url(mask.png), skyblue);
// 多個值
mask-image: image(url(mask.png), skyblue), linear-gradient(rgba(0, 0, 0, 1.0), transparent);
// 全域值
mask-image: inherit;
mask-image: initial;
mask-image: unset;
兼容性:

?此功能某些瀏覽器尚在開發中,需要使用瀏覽器前綴以兼容不同瀏覽器,
JavaScript 方法
① 繪制熱點圖
監聽滑鼠移動和點擊事件,在 canvas 上繪制波動路徑熱點,
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var sketch = document.getElementById('sketch');
var sketchStyle = window.getComputedStyle(sketch);
var mouse = { x: 0, y: 0 };
canvas.width = parseInt(sketchStyle.getPropertyValue('width'));
canvas.height = parseInt(sketchStyle.getPropertyValue('height'));
canvas.addEventListener('mousemove', e => {
mouse.x = e.pageX - canvas.getBoundingClientRect().left;
mouse.y = e.pageY - canvas.getBoundingClientRect().top;
}, false);
ctx.lineWidth = 40;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('mousedown', () => {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', () => {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = () => {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
var url = canvas.toDataURL();
document.querySelectorAll('div').forEach(item => {
item.style.cssText += `
display: initial;
-webkit-mask-image: url(${url});
mask-image: url(${url});
`;
});
};
繪制完成后,可以在頁面中右鍵保存生成的波動路徑熱點圖,直接將繪制滿意的熱點圖放到 CSS 中,就能給喜歡的圖片添加區域波動效果了,下面這張圖片就是本示例頁面使用的波動的熱點路徑圖,

② 生成影片
為了生成實時更新的波動效果,本文使用了 TweenMax 來通過改變 feTurbulence 的 baseFrequency 屬性值來實作,使用其他影片庫或使用 requestAnimationFrame 也是可以實作相同的功能,
feTurb = document.querySelector('#heatturb');
var timeline = new TimelineMax({
repeat: -1,
yoyo: true
}),
timeline.add(
new TweenMax.to(feTurb, 8, {
onUpdate: () => {
var bfX = this.progress() * 0.01 + 0.025,
bfY = this.progress() * 0.003 + 0.01,
bfStr = bfX.toString() + ' ' + bfY.toString();
feTurb.setAttribute('baseFrequency', bfStr);
}
}),
0);
③ 清除畫布
點擊清除畫布按鈕,可以清空已經繪制的波動路徑,主要是通過清除頁面元素 mask-image 的屬性值以及清 canvas 畫布來實作的,
function clear() {
document.querySelectorAll('div').forEach(item => {
item.style.cssText += `
display: none;
-webkit-mask-image: none;
mask-image: none;
`;
});
}
document.querySelectorAll('.button').forEach(item => {
item.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
clear();
})
});
④ 切換圖片
點擊切換圖片,可以加載本地的一張圖片作為繪制底圖,該功能是通過 input[type=file] 來實作圖片資源的獲取,然后通過修改 CSS 將它設定成新的畫布背景,
document.getElementById('upload').onchange = function () {
var imageFile = this.files[0];
var newImg = window.URL.createObjectURL(imageFile);
clear();
document.getElementById('sketch').style.cssText += `
background: url(${newImg});
background-size: cover;
background-position: center;
`;
document.getElementById('maskInner').style.cssText += `
background: url(${newImg});
background-size: cover;
background-position: center;
`;
};
到這里,全部功能都實作完畢了,大家趕快制作一張自己喜歡的 史詩皮膚 或 奧德賽小游戲 的啟動頁面吧 ??,

??原始碼地址:https://github.com/dragonir/paint-heat-map
總結
本文包含的新知識點主要包括:
mask-image遮罩元素feTurbulence和feDisplacementMapsvg濾鏡filter屬性Canvas繪制方法TimelineMax影片input[type=file]本地圖片資源加載
想了解其他前端知識或其他未在本文中詳細描述的
Web 3D開發技術相關知識,可閱讀我往期的文章,轉載請注明原文地址和作者,如果覺得文章對你有幫助,不要忘了一鍵三連哦 ??,
附錄
-
我的3D專欄可以點擊此鏈接訪問 ??
-
[1]. ?? 使用Three.js實作炫酷的賽博朋克風格3D數字地球大屏
-
[2]. ?? Three.js 實作3D開放世界小游戲:阿貍的多元宇宙
-
[3]. ?? Three.js 火焰效果實作艾爾登法環動態logo
-
[4]. ?? Three.js 實作2022冬奧主題3D趣味頁面,含冰墩墩
-
... -
[1]. ?? 前端實作很哇塞的瀏覽器端掃碼功能
-
[2]. ?? 前端瓦片地圖加載之塞爾達傳說曠野之息
-
[3]. ?? 僅用CSS幾步實作賽博朋克2077風格視覺效果
-
...
參考
- [1]. https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/feTurbulence
- [2]. https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/feDisplacementMap
- [3]. https://developer.mozilla.org/zh-CN/docs/Web/CSS/mask-image
- [4]. https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter
作者:dragonir 本文地址:https://www.cnblogs.com/dragonir/p/16545805.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/500834.html
標籤:其他
上一篇:物件及日期定時器
