Skip to content

Commit 2b352a2

Browse files
committed
chore: add gradient effect on reference line
1 parent 1ef687f commit 2b352a2

6 files changed

Lines changed: 207 additions & 88 deletions

File tree

packages/gizmo/src/Axis.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export class Axis extends Component {
66
private _color: Color = new Color();
77
private _highLightColor: Color = new Color();
88
private _yellowColor: Color = new Color(1.0, 1.0, 0.0, 1.0);
9-
private _grayColor: Color = new Color(0.5225215539683921, 0.5225215539683921, 0.5225215539683921, 0);
9+
private _grayColor: Color = new Color(1, 1, 1, 0.05);
1010
private _alpha: number = 1.0;
1111

1212
constructor(entity: Entity) {
@@ -20,10 +20,10 @@ export class Axis extends Component {
2020
this._alpha = this._color.a;
2121

2222
this._highLightColor.copyFrom(this._color);
23-
this._highLightColor.r = this._highLightColor.r + 0.3;
24-
this._highLightColor.g = this._highLightColor.g + 0.3;
25-
this._highLightColor.b = this._highLightColor.b + 0.3;
26-
this._highLightColor.a = this._highLightColor.a + 0.1;
23+
this._highLightColor.r = this._highLightColor.r + 0.6;
24+
this._highLightColor.g = this._highLightColor.g + 0.6;
25+
this._highLightColor.b = this._highLightColor.b + 0.6;
26+
this._highLightColor.a = 1;
2727

2828
// setup visible axis
2929
for (let i = 0; i < value.axisMesh.length; i++) {
@@ -70,7 +70,6 @@ export class Axis extends Component {
7070
}
7171
/** change axis color into gray */
7272
gray(): void {
73-
console.log('this._material.isTransparent', this._material.isTransparent)
7473
this._material.baseColor.copyFrom(this._grayColor);
7574
this._alpha = this._grayColor.a;
7675
}

packages/gizmo/src/Translate.ts

Lines changed: 147 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Camera, Entity, Plane, Ray, Vector3, Matrix, MeshRenderer, UnlitMaterial, ModelMesh } from "@galacean/engine";
1+
import { Camera, Entity, Plane, Ray, Vector3, Matrix, MeshRenderer, UnlitMaterial, ModelMesh, Shader, ShaderData, Color } from "@galacean/engine";
22

33
import { Axis } from "./Axis";
44
import { GizmoUtils, X_AXIS_ROTATION, Y_AXIS_ROTATION, Z_AXIS_ROTATION, XY_PLANE_ROTATION, YZ_PLANE_ROTATION, XZ_PLANE_ROTATION, LINE_TRANSLATION, END_TRANSLATION, PLANE_TRANSLATION } from "./constants";
@@ -32,15 +32,22 @@ export class TranslateControl extends GizmoComponent {
3232
private _tempScale: number = 1;
3333

3434
// Reference line entities and meshes
35-
private _referenceLineEntity: Entity;
36-
private _referenceLineMesh: ModelMesh;
35+
private _referenceLineEntityX: Entity;
36+
private _referenceLineEntityY: Entity;
37+
private _referenceLineEntityZ: Entity;
38+
private _referenceLineMeshX: ModelMesh;
39+
private _referenceLineMeshY: ModelMesh;
40+
private _referenceLineMeshZ: ModelMesh;
41+
private _referenceLineMaterialX: UnlitMaterial;
42+
private _referenceLineMaterialY: UnlitMaterial;
43+
private _referenceLineMaterialZ: UnlitMaterial;
3744

3845
constructor(entity: Entity) {
3946
super(entity);
4047
this.type = State.translate;
4148
this._initAxis();
4249
this._createAxis(entity);
43-
this._createReferenceLine(entity);
50+
this._createReferenceLines(entity);
4451
}
4552

4653
init(camera: Camera, group: Group): void {
@@ -81,10 +88,10 @@ export class TranslateControl extends GizmoComponent {
8188

8289
this._selectedAxis = null;
8390

84-
// Hide reference line
85-
if (this._referenceLineEntity) {
86-
this._referenceLineEntity.isActive = false;
87-
}
91+
// Hide all reference lines
92+
this._referenceLineEntityX.isActive = false;
93+
this._referenceLineEntityY.isActive = false;
94+
this._referenceLineEntityZ.isActive = false;
8895
}
8996

9097
onMoveStart(ray: Ray, axisName: string): void {
@@ -150,10 +157,10 @@ export class TranslateControl extends GizmoComponent {
150157
currComponent.recover && currComponent.recover();
151158
}
152159

153-
// Hide reference line
154-
if (this._referenceLineEntity) {
155-
this._referenceLineEntity.isActive = false;
156-
}
160+
// Hide all reference lines
161+
this._referenceLineEntityX.isActive = false;
162+
this._referenceLineEntityY.isActive = false;
163+
this._referenceLineEntityZ.isActive = false;
157164
}
158165

159166
onUpdate(isModified: boolean = false): void {
@@ -271,67 +278,140 @@ export class TranslateControl extends GizmoComponent {
271278
}
272279
}
273280

274-
private _createReferenceLine(entity: Entity): void {
275-
console.log('_createReferenceLine')
276-
// Create reference line entity
277-
this._referenceLineEntity = entity.createChild("referenceLine");
278-
this._referenceLineEntity.isActive = false;
279-
280-
// Create a long line mesh for reference that extends in both directions
281+
private _createReferenceLines(entity: Entity): void {
281282
const lineLength = 1000; // Very long line to appear infinite
282-
const start = new Vector3(-lineLength, 0, 0); // Negative direction
283-
const end = new Vector3(lineLength, 0, 0); // Positive direction
284-
this._referenceLineMesh = GizmoMesh.createLine(this.engine, [start, end]);
285283

286-
// Add renderer
287-
const renderer = this._referenceLineEntity.addComponent(MeshRenderer);
288-
renderer.receiveShadows = false;
289-
renderer.castShadows = false;
290-
renderer.mesh = this._referenceLineMesh;
284+
// Create shader for gradient lines if it doesn't exist
285+
if (!Shader.find("gradientLine")) {
286+
this._createGradientLineShader();
287+
}
288+
289+
// Create X axis reference line
290+
this._referenceLineEntityX = entity.createChild("referenceLineX");
291+
this._referenceLineEntityX.isActive = false;
292+
const startX = new Vector3(-lineLength, 0, 0);
293+
const endX = new Vector3(lineLength, 0, 0);
294+
this._referenceLineMeshX = GizmoMesh.createLine(this.engine, [startX, endX]);
295+
296+
// Create Y axis reference line
297+
this._referenceLineEntityY = entity.createChild("referenceLineY");
298+
this._referenceLineEntityY.isActive = false;
299+
const startY = new Vector3(0, -lineLength, 0);
300+
const endY = new Vector3(0, lineLength, 0);
301+
this._referenceLineMeshY = GizmoMesh.createLine(this.engine, [startY, endY]);
302+
303+
// Create Z axis reference line
304+
this._referenceLineEntityZ = entity.createChild("referenceLineZ");
305+
this._referenceLineEntityZ.isActive = false;
306+
const startZ = new Vector3(0, 0, -lineLength);
307+
const endZ = new Vector3(0, 0, lineLength);
308+
this._referenceLineMeshZ = GizmoMesh.createLine(this.engine, [startZ, endZ]);
291309

292-
// Create white material for the reference line
293-
const whiteMaterial = new UnlitMaterial(this.engine);
294-
whiteMaterial.isTransparent = true;
295-
whiteMaterial.renderState.depthState.enabled = false;
296-
whiteMaterial.baseColor.set(1, 1, 1, 0.5); // White with some transparency
297-
whiteMaterial.name = "referenceLineMaterial";
310+
// Create materials for each line with matching colors
311+
this._referenceLineMaterialX = this._createGradientMaterial(GizmoUtils.redMaterialTrans.baseColor);
312+
this._referenceLineMaterialY = this._createGradientMaterial(GizmoUtils.greenMaterialTrans.baseColor);
313+
this._referenceLineMaterialZ = this._createGradientMaterial(GizmoUtils.blueMaterialTrans.baseColor);
298314

299-
renderer.setMaterial(whiteMaterial);
315+
// Add renderers for each line
316+
const rendererX = this._referenceLineEntityX.addComponent(MeshRenderer);
317+
rendererX.receiveShadows = false;
318+
rendererX.castShadows = false;
319+
rendererX.mesh = this._referenceLineMeshX;
320+
rendererX.setMaterial(this._referenceLineMaterialX);
321+
322+
const rendererY = this._referenceLineEntityY.addComponent(MeshRenderer);
323+
rendererY.receiveShadows = false;
324+
rendererY.castShadows = false;
325+
rendererY.mesh = this._referenceLineMeshY;
326+
rendererY.setMaterial(this._referenceLineMaterialY);
327+
328+
const rendererZ = this._referenceLineEntityZ.addComponent(MeshRenderer);
329+
rendererZ.receiveShadows = false;
330+
rendererZ.castShadows = false;
331+
rendererZ.mesh = this._referenceLineMeshZ;
332+
rendererZ.setMaterial(this._referenceLineMaterialZ);
300333
}
301334

302-
private _showReferenceLine(axisName: string): void {
303-
console.log('_showReferenceLine', axisName, this._referenceLineEntity);
304-
if (!this._referenceLineEntity) return;
335+
private _createGradientLineShader(): void {
336+
const vertexSource = `
337+
#include <common>
338+
#include <common_vert>
339+
340+
uniform mat4 u_MVPMat;
341+
342+
attribute vec3 a_Position;
343+
344+
varying float v_Distance;
345+
346+
void main() {
347+
gl_Position = u_MVPMat * vec4(a_Position, 1.0);
348+
v_Distance = length(a_Position);
349+
}
350+
`;
305351

306-
// Reset rotation
307-
// this._referenceLineEntity.transform.rotation.set(0, 0, 0);
352+
const fragmentSource = `
353+
#include <common>
354+
355+
uniform vec4 u_LineColor;
356+
uniform float u_MaxDistance;
357+
358+
varying float v_Distance;
359+
360+
void main() {
361+
float normalizedDistance = v_Distance / u_MaxDistance;
362+
float alpha = max(0.0, 1.0 - normalizedDistance);
363+
gl_FragColor = vec4(u_LineColor.rgb, u_LineColor.a * alpha);
364+
}
365+
`;
308366

309-
// Show the reference line
367+
Shader.create("gradientLine", vertexSource, fragmentSource);
368+
}
369+
370+
private _createGradientMaterial(color: Color): UnlitMaterial {
371+
const material = new UnlitMaterial(this.engine);
372+
// material.shader = Shader.find("gradientLine")
373+
374+
material.isTransparent = true;
375+
material.renderState.depthState.enabled = false;
310376

311-
// Update the scale to match the current gizmo scale
312-
this._referenceLineEntity.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
377+
material.shaderData.setColor("u_LineColor", color);
378+
material.shaderData.setFloat("u_MaxDistance", 50.0);
313379

314-
// Update the position to match the current gizmo position
315-
// This ensures the reference line follows the gizmo when it moves
316-
this._referenceLineEntity.transform.worldMatrix = this.gizmoEntity.transform.worldMatrix.clone();
317-
318-
// Set rotation based on axis
380+
return material;
381+
}
382+
383+
private _showReferenceLine(axisName: string): void {
384+
// Hide all reference lines first
385+
this._referenceLineEntityX.isActive = false;
386+
this._referenceLineEntityY.isActive = false;
387+
this._referenceLineEntityZ.isActive = false;
388+
389+
// Show the appropriate reference line based on the axis
390+
let referenceLine: Entity;
319391
switch (axisName) {
320392
case "x":
321-
// X axis is default
393+
referenceLine = this._referenceLineEntityX;
322394
break;
323395
case "y":
324-
// Rotate to align with Y axis
325-
this._referenceLineEntity.transform.rotation.set(0, 0, 90);
396+
referenceLine = this._referenceLineEntityY;
326397
break;
327398
case "z":
328-
// Rotate to align with Z axis
329-
this._referenceLineEntity.transform.rotation.set(0, -90, 0);
399+
referenceLine = this._referenceLineEntityZ;
330400
break;
401+
default:
402+
return; // No reference line for plane controls
403+
}
404+
405+
if (referenceLine) {
406+
// Show the reference line
407+
referenceLine.isActive = true;
408+
409+
// Update the scale to match the current gizmo scale
410+
referenceLine.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
411+
412+
// Update the position to match the current gizmo position
413+
referenceLine.transform.worldMatrix = this.gizmoEntity.transform.worldMatrix.clone();
331414
}
332-
333-
this._referenceLineEntity.isActive = true;
334-
335415
}
336416

337417
private _getHitPlane(): void {
@@ -377,8 +457,18 @@ export class TranslateControl extends GizmoComponent {
377457
_tempVec0.set(this._tempScale, this._tempScale, this._tempScale)
378458
);
379459

380-
if (this._referenceLineEntity && this._referenceLineEntity.isActive) {
381-
this._referenceLineEntity.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
460+
// Update reference lines if any are active
461+
if (this._referenceLineEntityX.isActive) {
462+
this._referenceLineEntityX.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
463+
this._referenceLineEntityX.transform.worldMatrix = _tempMat.clone();
464+
}
465+
if (this._referenceLineEntityY.isActive) {
466+
this._referenceLineEntityY.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
467+
this._referenceLineEntityY.transform.worldMatrix = _tempMat.clone();
468+
}
469+
if (this._referenceLineEntityZ.isActive) {
470+
this._referenceLineEntityZ.transform.scale.set(this._tempScale, this._tempScale, this._tempScale);
471+
this._referenceLineEntityZ.transform.worldMatrix = _tempMat.clone();
382472
}
383473
}
384474

packages/gizmo/src/constants.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ export const INVISIBLE_COLOR = new Color(0.0, 0.0, 0.0, 0.0);
1717

1818
// Composite colors
1919
export const XY_COLOR = Color.lerp(RED_COLOR, GREEN_COLOR, 0.5, new Color());
20+
XY_COLOR.a = 0.4;
2021
export const XZ_COLOR = Color.lerp(RED_COLOR, BLUE_COLOR, 0.5, new Color());
22+
XZ_COLOR.a = 0.4;
2123
export const YZ_COLOR = Color.lerp(GREEN_COLOR, BLUE_COLOR, 0.5, new Color());
24+
YZ_COLOR.a = 0.4;
2225
export const XYZ_COLOR = Color.lerp(Color.lerp(RED_COLOR, GREEN_COLOR, 0.5, new Color()), BLUE_COLOR, 0.5, new Color());
2326
export const YELLOW_COLOR = Color.lerp(RED_COLOR, GREEN_COLOR, 0.5, new Color())
2427
export const GREY_COLOR = new Color(0.5225215539683921, 0.5225215539683921, 0.5225215539683921, 1.0);
@@ -31,13 +34,13 @@ export const ROTATE_CIRCLE_RADIUS = 1.6;
3134
export const RECT_FACTOR = 0.05;
3235

3336
// Line sizes
34-
export const LINE_RADIUS = 0.005;
37+
export const LINE_RADIUS = 0.004;
3538
export const LINE_LENGTH = 1.5;
3639
export const LINE_LENGTH_SHORT = 1.3;
3740

3841
// Arrow sizes
3942
export const ARROW_RADIUS = 0.05;
40-
export const ARROW_HEIGHT = 0.4;
43+
export const ARROW_HEIGHT = 0.2;
4144
export const ARROW_SEGMENTS = 8;
4245

4346
// Plane sizes

stories/BasicScene.stories.ts

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Camera, Entity, MeshRenderer, PrimitiveMesh } from "@galacean/engine";
1+
import { AmbientLight, AssetType, BackgroundMode, Camera, DirectLight, Entity, MeshRenderer, PBRMaterial, PrimitiveMesh, SkyBoxMaterial, Vector3, WebGLEngine } from "@galacean/engine";
2+
import { OrbitControl } from "../packages/controls/src/OrbitControl";
23

34
export default {
45
title: 'Basic Scene',
@@ -14,23 +15,46 @@ export default {
1415
export const BasicCube = {
1516
render: async (args, context) => {
1617
// Get the engine using the convenient getEngine function
17-
const engine = await context.getEngine();
18+
const engine: WebGLEngine = await context.getEngine();
1819

1920
const scene = engine.sceneManager.activeScene;
21+
2022
const rootEntity = scene.createRootEntity();
21-
23+
2224
// Create camera
23-
const cameraEntity = rootEntity.createChild("camera");
24-
cameraEntity.transform.setPosition(0, 0, 5);
25-
const camera = cameraEntity.addComponent(Camera);
26-
camera.enableFrustumCulling = true;
27-
28-
// Create cube
29-
const cubeEntity = rootEntity.createChild("cube");
30-
const renderer = cubeEntity.addComponent(MeshRenderer);
31-
renderer.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
32-
33-
// Auto-rotate cube
25+
const cameraNode = rootEntity.createChild("camera_node");
26+
cameraNode.transform.position = new Vector3(-3, 0, 3);
27+
cameraNode.addComponent(Camera);
28+
cameraNode.addComponent(OrbitControl);
29+
30+
// Create sky
31+
const sky = scene.background.sky;
32+
const skyMaterial = new SkyBoxMaterial(engine);
33+
sky.material = skyMaterial;
34+
sky.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
35+
36+
const lightEntity = rootEntity.createChild();
37+
lightEntity.transform.setPosition(-5, 5, 5);
38+
lightEntity.transform.lookAt(new Vector3(0, 0, 0));
39+
40+
// material ball
41+
const ball = rootEntity.createChild("ball");
42+
const ballRender = ball.addComponent(MeshRenderer);
43+
const material = new PBRMaterial(engine);
44+
material.metallic = 0;
45+
material.roughness = 0;
46+
ballRender.mesh = PrimitiveMesh.createSphere(engine, 1, 128);
47+
ballRender.setMaterial(material);
48+
49+
const ambientLight = await engine.resourceManager
50+
.load<AmbientLight>({
51+
type: AssetType.Env,
52+
url: "https://gw.alipayobjects.com/os/bmw-prod/6470ea5e-094b-4a77-a05f-4945bf81e318.bin",
53+
})
54+
scene.ambientLight = ambientLight;
55+
skyMaterial.texture = ambientLight.specularTexture;
56+
skyMaterial.textureDecodeRGBM = true;
57+
3458
engine.run();
3559

3660
// Return empty div as the canvas is already in the container

0 commit comments

Comments
 (0)