UNPKG

@giro3d/giro3d

Version:

A JS/WebGL framework for 3D geospatial data visualization

105 lines (102 loc) 4.19 kB
/* * Copyright (c) 2015-2018, IGN France. * Copyright (c) 2018-2026, Giro3D team. * SPDX-License-Identifier: MIT */ import { AdditiveBlending, BackSide, Color, FrontSide, Mesh, ShaderMaterial, Sphere, SphereGeometry, Uniform, Vector2, Vector3 } from 'three'; import Ellipsoid from '../core/geographic/Ellipsoid'; /* babel-plugin-inline-import '../renderer/shader/GlowFS.glsl' */ const GlowFS = "#include <logdepthbuf_pars_fragment>\n\nvarying float intensity;\nuniform vec3 glowColor;\nuniform float opacity;\n\nvoid main()\n{\n #include <logdepthbuf_fragment>\n vec4 glow = vec4(glowColor.rgb, opacity);\n gl_FragColor = glow * intensity;\n}\n"; /* babel-plugin-inline-import '../renderer/shader/GlowVS.glsl' */ const GlowVS = "#include <logdepthbuf_pars_vertex>\n#define EPSILON 1e-6\n\nuniform bool atmoIN;\nvarying float intensity;\n\nvoid main()\n{\n vec3 normalES = normalize( normalMatrix * normal );\n vec3 normalCAMES = normalize( normalMatrix * cameraPosition );\n\n float angle = dot(normalES, normalCAMES);\n\n if(atmoIN) {\n intensity = pow(1.0 - angle, 0.8);\n } else {\n intensity = pow(0.666 - angle, 4.0);\n }\n\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n #include <logdepthbuf_vertex>\n}\n"; import Entity3D from './Entity3D'; const tmpVec2 = new Vector2(); const sphere = new SphereGeometry(1, 64, 64); class GlowMaterial extends ShaderMaterial { constructor(options) { super({ vertexShader: GlowVS, fragmentShader: GlowFS, blending: AdditiveBlending, transparent: true, side: options.side, depthWrite: options.depthWrite }); const color = options.glowColor != null ? new Color(options.glowColor) : new Color(0.45, 0.74, 1.0); this.uniforms = { atmoIN: new Uniform(options.atmoIn), screenSize: new Uniform(new Vector2(1, 1)), glowColor: new Uniform(color), opacity: new Uniform(1) }; } get color() { return this.uniforms.glowColor.value; } set color(v) { this.uniforms.glowColor.value.copy(v); } set screenSize(v) { this.uniforms.screenSize.value.copy(v); } } /** * Constructor options for the {@link Glow} entity. */ /** * Displays a simple glow around an ellipsoid. */ class Glow extends Entity3D { isGlow = true; type = 'Glow'; get color() { return this._outerGlow.material.color; } set color(v) { const color = new Color(v); this._innerGlow.material.color = color; this._outerGlow.material.color = color; this.notifyChange(); } constructor(options) { super(options); this._ellipsoid = options?.ellipsoid ?? Ellipsoid.WGS84; this._sphere = new Sphere(new Vector3(0, 0, 0), this._ellipsoid.semiMajorAxis); this._innerGlow = this.createGlow(1.14, BackSide, false, true, options?.color); this._innerGlow.name = 'inner glow'; this._outerGlow = this.createGlow(1.002, FrontSide, true, false, options?.color); this._outerGlow.name = 'outer glow'; } createGlow(scale, side, atmoIn, depthWrite, glowColor) { const result = new Mesh(sphere, new GlowMaterial({ side, atmoIn, depthWrite, glowColor })); result.scale.set(scale * this._ellipsoid.semiMajorAxis, scale * this._ellipsoid.semiMajorAxis, scale * this._ellipsoid.semiMinorAxis); this.object3d.add(result); result.updateMatrixWorld(true); return result; } updateOpacity() { this._outerGlow.material.uniforms.opacity.value = this.opacity; this._innerGlow.material.uniforms.opacity.value = this.opacity; } updateMinMaxDistance(context) { const distance = context.distance.plane.distanceToPoint(this.object3d.position); const radius = this._sphere.radius * 2; this._distance.min = Math.min(this._distance.min, distance - radius); this._distance.max = Math.max(this._distance.max, distance + radius); } postUpdate(context) { this.instance.engine.getWindowSize(tmpVec2); this._outerGlow.material.screenSize = tmpVec2; this._innerGlow.material.screenSize = tmpVec2; this.updateMinMaxDistance(context); } pick() { return []; } } export default Glow;