ThreeJS通过制作渐变光效贴图方式实现光柱效果

这段代码是一个使用Three.js库创建的简单3D场景,其中包含一个可以动态缩放和旋转的柱子(Pillar)。以下是对代码的分析和解释:

1. 引入Three.js及其扩展

代码首先通过ES6模块语法引入了Three.js的核心模块和一些扩展模块,如OrbitControls用于相机控制。

2. 定义Pillar函数

Pillar函数用于创建一个柱子对象,该对象包含一个mesh(实际是一个包含两个平面的Group)和一个render方法用于动画效果。

  • 配置合并:函数接受一个可选配置对象,与默认配置合并。
  • 几何体创建 :使用PlaneGeometry创建一个平面,根据给定的高度和图片的比例计算宽度。
  • 材质加载 :使用TextureLoader加载贴图,并创建MeshBasicMaterial
  • 网格创建 :创建一个Mesh对象,并复制一个旋转90度以形成柱子的两个面。
  • 动画逻辑render方法实现柱子的缩放和旋转动画。

3. HTML和JavaScript集成

HTML部分设置了基本的页面结构和样式,JavaScript部分(作为模块脚本)则负责创建Three.js场景。

  • 场景、相机和渲染器 :初始化ScenePerspectiveCameraWebGLRenderer
  • 添加柱子 :调用Pillar函数创建柱子,并将其添加到场景中。
  • 灯光和背景:注释掉的部分显示了如何添加环境光和聚光灯,以及设置场景背景色。
  • 相机控制 :使用OrbitControls允许用户通过鼠标交互控制相机。
  • 动画循环animate函数通过requestAnimationFrame创建动画循环,调用render方法更新柱子状态,并渲染场景。
  • 窗口大小调整 :监听resize事件,以在窗口大小变化时更新相机和渲染器的设置。

4. 动画和交互

  • 柱子的缩放和旋转是通过Pillar函数内的render方法实现的,该方法在动画循环中被调用。
  • 用户可以通过OrbitControls自由旋转、缩放和平移相机,以不同角度查看场景。

总结

这段代码展示了如何使用Three.js创建一个简单的3D动态场景,包括几何体的创建、材质的加载、动画的实现以及用户交互的添加。通过修改配置和取消注释的灯光部分,可以进一步定制和丰富场景效果。

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
	<title>three.js webgl - particles - columns</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
	<style>
		body {
			margin: 0;
		}

		canvas {
			display: block;
		}
	</style>
</head>

<body>

	<script type="module">

		import { Scene, PerspectiveCamera, WebGLRenderer, AmbientLight, Color, SpotLight } from "three";
		import { Pillar } from "./LightColumnEffect.ts";
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

		// 初始化场景、相机和渲染器  
		const scene = new Scene();
		const camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
		const renderer = new WebGLRenderer();
		renderer.setSize(window.innerWidth, window.innerHeight);
		document.body.appendChild(renderer.domElement);

		// 创建柱子并添加到场景  
		const { mesh, render } = Pillar();
		scene.add(mesh);
		//
		// scene.background = new Color(0xf0f0f0);

		// scene.add(new AmbientLight(0xaaaaaa));

		// const light = new SpotLight(0xffffff, 10000);
		// light.position.set(0, 25, 50);
		// light.angle = Math.PI / 5;

		// light.castShadow = true;
		// light.shadow.camera.near = 10;
		// light.shadow.camera.far = 100;
		// light.shadow.mapSize.width = 1024;
		// light.shadow.mapSize.height = 1024;

		// scene.add(light);
		/
		// 设置相机位置  
		camera.position.z = 50;

		// 添加OrbitControls以便交互  
		const controls = new OrbitControls(camera, renderer.domElement);

		// 创建动画循环  
		const animate = function () {
			requestAnimationFrame(animate);
			render(); // 调用Pillar的渲染函数来旋转柱子  
			controls.update(); // 更新OrbitControls  
			renderer.render(scene, camera);
		};

		// 处理窗口大小调整  
		window.addEventListener('resize', () => {
			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();
			renderer.setSize(window.innerWidth, window.innerHeight);
		});

		// 开始动画循环  
		animate();

	</script>
</body>

</html>
javascript 复制代码
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { Group, PlaneGeometry, TextureLoader, MeshBasicMaterial, Mesh, DoubleSide } from 'three';

export const Pillar = (config?: Partial<{
    width: number;
    height: number;
    lightPillarUrl: string;
    color: number;
    minScale: number; // 最小缩放比例  
    maxScale: number; // 最大缩放比例  
    scaleSpeed: number; // 缩放速度  
}>) => {
    // 默认配置  
    const defaultConfig = {
        height: 20,
        lightPillarUrl: "./pillarTexture.png",
        color: 0x00ffff,
        minScale: 1, // 最小缩放比例  
        maxScale: 2, // 最大缩放比例  
        scaleSpeed: 0.01 // 缩放速度  
    };

    // 合并配置  
    const conf = {
        ...defaultConfig,
        ...config
    };

    // 图片的尺寸255*41  
    const ratios = 255 / 41;
    // 按给定的高度计算宽度  
    const width = conf.height / ratios;
    const group = new Group();

    // 使用PlaneGeometry生成一个平面  
    const geometry = new PlaneGeometry(width, conf.height);
    geometry.rotateX(Math.PI / 2);
    geometry.translate(0, 0, conf.height / 2);

    // 加载贴图  
    const textureLoader = new TextureLoader();
    const material = new MeshBasicMaterial({
        map: textureLoader.load(conf.lightPillarUrl),
        color: conf.color,
        transparent: true,
        depthWrite: false,
        side: DoubleSide
    });

    const mesh = new Mesh(geometry, material);
    // 复制一个,并旋转90度  
    const mesh2 = mesh.clone();
    mesh2.rotateZ(Math.PI / 2);

    group.add(mesh, mesh2);

    // 初始缩放比例  
    let currentScale = conf.minScale;
    // 缩放方向,初始为增大  
    let scalingUp = true;

    const render = () => {
        // 更新缩放比例  
        if (scalingUp) {
            currentScale += conf.scaleSpeed;
            if (currentScale >= conf.maxScale) {
                scalingUp = false; // 达到最大缩放比例,开始缩小  
            }
        } else {
            currentScale -= conf.scaleSpeed;
            if (currentScale <= conf.minScale) {
                scalingUp = true; // 达到最小缩放比例,开始增大  
            }
        }

        // 应用缩放比例到组  
        group.scale.set(currentScale, currentScale, currentScale);

        // 旋转组  
        group.rotation.z += 0.01;
    };

    return { mesh: group, render };
};
相关推荐
UTwelve10 小时前
【UE】如何手搓一个完美贴合地形的 Mesh Decal(面片贴花)
ue5·材质·贴图·着色器
♡すぎ♡4 天前
ShaderLab:可互动水面(基于RenderTexture,实时生成动态扰动)
计算机图形学·贴图·opengl·着色器
魔士于安7 天前
Unity完整小球迷宫项目
前端·unity·游戏引擎·贴图·模型
魔士于安8 天前
Unity 超市总动员 超市收银台 超市货架 超市购物手推车 超市常见商品
游戏·unity·游戏引擎·贴图·模型
魔士于安9 天前
Unity windows 同步 异步 打开文件文件夹工具
游戏·unity·游戏引擎·贴图·模型
魔士于安9 天前
unity lowpoly 风格 城市 建筑 道路 交通标志
游戏·unity·游戏引擎·贴图·模型
魔士于安10 天前
Unity UI图片 复活节UI,卡通风格
游戏·ui·unity·游戏引擎·材质·贴图
魔士于安10 天前
unity 卡通风整套资源 小鸟N套带动作+一套卡通风村落 和 相关道具+落叶粒子效果 buildin
游戏·unity·游戏引擎·贴图·模型
CG_MAGIC10 天前
幕后花絮:用Blender打造自己的建筑
3d·blender·贴图·uv·建模教程·渲云渲染
魔士于安12 天前
Unity类似博物馆场景
前端·unity·游戏引擎·贴图·模型