diff --git a/src/layers/globe.js b/src/layers/globe.js index 4b476e5..3406b49 100755 --- a/src/layers/globe.js +++ b/src/layers/globe.js @@ -23,7 +23,7 @@ const THREE = window.THREE }; import GeoJsonGeometry from 'three-geojson-geometry'; -import { createGlowMesh } from '../utils/three-glow-mesh'; +import GlowMesh from '../utils/GlowMesh.js'; import Kapsule from 'kapsule'; import { geoGraticule10 } from 'd3-geo'; @@ -132,12 +132,12 @@ export default Kapsule({ } if (state.atmosphereColor && state.atmosphereAltitude) { - const obj = state.atmosphereObj = createGlowMesh(state.globeObj.geometry, { - backside: true, + const obj = state.atmosphereObj = new GlowMesh(state.globeObj.geometry, { color: state.atmosphereColor, size: GLOBE_RADIUS * state.atmosphereAltitude, + hollowRadius: GLOBE_RADIUS, + coefficient: 0.1, power: 3.5, // dispersion - coefficient: 0.1 }); obj.visible = !!state.showAtmosphere; obj.__globeObjType = 'atmosphere'; // Add object type diff --git a/src/utils/three-glow-mesh.js b/src/utils/GlowMesh.js similarity index 56% rename from src/utils/three-glow-mesh.js rename to src/utils/GlowMesh.js index 68f21fc..e8f22af 100644 --- a/src/utils/three-glow-mesh.js +++ b/src/utils/GlowMesh.js @@ -16,13 +16,43 @@ const THREE = window.THREE ShaderMaterial }; +const vertexShader = ` +uniform float hollowRadius; + +varying vec3 vVertexWorldPosition; +varying vec3 vVertexNormal; +varying float vCameraDistanceToObjCenter; +varying float vVertexAngularDistanceToHollowRadius; + +void main() { + vVertexNormal = normalize(normalMatrix * normal); + vVertexWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz; + + vec4 objCenterViewPosition = modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0); + vCameraDistanceToObjCenter = length(objCenterViewPosition); + + float edgeAngle = atan(hollowRadius / vCameraDistanceToObjCenter); + float vertexAngle = acos(dot(normalize(modelViewMatrix * vec4(position, 1.0)), normalize(objCenterViewPosition))); + vVertexAngularDistanceToHollowRadius = vertexAngle - edgeAngle; + + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +}`; + const fragmentShader = ` uniform vec3 color; uniform float coefficient; uniform float power; +uniform float hollowRadius; + varying vec3 vVertexNormal; varying vec3 vVertexWorldPosition; +varying float vCameraDistanceToObjCenter; +varying float vVertexAngularDistanceToHollowRadius; + void main() { + if (vCameraDistanceToObjCenter < hollowRadius) discard; // inside the hollowRadius + if (vVertexAngularDistanceToHollowRadius < 0.0) discard; // frag position is within the hollow radius + vec3 worldCameraToVertex = vVertexWorldPosition - cameraPosition; vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz; viewCameraToVertex = normalize(viewCameraToVertex); @@ -33,30 +63,13 @@ void main() { gl_FragColor = vec4(color, intensity); }`; -const vertexShader = ` -varying vec3 vVertexWorldPosition; -varying vec3 vVertexNormal; -void main() { - vVertexNormal = normalize(normalMatrix * normal); - vVertexWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz; - gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); -} -`; - -export const defaultOptions = { - backside: true, - coefficient: 0.5, - color: 'gold', - size: 2, - power: 1, -}; - // Based off: http://stemkoski.blogspot.fr/2013/07/shaders-in-threejs-glow-and-halo.html -export function createGlowMaterial(coefficient, color, power) { +function createGlowMaterial(coefficient, color, power, hollowRadius) { return new THREE.ShaderMaterial({ depthWrite: false, - fragmentShader, transparent: true, + vertexShader, + fragmentShader, uniforms: { coefficient: { value: coefficient, @@ -67,13 +80,14 @@ export function createGlowMaterial(coefficient, color, power) { power: { value: power, }, + hollowRadius: { + value: hollowRadius, + } }, - vertexShader, }); } -export function createGlowGeometry(geometry, size) { - // expect BufferGeometry +function createGlowGeometry(geometry, size) { const glowGeometry = geometry.clone(); // Resize vertex positions according to normals @@ -88,15 +102,22 @@ export function createGlowGeometry(geometry, size) { return glowGeometry; } -export function createGlowMesh(geometry, options = defaultOptions) { - const { backside, coefficient, color, size, power } = options; +export default class GlowMesh extends THREE.Mesh { + constructor(geometry, { + color= 'gold', + size= 2, + coefficient= 0.5, + power= 1, + hollowRadius= 0, + backside = true + } = {}) { + super(); - const glowGeometry = createGlowGeometry(geometry, size); - const glowMaterial = createGlowMaterial(coefficient, color, power); + const glowGeometry = createGlowGeometry(geometry, size); + const glowMaterial = createGlowMaterial(coefficient, color, power, hollowRadius); + backside && (glowMaterial.side = THREE.BackSide); - if (backside) { - glowMaterial.side = THREE.BackSide; + this.geometry = glowGeometry; + this.material = glowMaterial; } - - return new THREE.Mesh(glowGeometry, glowMaterial); } \ No newline at end of file