forked from BabylonJS/Babylon.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrayHelper.ts
More file actions
232 lines (184 loc) · 7.49 KB
/
Copy pathrayHelper.ts
File metadata and controls
232 lines (184 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
import { Nullable } from "../types";
import { Ray } from "../Culling/ray";
import { Vector3 } from "../Maths/math.vector";
import { Color3 } from '../Maths/math.color';
import { Scene } from "../scene";
import { AbstractMesh } from "../Meshes/abstractMesh";
import { LinesMesh } from "../Meshes/linesMesh";
import "../Meshes/Builders/linesBuilder";
import { Observer } from '../Misc/observable';
import { CreateLines } from "../Meshes/Builders/linesBuilder";
/**
* As raycast might be hard to debug, the RayHelper can help rendering the different rays
* in order to better appreciate the issue one might have.
* @see https://doc.babylonjs.com/babylon101/raycasts#debugging
*/
export class RayHelper {
/**
* Defines the ray we are currently tryin to visualize.
*/
public ray: Nullable<Ray>;
private _renderPoints: Vector3[];
private _renderLine: Nullable<LinesMesh>;
private _renderFunction: Nullable<() => void>;
private _scene: Nullable<Scene>;
private _onAfterRenderObserver: Nullable<Observer<Scene>>;
private _onAfterStepObserver: Nullable<Observer<Scene>>;
private _attachedToMesh: Nullable<AbstractMesh>;
private _meshSpaceDirection: Vector3;
private _meshSpaceOrigin: Vector3;
/**
* Helper function to create a colored helper in a scene in one line.
* @param ray Defines the ray we are currently tryin to visualize
* @param scene Defines the scene the ray is used in
* @param color Defines the color we want to see the ray in
* @returns The newly created ray helper.
*/
public static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper {
var helper = new RayHelper(ray);
helper.show(scene, color);
return helper;
}
/**
* Instantiate a new ray helper.
* As raycast might be hard to debug, the RayHelper can help rendering the different rays
* in order to better appreciate the issue one might have.
* @see https://doc.babylonjs.com/babylon101/raycasts#debugging
* @param ray Defines the ray we are currently tryin to visualize
*/
constructor(ray: Ray) {
this.ray = ray;
}
/**
* Shows the ray we are willing to debug.
* @param scene Defines the scene the ray needs to be rendered in
* @param color Defines the color the ray needs to be rendered in
*/
public show(scene: Scene, color?: Color3): void {
if (!this._renderFunction && this.ray) {
var ray = this.ray;
this._renderFunction = this._render.bind(this);
this._scene = scene;
this._renderPoints = [ray.origin, ray.origin.add(ray.direction.scale(ray.length))];
this._renderLine = CreateLines("ray", { points: this._renderPoints, updatable: true }, scene);
this._renderLine.isPickable = false;
if (this._renderFunction) {
this._scene.registerBeforeRender(this._renderFunction);
}
}
if (color && this._renderLine) {
this._renderLine.color.copyFrom(color);
}
}
/**
* Hides the ray we are debugging.
*/
public hide(): void {
if (this._renderFunction && this._scene) {
this._scene.unregisterBeforeRender(this._renderFunction);
this._scene = null;
this._renderFunction = null;
if (this._renderLine) {
this._renderLine.dispose();
this._renderLine = null;
}
this._renderPoints = [];
}
}
private _render(): void {
var ray = this.ray;
if (!ray) {
return;
}
var point = this._renderPoints[1];
var len = Math.min(ray.length, 1000000);
point.copyFrom(ray.direction);
point.scaleInPlace(len);
point.addInPlace(ray.origin);
this._renderPoints[0].copyFrom(ray.origin);
CreateLines("ray", { points: this._renderPoints, updatable: true, instance: this._renderLine }, this._scene);
this._renderLine?.refreshBoundingInfo();
}
/**
* Attach a ray helper to a mesh so that we can easily see its orientation for instance or information like its normals.
* @param mesh Defines the mesh we want the helper attached to
* @param meshSpaceDirection Defines the direction of the Ray in mesh space (local space of the mesh node)
* @param meshSpaceOrigin Defines the origin of the Ray in mesh space (local space of the mesh node)
* @param length Defines the length of the ray
*/
public attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void {
this._attachedToMesh = mesh;
var ray = this.ray;
if (!ray) {
return;
}
if (!ray.direction) {
ray.direction = Vector3.Zero();
}
if (!ray.origin) {
ray.origin = Vector3.Zero();
}
if (length) {
ray.length = length;
}
if (!meshSpaceOrigin) {
meshSpaceOrigin = Vector3.Zero();
}
if (!meshSpaceDirection) {
// -1 so that this will work with Mesh.lookAt
meshSpaceDirection = new Vector3(0, 0, -1);
}
if (!this._scene) {
this._scene = mesh.getScene();
}
if (!this._meshSpaceDirection) {
this._meshSpaceDirection = meshSpaceDirection.clone();
this._meshSpaceOrigin = meshSpaceOrigin.clone();
} else {
this._meshSpaceDirection.copyFrom(meshSpaceDirection);
this._meshSpaceOrigin.copyFrom(meshSpaceOrigin);
}
if (!this._onAfterRenderObserver) {
this._onAfterRenderObserver = this._scene.onBeforeRenderObservable.add(() => this._updateToMesh());
this._onAfterStepObserver = this._scene.onAfterStepObservable.add(() => this._updateToMesh());
}
// force world matrix computation before the first ray helper computation
this._attachedToMesh.computeWorldMatrix(true);
this._updateToMesh();
}
/**
* Detach the ray helper from the mesh it has previously been attached to.
*/
public detachFromMesh(): void {
if (this._attachedToMesh && this._scene) {
if (this._onAfterRenderObserver) {
this._scene.onBeforeRenderObservable.remove(this._onAfterRenderObserver);
this._scene.onAfterStepObservable.remove(this._onAfterStepObserver);
}
this._attachedToMesh = null;
this._onAfterRenderObserver = null;
this._onAfterStepObserver = null;
this._scene = null;
}
}
private _updateToMesh(): void {
var ray = this.ray;
if (!this._attachedToMesh || !ray) {
return;
}
if (this._attachedToMesh.isDisposed()) {
this.detachFromMesh();
return;
}
this._attachedToMesh.getDirectionToRef(this._meshSpaceDirection, ray.direction);
Vector3.TransformCoordinatesToRef(this._meshSpaceOrigin, this._attachedToMesh.getWorldMatrix(), ray.origin);
}
/**
* Dispose the helper and release its associated resources.
*/
public dispose(): void {
this.hide();
this.detachFromMesh();
this.ray = null;
}
}