UNPKG

@xeokit/xeokit-sdk

Version:

3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision

359 lines (337 loc) 10.2 kB
import {Material} from './Material.js'; import {RenderState} from '../webgl/RenderState.js'; const PRESETS = { "default": { edgeColor: [0.0, 0.0, 0.0], edgeAlpha: 1.0, edgeWidth: 1 }, "defaultWhiteBG": { edgeColor: [0.2, 0.2, 0.2], edgeAlpha: 1.0, edgeWidth: 1 }, "defaultLightBG": { edgeColor: [0.2, 0.2, 0.2], edgeAlpha: 1.0, edgeWidth: 1 }, "defaultDarkBG": { edgeColor: [0.5, 0.5, 0.5], edgeAlpha: 1.0, edgeWidth: 1 } }; /** * @desc Configures the appearance of {@link Entity}s when their edges are emphasised. * * * Emphasise edges of an {@link Entity} by setting {@link Entity#edges} ````true````. * * When {@link Entity}s are within the subtree of a root {@link Entity}, then setting {@link Entity#edges} on the root * will collectively set that property on all sub-{@link Entity}s. * * EdgeMaterial provides several presets. Select a preset by setting {@link EdgeMaterial#preset} to the ID of a preset in {@link EdgeMaterial#presets}. * * By default, a {@link Mesh} uses the default EdgeMaterial in {@link Scene#edgeMaterial}, but you can assign each {@link Mesh#edgeMaterial} to a custom EdgeMaterial if required. * * ## Usage * * In the example below, we'll create a {@link Mesh} with its own EdgeMaterial and set {@link Mesh#edges} ````true```` to emphasise its edges. * * Recall that {@link Mesh} is a concrete subtype of the abstract {@link Entity} base class. * * [[Run this example](/examples/index.html#materials_EdgeMaterial)] * * ````javascript * import {Viewer, Mesh, buildSphereGeometry, * ReadableGeometry, PhongMaterial, EdgeMaterial} from "xeokit-sdk.es.js"; * * const viewer = new Viewer({ * canvasId: "myCanvas", * transparent: true * }); * * viewer.scene.camera.eye = [0, 0, 5]; * viewer.scene.camera.look = [0, 0, 0]; * viewer.scene.camera.up = [0, 1, 0]; * * new Mesh(viewer.scene, { * * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ * radius: 1.5, * heightSegments: 24, * widthSegments: 16, * edgeThreshold: 2 // Default is 10 * })), * * material: new PhongMaterial(viewer.scene, { * diffuse: [0.4, 0.4, 1.0], * ambient: [0.9, 0.3, 0.9], * shininess: 30, * alpha: 0.5, * alphaMode: "blend" * }), * * edgeMaterial: new EdgeMaterial(viewer.scene, { * edgeColor: [0.0, 0.0, 1.0] * edgeAlpha: 1.0, * edgeWidth: 2 * }), * * edges: true * }); * ```` * * Note the ````edgeThreshold```` configuration for the {@link ReadableGeometry} on our {@link Mesh}. EdgeMaterial configures * a wireframe representation of the {@link ReadableGeometry}, which will have inner edges (those edges between * adjacent co-planar triangles) removed for visual clarity. The ````edgeThreshold```` indicates that, for * this particular {@link ReadableGeometry}, an inner edge is one where the angle between the surface normals of adjacent triangles * is not greater than ````5```` degrees. That's set to ````2```` by default, but we can override it to tweak the effect * as needed for particular Geometries. * * Here's the example again, this time implicitly defaulting to the {@link Scene#edgeMaterial}. We'll also modify that EdgeMaterial * to customize the effect. * * ````javascript * new Mesh({ * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ * radius: 1.5, * heightSegments: 24, * widthSegments: 16, * edgeThreshold: 2 // Default is 10 * })), * material: new PhongMaterial(viewer.scene, { * diffuse: [0.2, 0.2, 1.0] * }), * edges: true * }); * * var edgeMaterial = viewer.scene.edgeMaterial; * * edgeMaterial.edgeColor = [0.2, 1.0, 0.2]; * edgeMaterial.edgeAlpha = 1.0; * edgeMaterial.edgeWidth = 2; * ```` * * ## Presets * * Let's switch the {@link Scene#edgeMaterial} to one of the presets in {@link EdgeMaterial#presets}: * * ````javascript * viewer.edgeMaterial.preset = EdgeMaterial.presets["sepia"]; * ```` * * We can also create an EdgeMaterial from a preset, while overriding properties of the preset as required: * * ````javascript * var myEdgeMaterial = new EdgeMaterial(viewer.scene, { * preset: "sepia", * edgeColor = [1.0, 0.5, 0.5] * }); * ```` */ class EdgeMaterial extends Material { /** @private */ get type() { return "EdgeMaterial"; } /** * Gets available EdgeMaterial presets. * * @type {Object} */ get presets() { return PRESETS; }; /** * @constructor * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. * @param {*} [cfg] The EdgeMaterial configuration * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. * @param {Number[]} [cfg.edgeColor=[0.2,0.2,0.2]] RGB edge color. * @param {Number} [cfg.edgeAlpha=1.0] Edge transparency. A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. * @param {Number} [cfg.edgeWidth=1] Edge width in pixels. * @param {String} [cfg.preset] Selects a preset EdgeMaterial configuration - see {@link EdgeMaterial#presets}. */ constructor(owner, cfg = {}) { super(owner, cfg); this._state = new RenderState({ type: "EdgeMaterial", edges: null, edgeColor: null, edgeAlpha: null, edgeWidth: null }); this._preset = "default"; if (cfg.preset) { // Apply preset then override with configs where provided this.preset = cfg.preset; if (cfg.edgeColor) { this.edgeColor = cfg.edgeColor; } if (cfg.edgeAlpha !== undefined) { this.edgeAlpha = cfg.edgeAlpha; } if (cfg.edgeWidth !== undefined) { this.edgeWidth = cfg.edgeWidth; } } else { this.edgeColor = cfg.edgeColor; this.edgeAlpha = cfg.edgeAlpha; this.edgeWidth = cfg.edgeWidth; } this.edges = (cfg.edges !== false); } /** * Sets if edges are visible. * * Default is ````true````. * * @type {Boolean} */ set edges(value) { value = value !== false; if (this._state.edges === value) { return; } this._state.edges = value; this.glRedraw(); } /** * Gets if edges are visible. * * Default is ````true````. * * @type {Boolean} */ get edges() { return this._state.edges; } /** * Sets RGB edge color. * * Default value is ````[0.2, 0.2, 0.2]````. * * @type {Number[]} */ set edgeColor(value) { let edgeColor = this._state.edgeColor; if (!edgeColor) { edgeColor = this._state.edgeColor = new Float32Array(3); } else if (value && edgeColor[0] === value[0] && edgeColor[1] === value[1] && edgeColor[2] === value[2]) { return; } if (value) { edgeColor[0] = value[0]; edgeColor[1] = value[1]; edgeColor[2] = value[2]; } else { edgeColor[0] = 0.2; edgeColor[1] = 0.2; edgeColor[2] = 0.2; } this.glRedraw(); } /** * Gets RGB edge color. * * Default value is ````[0.2, 0.2, 0.2]````. * * @type {Number[]} */ get edgeColor() { return this._state.edgeColor; } /** * Sets edge transparency. * * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. * * Default value is ````1.0````. * * @type {Number} */ set edgeAlpha(value) { value = (value !== undefined && value !== null) ? value : 1.0; if (this._state.edgeAlpha === value) { return; } this._state.edgeAlpha = value; this.glRedraw(); } /** * Gets edge transparency. * * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. * * Default value is ````1.0````. * * @type {Number} */ get edgeAlpha() { return this._state.edgeAlpha; } /** * Sets edge width. * * This is not supported by WebGL implementations based on DirectX [2019]. * * Default value is ````1.0```` pixels. * * @type {Number} */ set edgeWidth(value) { this._state.edgeWidth = value || 1.0; this.glRedraw(); } /** * Gets edge width. * * This is not supported by WebGL implementations based on DirectX [2019]. * * Default value is ````1.0```` pixels. * * @type {Number} */ get edgeWidth() { return this._state.edgeWidth; } /** * Selects a preset EdgeMaterial configuration. * * Default value is ````"default"````. * * @type {String} */ set preset(value) { value = value || "default"; if (this._preset === value) { return; } const preset = PRESETS[value]; if (!preset) { this.error("unsupported preset: '" + value + "' - supported values are " + Object.keys(PRESETS).join(", ")); return; } this.edgeColor = preset.edgeColor; this.edgeAlpha = preset.edgeAlpha; this.edgeWidth = preset.edgeWidth; this._preset = value; } /** * The current preset EdgeMaterial configuration. * * Default value is ````"default"````. * * @type {String} */ get preset() { return this._preset; } /** * Destroys this EdgeMaterial. */ destroy() { super.destroy(); this._state.destroy(); } } export {EdgeMaterial};