-
-
Notifications
You must be signed in to change notification settings - Fork 394
Support trail render #2873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support trail render #2873
Changes from all commits
1c376d4
2d070c1
f8691ec
5c8a90d
72c953d
cdaec88
0fe1e94
2c646ad
7c73618
9be80c4
b502942
1ddda45
451a2de
9f24210
3f9ed76
871a612
461b87d
dcd0193
2a8b7b8
aaca29e
2857302
11ecb81
e4350e4
08a4b13
4f15c06
f08e3ec
ea809c4
021144d
5683fab
85eda25
df12aa2
36eb579
a113b8f
69d2e82
66ef04e
a1a9c50
ea58aa7
8c7bece
eab4d2e
7700d68
2ce9918
e4a5ecf
18ea3a8
558d83d
7a2c617
c0d31f2
864b952
3151a42
23dbb36
7528533
557c533
1dea411
fe30e39
f6cfd79
9e10b9c
8984ad3
2b164b0
bda2efb
99cb1af
4878fa3
209faae
09a8fc6
8d73117
9decb80
bbf45ef
be0abf8
b67786e
18b6ef1
1b3bbc6
c905100
610fcdf
768042b
40adcb8
3818ceb
58fda34
1e7cd8b
1520daa
47a14d7
122ff01
2ebcbc7
4787769
698d26a
55c08ee
da302d9
3dfea8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,279 @@ | ||
| /** | ||
| * @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.width = config.width; | ||
| trail.minVertexDistance = 0.15; | ||
| trailMaterials.push(material); | ||
|
|
||
| // Tapered width curve | ||
| trail.widthCurve = new ParticleCurve(new CurveKey(0, 1), new CurveKey(0.8, 0.3), 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.Texture2D | ||
| }) | ||
| .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); | ||
| }); | ||
GuoLei1990 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }); | ||
|
|
||
| /** | ||
| * 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); | ||
| } | ||
GuoLei1990 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import { Color } from "@galacean/engine-math"; | ||
| import { Engine } from "../Engine"; | ||
| import { Shader } from "../shader"; | ||
| import { Texture2D } from "../texture"; | ||
| import { BaseMaterial } from "./BaseMaterial"; | ||
|
|
||
| /** | ||
| * Base material for visual effects like particles and trails. | ||
| */ | ||
| export class EffectMaterial extends BaseMaterial { | ||
| /** | ||
| * Base color. | ||
| */ | ||
| get baseColor(): Color { | ||
| return this.shaderData.getColor(BaseMaterial._baseColorProp); | ||
| } | ||
|
|
||
| set baseColor(value: Color) { | ||
| const baseColor = this.shaderData.getColor(BaseMaterial._baseColorProp); | ||
| if (value !== baseColor) { | ||
| baseColor.copyFrom(value); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Base texture. | ||
| */ | ||
| get baseTexture(): Texture2D { | ||
| return <Texture2D>this.shaderData.getTexture(BaseMaterial._baseTextureProp); | ||
| } | ||
|
|
||
| set baseTexture(value: Texture2D) { | ||
| this.shaderData.setTexture(BaseMaterial._baseTextureProp, value); | ||
| if (value) { | ||
| this.shaderData.enableMacro(BaseMaterial._baseTextureMacro); | ||
| } else { | ||
| this.shaderData.disableMacro(BaseMaterial._baseTextureMacro); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Emissive color. | ||
| */ | ||
| get emissiveColor(): Color { | ||
| return this.shaderData.getColor(BaseMaterial._emissiveColorProp); | ||
| } | ||
|
|
||
| set emissiveColor(value: Color) { | ||
| const emissiveColor = this.shaderData.getColor(BaseMaterial._emissiveColorProp); | ||
| if (value !== emissiveColor) { | ||
| emissiveColor.copyFrom(value); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Emissive texture. | ||
| */ | ||
| get emissiveTexture(): Texture2D { | ||
| return <Texture2D>this.shaderData.getTexture(BaseMaterial._emissiveTextureProp); | ||
| } | ||
|
|
||
| set emissiveTexture(value: Texture2D) { | ||
| this.shaderData.setTexture(BaseMaterial._emissiveTextureProp, value); | ||
| if (value) { | ||
| this.shaderData.enableMacro(BaseMaterial._emissiveTextureMacro); | ||
| } else { | ||
| this.shaderData.disableMacro(BaseMaterial._emissiveTextureMacro); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Create an effect material instance. | ||
| * @param engine - Engine to which the material belongs | ||
| * @param shader - Shader used by the material | ||
| */ | ||
| constructor(engine: Engine, shader: Shader) { | ||
| super(engine, shader); | ||
|
|
||
| const shaderData = this.shaderData; | ||
| shaderData.setColor(BaseMaterial._baseColorProp, new Color(1, 1, 1, 1)); | ||
| shaderData.setColor(BaseMaterial._emissiveColorProp, new Color(0, 0, 0, 1)); | ||
|
|
||
| this.isTransparent = true; | ||
| } | ||
| } | ||
|
Comment on lines
+10
to
+85
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused imports BloomEffect, PostProcess, TonemappingEffect, TonemappingMode.