Files
engine/e2e/case/trailRenderer-basic.ts
ChenMo c3e2077d33 Unify Texture2D and TextureCube into single TextureLoader (#2937)
* refactor: unify Texture2D and TextureCube into single TextureLoader
2026-03-23 21:41:24 +08:00

280 lines
7.0 KiB
TypeScript

/**
* @title Trail Renderer Basic
* @category Trail
*/
import {
AssetType,
BlendMode,
BloomEffect,
Camera,
Color,
CurveKey,
GradientAlphaKey,
GradientColorKey,
Logger,
ParticleCurve,
ParticleGradient,
PostProcess,
Script,
Texture2D,
TonemappingEffect,
TonemappingMode,
TrailMaterial,
TrailRenderer,
Vector3,
WebGLEngine
} from "@galacean/engine";
import { initScreenshot, updateForE2E } from "./.mockForE2E";
/**
* Trail configuration interface.
*/
interface TrailConfig {
color1: Color;
color2: Color;
color3: Color;
emissive: Color;
width: number;
time: number;
speed: number;
radius: number;
freqX: number;
freqY: number;
freqZ: number;
phaseOffset: number;
verticalAmp: number;
}
/**
* Neon aurora trail configurations.
*/
const trailConfigs: TrailConfig[] = [
// Neon Cyan-Magenta trail (main)
{
color1: new Color(0, 1, 1, 1),
color2: new Color(1, 0, 1, 1),
color3: new Color(0.5, 0, 1, 1),
emissive: new Color(0.8, 1.2, 2.0, 1),
width: 0.7,
time: 3.0,
speed: 1.5,
radius: 5,
freqX: 1,
freqY: 1.618,
freqZ: 0.618,
phaseOffset: 0,
verticalAmp: 3
},
// Solar Flare - warm orange/gold
{
color1: new Color(1, 0.8, 0, 1),
color2: new Color(1, 0.4, 0, 1),
color3: new Color(1, 0.2, 0.3, 1),
emissive: new Color(1.8, 1.0, 0.4, 1),
width: 0.55,
time: 2.5,
speed: 2.0,
radius: 4,
freqX: 1.414,
freqY: 0.707,
freqZ: 1.236,
phaseOffset: Math.PI / 4,
verticalAmp: 2.5
},
// Electric Blue
{
color1: new Color(0.3, 0.6, 1, 1),
color2: new Color(0, 0.8, 1, 1),
color3: new Color(0.5, 0.3, 1, 1),
emissive: new Color(0.6, 1.2, 2.0, 1),
width: 0.45,
time: 2.0,
speed: 2.8,
radius: 3.5,
freqX: 0.866,
freqY: 1.5,
freqZ: 1.732,
phaseOffset: Math.PI / 2,
verticalAmp: 2
},
// Mystic Purple-Pink
{
color1: new Color(1, 0.3, 0.6, 1),
color2: new Color(0.8, 0, 1, 1),
color3: new Color(0.5, 0.3, 1, 1),
emissive: new Color(1.5, 0.6, 1.5, 1),
width: 0.6,
time: 2.8,
speed: 1.4,
radius: 5.5,
freqX: 0.618,
freqY: 1.272,
freqZ: 0.809,
phaseOffset: (Math.PI * 3) / 4,
verticalAmp: 2.8
},
// Emerald Aurora - green
{
color1: new Color(0.2, 1, 0.5, 1),
color2: new Color(0, 1, 0.8, 1),
color3: new Color(0.3, 0.8, 1, 1),
emissive: new Color(0.6, 1.8, 1.0, 1),
width: 0.5,
time: 2.3,
speed: 1.8,
radius: 4.5,
freqX: 1.272,
freqY: 0.5,
freqZ: 1.414,
phaseOffset: Math.PI,
verticalAmp: 2.2
},
// White Core - bright center
{
color1: new Color(1, 1, 1, 1),
color2: new Color(0.9, 0.9, 1, 1),
color3: new Color(0.7, 0.8, 1, 1),
emissive: new Color(2.0, 2.0, 2.5, 1),
width: 0.35,
time: 1.5,
speed: 3.2,
radius: 2.5,
freqX: 2,
freqY: 1,
freqZ: 1.5,
phaseOffset: Math.PI / 6,
verticalAmp: 1.5
},
// Deep Space Purple - outer spiral
{
color1: new Color(0.6, 0, 1, 1),
color2: new Color(0.3, 0, 1, 1),
color3: new Color(0.2, 0.2, 0.8, 1),
emissive: new Color(1.0, 0.4, 1.8, 1),
width: 0.65,
time: 3.5,
speed: 1.2,
radius: 6,
freqX: 0.5,
freqY: 0.809,
freqZ: 0.618,
phaseOffset: (Math.PI * 5) / 4,
verticalAmp: 3.5
}
];
// Create engine
WebGLEngine.create({
canvas: "canvas"
}).then((engine) => {
Logger.enable();
engine.canvas.resizeByClientSize();
const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();
scene.background.solidColor = new Color(0, 0, 0, 1);
// Create camera
const cameraEntity = rootEntity.createChild("camera");
cameraEntity.transform.position = new Vector3(0, 5, 15);
cameraEntity.transform.lookAt(new Vector3(0, 0, 0));
const camera = cameraEntity.addComponent(Camera);
camera.fieldOfView = 60;
// // Enable post-processing with Bloom effect
// camera.enablePostProcess = true;
// camera.enableHDR = true;
// const postProcessEntity = rootEntity.createChild("PostProcess");
// const postProcess = postProcessEntity.addComponent(PostProcess);
// // Add Bloom effect for glowing trails
// const bloomEffect = postProcess.addEffect(BloomEffect);
// bloomEffect.threshold.value = 0.35;
// bloomEffect.intensity.value = 2.2;
// bloomEffect.scatter.value = 0.75;
// // Add Tonemapping for better HDR rendering
// const tonemappingEffect = postProcess.addEffect(TonemappingEffect);
// tonemappingEffect.mode.value = TonemappingMode.ACES;
// Store all trail materials for texture assignment
const trailMaterials: TrailMaterial[] = [];
// Create multiple artistic trails
trailConfigs.forEach((config, index) => {
const trailEntity = rootEntity.createChild(`trail_${index}`);
const trail = trailEntity.addComponent(TrailRenderer);
const material = new TrailMaterial(engine);
material.blendMode = BlendMode.Additive;
material.emissiveColor.copyFrom(config.emissive);
trail.setMaterial(material);
trail.time = config.time;
trail.minVertexDistance = 0.15;
trailMaterials.push(material);
// Tapered width curve (width baked into curve values)
const w = config.width;
trail.widthCurve = new ParticleCurve(new CurveKey(0, w), new CurveKey(0.8, 0.3 * w), new CurveKey(1, 0));
// Color gradient
const gradient = new ParticleGradient(
[
new GradientColorKey(0, config.color1),
new GradientColorKey(0.5, config.color2),
new GradientColorKey(1, config.color3)
],
[new GradientAlphaKey(0, 1), new GradientAlphaKey(0.6, 0.7), new GradientAlphaKey(1, 0)]
);
trail.colorGradient = gradient;
// Add movement
const moveScript = trailEntity.addComponent(TrailMoveScript);
moveScript.config = config;
});
// Load trail texture and apply to all trails
engine.resourceManager
.load<Texture2D>({
url: "https://mdn.alipayobjects.com/huamei_b4l2if/afts/img/A*-DEWQZ0ncrEAAAAASTAAAAgAeil6AQ/original",
type: AssetType.Texture
})
.then((texture) => {
// Set texture on all trail materials
trailMaterials.forEach((material) => {
material.baseTexture = texture;
});
// engine.run();
// Run for e2e testing
updateForE2E(engine, 50, 20);
initScreenshot(engine, camera);
});
});
/**
* Movement script with spiral and pulse effects.
*/
class TrailMoveScript extends Script {
config: TrailConfig;
private _time = 0;
onUpdate(deltaTime: number): void {
this._time += deltaTime;
const { speed, radius, freqX, freqY, freqZ, phaseOffset, verticalAmp } = this.config;
const t = this._time * speed + phaseOffset;
// Spiral pulsing effect
const pulseRadius = radius * (1 + Math.sin(t * 0.3) * 0.15);
// 3D Lissajous curve with spiral modulation
const x = Math.sin(t * freqX) * pulseRadius;
const y = Math.sin(t * freqY) * verticalAmp + Math.sin(t * 0.5) * 0.5;
const z = Math.cos(t * freqZ) * pulseRadius;
this.entity.transform.position.set(x, y, z);
}
}