Skip to content

Commit b7bf873

Browse files
feat(sample): add draw mesh line sample (#331)
--------- Co-authored-by: ShuangLiu <lslzl3000@gmail.com>
1 parent ff46984 commit b7bf873

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

samples/graphic/Sample_MeshLines.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import { Engine3D, Scene3D, CameraUtil, HoverCameraController, Object3D, MeshRenderer, View3D, PlaneGeometry, UnLitMaterial, Color, Vector3, PointerEvent3D, Camera3D, SphereGeometry, CylinderGeometry, MathUtil, BlendMode, GPUCullMode } from '@orillusion/core';
2+
import * as dat from "@orillusion/debug/dat.gui.module";
3+
import { Stats } from '@orillusion/stats';
4+
5+
class Sample_MeshLines {
6+
private onDraw: boolean = false
7+
private scene: Scene3D
8+
private camera: Camera3D
9+
private lastTime: number
10+
private path: Object3D[] = []
11+
private hoverCameraController: HoverCameraController;
12+
private lastX: number = -1
13+
private lastY: number = -1
14+
private pointGeometry: SphereGeometry
15+
private lineGeometry: CylinderGeometry
16+
private material: UnLitMaterial
17+
18+
public lineWidth: number = 0.1
19+
public drawInterval: number = 30
20+
public precision: number = 32
21+
public depth: number = 0
22+
public lineColor: Color = new Color(1, 0, 0)
23+
24+
async run() {
25+
// init engine
26+
await Engine3D.init();
27+
// create new Scene
28+
let scene = new Scene3D();
29+
scene.addComponent(Stats)
30+
this.scene = scene;
31+
32+
// init camera3D
33+
let mainCamera = CameraUtil.createCamera3D(null, scene);
34+
mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0);
35+
36+
// add a basic camera controller
37+
this.hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
38+
this.hoverCameraController.setCamera(0, 0, 20)
39+
40+
this.camera = mainCamera
41+
42+
this.pointGeometry = new SphereGeometry(0.5, 32, 32)
43+
this.lineGeometry = new CylinderGeometry(0.5, 0.5, 1, 32, 32)
44+
this.material = new UnLitMaterial()
45+
this.material.baseColor = this.lineColor
46+
47+
// add basic plane
48+
let plane = new Object3D();
49+
let mr = plane.addComponent(MeshRenderer);
50+
mr.geometry = new PlaneGeometry(20, 20, 1, 1, Vector3.Z_AXIS);
51+
let mat = new UnLitMaterial()
52+
mat.baseColor = new Color(1, 1, 1, 0.4)
53+
mat.transparent = true
54+
mat.cullMode = GPUCullMode.none
55+
mat.blendMode = BlendMode.NORMAL
56+
mr.material = mat;
57+
scene.addChild(plane);
58+
59+
// create a view with target scene and camera
60+
let view = new View3D();
61+
view.scene = scene;
62+
view.camera = mainCamera;
63+
64+
// start render
65+
Engine3D.startRenderView(view);
66+
67+
Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_DOWN, this.onMouseDown, this, null, 999);
68+
Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_MOVE, this.onMouseMove, this);
69+
Engine3D.inputSystem.addEventListener(PointerEvent3D.POINTER_UP, this.onMouseUp, this);
70+
71+
// debug GUI
72+
let gui = new dat.GUI();
73+
let f = gui.addFolder('Orillusion');
74+
f.add(this, 'lineWidth', 0.1, 2, 0.1);
75+
f.add(this, 'precision', 4, 64, 1).onChange((precision) => {
76+
this.lineGeometry = new CylinderGeometry(0.5, 0.5, 1, precision, precision)
77+
this.pointGeometry = new SphereGeometry(0.5, precision, precision)
78+
});
79+
f.add(this, 'depth', -1, 1, 0.01);
80+
f.add(this, 'drawInterval', 15, 100, 1);
81+
f.addColor({lineColor: Object.values(this.lineColor).map((v,i)=> i === 3 ? v : v*255)}, 'lineColor').onChange(v=>{
82+
this.lineColor = new Color(v[0]/255, v[1]/255, v[2]/255, v[3])
83+
this.material = new UnLitMaterial()
84+
this.material.baseColor = this.lineColor
85+
});
86+
f.add({'resetView': () => this.hoverCameraController.setCamera(0, 0, 20)}, 'resetView')
87+
f.add({'clearCanvas': () => {
88+
this.path.map((point) => {
89+
this.scene.removeChild(point)
90+
})
91+
this.path.length = 0
92+
}}, 'clearCanvas')
93+
f.open()
94+
95+
// add tips
96+
gui.add({tips: 'Press to rotate camera'}, 'tips').name('Left Mouse')
97+
gui.add({tips: 'Press to draw lines'}, 'tips').name('Right Mouse')
98+
}
99+
100+
onMouseDown(e: PointerEvent3D) {
101+
if(e.mouseCode === 2) {
102+
e.stopImmediatePropagation()
103+
this.lastTime = Date.now()
104+
this.onDraw = true;
105+
this.drawPoint(e.mouseX, e.mouseY);
106+
this.lastX = e.mouseX;
107+
this.lastY = e.mouseY;
108+
}
109+
}
110+
111+
onMouseMove(e: PointerEvent3D) {
112+
if (!this.onDraw) return;
113+
e.stopImmediatePropagation()
114+
const now = Date.now();
115+
if (now - this.lastTime > this.drawInterval) {
116+
this.drawLine(e.mouseX, e.mouseY);
117+
this.drawPoint(e.mouseX, e.mouseY);
118+
this.lastTime = now;
119+
this.lastX = e.mouseX
120+
this.lastY = e.mouseY
121+
}
122+
}
123+
124+
onMouseUp(e: PointerEvent3D) {
125+
this.onDraw = false;
126+
this.lastX = -1;
127+
this.lastY = -1;
128+
}
129+
130+
drawPoint(x: number, y: number) {
131+
let point = new Object3D();
132+
let mr = point.addComponent(MeshRenderer);
133+
mr.geometry = this.pointGeometry;
134+
mr.material = this.material;
135+
point.scaleX = point.scaleY = point.scaleZ = this.lineWidth
136+
this.camera.worldToScreenPoint(this.hoverCameraController.target, Vector3.HELP_0)
137+
const pos = this.camera.screenPointToWorld(x, y, Vector3.HELP_0.z + this.depth / 100);
138+
point.x = pos.x;
139+
point.y = pos.y;
140+
point.z = pos.z;
141+
this.path.push(point);
142+
this.scene.addChild(point);
143+
}
144+
145+
drawLine(x: number, y: number) {
146+
this.camera.worldToScreenPoint(this.hoverCameraController.target, Vector3.HELP_0)
147+
const start = this.camera.screenPointToWorld(this.lastX, this.lastY, Vector3.HELP_0.z + this.depth / 100);
148+
const end = this.camera.screenPointToWorld(x, y, Vector3.HELP_0.z);
149+
const distance = Math.sqrt(end.distanceToSquared(start))
150+
let line = new Object3D();
151+
let mr = line.addComponent(MeshRenderer);
152+
mr.geometry = this.lineGeometry;
153+
mr.material = this.material;
154+
line.scaleX = line.scaleZ = this.lineWidth;
155+
line.scaleY = distance;
156+
line.x = start.x + (end.x - start.x) / 2;
157+
line.y = start.y + (end.y - start.y) / 2;
158+
line.z = start.z + (end.z - start.z) / 2;
159+
160+
// normalize the direction vector
161+
const dir = Vector3.HELP_1.set(end.x - start.x, end.y - start.y, end.z - start.z).normalize()
162+
const rot = MathUtil.fromToRotation(Vector3.Y_AXIS, dir)
163+
// make sure the rotation is valid
164+
if (!Number.isNaN(rot.x) && !Number.isNaN(rot.y) && !Number.isNaN(rot.z)) {
165+
line.transform.localRotQuat = rot;
166+
}
167+
this.path.push(line);
168+
this.scene.addChild(line);
169+
}
170+
}
171+
172+
new Sample_MeshLines().run()

0 commit comments

Comments
 (0)