UV图像变换
UV Transform

你将学到什么
- EffectComposer 后期处理管线
- 相机交互控制器
- 轮廓高亮 OutlinePass
- requestAnimationFrame 渲染循环
效果说明
原场景 + 后期 Pass 叠加。
后期处理 · Three.js
核心概念
EffectComposer 多 Pass 链式渲染:RenderPass → 特效 Pass → 输出屏幕。
composer.render()替代renderer.render()。OrbitControls 轨道旋转缩放;开
enableDamping时每帧需controls.update()。选中物体外轮廓发光,常用于编辑器选中态。
实现步骤
- 搭建 Scene / Camera / Renderer 与 OrbitControls
- EffectComposer 组装 Pass 链并 render
代码要点
resize()— 案例中的独立逻辑模块,建议在线编辑器中跳转阅读
源码
js
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { RenderPass, EffectPass, EffectComposer, GodRaysEffect } from 'postprocessing'
// Max Muselmann https://unsplash.com/photos/oIVvGqqwVJw
const image_url =
FILE_HOST + "images/four/photo-1583766395091-2eb9994ed094.avif";
const image_ratio = 687 / 1031;
const image_tex = new THREE.TextureLoader().load(image_url);
image_tex.repeat.set(1, 1);
// Daniil Silantev https://unsplash.com/photos/dxGTQArsC3M
const alpha_url =
FILE_HOST + "images/four/photo-1510942752400-ebce99a8a2c0.avif";
const alpha_tex = new THREE.TextureLoader().load(alpha_url);
alpha_tex.repeat.set(0.6, 2);
alpha_tex.offset.x = (1 - alpha_tex.repeat.x) / 2;
alpha_tex.wrapT = THREE.RepeatWrapping;
// ----
// main
// ----
const renderer = new THREE.WebGLRenderer();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 2, 0.1, 100);
const controls = new OrbitControls(camera, renderer.domElement);
camera.position.set(0, 0, 1);
controls.enableDamping = true;
const light = new THREE.DirectionalLight();
light.position.set(0, 0, 1);
scene.add(light);
const geom = new THREE.PlaneGeometry(image_ratio * 2, 2);
const mat = new THREE.MeshLambertMaterial({
alphaMap: alpha_tex,
alphaTest: 0.15,
map: image_tex,
});
const mesh = new THREE.Mesh(geom, mat);
scene.add(mesh);
const wall = new THREE.Mesh(
geom,
new THREE.MeshBasicMaterial({
alphaMap: alpha_tex,
alphaTest: 0.15,
map: image_tex,
})
);
wall.scale.setScalar(1.2);
wall.position.z = -0.1;
scene.add(wall);
// ----
// render
// ----
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
const effect = new GodRaysEffect(camera, wall, {
density: 1,
decay: 0.96,
weight: 1,
});
const effectPass = new EffectPass(camera, effect);
composer.addPass(renderPass);
composer.addPass(effectPass);
renderer.setAnimationLoop((t) => {
composer.render();
controls.update();
alpha_tex.offset.y = t * -0.001;
});
// ----
// view
// ----
function resize(w, h, dpr = devicePixelRatio) {
renderer.setPixelRatio(dpr);
// renderer.setSize(w, h, false)
composer.setSize(w, h, false);
camera.aspect = w / h;
camera.updateProjectionMatrix();
}
addEventListener("resize", () => resize(innerWidth, innerHeight));
dispatchEvent(new Event("resize"));
document.body.prepend(renderer.domElement);小结
后期处理 · Three.js
