threejs做特效:實現(xiàn)物體的發(fā)光效果-EffectComposer詳解!
共 35748字,需瀏覽 72分鐘
·
2024-08-05 09:15
點擊上方 前端Q,關注公眾號
回復加群,加入前端Q技術交流群
簡介與效果概覽
各位大佬給個贊,感謝呢!
threejs的開發(fā)中,實現(xiàn)物體發(fā)光效果是一個常見需求,比如實現(xiàn)樓體的等待照明
要想實現(xiàn)這樣的效果,我們只需要了解一個效果合成器概念:EffectComposer。
效果合成器能夠合成各種花里胡哨的效果,好比是一個做特效的AE,本教程,我們將使用它來實現(xiàn)一個簡單的發(fā)光效果。
如圖,這是我們將導入的一個模型
.
我們要給他賦予靈魂,實現(xiàn)下面的發(fā)光效果
順帶的,我們要實現(xiàn)物體的自動旋轉、一個簡單的性能監(jiān)視器、一個發(fā)光參數(shù)調節(jié)的面板
技術方案
原生html框架搭建
借助threejs實現(xiàn)一個物體發(fā)光效果非常簡單,首先我們使用html搭建一個簡單的開發(fā)框架
參考官方起步文檔:three.js中文網(wǎng)
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js物體發(fā)光效果</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
<link type="text/css" rel="stylesheet" href="./main.css" />
<style>
#info>* {
max-width: 650px;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
</script>
</body>
</html>
上述代碼中,我們采用type="importmap"的方式引入了threejs開發(fā) 的一些核心依賴,"three"是開發(fā)的最基本依賴;在Three.js中,"addons" 通常指的是一些附加功能或擴展模塊,它們提供了額外的功能,可以用于增強或擴展Three.js的基本功能。
在type="module"中,我們引入了threejs的一些基礎依賴,OrbitControls軌道控制器和GLTFLoader模型加載器。
實現(xiàn)模型的加載
我們將下載好的模型放在文件根目錄
http://www.yanhuangxueyuan.com/threejs/examples/models/gltf/PrimaryIonDrive.glb
基于threejs的基礎知識,我們先實現(xiàn)模型的加載與渲染
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
init()
function init() {
const container = document.getElementById("container");
// WebGL渲染器
// antialias是否執(zhí)行抗鋸齒。默認為false.
renderer = new THREE.WebGLRenderer({ antialias: true });
// 設置設備像素比。通常用于避免HiDPI設備上繪圖模糊
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 設置色調映射 這個屬性用于在普通計算機顯示器或者移動設備屏幕等低動態(tài)范圍介質上,模擬、逼近高動態(tài)范圍(HDR)效果。
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild(renderer.domElement);
// 創(chuàng)建新的場景對象。
const scene = new THREE.Scene();
// 創(chuàng)建透視相機
camera = new THREE.PerspectiveCamera(
40,
window.innerWidth / window.innerHeight,
1,
100
);
camera.position.set(-5, 2.5, -3.5);
scene.add(camera);
// 創(chuàng)建軌道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 3;
controls.maxDistance = 8;
// 添加了一個環(huán)境光
scene.add(new THREE.AmbientLight(0xcccccc));
// 創(chuàng)建了一個點光源
const pointLight = new THREE.PointLight(0xffffff, 100);
camera.add(pointLight);
// 模型加載
new GLTFLoader().load("./PrimaryIonDrive.glb", function (gltf) {
const model = gltf.scene;
scene.add(model);
const clip = gltf.animations[0];
renderer.render(scene, camera);
});
}
</script>
現(xiàn)在,我們的頁面中就有了下面的場景
接下來,我們實現(xiàn)模型的發(fā)光效果添加。
模型發(fā)光效果添加
實現(xiàn)模型的發(fā)光效果,實際是EffectComposer效果合成器實現(xiàn)的。
官方定義:用于在three.js中實現(xiàn)后期處理效果。該類管理了產(chǎn)生最終視覺效果的后期處理過程鏈。 后期處理過程根據(jù)它們添加/插入的順序來執(zhí)行,最后一個過程會被自動渲染到屏幕上。
簡單來說,EffectComposer效果合成器只是一個工具,它可以將多種效果集成,進行渲染。我們來看一個偽代碼:
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
// 創(chuàng)建效果合成器
composer = new EffectComposer(renderer);
composer.addPass(發(fā)光效果);
composer.addPass(光暈效果);
composer.addPass(玻璃磨砂效果
// 渲染
composer.render();
它的實現(xiàn)過程大致如上述代碼。要實現(xiàn)發(fā)光效果,我們需要先熟悉三個Pass。
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
-
RenderPass: 渲染通道是用于傳遞渲染結果的對象。RenderPass是EffectComposer中的一個通道,用于將場景渲染到紋理上。(固定代碼,相當于混合效果的開始) -
UnrealBloomPass: 這是一個用于實現(xiàn)逼真的輝光效果的通道。它模擬了逼真的輝光,使得場景中的亮部分在渲染后產(chǎn)生耀眼的輝光效果。(不同效果有不同的pass) -
OutputPass: OutputPass是EffectComposer中的一個通道,用于將最終渲染結果輸出到屏幕上。(固定代碼,相當于混合效果的結束)
現(xiàn)在,我們完整的實現(xiàn)發(fā)光效果
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
let camera;
let composer, renderer;
const params = {
threshold: 0,
strength: 1,
radius: 0,
exposure: 1,
};
init();
function init() {
const container = document.getElementById("container");
// WebGL渲染器
// antialias是否執(zhí)行抗鋸齒。默認為false.
renderer = new THREE.WebGLRenderer({ antialias: true });
// 設置設備像素比。通常用于避免HiDPI設備上繪圖模糊
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 設置色調映射 這個屬性用于在普通計算機顯示器或者移動設備屏幕等低動態(tài)范圍介質上,模擬、逼近高動態(tài)范圍(HDR)效果。
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild(renderer.domElement);
// 創(chuàng)建新的場景對象。
const scene = new THREE.Scene();
// 創(chuàng)建透視相機
camera = new THREE.PerspectiveCamera(
40,
window.innerWidth / window.innerHeight,
1,
100
);
camera.position.set(-5, 2.5, -3.5);
scene.add(camera);
// 創(chuàng)建軌道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 3;
controls.maxDistance = 8;
// 添加了一個環(huán)境光
scene.add(new THREE.AmbientLight(0xcccccc));
// 創(chuàng)建了一個點光源
const pointLight = new THREE.PointLight(0xffffff, 100);
camera.add(pointLight);
// 創(chuàng)建了一個RenderPass對象,用于將場景渲染到紋理上。
const renderScene = new RenderPass(scene, camera);
// 創(chuàng)建了一個UnrealBloomPass對象,用于實現(xiàn)輝光效果。≈
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
// 設置發(fā)光參數(shù),閾值、強度和半徑。
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;
// 創(chuàng)建了一個OutputPass對象,用于將最終渲染結果輸出到屏幕上。
const outputPass = new OutputPass();
// 創(chuàng)建了一個EffectComposer對象,并將RenderPass、UnrealBloomPass和OutputPass添加到渲染通道中。
composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
composer.addPass(outputPass);
// 模型加載
new GLTFLoader().load("./PrimaryIonDrive.glb", function (gltf) {
const model = gltf.scene;
scene.add(model);
const clip = gltf.animations[0];
animate();
});
}
function animate() {
requestAnimationFrame(animate);
// 通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
</script>
現(xiàn)在,我們就實現(xiàn)發(fā)光的基本效果了!
實現(xiàn)物體的自動旋轉動畫
現(xiàn)在,我們實現(xiàn)一下物體自身的旋轉動畫
AnimationMixer是three中的動畫合成器,使用AnimationMixer可以解析到模型中的動畫數(shù)據(jù)
// 模型加載
new GLTFLoader().load("./PrimaryIonDrive.glb", function (gltf) {
const model = gltf.scene;
scene.add(model);
//創(chuàng)建了THREE.AnimationMixer 對象,用于管理模型的動畫。
mixer = new THREE.AnimationMixer(model);
//從加載的glTF模型文件中獲取動畫數(shù)據(jù)。
//這里假設模型文件包含動畫數(shù)據(jù),通過 gltf.animations[0] 獲取第一個動畫片段。
const clip = gltf.animations[0];
// 使用 mixer.clipAction(clip) 創(chuàng)建了一個動畫操作(AnimationAction),并立即播放該動畫
mixer.clipAction(clip.optimize()).play();
animate();
});
實現(xiàn)動畫更新
let clock;
clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
//使用了 clock 對象的 getDelta() 方法來獲取上一次調用后經(jīng)過的時間,即時間間隔(delta)。
const delta = clock.getDelta();
//根據(jù)上一次更新以來經(jīng)過的時間間隔來更新動畫。
//這個方法會自動調整動畫的播放速度,使得動畫看起來更加平滑,不受幀率的影響
mixer.update(delta);
// 通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
完整代碼
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
let camera, stats;
let composer, renderer, mixer, clock;
const params = {
threshold: 0,
strength: 1,
radius: 0,
exposure: 1,
};
init();
function init() {
const container = document.getElementById("container");
clock = new THREE.Clock();
// WebGL渲染器
// antialias是否執(zhí)行抗鋸齒。默認為false.
renderer = new THREE.WebGLRenderer({ antialias: true });
// .....
// 模型加載
new GLTFLoader().load("./PrimaryIonDrive.glb", function (gltf) {
const model = gltf.scene;
scene.add(model);
mixer = new THREE.AnimationMixer(model);
const clip = gltf.animations[0];
mixer.clipAction(clip.optimize()).play();
animate();
});
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
// 通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
</script>
優(yōu)化屏幕縮放邏輯
init{
// ....
window.addEventListener("resize", onWindowResize);
}
function onWindowResize() {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
composer.setSize(width, height);
}
添加參數(shù)調節(jié)面板
在Three.js中,GUI是一個用于創(chuàng)建用戶界面(UI)控件的庫。具體來說,GUI庫允許你在Three.js應用程序中創(chuàng)建交互式的圖形用戶界面元素,例如滑塊、復選框、按鈕等,這些元素可以用于控制場景中的對象、相機、光源等參數(shù)。
我們借助這個工具實現(xiàn)如下發(fā)光效果調試面板
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
init{
// ....
// 創(chuàng)建一個GUI實例
const gui = new GUI();
// 創(chuàng)建一個名為"bloom"的文件夾,用于容納調整泛光效果的參數(shù)
const bloomFolder = gui.addFolder("bloom");
// 在"bloom"文件夾中添加一個滑塊控件,用于調整泛光效果的閾值參數(shù)
bloomFolder
.add(params, "threshold", 0.0, 1.0)
.onChange(function (value) {
bloomPass.threshold = Number(value);
});
// 在"bloom"文件夾中添加另一個滑塊控件,用于調整泛光效果的強度參數(shù)
bloomFolder
.add(params, "strength", 0.0, 3.0)
.onChange(function (value) {
bloomPass.strength = Number(value);
});
// 在根容器中添加一個滑塊控件,用于調整泛光效果的半徑參數(shù)
gui
.add(params, "radius", 0.0, 1.0)
.step(0.01)
.onChange(function (value) {
bloomPass.radius = Number(value);
});
// 創(chuàng)建一個名為"tone mapping"的文件夾,用于容納調整色調映射效果的參數(shù)
const toneMappingFolder = gui.addFolder("tone mapping");
// 在"tone mapping"文件夾中添加一個滑塊控件,用于調整曝光度參數(shù)
toneMappingFolder
.add(params, "exposure", 0.1, 2)
.onChange(function (value) {
renderer.toneMappingExposure = Math.pow(value, 4.0);
});
window.addEventListener("resize", onWindowResize);
}
添加性能監(jiān)視器
import Stats from "three/addons/libs/stats.module.js";
init{
stats = new Stats();
container.appendChild(stats.dom);
// ...
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
stats.update();
// 通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
在Three.js中,Stats是一個性能監(jiān)視器,用于跟蹤幀速率(FPS)、內存使用量和渲染時間等信息。
完整demo代碼
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js物體發(fā)光效果</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
<link type="text/css" rel="stylesheet" href="./main.css" />
<style>
#info>* {
max-width: 650px;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from "three";
import Stats from "three/addons/libs/stats.module.js";
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
let camera, stats;
let composer, renderer, mixer, clock;
const params = {
threshold: 0,
strength: 1,
radius: 0,
exposure: 1,
};
init();
function init() {
const container = document.getElementById("container");
stats = new Stats();
container.appendChild(stats.dom);
clock = new THREE.Clock();
// WebGL渲染器
// antialias是否執(zhí)行抗鋸齒。默認為false.
renderer = new THREE.WebGLRenderer({ antialias: true });
// 設置設備像素比。通常用于避免HiDPI設備上繪圖模糊
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// 設置色調映射 這個屬性用于在普通計算機顯示器或者移動設備屏幕等低動態(tài)范圍介質上,模擬、逼近高動態(tài)范圍(HDR)效果。
renderer.toneMapping = THREE.ReinhardToneMapping;
container.appendChild(renderer.domElement);
// 創(chuàng)建新的場景對象。
const scene = new THREE.Scene();
// 創(chuàng)建透視相機
camera = new THREE.PerspectiveCamera(
40,
window.innerWidth / window.innerHeight,
1,
100
);
camera.position.set(-5, 2.5, -3.5);
scene.add(camera);
// 創(chuàng)建軌道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.maxPolarAngle = Math.PI * 0.5;
controls.minDistance = 3;
controls.maxDistance = 8;
// 添加了一個環(huán)境光
scene.add(new THREE.AmbientLight(0xcccccc));
// 創(chuàng)建了一個點光源
const pointLight = new THREE.PointLight(0xffffff, 100);
camera.add(pointLight);
// 創(chuàng)建了一個RenderPass對象,用于將場景渲染到紋理上。
const renderScene = new RenderPass(scene, camera);
// 創(chuàng)建了一個UnrealBloomPass對象,用于實現(xiàn)輝光效果。≈
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
// 設置發(fā)光參數(shù),閾值、強度和半徑。
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;
// 創(chuàng)建了一個OutputPass對象,用于將最終渲染結果輸出到屏幕上。
const outputPass = new OutputPass();
// 創(chuàng)建了一個EffectComposer對象,并將RenderPass、UnrealBloomPass和OutputPass添加到渲染通道中。
composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
composer.addPass(outputPass);
// 模型加載
new GLTFLoader().load("./PrimaryIonDrive.glb", function (gltf) {
const model = gltf.scene;
scene.add(model);
mixer = new THREE.AnimationMixer(model);
const clip = gltf.animations[0];
mixer.clipAction(clip.optimize()).play();
animate();
});
const gui = new GUI();
const bloomFolder = gui.addFolder("bloom");
bloomFolder
.add(params, "threshold", 0.0, 1.0)
.onChange(function (value) {
bloomPass.threshold = Number(value);
});
bloomFolder
.add(params, "strength", 0.0, 3.0)
.onChange(function (value) {
bloomPass.strength = Number(value);
});
gui
.add(params, "radius", 0.0, 1.0)
.step(0.01)
.onChange(function (value) {
bloomPass.radius = Number(value);
});
const toneMappingFolder = gui.addFolder("tone mapping");
toneMappingFolder
.add(params, "exposure", 0.1, 2)
.onChange(function (value) {
renderer.toneMappingExposure = Math.pow(value, 4.0);
});
window.addEventListener("resize", onWindowResize);
}
function onWindowResize() {
const width = window.innerWidth;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
composer.setSize(width, height);
}
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
stats.update();
// 通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
</script>
</body>
</html>
main.css
body {
margin: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}
a {
color: #ff0;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
button {
cursor: pointer;
text-transform: uppercase;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
z-index: 1; /* TODO Solve this in HTML */
}
a, button, input, select {
pointer-events: auto;
}
.lil-gui {
z-index: 2 !important; /* TODO Solve this in HTML */
}
@media all and ( max-width: 640px ) {
.lil-gui.root {
right: auto;
top: auto;
max-height: 50%;
max-width: 80%;
bottom: 0;
left: 0;
}
}
#overlay {
position: absolute;
font-size: 16px;
z-index: 2;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: rgba(0,0,0,0.7);
}
#overlay button {
background: transparent;
border: 0;
border: 1px solid rgb(255, 255, 255);
border-radius: 4px;
color: #ffffff;
padding: 12px 18px;
text-transform: uppercase;
cursor: pointer;
}
#notSupported {
width: 50%;
margin: auto;
background-color: #f00;
margin-top: 20px;
padding: 10px;
}
總結
通過本教程,我想現(xiàn)在你對效果合成器一定有了更深入的了解,現(xiàn)在,我們在看看官網(wǎng)的定義:
用于在three.js中實現(xiàn)后期處理效果。該類管理了產(chǎn)生最終視覺效果的后期處理過程鏈。 后期處理過程根據(jù)它們添加/插入的順序來執(zhí)行,最后一個過程會被自動渲染到屏幕上
結合代碼,我想現(xiàn)在理解其它非常容易
<script type="module">
import * as THREE from "three";
import { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";
import { RenderPass } from "three/addons/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "three/addons/postprocessing/UnrealBloomPass.js";
import { OutputPass } from "three/addons/postprocessing/OutputPass.js";
function init() {
// 1【渲染開始】創(chuàng)建了一個RenderPass對象,用于將場景渲染到紋理上。
const renderScene = new RenderPass(scene, camera);
// 2【需要合成的中間特效】創(chuàng)建了一個UnrealBloomPass對象,用于實現(xiàn)輝光效果。≈
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
// 【特效設置】設置發(fā)光參數(shù),閾值、強度和半徑。
bloomPass.threshold = params.threshold;
bloomPass.strength = params.strength;
bloomPass.radius = params.radius;
// 3【效果輸出】創(chuàng)建了一個OutputPass對象,用于將最終渲染結果輸出到屏幕上。
const outputPass = new OutputPass();
// 4【特效合并】創(chuàng)建了一個EffectComposer對象,并將RenderPass、UnrealBloomPass和OutputPass添加到渲染通道中。
composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
composer.addPass(outputPass);
}
function animate() {
requestAnimationFrame(animate);
// 5【渲染特效】通過調用 render 方法,將場景渲染到屏幕上。
composer.render();
}
</script>
往期推薦
最后
歡迎加我微信,拉你進技術群,長期交流學習...
歡迎關注「前端Q」,認真學前端,做個專業(yè)的技術人...
