meshPropertyGridComponent.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { Tools } from "babylonjs/Misc/tools";
  4. import { Vector3, TmpVectors } from "babylonjs/Maths/math.vector";
  5. import { Color3 } from 'babylonjs/Maths/math.color';
  6. import { Mesh } from "babylonjs/Meshes/mesh";
  7. import { VertexBuffer } from "babylonjs/Meshes/buffer";
  8. import { LinesBuilder } from "babylonjs/Meshes/Builders/linesBuilder";
  9. import { PhysicsImpostor } from "babylonjs/Physics/physicsImpostor";
  10. import { Scene } from "babylonjs/scene";
  11. import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
  12. import { LineContainerComponent } from "../../../lineContainerComponent";
  13. import { TextLineComponent } from "../../../lines/textLineComponent";
  14. import { CheckBoxLineComponent } from "../../../lines/checkBoxLineComponent";
  15. import { Vector3LineComponent } from "../../../lines/vector3LineComponent";
  16. import { SliderLineComponent } from "../../../lines/sliderLineComponent";
  17. import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent";
  18. import { FloatLineComponent } from "../../../lines/floatLineComponent";
  19. import { LockObject } from "../lockObject";
  20. import { GlobalState } from '../../../../globalState';
  21. import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
  22. import { StandardMaterial } from 'babylonjs/Materials/standardMaterial';
  23. import { Color3LineComponent } from '../../../lines/color3LineComponent';
  24. import { MorphTarget } from 'babylonjs/Morph/morphTarget';
  25. import { OptionsLineComponent } from '../../../lines/optionsLineComponent';
  26. import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
  27. import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
  28. import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
  29. interface IMeshPropertyGridComponentProps {
  30. globalState: GlobalState;
  31. mesh: Mesh;
  32. lockObject: LockObject;
  33. onSelectionChangedObservable?: Observable<any>;
  34. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  35. }
  36. export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGridComponentProps, {
  37. displayNormals: boolean,
  38. displayVertexColors: boolean
  39. }> {
  40. constructor(props: IMeshPropertyGridComponentProps) {
  41. super(props);
  42. this.state = {
  43. displayNormals: false,
  44. displayVertexColors: false
  45. };
  46. }
  47. renderWireframeOver() {
  48. const mesh = this.props.mesh;
  49. const scene = mesh.getScene();
  50. if (mesh.reservedDataStore && mesh.reservedDataStore.wireframeOver) {
  51. mesh.reservedDataStore.wireframeOver.dispose(false, true);
  52. mesh.reservedDataStore.wireframeOver = null;
  53. this.forceUpdate();
  54. return;
  55. }
  56. var wireframeOver = mesh.clone()!;
  57. wireframeOver.reservedDataStore = { hidden: true };
  58. // Sets up the mesh to be attached to the parent.
  59. // So all neutral in local space.
  60. wireframeOver.parent = mesh;
  61. wireframeOver.position = Vector3.Zero();
  62. wireframeOver.scaling = new Vector3(1, 1, 1);
  63. wireframeOver.rotation = Vector3.Zero();
  64. wireframeOver.rotationQuaternion = null;
  65. var material = new StandardMaterial("wireframeOver", scene);
  66. material.reservedDataStore = { hidden: true };
  67. wireframeOver.material = material;
  68. material.zOffset = 1;
  69. material.disableLighting = true;
  70. material.backFaceCulling = false;
  71. material.emissiveColor = Color3.White();
  72. material.wireframe = true;
  73. if (!mesh.reservedDataStore) {
  74. mesh.reservedDataStore = {};
  75. }
  76. mesh.reservedDataStore.wireframeOver = wireframeOver;
  77. this.forceUpdate();
  78. }
  79. renderNormalVectors() {
  80. const mesh = this.props.mesh;
  81. const scene = mesh.getScene();
  82. if (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) {
  83. mesh.reservedDataStore.normalLines.dispose();
  84. mesh.reservedDataStore.normalLines = null;
  85. this.forceUpdate();
  86. return;
  87. }
  88. var normals = mesh.getVerticesData(VertexBuffer.NormalKind);
  89. var positions = mesh.getVerticesData(VertexBuffer.PositionKind);
  90. const color = Color3.White();
  91. const bbox = mesh.getBoundingInfo();
  92. const diag = bbox.maximum.subtractToRef(bbox.minimum, TmpVectors.Vector3[0]);
  93. const size = diag.length() * 0.05;
  94. var lines = [];
  95. for (var i = 0; i < normals!.length; i += 3) {
  96. var v1 = Vector3.FromArray(positions!, i);
  97. var v2 = v1.add(Vector3.FromArray(normals!, i).scaleInPlace(size));
  98. lines.push([v1, v2]);
  99. }
  100. var normalLines = LinesBuilder.CreateLineSystem("normalLines", { lines: lines }, scene);
  101. normalLines.color = color;
  102. normalLines.parent = mesh;
  103. normalLines.reservedDataStore = { hidden: true };
  104. if (!mesh.reservedDataStore) {
  105. mesh.reservedDataStore = {};
  106. }
  107. mesh.reservedDataStore.normalLines = normalLines;
  108. this.forceUpdate();
  109. }
  110. displayNormals() {
  111. const mesh = this.props.mesh;
  112. const scene = mesh.getScene();
  113. if (mesh.material && mesh.material.getClassName() === "NormalMaterial") {
  114. mesh.material.dispose();
  115. mesh.material = mesh.reservedDataStore.originalMaterial;
  116. mesh.reservedDataStore.originalMaterial = null;
  117. this.setState({ displayNormals: false });
  118. } else {
  119. if (!(BABYLON as any).NormalMaterial) {
  120. this.setState({ displayNormals: true });
  121. Tools.LoadScript("https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.js", () => {
  122. this.displayNormals();
  123. });
  124. return;
  125. }
  126. if (!mesh.reservedDataStore) {
  127. mesh.reservedDataStore = {};
  128. }
  129. if (!mesh.reservedDataStore.originalMaterial) {
  130. mesh.reservedDataStore.originalMaterial = mesh.material;
  131. }
  132. const normalMaterial = new (BABYLON as any).NormalMaterial("normalMaterial", scene);
  133. normalMaterial.disableLighting = true;
  134. if (mesh.material) {
  135. normalMaterial.sideOrientation = mesh.material.sideOrientation;
  136. }
  137. normalMaterial.reservedDataStore = { hidden: true };
  138. mesh.material = normalMaterial;
  139. this.setState({ displayNormals: true });
  140. }
  141. }
  142. displayVertexColors() {
  143. const mesh = this.props.mesh;
  144. const scene = mesh.getScene();
  145. if (mesh.material && mesh.material.reservedDataStore && mesh.material.reservedDataStore.isVertexColorMaterial) {
  146. mesh.material.dispose();
  147. mesh.material = mesh.reservedDataStore.originalMaterial;
  148. mesh.reservedDataStore.originalMaterial = null;
  149. this.setState({ displayVertexColors: false });
  150. } else {
  151. if (!mesh.reservedDataStore) {
  152. mesh.reservedDataStore = {};
  153. }
  154. if (!mesh.reservedDataStore.originalMaterial) {
  155. mesh.reservedDataStore.originalMaterial = mesh.material;
  156. }
  157. const vertexColorMaterial = new StandardMaterial("vertex colors", scene);
  158. vertexColorMaterial.disableLighting = true;
  159. vertexColorMaterial.emissiveColor = Color3.White();
  160. if (mesh.material) {
  161. vertexColorMaterial.sideOrientation = mesh.material.sideOrientation;
  162. }
  163. vertexColorMaterial.reservedDataStore = { hidden: true, isVertexColorMaterial: true };
  164. mesh.useVertexColors = true;
  165. mesh.material = vertexColorMaterial;
  166. this.setState({ displayVertexColors: true });
  167. }
  168. }
  169. onMaterialLink() {
  170. if (!this.props.onSelectionChangedObservable) {
  171. return;
  172. }
  173. const mesh = this.props.mesh;
  174. this.props.onSelectionChangedObservable.notifyObservers(mesh.material);
  175. }
  176. onSourceMeshLink() {
  177. if (!this.props.onSelectionChangedObservable) {
  178. return;
  179. }
  180. const instanceMesh = this.props.mesh as any;
  181. this.props.onSelectionChangedObservable.notifyObservers(instanceMesh.sourceMesh);
  182. }
  183. onSkeletonLink() {
  184. if (!this.props.onSelectionChangedObservable) {
  185. return;
  186. }
  187. const mesh = this.props.mesh;
  188. this.props.onSelectionChangedObservable.notifyObservers(mesh.skeleton);
  189. }
  190. convertPhysicsTypeToString(): string {
  191. const mesh = this.props.mesh;
  192. switch (mesh.physicsImpostor!.type) {
  193. case PhysicsImpostor.NoImpostor:
  194. return "No impostor";
  195. case PhysicsImpostor.SphereImpostor:
  196. return "Sphere";
  197. case PhysicsImpostor.BoxImpostor:
  198. return "Box";
  199. case PhysicsImpostor.PlaneImpostor:
  200. return "Plane";
  201. case PhysicsImpostor.MeshImpostor:
  202. return "Mesh";
  203. case PhysicsImpostor.CylinderImpostor:
  204. return "Cylinder";
  205. case PhysicsImpostor.ParticleImpostor:
  206. return "Particle";
  207. case PhysicsImpostor.HeightmapImpostor:
  208. return "Heightmap";
  209. case PhysicsImpostor.ConvexHullImpostor:
  210. return "Convex hull";
  211. case PhysicsImpostor.RopeImpostor:
  212. return "Rope";
  213. case PhysicsImpostor.SoftbodyImpostor:
  214. return "Soft body";
  215. }
  216. return "Unknown";
  217. }
  218. render() {
  219. const mesh = this.props.mesh;
  220. const scene = mesh.getScene();
  221. const displayNormals = mesh.material != null && mesh.material.getClassName() === "NormalMaterial";
  222. const displayVertexColors = !!(mesh.material != null && mesh.material.reservedDataStore && mesh.material.reservedDataStore.isVertexColorMaterial);
  223. const renderNormalVectors = (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) ? true : false;
  224. const renderWireframeOver = (mesh.reservedDataStore && mesh.reservedDataStore.wireframeOver) ? true : false;
  225. var morphTargets: MorphTarget[] = [];
  226. if (mesh.morphTargetManager) {
  227. for (var index = 0; index < mesh.morphTargetManager.numTargets; index++) {
  228. morphTargets.push(mesh.morphTargetManager.getTarget(index));
  229. }
  230. }
  231. var algorithmOptions = [
  232. { label: "Accurate", value: AbstractMesh.OCCLUSION_ALGORITHM_TYPE_ACCURATE },
  233. { label: "Conservative", value: AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE },
  234. ];
  235. var occlusionTypeOptions = [
  236. { label: "None", value: AbstractMesh.OCCLUSION_TYPE_NONE },
  237. { label: "Optimistic", value: AbstractMesh.OCCLUSION_TYPE_OPTIMISTIC },
  238. { label: "Strict", value: AbstractMesh.OCCLUSION_TYPE_STRICT },
  239. ];
  240. let sortedMaterials = scene.materials.slice(0).sort((a, b) => (a.name || "no name").localeCompare(b.name || "no name"));
  241. var materialOptions = sortedMaterials.map((m, i) => {
  242. return {
  243. label: m.name || "no name",
  244. value: i
  245. };});
  246. materialOptions.splice(0, 0, {
  247. label: "None",
  248. value: -1
  249. });
  250. return (
  251. <div className="pane">
  252. <CustomPropertyGridComponent globalState={this.props.globalState} target={mesh}
  253. lockObject={this.props.lockObject}
  254. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  255. <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
  256. <TextLineComponent label="ID" value={mesh.id} />
  257. <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={mesh} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  258. <TextLineComponent label="Unique ID" value={mesh.uniqueId.toString()} />
  259. <TextLineComponent label="Class" value={mesh.getClassName()} />
  260. <TextLineComponent label="Vertices" value={mesh.getTotalVertices().toString()} />
  261. <TextLineComponent label="Faces" value={(mesh.getTotalIndices() / 3).toFixed(0)} />
  262. <TextLineComponent label="Sub-meshes" value={mesh.subMeshes ? mesh.subMeshes.length.toString() : "0"} />
  263. {
  264. mesh.parent &&
  265. <TextLineComponent label="Parent" value={mesh.parent.name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(mesh.parent)}/>
  266. }
  267. {
  268. mesh.skeleton &&
  269. <TextLineComponent label="Skeleton" value={mesh.skeleton.name} onLink={() => this.onSkeletonLink()}/>
  270. }
  271. <CheckBoxLineComponent label="Is enabled" isSelected={() => mesh.isEnabled()} onSelect={(value) => mesh.setEnabled(value)} />
  272. <CheckBoxLineComponent label="Is pickable" target={mesh} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  273. {
  274. mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) &&
  275. <TextLineComponent label="Link to material" value={mesh.material.name} onLink={() => this.onMaterialLink()} />
  276. }
  277. { !mesh.isAnInstance &&
  278. <OptionsLineComponent label="Active material" options={materialOptions}
  279. target={mesh} propertyName="material"
  280. noDirectUpdate={true}
  281. onSelect={(value: number) => {
  282. if (value < 0) {
  283. mesh.material = null;
  284. } else {
  285. mesh.material = sortedMaterials[value];
  286. }
  287. this.forceUpdate();
  288. }}
  289. extractValue={() => mesh.material ? sortedMaterials.indexOf(mesh.material) : -1}
  290. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  291. }
  292. {
  293. mesh.isAnInstance &&
  294. <TextLineComponent label="Source" value={(mesh as any).sourceMesh.name} onLink={() => this.onSourceMeshLink()} />
  295. }
  296. <ButtonLineComponent label="Dispose" onClick={() => {
  297. mesh.dispose();
  298. this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
  299. }} />
  300. </LineContainerComponent>
  301. <LineContainerComponent globalState={this.props.globalState} title="TRANSFORMS">
  302. <Vector3LineComponent label="Position" target={mesh} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  303. {
  304. !mesh.rotationQuaternion &&
  305. <Vector3LineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotation" step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  306. }
  307. {
  308. mesh.rotationQuaternion &&
  309. <QuaternionLineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotationQuaternion" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  310. }
  311. <Vector3LineComponent label="Scaling" target={mesh} propertyName="scaling" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  312. </LineContainerComponent>
  313. <LineContainerComponent globalState={this.props.globalState} title="DISPLAY" closed={true}>
  314. {
  315. !mesh.isAnInstance &&
  316. <SliderLineComponent label="Visibility" target={mesh} propertyName="visibility" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  317. }
  318. <FloatLineComponent lockObject={this.props.lockObject} label="Alpha index" target={mesh} propertyName="alphaIndex" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  319. <CheckBoxLineComponent label="Receive shadows" target={mesh} propertyName="receiveShadows" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  320. {
  321. mesh.isVerticesDataPresent(VertexBuffer.ColorKind) &&
  322. <CheckBoxLineComponent label="Use vertex colors" target={mesh} propertyName="useVertexColors" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  323. }
  324. {
  325. mesh.isVerticesDataPresent(VertexBuffer.ColorKind) &&
  326. <CheckBoxLineComponent label="Has vertex alpha" target={mesh} propertyName="hasVertexAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  327. }
  328. {
  329. scene.fogMode !== Scene.FOGMODE_NONE &&
  330. <CheckBoxLineComponent label="Apply fog" target={mesh} propertyName="applyFog" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  331. }
  332. {
  333. !mesh.parent &&
  334. <CheckBoxLineComponent label="Infinite distance" target={mesh} propertyName="infiniteDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  335. }
  336. </LineContainerComponent>
  337. {
  338. mesh.morphTargetManager != null &&
  339. <LineContainerComponent globalState={this.props.globalState} title="MORPH TARGETS" closed={true}>
  340. {
  341. morphTargets.map((mt, i) => {
  342. return (
  343. <SliderLineComponent label={mt.name} target={mt} propertyName="influence" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  344. );
  345. })
  346. }
  347. </LineContainerComponent>
  348. }
  349. <LineContainerComponent globalState={this.props.globalState} title="ADVANCED" closed={true}>
  350. {
  351. mesh.useBones &&
  352. <CheckBoxLineComponent label="Compute bones using shaders" target={mesh} propertyName="computeBonesUsingShaders" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  353. }
  354. <CheckBoxLineComponent label="Collisions" target={mesh} propertyName="checkCollisions" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  355. <TextLineComponent label="Has normals" value={mesh.isVerticesDataPresent(VertexBuffer.NormalKind) ? "Yes" : "No"} />
  356. <TextLineComponent label="Has vertex colors" value={mesh.isVerticesDataPresent(VertexBuffer.ColorKind) ? "Yes" : "No"} />
  357. <TextLineComponent label="Has UV set 0" value={mesh.isVerticesDataPresent(VertexBuffer.UVKind) ? "Yes" : "No"} />
  358. <TextLineComponent label="Has UV set 1" value={mesh.isVerticesDataPresent(VertexBuffer.UV2Kind) ? "Yes" : "No"} />
  359. <TextLineComponent label="Has UV set 2" value={mesh.isVerticesDataPresent(VertexBuffer.UV3Kind) ? "Yes" : "No"} />
  360. <TextLineComponent label="Has UV set 3" value={mesh.isVerticesDataPresent(VertexBuffer.UV4Kind) ? "Yes" : "No"} />
  361. <TextLineComponent label="Has tangents" value={mesh.isVerticesDataPresent(VertexBuffer.TangentKind) ? "Yes" : "No"} />
  362. <TextLineComponent label="Has matrix weights" value={mesh.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind) ? "Yes" : "No"} />
  363. <TextLineComponent label="Has matrix indices" value={mesh.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) ? "Yes" : "No"} />
  364. </LineContainerComponent>
  365. {
  366. mesh.physicsImpostor != null &&
  367. <LineContainerComponent globalState={this.props.globalState} title="PHYSICS" closed={true}>
  368. <FloatLineComponent lockObject={this.props.lockObject} label="Mass" target={mesh.physicsImpostor} propertyName="mass" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  369. <FloatLineComponent lockObject={this.props.lockObject} label="Friction" target={mesh.physicsImpostor} propertyName="friction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  370. <FloatLineComponent lockObject={this.props.lockObject} label="Restitution" target={mesh.physicsImpostor} propertyName="restitution" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  371. <TextLineComponent label="Type" value={this.convertPhysicsTypeToString()} />
  372. </LineContainerComponent>
  373. }
  374. <LineContainerComponent globalState={this.props.globalState} title="OCCLUSIONS" closed={true}>
  375. <OptionsLineComponent label="Type" options={occlusionTypeOptions} target={mesh} propertyName="occlusionType" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  376. <SliderLineComponent label="Retry count" minimum={-1} maximum={10} decimalCount={0} step={1} target={mesh} propertyName="occlusionRetryCount" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  377. <OptionsLineComponent label="Algorithm" options={algorithmOptions} target={mesh} propertyName="occlusionQueryAlgorithmType" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  378. </LineContainerComponent>
  379. <LineContainerComponent globalState={this.props.globalState} title="EDGE RENDERING" closed={true}>
  380. <CheckBoxLineComponent label="Enable" target={mesh} isSelected={() => mesh.edgesRenderer != null} onSelect={(value) => {
  381. if (value) {
  382. mesh.enableEdgesRendering();
  383. } else {
  384. mesh.disableEdgesRendering();
  385. }
  386. }} />
  387. <SliderLineComponent label="Edge width" minimum={0} maximum={10} step={0.1} target={mesh} propertyName="edgesWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  388. <Color3LineComponent label="Edge color" target={mesh} propertyName="edgesColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  389. </LineContainerComponent>
  390. {
  391. !mesh.isAnInstance &&
  392. <LineContainerComponent globalState={this.props.globalState} title="OUTLINE & OVERLAY" closed={true}>
  393. <CheckBoxLineComponent label="Render overlay" target={mesh} propertyName="renderOverlay" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  394. <Color3LineComponent label="Overlay color" target={mesh} propertyName="overlayColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  395. <CheckBoxLineComponent label="Render outline" target={mesh} propertyName="renderOutline" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  396. <Color3LineComponent label="Outline color" target={mesh} propertyName="outlineColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  397. </LineContainerComponent>
  398. }
  399. <LineContainerComponent globalState={this.props.globalState} title="DEBUG" closed={true}>
  400. {
  401. !mesh.isAnInstance &&
  402. <CheckBoxLineComponent label="Display normals" isSelected={() => displayNormals} onSelect={() => this.displayNormals()} />
  403. }
  404. {
  405. !mesh.isAnInstance &&
  406. <CheckBoxLineComponent label="Display vertex colors" isSelected={() => displayVertexColors} onSelect={() => this.displayVertexColors()} />
  407. }
  408. {
  409. mesh.isVerticesDataPresent(VertexBuffer.NormalKind) &&
  410. <CheckBoxLineComponent label="Render vertex normals" isSelected={() => renderNormalVectors} onSelect={() => this.renderNormalVectors()} />
  411. }
  412. {
  413. !mesh.isAnInstance &&
  414. <CheckBoxLineComponent label="Render wireframe over mesh" isSelected={() => renderWireframeOver} onSelect={() => this.renderWireframeOver()} />
  415. }
  416. </LineContainerComponent>
  417. </div>
  418. );
  419. }
  420. }