Changeset 21341 for issm/trunk/src/m/plot/webgl.js
- Timestamp:
- 11/04/16 13:48:43 (8 years ago)
- Location:
- issm/trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
issm/trunk
-
issm/trunk/src
- Property svn:mergeinfo changed
-
issm/trunk/src/m/plot/webgl.js
r20500 r21341 1 1 /*This is where we have all our webgl relevant functionality for the plotting routines: */ 2 //{{{ GL Initialization 2 3 //{{{ Canvas Initialization 4 function initCanvas(options) { 5 //Initialize open Gl for each canvas, if needed: 6 canvas = document.getElementById(options.getfieldvalue('canvasid')); 7 //var canvas = document.getElementById(options.getfieldvalue('canvasid')); 8 if (!canvas.initialized) { 9 typedArraySliceSupport(); 10 canvas.gl = initWebGL(canvas,options); 11 canvas.nodes = []; 12 if (canvas.drawHandler) { window.cancelAnimationFrame(canvas.drawHandler); } 13 draw(canvas,options); 14 canvas.initialized = true; 15 } 16 return canvas; 17 } 3 18 function initWebGL(canvas,options) { //{{{ 4 gl = null; 5 19 var gl; 6 20 try { 7 // Try to grab the standard context. If it fails, fallback to experimental. 8 gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); 9 } 10 catch(e) {} 11 12 // If we don't have a GL context, give up now 13 if (!gl) { 14 alert("Unable to initialize WebGL. Your browser may not support it."); 15 gl = null; 16 } 17 18 // Enable depth testing 19 gl.enable(gl.DEPTH_TEST); 20 // Near things obscure far things 21 gl.depthFunc(gl.LEQUAL); 22 // Clear the color as well as the depth buffer. 23 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 24 // Enable color blending/overlay 25 gl.enable(gl.BLEND); 26 27 // Allocate arrays equal to maximium number of attributes used by any one shader 28 gl.enableVertexAttribArray(0); 29 gl.enableVertexAttribArray(1); 30 31 // Load shaders and store them in gl object 32 gl.shaders = loadShaders(gl); 21 if (!canvas.gl) { 22 gl = GL.create({canvas:canvas}); 23 // Enable depth testing 24 gl.enable(gl.DEPTH_TEST); 25 // Near things obscure far things 26 gl.depthFunc(gl.LEQUAL); 27 // Enable color blending/overlay 28 gl.enable(gl.BLEND); 29 // Enable face culling 30 gl.enable(gl.CULL_FACE); 31 gl.cullFace(gl.FRONT); 32 // Load shaders and store them in gl object 33 gl.shaders = loadShaders(gl,options.getfieldvalue('rootpath','../../../js/')); 34 35 // Add event listeners for canvas 36 var displayview = options.getfieldvalue('displayview','off') == 'on'; 37 var displayzoom = options.getfieldvalue('displayzoom','off') == 'on'; 38 var mc = new Hammer.Manager(canvas); 39 40 mc.add( new Hammer.Tap({ event: 'singletap' }) ); 41 mc.add(new Hammer.Pan({threshold:0, pointers:0})); 42 mc.add(new Hammer.Pinch({threshold:0})).recognizeWith(mc.get('pan')); 43 mc.on('singletap', function (ev) {onTap(ev,canvas);}); 44 mc.on('panstart panmove', function (ev) {onPan(ev,canvas,displayview);}); 45 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev,canvas,displayview);}); 46 47 //canvas.addEventListener('mousemove', function (ev) {onTap(ev,canvas);}, false); 48 canvas.addEventListener('mousewheel', function (ev) {onZoom(ev,canvas,displayzoom)}, false); 49 canvas.addEventListener('DOMMouseScroll', function (ev) {onZoom(ev,canvas,displayzoom)}, false); 50 } 51 else { 52 gl = canvas.gl; 53 } 54 } 55 catch(e) { 56 console.log(e); 57 return; 58 } 33 59 34 60 // Add context state variables 35 61 //TODO:Group variables in objects for organization and naming 36 canvas. zoomBounds = options.getfieldvalue('zoombounds',[0.001,100.0]);37 canvas. zoomFactor = clamp(options.getfieldvalue('zoomfactor',1.0), canvas.zoomBounds[0], canvas.zoomBounds[1]);38 canvas. zoomLast = canvas.zoomFactor;62 canvas.gl = gl; 63 canvas.rootPath = options.getfieldvalue('rootpath','../../../js/'); 64 canvas.cameraPosition = vec3.create(); 39 65 canvas.cameraMatrix = mat4.create(); 40 canvas.translation = options.getfieldvalue('centeroffset',[0,0,0.0]); 41 canvas.rotationAzimuthBounds = options.getfieldvalue('azimuthbounds',[0,360]); 42 canvas.rotationElevationBounds = options.getfieldvalue('elevationbounds',[-180,180]); 43 canvas.rotationDefault = options.getfieldvalue('view',[0,90]); //0 azimuth - up is north, 90 elevation - looking straight down 44 canvas.rotation = canvas.rotationDefault; 45 canvas.controlsensitivity = 1; 46 canvas.twod = options.getfieldvalue('2d','off') == 'on'; 66 canvas.controlSensitivity = options.getfieldvalue('controlsensitivity',1); 67 canvas.dataMarkersAllowed = options.getfieldvalue('datamarkers','off') == 'on'; 68 canvas.dataMarkersEnabled = true; //if data marker feature is on, user can toggle feature on and off 69 canvas.dataMarkerImage = options.getfieldvalue('datamarkers_image',canvas.rootPath+'textures/data_marker.svg'); 70 canvas.dataMarkerSize = options.getfieldvalue('datamarkerssize',[32,32]); 71 canvas.dataMarkerOptions = options.getfieldvalue('datamarkersoptions',{'enabled':'on','image':canvas.rootPath+'textures/data_marker.svg','size':[32,32],'format':['X: %.2e<br>Y: %.2e<br>Z: %.2e]<br>Value: %0.1f','x','y','z','value']}); 72 canvas.inverseCameraMatrix = mat4.create(); 73 canvas.id = options.getfieldvalue('canvasid','.sim-canvas'); 74 canvas.movieFrame = 0; 47 75 canvas.moviePlay = true; 48 76 canvas.movieReverse = false; 49 77 canvas.movieIncrement = true; 50 51 if (canvas.twod) { 52 canvas.rotationAzimuthBounds = [0,0]; 53 canvas.rotationElevationBounds = [90,90]; 54 canvas.rotationDefault = [0,90]; 55 canvas.rotation = canvas.rotationDefault; 56 } 57 58 // Add event listeners for canvas 59 canvas.addEventListener("mousewheel", function (ev) {onZoom(ev,canvas,options.getfieldvalue('displayzoom','off') == 'on')}, false); 60 canvas.addEventListener("DOMMouseScroll", function (ev) {onZoom(ev,canvas,options.getfieldvalue('displayzoom','off') == 'on')}, false); 61 62 var mc = new Hammer.Manager(canvas); 63 64 mc.add(new Hammer.Pan({threshold:0, pointers:0})); 65 mc.add(new Hammer.Pinch({threshold:0})).recognizeWith(mc.get('pan')); 66 67 mc.on("panstart panmove", function (ev) {onPan(ev,canvas,options.getfieldvalue('displayview','off') == 'on');}); 68 mc.on("pinchstart pinchmove", function (ev) {onPinch(ev,canvas,options.getfieldvalue('displayview','off') == 'on');}); 69 //mc.on("mousewheel DOMMouseScroll", function (ev) {onZoom(ev,canvas,options);}); 78 canvas.movieOptions = options.getfieldvalue('movieoptions',{'fps':4,'loop':true}); 79 canvas.moviefps = options.getfieldvalue('moviefps',5); 80 canvas.rotation = options.getfieldvalue('view',[0,90]); //0 azimuth, 90 elevation 81 canvas.rotationAzimuthBounds = options.getfieldvalue('azlim',[0,360]); 82 canvas.rotationElevationBounds = options.getfieldvalue('ellim',[-180,180]); 83 canvas.translation = options.getfieldvalue('origin',[0,0,0]); 84 canvas.twod = options.getfieldvalue('2d','off') == 'on'; 85 canvas.view = options.getfieldvalue('view',[0,90]); 86 canvas.viewPanning = options.getfieldvalue('enablepanning','off') == 'on'; 87 canvas.vInverseMatrix = mat4.create(); 88 canvas.zoomBounds = options.getfieldvalue('zoomlim',[0.001,100.0]); 89 canvas.zoom = clamp(options.getfieldvalue('zoom',1.0), canvas.zoomBounds[0], canvas.zoomBounds[1]); 90 canvas.zoomLast = canvas.zoom; 91 var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor','lightcyan')); 92 if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; } 93 else { throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for curent canvas ',canvas)); } 70 94 71 95 return gl; 72 96 } //}}} 73 function initBuffers(gl,arrays) { //{{{ 74 var bufferArray = []; 75 for (var i = 0; i < arrays.length; i++) { 76 bufferArray[i] = gl.createBuffer(); 77 bufferArray[i].itemSize = arrays[i].itemSize; 78 bufferArray[i].numItems = arrays[i].length/bufferArray[i].itemSize; 79 80 if (bufferArray[i].itemSize > 1) { 81 gl.bindBuffer(gl.ARRAY_BUFFER, bufferArray[i]); 82 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(arrays[i]), gl.STATIC_DRAW); 83 } 84 else { 85 //TODO: identify index buffers uniquely (by name) 86 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferArray[i]); 87 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(arrays[i]), gl.STATIC_DRAW); 88 } 89 } 90 return bufferArray; 97 function loadShaders(gl,rootPath) { //{{{ 98 var shaders = {}; 99 shaders.Colored = new GL.Shader.fromURL(rootPath+'shaders/Colored.vsh', rootPath+'shaders/Colored.fsh', null, gl); 100 shaders.Textured = new GL.Shader.fromURL(rootPath+'shaders/Textured.vsh', rootPath+'shaders/Textured.fsh', null, gl); 101 shaders.SkyFromSpace = new GL.Shader.fromURL(rootPath+'shaders/SkyFromSpace.vert', rootPath+'shaders/SkyFromSpace.frag', null, gl); 102 shaders.GroundFromSpace = new GL.Shader.fromURL(rootPath+'shaders/GroundFromSpace.vert', rootPath+'shaders/GroundFromSpace.frag', null, gl); 103 return shaders; 91 104 } //}}} 92 105 function initTexture(gl,imageSource) { //{{{ 93 var texture = gl.createTexture(); 94 texture.image = new Image(); 95 texture.isLoaded = false; 96 texture.image.onload = function () { 97 handleLoadedTexture(gl,texture); 98 } 99 texture.image.src = imageSource; 100 return texture; 101 } //}}} 102 function handleLoadedTexture(gl,texture) { //{{{ 103 gl.activeTexture(gl.TEXTURE0); 104 gl.bindTexture(gl.TEXTURE_2D, texture); 105 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); 106 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image); 107 gl.generateMipmap(gl.TEXTURE_2D); 108 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); 109 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 110 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 111 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 112 gl.bindTexture(gl.TEXTURE_2D, null); 113 texture.isLoaded = true; 114 } //}}} 115 function Node(gl,options) { //{{{ 116 //Returns a Node object that contains default display states for webgl object 117 return {buffers:[], 118 shader:gl.shaders["colored"]["program"], 119 draw:null, 106 return GL.Texture.fromURL(imageSource, {minFilter:gl.LINEAR_MIPMAP_LINEAR, magFilter:gl.LINEAR}, null, gl); 107 } //}}} 108 function Node(gl) { //{{{ 109 //Returns a Node object that contains default display states for webgl object. center represents pivot point of rotation. 110 return { 111 alpha:1.0, 112 buffers:[], 113 cullFace:gl.FRONT, 114 disableDepthTest:false, 115 drawMode:gl.TRIANGLES, 116 drawOrder:0, 117 enabled:true, 118 enableCullFace:false, 120 119 hideOcean:false, 121 level:0, 122 useIndexBuffer:true, 123 alpha:1.0, 124 disableDepthTest:false, 125 enableCullFace:false, 126 cullFace:gl.FRONT, 127 drawMode:gl.TRIANGLES, 128 texture:null, 129 translation:vec3.create(), 130 rotation:vec3.fromValues(-90, 0, 0), 131 scale:vec3.fromValues(1, 1, 1), 132 modelMatrix:mat4.create(), 133 shaderName:"colored", 134 drawOrder:0, 120 lineWidth:1.0, 135 121 maskEnabled:false, 136 122 maskHeight:150.0, 137 123 maskColor:vec4.fromValues(0.0, 0.0, 1.0, 1.0), 138 enabled:true, 124 mesh:null, 125 name:'node', 126 shaderName:'Colored', 127 shader:gl.shaders.Colored, 128 texture:null, 129 useIndexBuffer:true, 130 center:vec3.create(), 131 scale:vec3.fromValues(1, 1, 1), 132 rotation:vec3.create(), 133 translation:vec3.create(), 134 modelMatrix:mat4.create(), 135 rotationMatrix:mat4.create(), 136 inverseModelMatrix:mat4.create(), 137 inverseRotationMatrix:mat4.create() 139 138 }; 140 139 } //}}} 141 function recalculateModelMatrix(node) { //{{{ 142 //TODO: move to 0,0,0, rotate,move back to normal space, then apply transform 140 function debugNodes(canvasid) { //{{{ 141 var canvasid = canvasid || '.sim-canvas'; 142 var nodes = $(canvasid)[0].nodes; 143 console.log(canvasid, 'Nodes:'); 144 for (var node in nodes) { 145 console.log('name: ', nodes[node].name, ' node: ', nodes[node], ' mesh: ', nodes[node].mesh, ' translation: ', nodes[node].translation, ' center:', nodes[node].center, ' rotation:', nodes[node].rotation); 146 } 147 return nodes; 148 } //}}} 149 function updateModelMatrix(node) { //{{{ 143 150 var modelMatrix = mat4.create(); 144 151 152 var translationMatrix = mat4.create(); 153 mat4.translate(translationMatrix, translationMatrix, [-node.center[0],-node.center[1],-node.center[2]]); //scale/rotation centering 154 mat4.multiply(modelMatrix, translationMatrix, modelMatrix); 155 145 156 var scaleMatrix = mat4.create(); 146 mat4.scale(scaleMatrix, scaleMatrix, node ["scale"]);157 mat4.scale(scaleMatrix, scaleMatrix, node.scale); 147 158 mat4.multiply(modelMatrix, scaleMatrix, modelMatrix); 148 149 var translationMatrix = mat4.create(); 150 mat4.translate(translationMatrix, translationMatrix, node["translation"]); //relative translation 159 160 var rotationMatrix = mat4.create(); 161 var zRotationMatrix = mat4.create(); 162 mat4.rotate(zRotationMatrix, zRotationMatrix, DEG2RAD * node.rotation[2], [0.0, 0.0, 1.0]); 163 mat4.multiply(rotationMatrix, zRotationMatrix, rotationMatrix); 164 var yRotationMatrix = mat4.create(); 165 mat4.rotate(yRotationMatrix, yRotationMatrix, DEG2RAD * node.rotation[1], [0.0, 1.0, 0.0]); 166 mat4.multiply(rotationMatrix, yRotationMatrix, rotationMatrix); 167 var xRotationMatrix = mat4.create(); 168 mat4.rotate(xRotationMatrix, xRotationMatrix, DEG2RAD * node.rotation[0], [1.0, 0.0, 0.0]); 169 mat4.multiply(rotationMatrix, xRotationMatrix, rotationMatrix); 170 mat4.multiply(modelMatrix, rotationMatrix, modelMatrix); 171 172 mat4.identity(translationMatrix); 173 mat4.translate(translationMatrix, translationMatrix, node.center); //relative translation 151 174 mat4.multiply(modelMatrix, translationMatrix, modelMatrix); 152 175 153 var zRotationMatrix = mat4.create(); 154 mat4.rotate(zRotationMatrix, zRotationMatrix, radians(node["rotation"][2]), [0.0, 0.0, 1.0]); 155 mat4.multiply(modelMatrix, zRotationMatrix, modelMatrix); 156 var yRotationMatrix = mat4.create(); 157 mat4.rotate(yRotationMatrix, yRotationMatrix, radians(node["rotation"][1]), [0.0, 1.0, 0.0]); 158 mat4.multiply(modelMatrix, yRotationMatrix, modelMatrix); 159 var xRotationMatrix = mat4.create(); 160 mat4.rotate(xRotationMatrix, xRotationMatrix, radians(node["rotation"][0]), [1.0, 0.0, 0.0]); 161 mat4.multiply(modelMatrix, xRotationMatrix, modelMatrix); 162 163 return modelMatrix; 164 } //}}} 165 function radians (degrees) { //{{{ 166 return degrees * Math.PI / 180; 167 } //}}} 168 function degrees (radians) { //{{{ 169 return radians * 180 / Math.PI; 176 mat4.identity(translationMatrix); 177 mat4.translate(translationMatrix, translationMatrix, node.translation); //absolute translation 178 mat4.multiply(modelMatrix, translationMatrix, modelMatrix); 179 180 node.modelMatrix = modelMatrix; 181 node.inverseModelMatrix = mat4.invert(mat4.create(), modelMatrix); 182 node.rotationMatrix = rotationMatrix; 183 node.inverseRotationMatrix = mat4.invert(mat4.create(), rotationMatrix);; 170 184 } //}}} 171 185 function clamp(value, min, max) { //{{{ 172 186 return Math.max(min, Math.min(value, max)); 173 187 } //}}} 174 function recoverview(canvasid,defaultview) { //{{{ 175 var canvas = document.getElementById(canvasid); 176 if (canvas && canvas.hasOwnProperty("rotation")) { 177 return canvas.rotation; 178 } 179 return defaultview; 180 } //}}} 181 function recovercenteroffset(canvasid,defaultcenter) { //{{{ 182 var canvas = document.getElementById(canvasid); 183 if (canvas && canvas.hasOwnProperty("translation")) { 184 return canvas.translation; 185 } 186 return defaultcenter; 187 } //}}} 188 //}}} 189 //{{{ Shader Loading 190 function loadShaders(gl) { //{{{ 191 var shaderNames = ["colored", "unlit_textured"]; 192 shaders = {}; 193 shaders["colored"] = {loaded:false, vsh:{}, fsh:{}}; 194 shaders["colored"]["vsh"]["string"] = 195 ['attribute vec3 aVertexPosition;', 196 'attribute vec4 aVertexColor;', 197 '', 198 'uniform mat4 uMVPMatrix;', 199 'uniform float uAlpha;', 200 '', 201 'varying vec4 vColor;', 202 '', 203 'void main(void) {', 204 ' gl_PointSize = 3.0;', 205 ' gl_Position = uMVPMatrix * vec4(aVertexPosition.xyz, 1.0);', 206 ' vColor = vec4(aVertexColor.xyz, uAlpha);', 207 '}'].join('\n'); 208 shaders["colored"]["fsh"]["string"] = 209 ['precision mediump float;', 210 '', 211 'varying vec4 vColor;', 212 '', 213 'void main(void) {', 214 ' gl_FragColor = vColor;', 215 '}'].join('\n'); 216 shaders["unlit_textured"] = {loaded:false, vsh:{}, fsh:{}}; 217 shaders["unlit_textured"]["vsh"]["string"] = 218 ['attribute vec3 aVertexPosition;', 219 'attribute vec2 aTextureCoord;', 220 '', 221 'uniform mat4 uMVPMatrix;', 222 '', 223 'varying vec2 vTextureCoord;', 224 'varying float vZCoord;', 225 '', 226 'void main(void) {', 227 ' gl_PointSize = 3.0;', 228 ' gl_Position = uMVPMatrix * vec4(aVertexPosition.xyz, 1.0);', 229 ' vTextureCoord = aTextureCoord;', 230 ' vZCoord = aVertexPosition.z;', 231 '}'].join('\n'); 232 shaders["unlit_textured"]["fsh"]["string"] = 233 ['precision mediump float;', 234 '', 235 'varying vec2 vTextureCoord;', 236 'varying float vZCoord;', 237 '', 238 'uniform sampler2D uColorSampler;', 239 'uniform float uAlpha;', 240 'uniform bool uMaskEnabled;', 241 'uniform float uMaskHeight;', 242 'uniform vec4 uMaskColor;', 243 '', 244 'void main(void) {', 245 ' if (uMaskEnabled && (vZCoord < uMaskHeight)) {', 246 ' gl_FragColor = vec4(uMaskColor.xyz, uAlpha);', 247 ' }', 248 ' else {', 249 ' gl_FragColor = vec4(texture2D(uColorSampler, vec2(vTextureCoord.s, vTextureCoord.t)).rgb, uAlpha);', 250 ' }', 251 '}'].join('\n'); 252 shaderNames.forEach(function(shaderName){ 253 shaders[shaderName]["vsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["vsh"]["string"], "vsh"); 254 shaders[shaderName]["fsh"]["shader"] = getShaderByString(gl, shaders[shaderName]["fsh"]["string"], "fsh"); 255 256 shaders[shaderName]["program"] = gl.createProgram(); 257 gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["vsh"]["shader"]); 258 gl.attachShader(shaders[shaderName]["program"], shaders[shaderName]["fsh"]["shader"]); 259 gl.linkProgram(shaders[shaderName]["program"]); 260 261 if (!gl.getProgramParameter(shaders[shaderName]["program"], gl.LINK_STATUS)) { 262 alert("Could not initialise shaders"); 263 } 264 265 var vshStringArray = shaders[shaderName]["vsh"]["string"].split("\n"); 266 var fshStringArray = shaders[shaderName]["fsh"]["string"].split("\n"); 267 var line = ""; 268 var property = ""; 269 for (var i = 0; i < vshStringArray.length; i++) { 270 line = vshStringArray[i]; 271 if (line.search("attribute") != -1) { 272 property = nameFromLine(line); 273 shaders[shaderName]["program"][property] = gl.getAttribLocation(shaders[shaderName]["program"], property); 274 } 275 else if (line.search("uniform") != -1) { 276 property = nameFromLine(line); 277 shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property); 278 } 279 else if (line.search("void main") != -1) { 280 break; 281 } 282 } 283 for (var i = 0; i < fshStringArray.length; i++) { 284 line = fshStringArray[i]; 285 if (line.search("uniform") != -1) { 286 property = nameFromLine(line); 287 shaders[shaderName]["program"][property] = gl.getUniformLocation(shaders[shaderName]["program"], property); 288 } 289 else if (line.search("void main") != -1) { 290 break; 291 } 292 } 293 shaders[shaderName]["loaded"] = true; 294 }); 295 return shaders; 296 } //}}} 297 function getShaderByString(gl,str,type) { //{{{ 298 var shader; 299 if (type == "fsh") { 300 shader = gl.createShader(gl.FRAGMENT_SHADER); 301 } 302 else if (type == "vsh") { 303 shader = gl.createShader(gl.VERTEX_SHADER); 304 } 305 else { 306 return null; 307 } 308 309 gl.shaderSource(shader, str); 310 gl.compileShader(shader); 311 312 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 313 alert(gl.getShaderInfoLog(shader)); 314 return null; 315 } 316 317 return shader; 318 } //}}} 319 function nameFromLine(line) { //{{{ 320 //returns lowerCamelCase property name from shader line 321 var fullName = line.split(" ")[2]; 322 return fullName.slice(0, fullName.search(";")); 188 function recover(canvasid,name,defaultvalue) { //{{{ 189 var canvas = document.getElementById(canvasid); 190 if (canvas && canvas.hasOwnProperty(name)) { return canvas[name]; } 191 return defaultvalue; 192 } //}}} 193 function typedArraySliceSupport() { //{{{ 194 //TypedArray compatibility for Safari/IE 195 if (typeof Int8Array !== 'undefined') { 196 if (!Int8Array.prototype.fill) { Int8Array.prototype.fill = Array.prototype.fill; } 197 if (!Int8Array.prototype.slice) { Int8Array.prototype.slice = Array.prototype.slice; } 198 } 199 if (typeof Uint8Array !== 'undefined') { 200 if (!Uint8Array.prototype.fill) { Uint8Array.prototype.fill = Array.prototype.fill; } 201 if (!Uint8Array.prototype.slice) { Uint8Array.prototype.slice = Array.prototype.slice; } 202 } 203 if (typeof Uint8ClampedArray !== 'undefined') { 204 if (!Uint8ClampedArray.prototype.fill) { Uint8ClampedArray.prototype.fill = Array.prototype.fill; } 205 if (!Uint8ClampedArray.prototype.slice) { Uint8ClampedArray.prototype.slice = Array.prototype.slice; } 206 } 207 if (typeof Int16Array !== 'undefined') { 208 if (!Int16Array.prototype.fill) { Int16Array.prototype.fill = Array.prototype.fill; } 209 if (!Int16Array.prototype.slice) { Int16Array.prototype.slice = Array.prototype.slice; } 210 } 211 if (typeof Uint16Array !== 'undefined') { 212 if (!Uint16Array.prototype.fill) { Uint16Array.prototype.fill = Array.prototype.fill; } 213 if (!Uint16Array.prototype.slice) { Uint16Array.prototype.slice = Array.prototype.slice; } 214 } 215 if (typeof Int32Array !== 'undefined') { 216 if (!Int32Array.prototype.fill) { Int32Array.prototype.fill = Array.prototype.fill; } 217 if (!Int32Array.prototype.slice) { Int32Array.prototype.slice = Array.prototype.slice; } 218 } 219 if (typeof Uint32Array !== 'undefined') { 220 if (!Uint32Array.prototype.fill) { Uint32Array.prototype.fill = Array.prototype.fill; } 221 if (!Uint32Array.prototype.slice) { Uint32Array.prototype.slice = Array.prototype.slice; } 222 } 223 if (typeof Float32Array !== 'undefined') { 224 if (!Float32Array.prototype.fill) { Float32Array.prototype.fill = Array.prototype.fill; } 225 if (!Float32Array.prototype.slice) { Float32Array.prototype.slice = Array.prototype.slice; } 226 } 227 if (typeof Float64Array !== 'undefined') { 228 if (!Float64Array.prototype.fill) { Float64Array.prototype.fill = Array.prototype.fill; } 229 if (!Float64Array.prototype.slice) { Float64Array.prototype.slice = Array.prototype.slice; } 230 } 231 if (typeof TypedArray !== 'undefined') { 232 if (!TypedArray.prototype.fill) { TypedArray.prototype.fill = Array.prototype.fill; } 233 if (!TypedArray.prototype.slice) { TypedArray.prototype.slice = Array.prototype.slice; } 234 } 235 } //}}} 236 function raycast(canvas, origin, ray) { //{{{ 237 var mesh = canvas.unitNode.mesh; 238 if (!mesh || mesh.ready == false) { return; } 239 if (!mesh.octree) { mesh.octree = new GL.Octree(mesh); } 240 241 var hit = mesh.octree.testRay(origin, ray, 1e3, 1e10); 242 243 if(!hit) { return; } 244 245 hit.modelPos = vec3.copy(vec3.create(), hit.pos); 246 vec3.transformMat4(hit.pos, hit.pos, canvas.unitNode.modelMatrix); 247 vec3.transformMat4(hit.normal, hit.normal, canvas.unitNode.modelMatrix); 248 249 return hit; 323 250 } //}}} 324 251 //}}} 325 252 //{{{ Interface Functions 253 function onTap(ev, canvas) { //{{{ 254 //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. 255 ev.preventDefault(); 256 if (!(canvas.dataMarkersAllowed && canvas.dataMarkersEnabled)) { return; } 257 updateMarker(canvas, ev.srcEvent.layerX, ev.srcEvent.layerY, true); 258 } //}}} 259 function updateMarker(canvas, x, y, reset, origin, far) { //{{{ 260 //Can be called by onTap to create/reuse a marker, or by the marker's update function. Origin and far are optional and only used by the update function for recreating the raycast. 261 if (!canvas.unitNode) { return; } 262 263 var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.cameraMatrix, canvas.unitNode.modelMatrix)); 264 var origin = origin || vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 0], inverseMVPMatrix); 265 var far = far || vec3.transformMat4(vec3.create(), [(x - canvas.width / 2) / (canvas.width / 2), (canvas.height / 2 - y) / (canvas.height / 2), 1.0], inverseMVPMatrix); 266 var ray = vec3.subtract(vec3.create(), far, origin); 267 var hit = raycast(canvas, origin, ray); 268 269 if (hit) { 270 var coords = canvas.unitNode.mesh.vertexBuffers.coords.data; 271 var latitude = md.mesh.lat; 272 var longitude = md.mesh.long; 273 var thickness; 274 var velocity; 275 if (md.results[0]) { 276 thickness = md.results[canvas.movieFrame].Thickness; 277 velocity = md.results[canvas.movieFrame].Vel; 278 } 279 else { 280 thickness = md.geometry.thickness; 281 velocity = md.initialization.vel; 282 } 283 284 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]]; 285 var hitLatitude = [latitude[hit.indices[0]], latitude[hit.indices[1]], latitude[hit.indices[2]]]; 286 var hitLongitude = [longitude[hit.indices[0]], longitude[hit.indices[1]], longitude[hit.indices[2]]]; 287 var hitThickness = [thickness[hit.indices[0]], thickness[hit.indices[1]], thickness[hit.indices[2]]]; 288 var hitVelocity = [velocity[hit.indices[0]], velocity[hit.indices[1]], velocity[hit.indices[2]]]; 289 var u = hitCoords[0] * hit.uvw[0] + hitCoords[2] * hit.uvw[1] + hitCoords[4] * hit.uvw[2]; 290 var v = hitCoords[1] * hit.uvw[0] + hitCoords[3] * hit.uvw[1] + hitCoords[5] * hit.uvw[2]; 291 var value = canvas.unitNode.caxis[0] * (1.0 - v) + canvas.unitNode.caxis[1] * v; 292 var valueLatitude = Math.abs(hitLatitude[0] * hit.uvw[0] + hitLatitude[1] * hit.uvw[1] + hitLatitude[2] * hit.uvw[2]); 293 var valueLongitude = Math.abs(hitLongitude[0] * hit.uvw[0] + hitLongitude[1] * hit.uvw[1] + hitLongitude[2] * hit.uvw[2]); 294 var valueThickness = hitThickness[0] * hit.uvw[0] + hitThickness[1] * hit.uvw[1] + hitThickness[2] * hit.uvw[2]; 295 var valueVelocity = hitVelocity[0] * hit.uvw[0] + hitVelocity[1] * hit.uvw[1] + hitVelocity[2] * hit.uvw[2]; 296 297 var dataMarkerSize = canvas.dataMarkerSize; 298 if (!canvas.marker) { 299 $('#' + canvas.id).after( '<img src=' + canvas.dataMarkerImage + ' alt="data marker" width="' + dataMarkerSize[0] + '" height="' + dataMarkerSize[1] + '" id="sim-data-marker-' + canvas.id + '" class="sim-data-marker noselect tooltip" data-tooltip-content="#tooltip-content-data-marker-' + canvas.id + '"></img><span id="tooltip-content-data-marker-' + canvas.id + '"></span>'); 300 $('#sim-data-marker-' + canvas.id).css({ 301 'position': 'absolute', 302 'left': (Math.round(x) - dataMarkerSize[0] / 2) + 'px', 303 'top': (Math.round(y) - dataMarkerSize[1]) + 'px', 304 'width': dataMarkerSize[0] + 'px', 305 'height': dataMarkerSize[1] + 'px', 306 'pointer-events': 'all', 307 'cursor': 'pointer', 308 'display': 'none' 309 }); 310 $('#sim-data-marker-' + canvas.id).tooltipster({ 311 maxWidth: 320, 312 zIndex: 2200, 313 trigger: 'custom', 314 triggerOpen: { 315 mouseenter: false, 316 originClick: true, 317 touchstart: false 318 }, 319 triggerClose: { 320 mouseleave: false, 321 originClick: true, 322 touchleave: false 323 } 324 }); 325 canvas.marker = $('#sim-data-marker-' + canvas.id); 326 canvas.marker.on('click touch', function () { 327 canvas.marker.fadeOut(175); 328 canvas.dataMarkerDisplay.tooltipster('close'); 329 }); 330 canvas.marker.fadeIn(175); 331 } 332 333 334 canvas.marker.hit = hit; 335 canvas.marker.update = function() { 336 if (!canvas.unitNode) { return; } 337 var screenPoint = vec3.transformMat4(vec3.create(), canvas.marker.hit.pos, canvas.cameraMatrix); 338 var x = screenPoint[0] * (canvas.width / 2) + canvas.width / 2; 339 var y = -screenPoint[1] * (canvas.height / 2) + canvas.height / 2; 340 updateMarker(canvas, Math.round(x), Math.round(y), false, origin, far); 341 canvas.marker.css({ 342 'left': (Math.round(x) - dataMarkerSize[0] / 2) + 'px', 343 'top': (Math.round(y) - dataMarkerSize[1]) + 'px' 344 }); 345 if (canvas.dataMarkerDisplay.tooltipster('status').state != 'closed') { canvas.dataMarkerDisplay.tooltipster('reposition'); } 346 }; 347 348 if (!canvas.dataMarkerDisplay) { 349 canvas.dataMarkerDisplay = $('#sim-data-marker-' + canvas.id); 350 canvas.dataMarkerDisplay.tooltipster('open'); 351 } 352 if (canvas.dataMarkerOptions) { 353 var format = [canvas.dataMarkerOptions.format[0]]; 354 for (var i = 1; i < canvas.dataMarkerOptions.format.length; i++) { 355 var formatString = canvas.dataMarkerOptions.format[i]; 356 if (formatString.toLowerCase() == 'x') { format.push(hit.modelPos[0]); } 357 else if (formatString.toLowerCase() == 'y') { format.push(hit.modelPos[1]); } 358 else if (formatString.toLowerCase() == 'z') { format.push(hit.modelPos[2]); } 359 else if (formatString.toLowerCase() == 'lat') { format.push(valueLatitude); } 360 else if (formatString.toLowerCase() == 'long') { format.push(valueLongitude); } 361 else if (formatString.toLowerCase() == 'thickness') { format.push(valueThickness); } 362 else if (formatString.toLowerCase() == 'vel') { format.push(valueVelocity); } 363 else if (formatString.toLowerCase() == 'value') { format.push(value); } 364 else {format.push(formatString); } 365 } 366 367 $('#tooltip-content-data-marker-' + canvas.id).html(sprintf.apply(null, format)); 368 $('#tooltip-content-data-marker-' + canvas.id).css({ 369 'font': canvas.dataMarkerOptions.font 370 }); 371 } 372 373 if (reset) { modifyDataMarkersEnabled(true,canvas); } 374 } 375 } //}}} 326 376 function onPan(ev,canvas,displaylog) { //{{{ 327 377 ev.preventDefault(); … … 331 381 } 332 382 if (ev.srcEvent.shiftKey || ev.pointers.length == 2) { 333 var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.zoomFactor * -2; 334 var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.zoomFactor * -2; 335 336 canvas.translation[0] += Math.cos(radians(canvas.rotation[0])) * deltaX - Math.sin(radians(canvas.rotation[0])) * deltaY; 337 canvas.translation[1] += Math.sin(radians(canvas.rotation[0])) * deltaX + Math.cos(radians(canvas.rotation[0])) * deltaY; 383 if (!canvas.viewPanning) return; 384 var deltaX = (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.zoom * 2 * canvas.controlSensitivity * 6.371e6; 385 var deltaY = (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.zoom * 2 * canvas.controlSensitivity * 6.371e6; 386 387 if (canvas.twod) { 388 canvas.translation[0] += Math.cos(DEG2RAD * canvas.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY; 389 canvas.translation[2] += Math.sin(DEG2RAD * canvas.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY; 390 } 391 else { 392 canvas.translation[0] += Math.cos(DEG2RAD * canvas.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.rotation[0]) * deltaY; 393 canvas.translation[2] += Math.sin(DEG2RAD * canvas.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.rotation[0]) * deltaY; 394 } 338 395 } 339 396 else { 340 canvas.rotation[0] += degrees((canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth / canvas.zoomFactor * -2);341 canvas.rotation[1] += degrees((canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight / canvas.zoomFactor * -2);342 343 if (canvas.rotation[0] > 360) { canvas.rotation[0] -= 360};344 if (canvas.rotation[0] < -360) { canvas.rotation[0] += 360};345 if (canvas.rotation[1] > 180) { canvas.rotation[1] -= 360};346 if (canvas.rotation[1] < -180) { canvas.rotation[1] += 360};397 canvas.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * -2 * canvas.controlSensitivity * RAD2DEG; 398 canvas.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG; 399 400 if (canvas.rotation[0] > 360) { canvas.rotation[0] -= 360; }; 401 if (canvas.rotation[0] < -360) { canvas.rotation[0] += 360; }; 402 if (canvas.rotation[1] > 180) { canvas.rotation[1] -= 360; }; 403 if (canvas.rotation[1] < -180) { canvas.rotation[1] += 360; }; 347 404 348 405 canvas.rotation[0] = clamp(canvas.rotation[0], canvas.rotationAzimuthBounds[0], canvas.rotationAzimuthBounds[1]); … … 351 408 canvas.lastDeltaX = ev.deltaX; 352 409 canvas.lastDeltaY = ev.deltaY; 353 354 if (displaylog) console.log(canvas.rotation);410 411 if (displaylog) { console.log(canvas.rotation); } 355 412 } //}}} 356 413 function onPinch(ev,canvas,displaylog) { //{{{ 357 414 ev.preventDefault(); 358 if (ev.type == 'pinchstart') { 359 canvas.zoomLast = canvas.zoomFactor; 360 } 361 else { 362 canvas.zoomFactor = clamp(ev.scale * canvas.zoomLast, canvas.zoomBounds[0], canvas.zoomBounds[1]); 363 if (displaylog) console.log(canvas.zoomFactor); 364 } 415 if (ev.type == 'pinchstart') { canvas.zoomLast = canvas.zoom; } 416 else { modifyZoom(ev.scale * canvas.zoomLast, canvas, displaylog); } 365 417 } //}}} 366 418 function onZoom(ev,canvas,displaylog) { //{{{ 367 419 ev.preventDefault(); 368 var delta = clamp(clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) / (1000 * canvas.zoomFactor), -0.1, 0.1); 369 canvas.zoomFactor = clamp(canvas.zoomFactor + delta, canvas.zoomBounds[0], canvas.zoomBounds[1]); 370 371 if (displaylog) console.log(canvas.zoomFactor); 420 var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.zoom / 20; 421 modifyZoom(canvas.zoom + delta, canvas, displaylog); 422 } //}}} 423 function modifyZoom(value,canvas,displaylog) { //{{{ 424 canvas.zoom = clamp(value, canvas.zoomBounds[0], canvas.zoomBounds[1]); 425 if (displaylog) { console.log(canvas.zoom); } 426 } //}}} 427 function modifyDataMarkersEnabled(value,canvas) { //{{{ 428 canvas.dataMarkersEnabled = value; 429 if (!canvas.dataMarkersEnabled && canvas.marker) { 430 canvas.marker.fadeOut(175); 431 canvas.dataMarkerDisplay.tooltipster('close'); 432 } 433 else if (canvas.dataMarkersEnabled && canvas.marker) { 434 canvas.marker.fadeIn(175); 435 canvas.dataMarkerDisplay.tooltipster('open'); 436 } 437 } //}}} 438 function toggleMoviePlay(canvas) { //{{{ 439 canvas.moviePlay = !canvas.moviePlay; 440 if (canvas.moviePlay){ 441 canvas.playButton.find("span").removeClass("fa-play"); 442 canvas.playButton.find("span").addClass("fa-pause"); 443 } 444 else{ 445 canvas.playButton.find("span").removeClass("fa-pause"); 446 canvas.playButton.find("span").addClass("fa-play"); 447 } 372 448 } //}}} 373 449 //}}} … … 381 457 var azimuthRotationMatrix = mat4.create(); 382 458 var elevationRotationMatrix = mat4.create(); 383 459 var aspectRatio = canvas.clientWidth / canvas.clientHeight; 460 var cameraPosition = vec3.create(); 461 462 if (canvas.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/canvas.zoom, aspectRatio*6.371e6/canvas.zoom, -6.371e6/canvas.zoom, 6.371e6/canvas.zoom, -1.0, 1e10); } 463 else { mat4.perspective(pMatrix, 45 * DEG2RAD, aspectRatio, 1e3, 1e10); } 464 465 //Apply worldspace translation 466 mat4.translate(translateMatrix, translateMatrix, [-canvas.translation[0],-canvas.translation[1],-canvas.translation[2]]); 467 mat4.multiply(vMatrix, translateMatrix, vMatrix); 468 469 //Calculate rotation around camera focal point about worldspace origin 384 470 if (canvas.twod) { 385 mat4.ortho(pMatrix, -1/canvas.zoomFactor, 1/canvas.zoomFactor, -1/canvas.zoomFactor, 1/canvas.zoomFactor, -1.0, 10000.0); 471 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, DEG2RAD * 0, [0, 1, 0]); 472 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * 90, [1, 0, 0]); 473 mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix); 386 474 } 387 475 else { 388 mat4.perspective(pMatrix, 90 * Math.PI / 180, canvas.clientWidth / canvas.clientHeight, 0.001, 10000.0); 389 } 390 391 //Apply worldspace translation 392 mat4.translate(translateMatrix, translateMatrix, [canvas.translation[0], canvas.translation[2], canvas.translation[1]]); 393 mat4.multiply(vMatrix, translateMatrix, vMatrix); 394 395 //Calculate rotation around camera focal point about worldspace origin 396 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, radians(canvas.rotation[0]), [0, 1, 0]); 397 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, radians(canvas.rotation[1]), [1, 0, 0]); 398 mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix); 399 400 //Apply rotation and scaling transform 476 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, DEG2RAD * canvas.rotation[0], [0, 1, 0]); 477 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * canvas.rotation[1], [1, 0, 0]); 478 mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix); 479 } 480 481 //Apply rotation transform 401 482 mat4.multiply(vMatrix, rotationMatrix, vMatrix); 402 483 403 484 //Apply screenspace translation 404 485 mat4.identity(translateMatrix); 405 mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, - 1/canvas.zoomFactor]);486 mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/canvas.zoom]); 406 487 mat4.multiply(vMatrix, translateMatrix, vMatrix); 407 488 489 //Calculate fields for lighting and raycasts 490 mat4.invert(canvas.vInverseMatrix, vMatrix); 491 408 492 //Apply projection matrix to get camera matrix 409 493 mat4.multiply(canvas.cameraMatrix, pMatrix, vMatrix); 410 // canvas.cameraMatrix = mat4.create(); 494 mat4.invert(canvas.inverseCameraMatrix, canvas.cameraMatrix); 495 vec3.transformMat4(canvas.cameraPosition, cameraPosition, canvas.inverseCameraMatrix); 411 496 }//}}} 412 function drawSceneGraphNode(gl,canvas,node) { //{{{ 413 if (!node["enabled"]) { 497 function drawSceneGraphNode(canvas,node) { //{{{ 498 if (!node.enabled) { return; } 499 500 var gl = canvas.gl; 501 gl.makeCurrent(); 502 503 var mvpMatrix = mat4.create(); 504 mat4.multiply(mvpMatrix, canvas.cameraMatrix, node.modelMatrix); 505 506 if (node.texture) { node.texture.bind(0); } 507 if (node.disableDepthTest) { gl.disable(gl.DEPTH_TEST); } 508 if (node.enableCullFace) { gl.enable(gl.CULL_FACE); } 509 510 gl.cullFace(node.cullFace); 511 gl.lineWidth(node.lineWidth); 512 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 513 514 //Setup for light that originates from camera 515 var origin = vec3.fromValues(0, 0, 0); 516 var lightOrigin = vec3.fromValues(0, 0, 0); 517 var cameraPositionRelative = vec3.create(); 518 vec3.transformMat4(origin, origin, canvas.vInverseMatrix); 519 vec3.normalize(lightOrigin, lightOrigin); 520 vec3.sub(cameraPositionRelative, origin, node.translation); 521 cameraHeight = vec3.length(cameraPositionRelative); 522 523 var atm = { //Default Values 524 wavelength_r: 0.65, //0.65 Red wavelength (micrometers) 525 wavelength_g: 0.57, //0.57 Green wavelength (micrometers) 526 wavelength_b: 0.475, //0.475 Green wavelength (micrometers) 527 eSun: 100.0, //20.0 Sun intensity 528 kRayleigh: 0.0025, //0.0025 Rayleigh scattering amount 529 kMie: 0.000, //0.01 Mie scattering amount 530 g: -0.99, //-0.99 Mie phase asymmetry/direction factor 531 hdr_exposure: 0.8, //0.8 High Dynamic Range Exposure 532 scale: 1.25, //1.025 Scale of atmosphere. WARNING: Change atmosphereScale in applyoptions.js, and scaling constants. 533 scaleDepth: 0.25, //0.25 Percentage altitude at which the atmosphere's average density is found 534 a: -0.00287, //-0.00287 Scaling constant a 535 b: 0.459, //0.459 Scaling constant b 536 c: 3.83, //3.83 Scaling constant c 537 d: -6.80, //-6.80 Scaling constant d 538 e: 3.6, //5.25 Scaling constant e. Lower when increasing atmosphere scale. 539 attenuation: 0.5 //0.5 Strength of atmospheric scattering on ground shading. 540 }; 541 542 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)]; 543 var innerRadius = 6.371e6; 544 var outerRadius = innerRadius*atm.scale; 545 var scale = 1.0 / (outerRadius - innerRadius); 546 var scaleDepth = atm.scaleDepth; 547 548 node.shader.uniforms({ 549 m4MVP: mvpMatrix, 550 m4Model: node.modelMatrix, 551 u_texture: 0, 552 u_alpha: node.alpha, 553 u_maskEnabled: node.maskEnabled, 554 u_maskHeight: node.maskHeight, 555 u_maskColor: node.maskColor, 556 v3CameraPosition: origin, 557 v3Translate: node.translation, 558 v3LightPos: lightOrigin, 559 v3InvWavelength: inv_wavelength4, 560 fOuterRadius: outerRadius, 561 fOuterRadius2: outerRadius * outerRadius, 562 fInnerRadius: innerRadius, 563 fInnerRadius2: innerRadius * innerRadius, 564 fKrESun: atm.kRayleigh * atm.eSun, 565 fKmESun: atm.kMie * atm.eSun, 566 fKr4PI: atm.kRayleigh * 4 * Math.PI, 567 fKm4PI: atm.kMie * 4 * Math.PI, 568 fScale: scale, 569 fScaleDepth: scaleDepth, 570 fScaleOverScaleDepth: scale/scaleDepth, 571 v3LightPosFrag: lightOrigin, 572 fHdrExposure: atm.hdr_exposure, 573 g: atm.g, 574 g2: atm.g * atm.g, 575 a: atm.a, 576 b: atm.b, 577 c: atm.c, 578 d: atm.d, 579 e: atm.e, 580 attenuation: atm.attenuation 581 }).draw(node.mesh, node.drawMode, 'triangles'); 582 583 gl.enable(gl.DEPTH_TEST); 584 gl.disable(gl.CULL_FACE); 585 } //}}} 586 function draw(canvas,options) { //{{{ 587 if (canvas.textcanvas) { canvas.textcanvas.draw(canvas); } 588 589 var nodes = canvas.nodes; 590 if (nodes.length < 1) { 591 canvas.drawHandler = window.requestAnimationFrame(function(time) { draw(canvas,options); }); 414 592 return; 415 593 } 416 if (node["texture"]) { 417 if (!node["texture"]["isLoaded"]) { 594 for (var node in nodes) { 595 if ((nodes[node].texture && nodes[node].texture.ready == false) || nodes[node].shader.ready == false || nodes[node].mesh.ready == false) { 596 canvas.drawHandler = window.requestAnimationFrame(function(time) { draw(canvas,options); }); 418 597 return; 419 598 } 420 599 } 421 bindAttributes(gl, node["shader"], node["buffers"]); 422 var mvpMatrix = mat4.create(); 423 mat4.multiply(mvpMatrix, canvas.cameraMatrix, node["modelMatrix"]); 424 gl.uniformMatrix4fv(node["shader"]["uMVPMatrix"], false, mvpMatrix); 425 gl.uniform1f(node["shader"]["uAlpha"], node["alpha"]); 426 gl.uniform1i(node["shader"]["uMaskEnabled"], node["maskEnabled"]); 427 gl.uniform1f(node["shader"]["uMaskHeight"], node["maskHeight"]); 428 gl.uniform4fv(node["shader"]["uMaskColor"], node["maskColor"]); 429 if (node["texture"]) { 430 gl.activeTexture(gl.TEXTURE0); 431 gl.bindTexture(gl.TEXTURE_2D, node["texture"]); 432 gl.uniform1i(node["shader"]["uColorSampler"], 0); 433 } 434 if (node["disableDepthTest"]) { 435 gl.disable(gl.DEPTH_TEST); 436 } 437 gl.blendFunc (gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 438 if (node["useIndexBuffer"] == true) { 439 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, node["buffers"][node["buffers"].length - 1]); 440 gl.drawElements(node["drawMode"], node["buffers"][node["buffers"].length - 1].numItems, gl.UNSIGNED_SHORT, 0); 441 } 442 else { 443 gl.drawArrays(node["drawMode"], 0, node["buffers"][0].numItems); 444 } 445 gl.enable(gl.DEPTH_TEST); 446 } //}}} 447 function bindAttributes(gl,shaderProgram,bufferArray) { //{{{ 448 gl.useProgram(shaderProgram); 449 var arrayNumber = 0; 450 for (var propertyName in shaderProgram) { 451 if (propertyName[0] == "a") { 452 if (bufferArray[arrayNumber].itemSize > 1) { 453 gl.bindBuffer(gl.ARRAY_BUFFER, bufferArray[arrayNumber]); 454 gl.vertexAttribPointer(shaderProgram[propertyName], bufferArray[arrayNumber].itemSize, gl.FLOAT, false, 0, 0); 455 arrayNumber++; 456 } 457 } 458 } 459 } //}}} 460 function draw(gl,options,canvas,nodes) { //{{{ 461 // Ensure canvas and gl viewport sizes are the same 462 var displayWidth = canvas.clientWidth; 463 var displayHeight = canvas.clientHeight; 464 if (canvas.width != displayWidth || canvas.height != displayHeight) { 465 canvas.width = displayWidth; 466 canvas.height = displayHeight; 467 gl.viewport(0, 0, canvas.width, canvas.height); 468 } 469 470 if (canvas.textcanvas) { 471 canvas.textcanvas.draw(canvas); 472 } 473 474 // Set clear color to black, fully opaque 475 var backgroundcolor=new RGBColor(options.getfieldvalue('backgroundcolor','lightcyan')); 476 if(backgroundcolor.ok){ 477 gl.clearColor(backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0); 478 } 479 else throw Error(sprintf("s%s%s\n","initWebGL error message: cound not find out background color for curent canvas ",canvas)); 480 481 // Skip drawing of new frame if any texture is not yet loaded 482 var nodes = canvas.nodes; 483 for (var node in nodes) { 484 if (nodes[node]["texture"] && !nodes[node]["texture"]["isLoaded"]) { 485 window.requestAnimationFrame(function(time) {draw(gl,options,canvas,nodes)}); 486 return; 487 } 488 } 489 // Else, clear the color as well as the depth buffer for new frame 600 601 var rect = canvas.getBoundingClientRect(); 602 canvas.width = rect.width; 603 canvas.height = rect.height; 604 605 var gl = canvas.gl; 606 gl.makeCurrent(); //litegl function to handle switching between multiple canvases 607 gl.viewport(0, 0, rect.width, rect.height); 608 gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]); 490 609 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 491 492 window.requestAnimationFrame(function(time) {draw(gl,options,canvas,nodes)});493 610 494 611 updateCameraMatrix(canvas); 495 612 496 var drawPassNumber = 2; 613 if (canvas.marker) { canvas.marker.update(); } 614 615 var drawPassNumber = 3; 497 616 for (var i = drawPassNumber - 1; i >= 0; i--) { 498 617 for (var node in nodes) { 499 if (nodes[node] ["drawOrder"] == i) {500 drawSceneGraphNode(gl, canvas, nodes[node]);501 502 } 503 }618 if (nodes[node].drawOrder == i) { drawSceneGraphNode(canvas,nodes[node]); } 619 } 620 } 621 622 canvas.drawHandler = window.requestAnimationFrame(function(time) { draw(canvas,options); }); 504 623 } //}}} 505 624 //}}}
Note:
See TracChangeset
for help on using the changeset viewer.