Changeset 21911 for issm/trunk-jpl/src/m/plot/webgl.js
- Timestamp:
- 08/03/17 15:17:23 (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk-jpl/src/m/plot/webgl.js
r21768 r21911 9 9 if (!isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); } 10 10 initWebGL(canvas, options); 11 initializeMarker(canvas);12 11 draw(canvas); 13 12 canvas.initialized = true; 13 14 //The onStart event triggers once per plotmodel call load after WebGL and canvas initialization are complete 15 canvas.selector.trigger('onStart', [canvas]); 14 16 } 15 17 return canvas; … … 34 36 mc.add(new Hammer.Pan({threshold: 0, pointers: 0})); 35 37 mc.add(new Hammer.Pinch({threshold: 0})).recognizeWith(mc.get('pan')); 36 mc.on('tap press', function (ev) {onTap(ev, canvas);});38 mc.on('tap', function (ev) {onTap(ev, canvas);}); 37 39 mc.on('panstart panmove', function (ev) {onPan(ev, canvas, displayview);}); 38 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);}); 40 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);}); 39 41 canvas.addEventListener('mousewheel', function (ev) {onZoom(ev, canvas, displayzoom)}, false); 40 42 canvas.addEventListener('DOMMouseScroll', function (ev) {onZoom(ev, canvas, displayzoom)}, false); … … 46 48 canvas.unitData = {}; 47 49 canvas.unitMovieData = {}; 50 48 51 canvas.gl = gl; 49 52 canvas.rootPath = options.getfieldvalue('rootpath', '../../../js/'); … … 57 60 58 61 //Add context state variables 62 canvas.render = options.getfieldvalue('render', {}); 59 63 canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1); 64 canvas.overlayHandlers = {}; 60 65 var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan')); 61 66 if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; } … … 63 68 64 69 //Property intiialization, using values from options first, then from default values. 70 var atmosphere = options.getfieldvalue('atmosphere', {}); 71 canvas.atmosphere = { //Default Values 72 wavelength_r: defaultFor(atmosphere.wavelength_r, 0.65), //0.65 Red wavelength (micrometers) 73 wavelength_g: defaultFor(atmosphere.wavelength_g, 0.57), //0.57 Green wavelength (micrometers) 74 wavelength_b: defaultFor(atmosphere.wavelength_b, 0.475), //0.475 Green wavelength (micrometers) 75 eSun: defaultFor(atmosphere.eSun, 100.0), //20.0 Sun intensity 76 kRayleigh: defaultFor(atmosphere.kRayleigh, 0.0025), //0.0025 Rayleigh scattering amount 77 kMie: defaultFor(atmosphere.kMie, 0.000), //0.01 Mie scattering amount 78 g: defaultFor(atmosphere.g, -0.99), //-0.99 Mie phase asymmetry/direction factor 79 hdr_exposure: defaultFor(atmosphere.hdr_exposure, 0.8), //0.8 High Dynamic Range Exposure 80 scaleHeight: defaultFor(atmosphere.scaleHeight, 1.25), //1.025 Scale of height of atmosphere to earth radius. 81 scaleDepth: defaultFor(atmosphere.scaleDepth, 0.25), //0.25 Percentage altitude at which the atmosphere's average density is found 82 a: defaultFor(atmosphere.a, -0.00287), //-0.00287 Scaling constant a 83 b: defaultFor(atmosphere.b, 0.459), //0.459 Scaling constant b 84 c: defaultFor(atmosphere.c, 3.83), //3.83 Scaling constant c 85 d: defaultFor(atmosphere.d, -6.80), //-6.80 Scaling constant d 86 e: defaultFor(atmosphere.e, 3.6), //5.25 Scaling constant e. Lower when increasing atmosphere scale. 87 attenuation: defaultFor(atmosphere.attenuation, 0.5) //0.5 Strength of atmospheric scattering on ground shading. 88 }; 89 updateAtmosphereParameters(canvas); 65 90 var animation = options.getfieldvalue('movies', {}); 66 91 canvas.animation = { 67 frame: defaultFor(animation.frame, 0),68 play: defaultFor(animation.play, true),69 increment: defaultFor(animation.increment, true),70 fps: defaultFor(animation.fps, 4),71 interval: defaultFor(animation.interval, 1000 / animation.fps),72 loop: defaultFor(animation.loop, true),73 handler: defaultFor(animation.handler, 0)92 frame: defaultFor(animation.frame, 0), 93 play: defaultFor(animation.play, true), 94 increment: defaultFor(animation.increment, true), 95 fps: defaultFor(animation.fps, 4), 96 interval: defaultFor(animation.interval, 1000 / defaultFor(animation.fps, 4)), 97 loop: defaultFor(animation.loop, true), 98 handler: defaultFor(animation.handler, 0) 74 99 } 75 100 var brush = options.getfieldvalue('brush', {}); 76 101 canvas.brush = { 77 enabled: defaultFor(brush.enabled, false),78 strength: defaultFor(brush.strength, 0.075),79 falloff: defaultFor(brush.falloff, 0.5),80 hit: defaultFor(brush.hit, {})102 enabled: defaultFor(brush.enabled, false), 103 strength: defaultFor(brush.strength, 0.075), 104 falloff: defaultFor(brush.falloff, 0.5), 105 hit: defaultFor(brush.hit, {}) 81 106 }; 82 107 var camera = options.getfieldvalue('camera', {}); 83 108 canvas.camera = { 84 position: defaultFor(camera.position, vec3.create()), 85 rotation: defaultFor(camera.rotation, vec3.create()), 86 near: defaultFor(camera.near, 1e3), 87 far: defaultFor(camera.far, 1e10), 88 fov: defaultFor(camera.fov, 45), 89 vMatrix: defaultFor(camera.vMatrix, mat4.create()), 90 pMatrix: defaultFor(camera.pMatrix, mat4.create()), 91 vpMatrix: defaultFor(camera.vpMatrix, mat4.create()), 92 vInverseMatrix: defaultFor(camera.vInverseMatrix, mat4.create()), 93 pInverseMatrix: defaultFor(camera.pInverseMatrix, mat4.create()), 94 vpInverseMatrix: defaultFor(camera.vpInverseMatrix, mat4.create()), 95 ready: defaultFor(camera.ready, false) 96 }; 97 var clouds = options.getfieldvalue('clouds', {}); 98 canvas.clouds = { 99 enabled: defaultFor(clouds.enabled, false), 100 height: defaultFor(clouds.height, 7500), 101 quantity: defaultFor(clouds.quantity, 10), 102 hit: defaultFor(clouds.hit, {}) 109 position: defaultFor(camera.position, vec3.create()), 110 rotation: defaultFor(camera.rotation, quat.create()), 111 relativePosition: defaultFor(camera.relativePosition, vec3.create()), 112 direction: defaultFor(camera.direction, vec3.create()), 113 near: defaultFor(camera.near, 1e3), 114 far: defaultFor(camera.far, 1e10), 115 fov: defaultFor(camera.fov, 45), 116 vMatrix: defaultFor(camera.vMatrix, mat4.create()), 117 pMatrix: defaultFor(camera.pMatrix, mat4.create()), 118 vpMatrix: defaultFor(camera.vpMatrix, mat4.create()), 119 vInverseMatrix: defaultFor(camera.vInverseMatrix, mat4.create()), 120 pInverseMatrix: defaultFor(camera.pInverseMatrix, mat4.create()), 121 vpInverseMatrix: defaultFor(camera.vpInverseMatrix, mat4.create()), 122 ready: defaultFor(camera.ready, false) 103 123 }; 104 124 var dataMarkers = options.getfieldvalue('datamarkers', {}); 105 125 canvas.dataMarkers = { 106 enabled: defaultFor(dataMarkers.enabled, true),107 values: defaultFor(dataMarkers.values, []),108 image: defaultFor(dataMarkers.image, canvas.rootPath+'textures/data_marker.svg'),109 size: defaultFor(dataMarkers.size, [32, 32]),110 format: defaultFor(dataMarkers.format, ['X: %.2e<br>Y: %.2e<br>Z: %.2e<br>Value: %0.1f', 'x', 'y', 'z', 'value']),111 animated: defaultFor(dataMarkers.animated, false),112 labels: defaultFor(dataMarkers.labels, []),113 font: defaultFor(dataMarkers.font, ''),114 marker: defaultFor(dataMarkers.marker, document.getElementById('sim-data-marker-' + canvas.id)),115 reposition: defaultFor(dataMarkers.reposition, true)126 enabled: defaultFor(dataMarkers.enabled, true), 127 values: defaultFor(dataMarkers.values, []), 128 image: defaultFor(dataMarkers.image, canvas.rootPath + 'textures/data_marker.svg'), 129 size: defaultFor(dataMarkers.size, [32, 32]), 130 format: defaultFor(dataMarkers.format, ['X: %.2e<br>Y: %.2e<br>Z: %.2e<br>Value: %0.1f', 'x', 'y', 'z', 'value']), 131 animated: defaultFor(dataMarkers.animated, false), 132 labels: defaultFor(dataMarkers.labels, []), 133 font: defaultFor(dataMarkers.font, ''), 134 marker: defaultFor(dataMarkers.marker, document.getElementById('sim-data-marker-' + canvas.id)), 135 reposition: defaultFor(dataMarkers.reposition, true) 116 136 }; 117 137 var draw = options.getfieldvalue('draw', {}); 118 138 canvas.draw = { 119 ready: defaultFor(draw.ready, false),120 handler: defaultFor(draw.handler, null)139 ready: defaultFor(draw.ready, false), 140 handler: defaultFor(draw.handler, null) 121 141 }; 122 142 var view = options.getfieldvalue('view', {}); 123 143 canvas.view = { 124 position: defaultFor(view.position, [0.0, 0.0, 0.0]), 125 rotation: defaultFor(view.rotation, [0, 90]), 126 zoom: defaultFor(view.zoom, 1.0), 127 zoomLimits: defaultFor(view.zoomLimits, [0.001, 100.0]), 128 lastZoom: defaultFor(view.lastZoom, 1.0), 129 azimuthLimits: defaultFor(view.azimuthLimits, [0, 360]), 130 elevationLimits: defaultFor(view.elevationLimits, [-180, 180]), 131 panningEnabled: defaultFor(view.panningEnabled, false), 132 twod: defaultFor(view.twod, false) 144 position: defaultFor(view.position, [0.0, 0.0, 0.0]), 145 rotation: defaultFor(view.rotation, [0, 90]), 146 zoom: defaultFor(view.zoom, 1.0), 147 zoomLimits: defaultFor(view.zoomLimits, [0.001, 100.0]), 148 lastZoom: defaultFor(view.lastZoom, 1.0), 149 azimuthLimits: defaultFor(view.azimuthLimits, [0, 360]), 150 elevationLimits: defaultFor(view.elevationLimits, [-180, 180]), 151 panningEnabled: defaultFor(view.panningEnabled, false), 152 preventDefaultOnPan: defaultFor(view.preventDefaultOnPan, false), 153 twod: defaultFor(view.twod, false) 133 154 }; 134 155 … … 171 192 var shaders = {}; 172 193 shaders.Colored = new GL.Shader.fromURL(rootPath+'shaders/Colored.vsh', rootPath+'shaders/Colored.fsh', null, gl); 194 shaders.ColoredDiffuse = new GL.Shader.fromURL(rootPath+'shaders/ColoredDiffuse.vsh', rootPath+'shaders/ColoredDiffuse.fsh', null, gl); 173 195 shaders.Textured = new GL.Shader.fromURL(rootPath+'shaders/Textured.vsh', rootPath+'shaders/Textured.fsh', null, gl); 196 shaders.TexturedDiffuse = new GL.Shader.fromURL(rootPath+'shaders/TexturedDiffuse.vsh', rootPath+'shaders/TexturedDiffuse.fsh', null, gl); 174 197 shaders.SkyFromSpace = new GL.Shader.fromURL(rootPath+'shaders/SkyFromSpace.vert', rootPath+'shaders/SkyFromSpace.frag', null, gl); 175 198 shaders.GroundFromSpace = new GL.Shader.fromURL(rootPath+'shaders/GroundFromSpace.vert', rootPath+'shaders/GroundFromSpace.frag', null, gl); 176 shaders.Clouds = new GL.Shader.fromURL(rootPath+'shaders/Clouds.vert', rootPath+'shaders/Clouds.frag', null, gl);177 199 return shaders; 178 200 } //}}} … … 184 206 return gl.textures[imageSource]; 185 207 } //}}} 208 function updateAtmosphereParameters(canvas) { 209 //Precalculate derived atmosphere shader parameters 210 //TODO: Find a better way to structure this 211 var atm = canvas.atmosphere; 212 atm.inv_wavelength4 = [1.0 / Math.pow(atm.wavelength_r, 4), 1.0 / Math.pow(atm.wavelength_g, 4), 1.0 / Math.pow(atm.wavelength_b, 4)]; 213 atm.innerRadius = 6.371e6; 214 atm.innerRadius2 = atm.innerRadius * atm.innerRadius; 215 atm.outerRadius = atm.innerRadius * atm.scaleHeight; 216 atm.outerRadius2 = atm.outerRadius * atm.outerRadius; 217 atm.krESun = atm.kRayleigh * atm.eSun; 218 atm.kmESun = atm.kMie * atm.eSun; 219 atm.kr4PI = atm.kRayleigh * 4 * Math.PI; 220 atm.km4PI = atm.kMie * 4 * Math.PI; 221 atm.scale = 1.0 / (atm.outerRadius - atm.innerRadius); 222 atm.scaleOverScaleDepth = atm.scale / atm.scaleDepth; 223 atm.g2 = atm.g * atm.g; 224 canvas.atmosphere = atm; 225 } 186 226 function clamp(value, min, max) { //{{{ 187 227 return Math.max(min, Math.min(value, max)); … … 253 293 } //}}} 254 294 //}}} 255 //{{{ Inter faceFunctions295 //{{{ Interaction Functions 256 296 function onTap(ev, canvas) { //{{{ 257 //Sets up a marker on a canvas that will track a point on the mesh. Can be dismissed by closing the display or clicking the marker.258 297 ev.preventDefault(); 259 298 260 if (canvas.clouds.enabled) { 261 for (var i = 0; i < canvas.clouds.quantity; i++) { 262 raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes["clouds" + i]); 263 } 264 } 265 var hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode); 266 if ('cities' in canvas.nodes) { 267 var hitCities = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes.cities); 268 canvas.nodes.cities.hit = hitCities; 269 updateCities(canvas); 270 } 271 272 canvas.brush.hit = hit; 273 274 if (canvas.dataMarkers.enabled) { 275 canvas.dataMarkers.marker.selector.closed = false; 276 canvas.dataMarkers.marker.hit = hit; 277 updateMarker(canvas, true); 278 } 279 280 brushModify(canvas); 299 var hit = raycastXY(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode); 300 301 //Trigger any handlers attatched to this canvas event. 302 canvas.selector.trigger('onTap', [ev, canvas, hit]); 281 303 } //}}} 282 304 function onPan(ev, canvas, displaylog) { //{{{ 283 305 ev.preventDefault(); 284 285 if (canvas.dataMarkers.enabled) {286 if (!isEmptyOrUndefined(canvas.unitNode)) {287 canvas.brush.hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.unitNode);288 brushModify(canvas);289 }290 }291 292 if (canvas.clouds.enabled) {293 if (!isEmptyOrUndefined(canvas.nodes['overlay'])) {294 canvas.clouds.hit = raycast(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, canvas.nodes['overlay']);295 updateClouds(canvas);296 }297 }298 306 299 307 if (ev.type === 'panstart') { … … 301 309 canvas.lastDeltaY = 0; 302 310 } 303 if (ev.srcEvent.shiftKey || ev.pointers.length === 2) { 304 if (!canvas.view.panningEnabled) return; 305 var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6; 306 var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6; 307 308 if (canvas.view.twod) { 309 canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY; 310 canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY; 311 312 //Trigger any handlers attatched to this canvas event. 313 canvas.selector.trigger('onPan', [ev, canvas]); 314 315 //If any onPan handler sets preventDefaultOnPan to true, skips default onPan camera behavior 316 if (!canvas.view.preventDefaultOnPan) { 317 //If panning with two fingers or shift key, translate camera center 318 if (ev.srcEvent.shiftKey || ev.pointers.length === 2) { 319 if (canvas.view.panningEnabled) { 320 var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6; 321 var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.view.zoom * 2 * canvas.controlSensitivity * 6.371e6; 322 323 //TODO: convert canvas.view.rotation from az/el euler to quaternion 324 if (canvas.view.twod) { 325 canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY; 326 canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY; 327 } 328 else { 329 canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaY; 330 canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaY; 331 } 332 } 311 333 } 334 //Else, rotate around camera center 312 335 else { 313 canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaY; 314 canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaY; 336 canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG; 337 canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG; 338 339 if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; }; 340 if (canvas.view.rotation[0] < -360) { canvas.view.rotation[0] += 360; }; 341 if (canvas.view.rotation[1] > 180) { canvas.view.rotation[1] -= 360; }; 342 if (canvas.view.rotation[1] < -180) { canvas.view.rotation[1] += 360; }; 343 344 canvas.view.rotation[0] = clamp(canvas.view.rotation[0], canvas.view.azimuthLimits[0], canvas.view.azimuthLimits[1]); 345 canvas.view.rotation[1] = clamp(canvas.view.rotation[1], canvas.view.elevationLimits[0], canvas.view.elevationLimits[1]); 346 347 if (displaylog) { console.log(canvas.view.rotation); } 315 348 } 316 } 317 318 else { 319 canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG; 320 canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG; 321 322 if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; }; 323 if (canvas.view.rotation[0] < -360) { canvas.view.rotation[0] += 360; }; 324 if (canvas.view.rotation[1] > 180) { canvas.view.rotation[1] -= 360; }; 325 if (canvas.view.rotation[1] < -180) { canvas.view.rotation[1] += 360; }; 326 327 canvas.view.rotation[0] = clamp(canvas.view.rotation[0], canvas.view.azimuthLimits[0], canvas.view.azimuthLimits[1]); 328 canvas.view.rotation[1] = clamp(canvas.view.rotation[1], canvas.view.elevationLimits[0], canvas.view.elevationLimits[1]) 329 } 349 } 350 351 canvas.view.preventDefaultOnPan = false; 330 352 canvas.lastDeltaX = ev.deltaX; 331 353 canvas.lastDeltaY = ev.deltaY; 332 333 canvas.dataMarkers.reposition = true;334 335 if (displaylog) { console.log(canvas.view.rotation); }336 354 } //}}} 337 355 function onPinch(ev, canvas, displaylog) { //{{{ 338 356 ev.preventDefault(); 339 357 if (ev.type === 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; } 340 else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog ); }358 else { modifyZoom(ev.scale * canvas.view.lastZoom, canvas, displaylog, ev, 0); } 341 359 } //}}} 342 360 function onZoom(ev, canvas, displaylog) { //{{{ 343 361 ev.preventDefault(); 344 var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 20; 345 modifyZoom(canvas.view.zoom + delta, canvas, displaylog); 346 } //}}} 347 function modifyZoom(value, canvas, displaylog) { //{{{ 348 canvas.view.zoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]); 349 canvas.dataMarkers.reposition = true; 350 if (displaylog) { console.log(canvas.view.zoom); } 351 } //}}} 352 function modifyDataMarkersEnabled(value, canvas) { //{{{ 353 canvas.dataMarkers.enabled = value; 362 var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 2; 363 modifyZoom(canvas.view.zoom + delta, canvas, displaylog, ev, 0); 364 } //}}} 365 function modifyZoom(value, canvas, displaylog, ev, duration) { //{{{ 366 if (isEmptyOrUndefined(duration)) duration = 200; 367 var targetZoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]); 368 var currentZoom = canvas.view.zoom; 369 animateValue( 370 0, 371 1.0, 372 duration, 373 function(value, info) { 374 canvas.view.zoom = currentZoom * (1 - value) + targetZoom * value; 375 if (displaylog) { console.log(canvas.view.zoom); } 376 377 //Trigger any handlers attatched to this canvas event. 378 canvas.selector.trigger('onZoom', [ev, canvas]); 379 } 380 ); 354 381 } //}}} 355 382 function toggleMoviePlay(canvas) { //{{{ … … 364 391 } 365 392 } //}}} 366 //}}} 367 //{{{ Interaction Functions 368 function raycast(canvas, x, y, node) { //{{{ 369 //Performs raycast on canvas.unitNode.mesh using x/y screen coordinates. Returns hit objects with hit position, coords, and indicies of ray-triangle intersection. 393 function screenToWorldPoint(canvas, x, y) { //{{{ 394 var viewportX = (x - canvas.width / 2) / (canvas.width / 2); 395 var viewportY = (canvas.height / 2 - y) / (canvas.height / 2); 396 var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], canvas.camera.vpInverseMatrix); 397 return origin; 398 } //}}} 399 function screenToModelRay(canvas, x, y, node) { //{{{ 400 var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix)); 401 var viewportX = (x - canvas.width / 2) / (canvas.width / 2); 402 var viewportY = (canvas.height / 2 - y) / (canvas.height / 2); 403 var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], inverseMVPMatrix); 404 var far = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 1.0], inverseMVPMatrix); 405 var direction = vec3.subtract(vec3.create(), far, origin); 406 return {'origin':origin, 'direction':direction}; 407 } //}}} 408 function raycast(canvas, origin, direction, node) { //{{{ 409 //Performs raycast on given node using ray origin and direction vectors. 410 //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection. 370 411 //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins. 371 var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix)); 372 var origin = vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 0], inverseMVPMatrix); 373 var far = far || vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 1.0], inverseMVPMatrix); 374 var ray = vec3.subtract(vec3.create(), far, origin); 375 376 var mesh = node.mesh; 377 378 if (!mesh) { return; } 379 if (!node.octree) { node.octree = new GL.Octree(mesh); } 380 381 var hit = node.octree.testRay(origin, ray, 1e3, 1e10); 382 383 if(!hit) { return; } 384 385 if (node.name.startsWith("clouds")) { canvas.clouds.selected = node.name; alert("New selected cloud: " + canvas.clouds.selected); } 412 if (!node.octree) { node.octree = new GL.Octree(node.mesh); } 413 414 var hit = node.octree.testRay(origin, direction, 1e3, 1e10); 415 if (!hit) { return; } 386 416 387 417 hit.modelPos = vec3.copy(vec3.create(), hit.pos); 388 418 vec3.transformMat4(hit.pos, hit.pos, node.modelMatrix); 389 vec3.transformMat4(hit.normal, hit.normal, node.modelMatrix); 390 419 391 420 return hit; 392 421 } //}}} 393 function updateCities(canvas) { 394 //Update selected city 395 var hit = canvas.nodes.cities.hit; 396 if (hit) { 397 citiesIndex = Math.floor(hit.indices[0] / ((ArrayMax(canvas.nodes.cities.mesh.getIndexBuffer('triangles').data) + 1) / cities.length)); 398 cityName = cities[citiesIndex]; 399 if (cityName !== $('#gfm-sim-controls-select-city').val()) { 400 $('#gfm-sim-controls-select-city').val(cityName).selectmenu("refresh"); 401 changeCity(canvas); 402 } 403 } 404 } 405 function brushModify(canvas) { //{{{ 406 //This function takes in the canvas and x/y coordinates, performing a raycast against the mesh, and modifies the mesh using a the canvas.brush.strength and canvas.brush.falloff properties. 407 //Currently the brush extends to the raycasted element and its immediate neighbors. 408 //TODO: Allow variable brush size/additional neighbors. Allow the function to work on multiple models (currently hardcoded to md model). 409 if (!canvas.unitNode || canvas.brush.enabled != 'on') { return; } 410 411 var hit = canvas.brush.hit; 412 413 if (hit) { 414 var bufferVertices = canvas.unitNode.mesh.getBuffer('vertices'); 415 var vertices = bufferVertices.data; 416 var bufferCoords = canvas.unitNode.mesh.getBuffer('coords'); 417 var coords = bufferCoords.data; 418 419 //Query nearby elements and store indicies of affected vertices using pregenerated vertexconnectivity list (from NodeConnectivity) 420 var baseIndices = new Set(hit.indices); 421 var connectedIndices = new Set(hit.indices); 422 var connectedElement; 423 var indices; 424 var lengthIndex = md.mesh.vertexconnectivity[0].length - 1; 425 var length; 426 for (var i = 0; i < 3; i++) { 427 length = md.mesh.vertexconnectivity[hit.indices[i]][lengthIndex]; 428 for (var j = 0; j < length; j++) { 429 //Shift elements down by one (matlab 1-based index to 0-based index) 430 connectedElement = md.mesh.vertexconnectivity[hit.indices[i]][j] - 1; 431 indices = md.mesh.elements[connectedElement]; 432 connectedIndices.add(indices[0] - 1); 433 connectedIndices.add(indices[1] - 1); 434 connectedIndices.add(indices[2] - 1); 435 } 436 } 437 438 //Apply modifications to included vertices in mesh using brush strength and falloff. 439 var strength; 440 for (var index of connectedIndices) { 441 if (!baseIndices.has(index)) { 442 strength = canvas.brush.strength * canvas.brush.falloff; 443 } 444 else { 445 strength = canvas.brush.strength; 446 } 447 vertices[index*3+2] += strength * 100; 448 md.geometry.surface[index] += strength; 449 md.geometry.thickness[index] += strength; 450 coords[index*2+1] += strength; 451 canvas.unitData[index] += strength; 452 } 453 454 //Update mesh on GPU 455 bufferVertices.upload(canvas.gl.DYNAMIC_DRAW); 456 bufferCoords.upload(canvas.gl.DYNAMIC_DRAW); 457 canvas.unitNode.octree = new GL.Octree(canvas.unitNode.mesh); 458 } 459 } //}}} 460 function updateClouds(canvas) { 461 //Update clouds if rendered 462 //TODO: Steven, the hit now queries the radaroverlay. 463 if (canvas.nodes[canvas.clouds.selected]) { 464 var v1 = vec3.fromValues(vertices[hit.indices[0] * 3], vertices[hit.indices[0] * 3 + 1], vertices[hit.indices[0] * 3 + 2]); 465 var v2 = vec3.fromValues(vertices[hit.indices[1] * 3], vertices[hit.indices[1] * 3 + 1], vertices[hit.indices[1] * 3 + 2]); 466 var v3 = vec3.fromValues(vertices[hit.indices[2] * 3], vertices[hit.indices[2] * 3 + 1], vertices[hit.indices[2] * 3 + 2]); 467 vec3.transformMat4(v1, v1, canvas.unitNode.modelMatrix);//move out of brushModify, perhaps onto onPan 468 vec3.transformMat4(v2, v2, canvas.unitNode.modelMatrix); 469 vec3.transformMat4(v3, v3, canvas.unitNode.modelMatrix); 470 var x = (v1[0] + v2[0] + v3[0]) / 3;// + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000))); 471 var y = (v1[1] + v2[1] + v3[1]) / 3;// + Math.floor((Math.random() * (1 + 10000 - (-10000)) + (-10000))); 472 var z = (v1[2] + v2[2] + v3[2]) / 3; 473 canvas.nodes[canvas.clouds.selected].translation = [x, y + canvas.clouds.height, z]; 474 updateModelMatrix(canvas.nodes[canvas.clouds.selected]); 475 } 476 } 477 function initializeMarker(canvas) { //{{{ 478 //Initialize data marker and tooltip display once per page load 479 var marker = $('#' + canvas.dataMarkers.marker.id); 480 var size = canvas.dataMarkers.size; 481 if (!marker.hasClass('tooltipstered')) { 482 marker.css({ 483 'position': 'absolute', 484 'left': -size[0] + 'px', 485 'top': -size[1] + '0px', 486 'width': size[0] + 'px', 487 'height': size[1] + 'px', 488 'pointer-events': 'all', 489 'cursor': 'pointer', 490 'display': 'none' 491 }); 492 marker.tooltipster({ 493 contentAsHTML: true, 494 maxWidth: 320, 495 maxHeight: 320, 496 zIndex: 1000, 497 trigger: 'custom', 498 triggerOpen: { 499 mouseenter: false, 500 originClick: true, 501 touchstart: false 502 }, 503 triggerClose: { 504 mouseleave: false, 505 originClick: true, 506 touchleave: false 507 }, 508 }); 509 marker.on('click touch', function () { 510 marker.fadeOut(175); 511 marker.tooltipster('close'); 512 marker.closed = true; 513 }); 514 marker.closed = false; 515 canvas.dataMarkers.marker.selector = marker; 516 } 517 updateMarker(canvas, true); 518 } //}}} 519 function repositionMarker(canvas) { //{{{ 520 //Mover marker to point to mouse position, offset in y by 1 to enable immediate clicking. 521 //Return if no marker hit exists, the camera is not rendering, or if no reposition has been scheduled. 522 if (isEmptyOrUndefined(canvas.dataMarkers.marker.hit) || !canvas.camera.ready || !canvas.dataMarkers.reposition) { return; } 523 var size = canvas.dataMarkers.size; 524 var screenPoint = vec3.transformMat4(vec3.create(), canvas.dataMarkers.marker.hit.pos, canvas.camera.vpMatrix); 525 var x = (screenPoint[0] + 1.0) * (canvas.width / 2) + canvas.selector.offset().left; 526 var y = (-screenPoint[1] + 1.0) * (canvas.height / 2) + canvas.selector.offset().top; 527 canvas.dataMarkers.marker.selector.css({ 528 'left': (Math.round(x) - size[0] / 2) + 'px', 529 'top': (Math.round(y) - size[1] + 1) + 'px' 530 }); 531 if (canvas.dataMarkers.marker.selector.tooltipster('status').state != 'closed') { canvas.dataMarkers.marker.selector.tooltipster('reposition'); } 532 canvas.dataMarkers.reposition = false; 533 } //}}} 534 function updateMarker(canvas, reset) { //{{{ 535 //Retrieve data value fields and plots them on data marker popup if a hit has been registered. 536 //TODO: Automatically pick up any field of size md.mesh.numberofelements 537 //If no marker has been placed, no update is needed. If canvas is resimulating and unitNode has not been set yet, wait and try again. 538 if (!canvas.dataMarkers.enabled || isEmptyOrUndefined(canvas.dataMarkers.marker.hit)) { return; } 539 if (isEmptyOrUndefined(canvas.unitNode) || isEmptyOrUndefined(canvas.unitNode.mesh)) { setTimeout( function(){ updateMarker(canvas, reset); }, 750); return; } 540 541 var hit = canvas.dataMarkers.marker.hit; 542 543 var coords = canvas.unitNode.mesh.vertexBuffers.coords.data; 544 var latitude = md.mesh.lat; 545 var longitude = md.mesh.long; 546 var thickness; 547 var velocity; 548 if (md.results[0]) { 549 thickness = md.results[canvas.animation.frame].Thickness; 550 velocity = md.results[canvas.animation.frame].Vel; 551 } 552 else { 553 thickness = md.geometry.thickness; 554 velocity = md.initialization.vel; 555 } 556 557 //Construct new argument array of the data display format for sprintf using first first argument as the formatSpecifier string and the rest as the additional arguments. 558 var labels = canvas.dataMarkers.labels.slice(); 559 for (var i = 0; i < labels.length; i++) { 560 if (labels[i].toLowerCase() === 'x') { labels[i] = hit.modelPos[0]; } 561 else if (labels[i].toLowerCase() === 'y') { labels[i] = hit.modelPos[1]; } 562 else if (labels[i].toLowerCase() === 'z') { labels[i] = hit.modelPos[2]; } 563 else if (labels[i].toLowerCase() === 'latitude') { 564 var hitLatitude = [latitude[hit.indices[0]], latitude[hit.indices[1]], latitude[hit.indices[2]]]; 565 var valueLatitude = Math.abs(hitLatitude[0] * hit.uvw[0] + hitLatitude[1] * hit.uvw[1] + hitLatitude[2] * hit.uvw[2]); 566 labels[i] = valueLatitude; 567 } 568 else if (labels[i].toLowerCase() === 'longitude') { 569 var hitLongitude = [longitude[hit.indices[0]], longitude[hit.indices[1]], longitude[hit.indices[2]]]; 570 var valueLongitude = Math.abs(hitLongitude[0] * hit.uvw[0] + hitLongitude[1] * hit.uvw[1] + hitLongitude[2] * hit.uvw[2]); 571 labels[i] = valueLongitude; 572 } 573 else if (labels[i].toLowerCase() === 'thickness') { 574 var hitThickness = [thickness[hit.indices[0]], thickness[hit.indices[1]], thickness[hit.indices[2]]]; 575 var valueThickness = hitThickness[0] * hit.uvw[0] + hitThickness[1] * hit.uvw[1] + hitThickness[2] * hit.uvw[2]; 576 labels[i] = valueThickness; 577 } 578 else if (labels[i].toLowerCase() === 'velocity') { 579 var hitVelocity = [velocity[hit.indices[0]], velocity[hit.indices[1]], velocity[hit.indices[2]]]; 580 var valueVelocity = hitVelocity[0] * hit.uvw[0] + hitVelocity[1] * hit.uvw[1] + hitVelocity[2] * hit.uvw[2]; 581 labels[i] = valueVelocity; 582 } 583 else if (labels[i].toLowerCase() === 'value') { 584 var hitCoords = [coords[hit.indices[0]*2], coords[hit.indices[0]*2+1], coords[hit.indices[1]*2], coords[hit.indices[1]*2+1], coords[hit.indices[2]*2], coords[hit.indices[2]*2+1]]; 585 var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2]; 586 var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2]; 587 var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v; 588 labels[i] = value; 589 } 590 } 591 592 //Apply changes to tooltip 593 $('#tooltip-content-data-marker-' + canvas.id).html(sprintf.apply(null, canvas.dataMarkers.format.concat(labels))); 594 $('#tooltip-content-data-marker-' + canvas.id).css({'font': canvas.dataMarkers.font}); 595 596 //If animated, setup animation loop to update plot as movie plays. 597 if (canvas.dataMarkers.animated) { 598 var isEmpty = (canvas.dataMarkers.values.length === 0); 599 var lastUpdatedIndex = (canvas.dataMarkers.values.length - 1); 600 var newMovieFrame = (!isEmpty && canvas.dataMarkers.values[lastUpdatedIndex][0] != canvas.animation.frame); 601 //If new data marker has been placed, reinitialize plot. If not, push new value into plot value array. 602 if (reset) { 603 canvas.dataMarkers.values = []; 604 newMovieFrame = true; 605 for (var currentFrame = 0; currentFrame < (canvas.unitNode.movieLength); currentFrame++) { 606 coords = canvas.unitMovieData[currentFrame]; 607 var hitCoords = [coords[hit.indices[0]*2], coords[hit.indices[0]*2+1], coords[hit.indices[1]*2], coords[hit.indices[1]*2+1], coords[hit.indices[2]*2], coords[hit.indices[2]*2+1]]; 608 var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2]; 609 var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2]; 610 var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v; 611 canvas.dataMarkers.values.push([currentFrame, value]); 612 } 613 } 614 else { 615 if (canvas.animation.lastFrame > canvas.animation.frame) { 616 canvas.dataMarkers.values = []; 617 } 618 if (isEmpty || newMovieFrame) { 619 coords = canvas.unitMovieData[canvas.animation.frame]; 620 var hitValues = [coords[hit.indices[0]], coords[hit.indices[1]], coords[hit.indices[2]]]; 621 var value = hitValues[0] * hit.uvw[0] + hitValues[1] * hit.uvw[1] + hitValues[2] * hit.uvw[2]; 622 canvas.dataMarkers.values.push([canvas.animation.frame, value]); 623 } 624 } 625 626 //Replot data marker popup using update data value array. 627 if (isEmpty || newMovieFrame) { 628 var dataLabels = {'latitude': valueLatitude, 'longitude': valueLongitude, 'thickness': valueThickness, 'velocity': valueVelocity, 'value': value}; 629 var dataDisplay = canvas.dataMarkers.values.slice(0, canvas.animation.frame + 1); 630 plot( 631 'id', '#sim-plot', 632 'type', 'bar', 633 'width', 400, 634 'height', 300, 635 'nticks', 25, 636 'xlabel', 'Time', 637 'ylabel', 'Value', 638 'title', 'Changes Over Time', 639 'datalabels', canvas.dataMarkers.labels, 640 'labelvalues', dataLabels, 641 'data', dataDisplay 642 ); 643 } 644 } 645 canvas.dataMarkers.reposition = true; 646 if (reset && !canvas.dataMarkers.marker.selector.closed) { 647 canvas.dataMarkers.marker.selector.fadeIn(175); 648 canvas.dataMarkers.marker.selector.tooltipster('open'); 649 } 422 function raycastXY(canvas, x, y, node) { //{{{ 423 //Performs raycast on given node using x and y screenspace coordinates. 424 //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection. 425 //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins. 426 var ray = screenToModelRay(canvas, x, y, node); 427 return raycast(canvas, ray.origin, ray.direction, node); 650 428 } //}}} 651 429 function animateValue(current, target, duration, stepCallback, doneCallback) { //{{{ … … 669 447 var elevationRotationMatrix = mat4.create(); 670 448 var aspectRatio = canvas.clientWidth / canvas.clientHeight; 671 var cameraPosition = vec3.create(); 672 673 if (canvas.view.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/canvas.view.zoom, aspectRatio*6.371e6/canvas.view.zoom, -6.371e6/canvas.view.zoom, 6.371e6/canvas.view.zoom, canvas.camera.near, canvas.camera.far); } 674 else { mat4.perspective(pMatrix, canvas.camera.fov * DEG2RAD, aspectRatio, canvas.camera.near, canvas.camera.far); } 449 var camera = canvas.camera; 450 var view = canvas.view; 451 452 if (view.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/view.zoom, aspectRatio*6.371e6/view.zoom, -6.371e6/view.zoom, 6.371e6/view.zoom, camera.near, camera.far); } 453 else { mat4.perspective(pMatrix, camera.fov * DEG2RAD, aspectRatio, camera.near, camera.far); } 675 454 676 455 //Apply worldspace translation 677 mat4.translate(vMatrix, translateMatrix, vec3.negate(vec3.create(), canvas.view.position));456 mat4.translate(vMatrix, translateMatrix, vec3.negate(vec3.create(), view.position)); 678 457 679 458 //Calculate rotation around camera focal point about worldspace origin 680 if ( canvas.view.twod) {459 if (view.twod) { 681 460 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * 0, [0, 1, 0]); 682 461 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * 90, [1, 0, 0]); … … 684 463 } 685 464 else { 686 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * ( canvas.view.rotation[0] + 90), [0, 1, 0]);687 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * canvas.view.rotation[1], [1, 0, 0]);465 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * (view.rotation[0] + 90), [0, 1, 0]); 466 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * view.rotation[1], [1, 0, 0]); 688 467 mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix); 468 //var quaternionWorldX = Node.prototype.eulerToQuaternion(0, 0, DEG2RAD * (view.rotation[0])); 469 //var quaternionWorldY = Node.prototype.eulerToQuaternion(0, DEG2RAD * (view.rotation[1]), 0); 470 //var quaternionWorldZ = Node.prototype.eulerToQuaternion(DEG2RAD * (view.rotation[2]), 0, 0); 471 //var quaternionTemp = quat.multiply(quat.create(), quaternionWorldY, quaternionWorldX); 472 //quat.multiply(camera.rotation, quaternionWorldZ, quaternionTemp); 473 //mat4.fromQuat(rotationMatrix, camera.rotation); 689 474 } 690 475 … … 694 479 //Apply screenspace translation to emulate rotation around point 695 480 mat4.identity(translateMatrix); 696 mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/ canvas.view.zoom]);481 mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/view.zoom]); 697 482 mat4.multiply(vMatrix, translateMatrix, vMatrix); 698 483 699 484 //Apply projection matrix to get camera matrix 700 mat4.copy(ca nvas.camera.vMatrix, vMatrix);701 mat4.multiply(ca nvas.camera.vpMatrix, pMatrix, vMatrix);485 mat4.copy(camera.vMatrix, vMatrix); 486 mat4.multiply(camera.vpMatrix, pMatrix, vMatrix); 702 487 703 488 //Calculate inverse view matrix fields for lighting and raycasts 704 mat4.invert(canvas.camera.vInverseMatrix, canvas.camera.vMatrix); 705 mat4.invert(canvas.camera.vpInverseMatrix, canvas.camera.vpMatrix); 706 707 vec3.transformMat4(canvas.camera.position, cameraPosition, canvas.camera.vpInverseMatrix); 708 canvas.camera.ready = true; 709 repositionMarker(canvas); 489 mat4.invert(camera.vInverseMatrix, camera.vMatrix); 490 mat4.invert(camera.vpInverseMatrix, camera.vpMatrix); 491 492 vec3.transformMat4(camera.position, vec3.create(), camera.vInverseMatrix); 493 vec3.sub(camera.relativePosition, camera.position, view.position); 494 vec3.normalize(camera.direction, camera.relativePosition); 495 496 camera.ready = true; 710 497 }//}}} 711 498 function drawSceneGraphNode(canvas, node) { //{{{ … … 718 505 mat4.multiply(mvpMatrix, canvas.camera.vpMatrix, node.modelMatrix); 719 506 720 var mvMatrix = mat4.create(); 721 mat4.multiply(mvMatrix, canvas.camera.vMatrix, node.modelMatrix); 722 723 var normalMatrix = mat4.create(); 724 mat4.invert(normalMatrix, node.modelMatrix); 725 mat4.transpose(normalMatrix, normalMatrix); 507 var normalMatrix = mat3.create(); 508 var tempMatrix = mat4.create(); 509 mat4.invert(tempMatrix, node.modelMatrix); 510 mat4.transpose(tempMatrix, tempMatrix); 511 mat3.fromMat4(normalMatrix, tempMatrix); 726 512 727 513 if (node.texture) { node.texture.bind(0); } … … 732 518 gl.lineWidth(node.lineWidth); 733 519 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 734 520 735 521 //Setup for light that originates from camera 736 var origin = vec3.fromValues(0, 0, 0); 737 var lightOrigin = vec3.fromValues(0, 0, 0); 738 var cameraPositionRelative = vec3.create(); 739 vec3.transformMat4(origin, origin, canvas.camera.vInverseMatrix); 740 vec3.normalize(lightOrigin, lightOrigin); 741 vec3.sub(cameraPositionRelative, origin, node.translation); 742 cameraHeight = vec3.length(cameraPositionRelative); 743 744 var atm = { //Default Values 745 wavelength_r: 0.65, //0.65 Red wavelength (micrometers) 746 wavelength_g: 0.57, //0.57 Green wavelength (micrometers) 747 wavelength_b: 0.475, //0.475 Green wavelength (micrometers) 748 eSun: 100.0, //20.0 Sun intensity 749 kRayleigh: 0.0025, //0.0025 Rayleigh scattering amount 750 kMie: 0.000, //0.01 Mie scattering amount 751 g: -0.99, //-0.99 Mie phase asymmetry/direction factor 752 hdr_exposure: 0.8, //0.8 High Dynamic Range Exposure 753 scale: 1.25, //1.025 Scale of atmosphere. WARNING: Change atmosphereScale in applyoptions.js, and scaling constants. 754 scaleDepth: 0.25, //0.25 Percentage altitude at which the atmosphere's average density is found 755 a: -0.00287, //-0.00287 Scaling constant a 756 b: 0.459, //0.459 Scaling constant b 757 c: 3.83, //3.83 Scaling constant c 758 d: -6.80, //-6.80 Scaling constant d 759 e: 3.6, //5.25 Scaling constant e. Lower when increasing atmosphere scale. 760 attenuation: 0.5 //0.5 Strength of atmospheric scattering on ground shading. 761 }; 762 763 var inv_wavelength4 = [1.0 / Math.pow(atm.wavelength_r, 4), 1.0 / Math.pow(atm.wavelength_g, 4), 1.0 / Math.pow(atm.wavelength_b, 4)]; 764 var innerRadius = 6.371e6; 765 var outerRadius = innerRadius*atm.scale; 766 var scale = 1.0 / (outerRadius - innerRadius); 767 var scaleDepth = atm.scaleDepth; 522 var atm = canvas.atmosphere; 523 var lightOrigin = vec3.create(); 768 524 769 525 node.shader.uniforms({ 770 m4MVP: mvpMatrix, 771 m4Normal: normalMatrix, 772 m4Model: node.modelMatrix, 773 u_lightPosition: lightOrigin, 774 //u_lightPosition: [1.0, 1.0, 1.0], 775 u_diffuseColor: node.diffuseColor, 776 u_texture: 0, 777 u_alpha: node.alpha, 778 u_maskZerosColor: node.maskZerosColor, 779 u_maskZerosEnabled: node.maskZerosEnabled, 780 u_maskZerosTolerance: node.maskZerosTolerance, 781 u_maskZerosZeroValue: node.maskZerosZeroValue, 782 u_maskEnabled: node.maskEnabled, 783 u_maskHeight: node.maskHeight, 784 u_maskColor: node.maskColor, 785 u_pointSize: node.pointSize, 786 v3CameraPosition: origin, 787 v3Translate: node.translation, 788 v3LightPos: lightOrigin, 789 v3InvWavelength: inv_wavelength4, 790 fOuterRadius: outerRadius, 791 fOuterRadius2: outerRadius * outerRadius, 792 fInnerRadius: innerRadius, 793 fInnerRadius2: innerRadius * innerRadius, 794 fKrESun: atm.kRayleigh * atm.eSun, 795 fKmESun: atm.kMie * atm.eSun, 796 fKr4PI: atm.kRayleigh * 4 * Math.PI, 797 fKm4PI: atm.kMie * 4 * Math.PI, 798 fScale: scale, 799 fScaleDepth: scaleDepth, 800 fScaleOverScaleDepth: scale/scaleDepth, 801 v3LightPosFrag: lightOrigin, 802 fHdrExposure: atm.hdr_exposure, 803 g: atm.g, 804 g2: atm.g * atm.g, 805 a: atm.a, 806 b: atm.b, 807 c: atm.c, 808 d: atm.d, 809 e: atm.e, 810 attenuation: atm.attenuation 526 m4MVP: mvpMatrix, 527 m3Normal: normalMatrix, 528 m4Model: node.modelMatrix, 529 u_alpha: node.alpha, 530 u_ambientColor: node.ambientColor, 531 u_cameraPosition: canvas.camera.position, 532 u_diffuseColor: node.diffuseColor, 533 u_lightDirection: canvas.camera.direction, 534 u_lightingBias: node.lightingBias, 535 u_maskZerosColor: node.maskZerosColor, 536 u_maskZerosEnabled: node.maskZerosEnabled, 537 u_maskZerosTolerance: node.maskZerosTolerance, 538 u_maskZerosZeroValue: node.maskZerosZeroValue, 539 u_maskEnabled: node.maskEnabled, 540 u_maskHeight: node.maskHeight, 541 u_maskColor: node.maskColor, 542 u_pointSize: node.pointSize, 543 u_specularColor: node.specularColor, 544 u_specularPower: node.specularPower, 545 u_specularStrength: node.specularStrength, 546 u_texture: 0, 547 v3CameraPosition: canvas.camera.position, 548 v3Translate: node.translation, 549 v3LightPos: lightOrigin, 550 v3InvWavelength: atm.inv_wavelength4, 551 fOuterRadius: atm.outerRadius, 552 fOuterRadius2: atm.outerRadius2, 553 fInnerRadius: atm.innerRadius, 554 fInnerRadius2: atm.innerRadius2, 555 fKrESun: atm.krESun, 556 fKmESun: atm.kmESun, 557 fKr4PI: atm.kr4PI, 558 fKm4PI: atm.km4PI, 559 fScale: atm.scale, 560 fScaleDepth: atm.scaleDepth, 561 fScaleOverScaleDepth: atm.scaleOverScaleDepth, 562 v3LightPosFrag: lightOrigin, 563 fHdrExposure: atm.hdr_exposure, 564 g: atm.g, 565 g2: atm.g2, 566 a: atm.a, 567 b: atm.b, 568 c: atm.c, 569 d: atm.d, 570 e: atm.e, 571 attenuation: atm.attenuation 811 572 }).draw(node.mesh, node.drawMode, 'triangles'); 812 573 … … 814 575 gl.disable(gl.CULL_FACE); 815 576 } //}}} 577 function canvasResize(canvas) { 578 var rect = canvas.getBoundingClientRect(); 579 canvas.width = rect.width; 580 canvas.height = rect.height; 581 canvas.gl.viewport(0, 0, canvas.width, canvas.height); 582 583 if (!isEmptyOrUndefined(canvas.overlaycanvas)) { 584 rect = canvas.overlaycanvas.getBoundingClientRect(); 585 canvas.overlaycanvas.width = rect.width; 586 canvas.overlaycanvas.height = rect.height; 587 } 588 } 816 589 function draw(canvas) { //{{{ 817 590 //Ensure all nodes are ready to render … … 833 606 //Begin rendering nodes 834 607 if (canvas.draw.ready) { 835 var rect = canvas.getBoundingClientRect(); 836 canvas.width = rect.width; 837 canvas.height = rect.height; 608 //Handle canvas resizing and viewport/screenspace coordinate synchronization 609 canvasResize(canvas); 838 610 839 611 var gl = canvas.gl; 840 612 gl.makeCurrent(); //litegl function to handle switching between multiple canvases 841 gl.viewport(0, 0, canvas.width, canvas.height);842 613 gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]); 843 614 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); … … 845 616 updateCameraMatrix(canvas); 846 617 847 if (canvas.textcanvas) { canvas.textcanvas.draw(canvas); } 848 if (canvas.overlaycanvas) { canvas.overlaycanvas.draw(canvas); } 618 //Trigger any handlers attatched to this canvas event. 619 canvas.selector.trigger('onPreRender', [canvas]); 620 621 for (var handler in canvas.overlayHandlers) { canvas.overlayHandlers[handler](canvas); } 849 622 850 623 var drawPassNumber = 3;
Note:
See TracChangeset
for help on using the changeset viewer.