Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
1c376d4
feat: init trail render
GuoLei1990 Dec 27, 2025
2d070c1
feat: add e2e testing support for trail renderer
GuoLei1990 Dec 27, 2025
f8691ec
chore: remove unnecessary blank lines in trail-related files
GuoLei1990 Dec 27, 2025
5c8a90d
feat: add basic trail renderer image for e2e testing
GuoLei1990 Dec 27, 2025
72c953d
feat: update TrailRenderer to support texture loading and material setup
GuoLei1990 Dec 27, 2025
cdaec88
feat: add trail shader support in ShaderPool
GuoLei1990 Dec 27, 2025
0fe1e94
feat: add emissive color and texture support in TrailMaterial
GuoLei1990 Dec 27, 2025
2c646ad
feat: refactor TrailMaterial to use new blend and render face enums
GuoLei1990 Dec 27, 2025
7c73618
feat: remove unused imports and set render face to default in TrailMa…
GuoLei1990 Dec 27, 2025
9be80c4
feat: refactor ParticleMaterial and TrailMaterial to extend EffectMat…
GuoLei1990 Dec 27, 2025
b502942
feat: enhance TrailRenderer to optimize vertex buffer updates and man…
GuoLei1990 Dec 27, 2025
1ddda45
no message
GuoLei1990 Dec 27, 2025
451a2de
feat: optimize bounds calculation in TrailRenderer with caching and d…
GuoLei1990 Dec 27, 2025
9f24210
feat: optimize bounds calculation and shader data updates in TrailRen…
GuoLei1990 Dec 27, 2025
3f9ed76
feat: remove internal documentation comments and improve variable nam…
GuoLei1990 Dec 27, 2025
871a612
feat: simplify property initialization in TrailRenderer
GuoLei1990 Dec 27, 2025
461b87d
feat: refactor vertex buffer and primitive initialization in TrailRen…
GuoLei1990 Dec 27, 2025
dcd0193
feat: update vertex attributes in TrailRenderer for improved data str…
GuoLei1990 Dec 27, 2025
2a8b7b8
feat: streamline property definitions and improve code readability in…
GuoLei1990 Dec 27, 2025
aaca29e
feat: optimize color and alpha key handling in TrailRenderer
GuoLei1990 Dec 27, 2025
2857302
feat: rename tileScale to textureScale for consistency in TrailRenderer
GuoLei1990 Dec 28, 2025
11ecb81
feat: remove unnecessary blank line at the end of EffectMaterial.ts
GuoLei1990 Dec 28, 2025
e4350e4
feat: refactor TrailRenderer to use GradientColorKey and GradientAlph…
GuoLei1990 Dec 29, 2025
08a4b13
feat: enhance TrailRenderer to support dynamic point capacity and buf…
GuoLei1990 Dec 29, 2025
4f15c06
feat: refactor TrailRenderer to eliminate index buffer and optimize v…
GuoLei1990 Dec 29, 2025
f08e3ec
refactor: opt code
GuoLei1990 Dec 29, 2025
ea809c4
feat: optimize TrailRenderer for better vertex data handling and mate…
GuoLei1990 Dec 29, 2025
021144d
feat: simplify TrailRenderer's rendering logic and improve buffer man…
GuoLei1990 Dec 29, 2025
5683fab
feat: optimize vertex upload logic in TrailRenderer for improved perf…
GuoLei1990 Dec 29, 2025
85eda25
feat: add oldest and newest birth time calculations for UV mapping in…
GuoLei1990 Dec 29, 2025
df12aa2
feat: update TrailRenderer settings and optimize background color
GuoLei1990 Dec 30, 2025
36eb579
feat: enhance TrailRenderer by managing retired points and optimizing…
GuoLei1990 Dec 30, 2025
a113b8f
feat: optimize TrailRenderer update logic and improve point management
GuoLei1990 Dec 30, 2025
69d2e82
feat: refine width curve handling in TrailRenderer for improved flexi…
GuoLei1990 Dec 30, 2025
66ef04e
feat: update width curve handling in TrailRenderer for improved clari…
GuoLei1990 Dec 30, 2025
a1a9c50
feat: streamline shader data updates in TrailRenderer for improved pe…
GuoLei1990 Dec 30, 2025
ea58aa7
feat: simplify width curve evaluation in TrailRenderer for improved c…
GuoLei1990 Dec 30, 2025
8c7bece
feat: refactor TrailRenderer to use packed uniforms for time and trai…
GuoLei1990 Dec 30, 2025
eab4d2e
feat: consolidate static constants in TrailRenderer for improved clar…
GuoLei1990 Dec 30, 2025
7700d68
feat: improve comments for clarity in TrailRenderer parameters
GuoLei1990 Dec 30, 2025
2ce9918
refactor: opt code
GuoLei1990 Dec 30, 2025
e4a5ecf
feat: improve comments for clarity in TrailRenderer
GuoLei1990 Dec 30, 2025
18ea3a8
feat: rename subPrimitive variables for clarity in TrailRenderer
GuoLei1990 Dec 30, 2025
558d83d
fix: correct vertex count calculation and clean up vertex buffer bind…
GuoLei1990 Dec 30, 2025
7a2c617
feat: update point stride constants for improved clarity in TrailRend…
GuoLei1990 Dec 30, 2025
c0d31f2
fix: streamline vertex buffer creation and clarify comments in TrailR…
GuoLei1990 Dec 30, 2025
864b952
refactor: simplify comments and streamline vertex data migration in T…
GuoLei1990 Dec 30, 2025
3151a42
refactor: rename _tryAddNewPoint to _emitNewPoint for clarity in Trai…
GuoLei1990 Dec 30, 2025
23dbb36
fix: optimize time parameter updates and streamline vertex upload log…
GuoLei1990 Dec 30, 2025
7528533
refactor: improve rendering logic and encapsulate sub-render element …
GuoLei1990 Dec 30, 2025
557c533
feat: add segment bounds management for improved trail rendering effi…
GuoLei1990 Dec 31, 2025
1dea411
refactor: update segment bounds management for improved frame handlin…
GuoLei1990 Dec 31, 2025
fe30e39
refactor: streamline segment bounds generation logic in TrailRenderer
GuoLei1990 Dec 31, 2025
f6cfd79
fix: update oldest birth time handling in time parameters for TrailRe…
GuoLei1990 Dec 31, 2025
9e10b9c
refactor: reorganize shader parameters and improve point management i…
GuoLei1990 Jan 1, 2026
8984ad3
refactor: remove unused segment bounds management in TrailRenderer
GuoLei1990 Jan 1, 2026
2b164b0
refactor: optimize world bounds calculation in TrailRenderer
GuoLei1990 Jan 1, 2026
bda2efb
refactor: simplify point position initialization in TrailRenderer
GuoLei1990 Jan 1, 2026
99cb1af
refactor: move emitting property declaration and improve point initia…
GuoLei1990 Jan 1, 2026
4878fa3
refactor: streamline vertex buffer binding and improve point retireme…
GuoLei1990 Jan 1, 2026
209faae
refactor: optimize tangent handling and improve active point count ca…
GuoLei1990 Jan 1, 2026
09a8fc6
refactor: reorganize uniform declarations for clarity in TrailRenderer
GuoLei1990 Jan 1, 2026
8d73117
refactor: opt code
GuoLei1990 Jan 1, 2026
9decb80
refactor: enhance gradient handling in TrailRenderer and shader modules
GuoLei1990 Jan 1, 2026
bbf45ef
refactor: update TrailRenderer to use distance-based calculations and…
GuoLei1990 Jan 1, 2026
be0abf8
refactor: update TrailRenderer image asset with new version and size
GuoLei1990 Jan 1, 2026
b67786e
refactor: optimize TrailRenderer bounds calculation and add unit tests
GuoLei1990 Jan 1, 2026
18b6ef1
refactor: format code for better readability in TrailRenderer
GuoLei1990 Jan 1, 2026
1b3bbc6
refactor: enhance TrailRenderer with multiple artistic trails and mov…
GuoLei1990 Jan 1, 2026
c905100
refactor: improve vertex buffer management in TrailRenderer for bette…
GuoLei1990 Jan 1, 2026
610fcdf
refactor: streamline vertex processing in TrailRenderer by removing e…
GuoLei1990 Jan 4, 2026
768042b
refactor: rename gradientMaxTime to curveMaxTime for consistency in T…
GuoLei1990 Jan 4, 2026
40adcb8
refactor: enhance buffer handling in TrailRenderer to improve wrap-ar…
GuoLei1990 Jan 4, 2026
3818ceb
refactor: simplify conditional checks and formatting in TrailRenderer…
GuoLei1990 Jan 4, 2026
58fda34
refactor: optimize right vector calculation in TrailRenderer for impr…
GuoLei1990 Jan 22, 2026
1e7cd8b
refactor: clarify minVertexDistance comment to specify units in Trail…
GuoLei1990 Jan 24, 2026
1520daa
refactor: update clone decorators for trail parameters to deepClone i…
GuoLei1990 Jan 24, 2026
47a14d7
refactor: calculate half width using max width multiplier from widthC…
GuoLei1990 Jan 24, 2026
122ff01
refactor: improve boundary handling in point merging logic in TrailRe…
GuoLei1990 Jan 24, 2026
2ebcbc7
refactor: add dirty flag update for retired points in TrailRenderer
GuoLei1990 Jan 24, 2026
4787769
refactor: clarify comment for a_PositionBirthTime and remove unused v…
GuoLei1990 Jan 24, 2026
698d26a
refactor: update distance parameters in TrailRenderer and shader to u…
GuoLei1990 Jan 24, 2026
55c08ee
refactor: update comment for engine.update() in Trail test to clarify…
GuoLei1990 Jan 24, 2026
da302d9
refactor: add cumulativeDistance and playTime properties in TrailRend…
GuoLei1990 Jan 24, 2026
3dfea8b
refactor: clarify fade-out duration comment in TrailRenderer
GuoLei1990 Jan 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 279 additions & 0 deletions e2e/case/trailRenderer-basic.ts
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";
Comment on lines +5 to +26
Copy link

Copilot AI Jan 24, 2026

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.

Copilot uses AI. Check for mistakes.
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);
});
});

/**
* 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);
}
}
8 changes: 8 additions & 0 deletions e2e/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,14 @@ export const E2E_CONFIG = {
diffPercentage: 0
}
},
Trail: {
basic: {
category: "Trail",
caseFileName: "trailRenderer-basic",
threshold: 0,
diffPercentage: 0
}
},
Other: {
ProjectLoader: {
category: "Advance",
Expand Down
3 changes: 3 additions & 0 deletions e2e/fixtures/originImage/Trail_trailRenderer-basic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 85 additions & 0 deletions packages/core/src/material/EffectMaterial.ts
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
Copy link

Copilot AI Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The EffectMaterial class is not exported from the material module's index.ts file. While TrailMaterial and ParticleMaterial are exported via their respective modules, EffectMaterial serves as a base class for effect-type materials and should be exported from the material module for consistency and to allow users to extend it for custom effect materials. Add export { EffectMaterial } from "./EffectMaterial"; to packages/core/src/material/index.ts.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EffectMaterial is internal material

Loading
Loading