lightGizmo.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import { Nullable } from "../types";
  2. import { Color3, Vector3, Quaternion } from "../Maths/math";
  3. import { AbstractMesh } from "../Meshes/abstractMesh";
  4. import { Mesh } from "../Meshes/mesh";
  5. import { Gizmo } from "./gizmo";
  6. import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
  7. import { StandardMaterial } from '../Materials/standardMaterial';
  8. import { Light } from '../Lights/light';
  9. import { Scene } from '../scene';
  10. import { HemisphericLight } from '../Lights/hemisphericLight';
  11. import { DirectionalLight } from '../Lights/directionalLight';
  12. import { SphereBuilder } from '../Meshes/Builders/sphereBuilder';
  13. import { HemisphereBuilder } from '../Meshes/Builders/hemisphereBuilder';
  14. import { SpotLight } from '../Lights/spotLight';
  15. /**
  16. * Gizmo that enables viewing a light
  17. */
  18. export class LightGizmo extends Gizmo {
  19. private _lightMesh: Mesh;
  20. private _material: StandardMaterial;
  21. private cachedPosition = new Vector3();
  22. private cachedForward = new Vector3(0, 0, 1);
  23. /**
  24. * Creates a LightGizmo
  25. * @param gizmoLayer The utility layer the gizmo will be added to
  26. */
  27. constructor(gizmoLayer?: UtilityLayerRenderer) {
  28. super(gizmoLayer);
  29. this.attachedMesh = new AbstractMesh("", this.gizmoLayer.utilityLayerScene);
  30. this._material = new StandardMaterial("light", this.gizmoLayer.originalScene);
  31. this._material.diffuseColor = new Color3(0.5, 0.5, 0.5);
  32. this._material.specularColor = new Color3(0.1, 0.1, 0.1);
  33. }
  34. private _light: Nullable<Light> = null;
  35. /**
  36. * The light that the gizmo is attached to
  37. */
  38. public set light(light: Nullable<Light>) {
  39. this._light = light;
  40. if (light) {
  41. // Create the mesh for the given light type
  42. if (this._lightMesh) {
  43. this._lightMesh.dispose();
  44. }
  45. if (light instanceof HemisphericLight) {
  46. this._lightMesh = LightGizmo._CreateHemisphericLightMesh(this.gizmoLayer.utilityLayerScene);
  47. }else if (light instanceof DirectionalLight) {
  48. this._lightMesh = LightGizmo._CreateDirectionalLightMesh(this.gizmoLayer.utilityLayerScene);
  49. }else if (light instanceof SpotLight) {
  50. this._lightMesh = LightGizmo._CreateSpotLightMesh(this.gizmoLayer.utilityLayerScene);
  51. }else {
  52. this._lightMesh = LightGizmo._CreatePointLightMesh(this.gizmoLayer.utilityLayerScene);
  53. }
  54. this._lightMesh.getChildMeshes(false).forEach((m) => {
  55. m.material = this._material;
  56. });
  57. this._lightMesh.parent = this._rootMesh;
  58. // Add lighting to the light gizmo
  59. var gizmoLight = this.gizmoLayer._getSharedGizmoLight();
  60. gizmoLight.includedOnlyMeshes = gizmoLight.includedOnlyMeshes.concat(this._lightMesh.getChildMeshes(false));
  61. this._lightMesh.rotationQuaternion = new Quaternion();
  62. // Get update position and direction if the light has it
  63. if ((light as any).position) {
  64. this.attachedMesh!.position.copyFrom((light as any).position);
  65. }
  66. if ((light as any).direction) {
  67. this.attachedMesh!.setDirection((light as any).direction);
  68. }
  69. this._update();
  70. }
  71. }
  72. public get light() {
  73. return this._light;
  74. }
  75. /**
  76. * @hidden
  77. * Updates the gizmo to match the attached mesh's position/rotation
  78. */
  79. protected _update() {
  80. super._update();
  81. if (!this._light) {
  82. return;
  83. }
  84. if ((this._light as any).position) {
  85. // If the gizmo is moved update the light otherwise update the gizmo to match the light
  86. if (!this.attachedMesh!.position.equals(this.cachedPosition)) {
  87. // update light to match gizmo
  88. (this._light as any).position.copyFrom(this.attachedMesh!.position);
  89. this.cachedPosition.copyFrom(this.attachedMesh!.position);
  90. }else {
  91. // update gizmo to match light
  92. this.attachedMesh!.position.copyFrom((this._light as any).position);
  93. }
  94. }
  95. if ((this._light as any).direction) {
  96. // If the gizmo is moved update the light otherwise update the gizmo to match the light
  97. if (Vector3.DistanceSquared(this.attachedMesh!.forward, this.cachedForward) > 0.0001) {
  98. // update light to match gizmo
  99. (this._light as any).direction.copyFrom(this.attachedMesh!.forward);
  100. this.cachedForward.copyFrom(this.attachedMesh!.forward);
  101. }else if (Vector3.DistanceSquared(this.attachedMesh!.forward, (this._light as any).direction) > 0.0001) {
  102. // update gizmo to match light
  103. this.attachedMesh!.setDirection((this._light as any).direction);
  104. this.cachedForward.copyFrom(this._lightMesh.forward);
  105. }
  106. }
  107. if (!this._light.isEnabled()) {
  108. this._material.diffuseColor.set(0, 0, 0);
  109. } else {
  110. this._material.diffuseColor.set(this._light.diffuse.r / 3, this._light.diffuse.g / 3, this._light.diffuse.b / 3);
  111. }
  112. }
  113. // Static helper methods
  114. private static _Scale = 0.007;
  115. /**
  116. * Creates the lines for a light mesh
  117. */
  118. private static _createLightLines = (levels: number, scene: Scene) => {
  119. var distFromSphere = 1.2;
  120. var root = new Mesh("root", scene);
  121. root.rotation.x = Math.PI / 2;
  122. // Create the top line, this will be cloned for all other lines
  123. var linePivot = new Mesh("linePivot", scene);
  124. linePivot.parent = root;
  125. var line = Mesh.CreateCylinder("line", 2, 0.2, 0.3, 6, 1, scene);
  126. line.position.y = line.scaling.y / 2 + distFromSphere;
  127. line.parent = linePivot;
  128. if (levels < 2) {
  129. return linePivot;
  130. }
  131. for (var i = 0; i < 4; i++) {
  132. var l = linePivot.clone("lineParentClone");
  133. l.rotation.z = Math.PI / 4;
  134. l.rotation.y = (Math.PI / 2) + (Math.PI / 2 * i);
  135. l.getChildMeshes()[0].scaling.y = 0.5;
  136. l.getChildMeshes()[0].scaling.x = l.getChildMeshes()[0].scaling.z = 0.8;
  137. l.getChildMeshes()[0].position.y = l.getChildMeshes()[0].scaling.y / 2 + distFromSphere;
  138. }
  139. if (levels < 3) {
  140. return root;
  141. }
  142. for (var i = 0; i < 4; i++) {
  143. var l = linePivot.clone("linePivotClone");
  144. l.rotation.z = Math.PI / 2;
  145. l.rotation.y = (Math.PI / 2 * i);
  146. }
  147. if (levels < 4) {
  148. return root;
  149. }
  150. for (var i = 0; i < 4; i++) {
  151. var l = linePivot.clone("linePivotClone");
  152. l.rotation.z = Math.PI + (Math.PI / 4);
  153. l.rotation.y = (Math.PI / 2) + (Math.PI / 2 * i);
  154. l.getChildMeshes()[0].scaling.y = 0.5;
  155. l.getChildMeshes()[0].scaling.x = l.getChildMeshes()[0].scaling.z = 0.8;
  156. l.getChildMeshes()[0].position.y = l.getChildMeshes()[0].scaling.y / 2 + distFromSphere;
  157. }
  158. if (levels < 5) {
  159. return root;
  160. }
  161. var l = linePivot.clone("linePivotClone");
  162. l.rotation.z = Math.PI;
  163. return root;
  164. }
  165. private static _CreateHemisphericLightMesh(scene: Scene) {
  166. var root = new Mesh("hemisphereLight", scene);
  167. var hemisphere = HemisphereBuilder.CreateHemisphere(root.name, {segments: 10, diameter: 1}, scene);
  168. hemisphere.position.z = -0.15;
  169. hemisphere.rotation.x = Math.PI / 2;
  170. hemisphere.parent = root;
  171. var lines = this._createLightLines(3, scene);
  172. lines.parent = root;
  173. lines.position.z - 0.15;
  174. root.scaling.scaleInPlace(LightGizmo._Scale);
  175. root.rotation.x = Math.PI / 2;
  176. return root;
  177. }
  178. private static _CreatePointLightMesh(scene: Scene) {
  179. var root = new Mesh("pointLight", scene);
  180. var sphere = SphereBuilder.CreateSphere(root.name, {segments: 10, diameter: 1}, scene);
  181. sphere.rotation.x = Math.PI / 2;
  182. sphere.parent = root;
  183. var lines = this._createLightLines(5, scene);
  184. lines.parent = root;
  185. root.scaling.scaleInPlace(LightGizmo._Scale);
  186. root.rotation.x = Math.PI / 2;
  187. return root;
  188. }
  189. private static _CreateSpotLightMesh(scene: Scene) {
  190. var root = new Mesh("spotLight", scene);
  191. var sphere = SphereBuilder.CreateSphere(root.name, {segments: 10, diameter: 1}, scene);
  192. sphere.parent = root;
  193. var hemisphere = HemisphereBuilder.CreateHemisphere(root.name, {segments: 10, diameter: 2}, scene);
  194. hemisphere.parent = root;
  195. hemisphere.rotation.x = -Math.PI / 2;
  196. var lines = this._createLightLines(2, scene);
  197. lines.parent = root;
  198. root.scaling.scaleInPlace(LightGizmo._Scale);
  199. root.rotation.x = Math.PI / 2;
  200. return root;
  201. }
  202. private static _CreateDirectionalLightMesh(scene: Scene) {
  203. var root = new Mesh("directionalLight", scene);
  204. var mesh = new Mesh(root.name, scene);
  205. mesh.parent = root;
  206. var sphere = SphereBuilder.CreateSphere(root.name, {diameter: 1.2, segments: 10}, scene);
  207. sphere.parent = mesh;
  208. var line = Mesh.CreateCylinder(root.name, 6, 0.3, 0.3, 6, 1, scene);
  209. line.parent = mesh;
  210. var left = line.clone(root.name);
  211. left.scaling.y = 0.5;
  212. left.position.x += 1.25;
  213. var right = line.clone(root.name);
  214. right.scaling.y = 0.5;
  215. right.position.x += -1.25;
  216. var arrowHead = Mesh.CreateCylinder(root.name, 1, 0, 0.6, 6, 1, scene);
  217. arrowHead.position.y += 3;
  218. arrowHead.parent = mesh;
  219. var left = arrowHead.clone(root.name);
  220. left.position.y = 1.5;
  221. left.position.x += 1.25;
  222. var right = arrowHead.clone(root.name);
  223. right.position.y = 1.5;
  224. right.position.x += -1.25;
  225. mesh.scaling.scaleInPlace(LightGizmo._Scale);
  226. mesh.rotation.z = Math.PI / 2;
  227. mesh.rotation.y = Math.PI / 2;
  228. return root;
  229. }
  230. }