Index: ../trunk-jpl/src/m/plot/applyoptions.js =================================================================== --- ../trunk-jpl/src/m/plot/applyoptions.js (revision 21137) +++ ../trunk-jpl/src/m/plot/applyoptions.js (revision 21138) @@ -330,4 +330,61 @@ } canvas.textcanvas = textcanvas; } //}}} + //Atmosphere {{{ + if (options.exist('atmosphere')) { + if (options.getfieldvalue('atmosphere')=='on') { + var meshresults = processmesh(md,data,options); + var x = meshresults[0]; + var y = meshresults[1]; + var z = meshresults[2]; + var elements = meshresults[3]; + var is2d = meshresults[4]; + var isplanet = meshresults[5]; + + var modelxlim = [ArrayMin(x),ArrayMax(x)]; + var modelylim = [ArrayMin(y),ArrayMax(y)]; + var modelzlim = [ArrayMin(z),ArrayMax(z)]; + var xlim = options.getfieldvalue('xlim',modelxlim); + var ylim = options.getfieldvalue('ylim',modelylim); + var zlim = options.getfieldvalue('zlim',modelzlim); + xmin = xlim[0]; + xmax = xlim[1]; + ymin = ylim[0]; + ymax = ylim[1]; + zmin = zlim[0]; + zmax = zlim[1]; + + var scale = 1; + var atmosphereScale = 1.25; + + //Atmosphere + var node = Node(gl,options); + canvas.nodes[canvas.nodes.length] = node; + node["shaderName"] = "SkyFromSpace"; + node["shader"] = gl["shaders"][node["shaderName"]]; + node["drawOrder"] = 1; + node["enableCullFace"] = true; + node["mesh"] = GL.Mesh.icosahedron({size:6371000*atmosphereScale,subdivisions:6}); + node["useIndexBuffer"] = false; + node["rotation"] = [0,0,0]; + node["translation"] = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (2 / scale)]; + node["scale"] = [scale, scale, scale]; + node["modelMatrix"] = recalculateModelMatrix(node); + + //Skysphere + var node = Node(gl,options); + canvas.nodes[canvas.nodes.length] = node; + node["shaderName"] = "Textured"; + node["shader"] = gl["shaders"][node["shaderName"]]; + node["drawOrder"] = 2; + node["enableCullFace"] = true; + node["mesh"] = GL.Mesh.sphere({size:6371000*10}); + node["texture"] = initTexture(gl,'../../../js/textures/TychoSkymapII_t4_2k.jpg'); + node["useIndexBuffer"] = false; + node["rotation"] = [0,0,0]; + node["translation"] = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (2 / scale)]; + node["scale"] = [scale, scale, scale]; + node["modelMatrix"] = recalculateModelMatrix(node); + } + } //}}} } Index: ../trunk-jpl/src/m/plot/plot_mesh.js =================================================================== --- ../trunk-jpl/src/m/plot/plot_mesh.js (revision 21137) +++ ../trunk-jpl/src/m/plot/plot_mesh.js (revision 21138) @@ -60,8 +60,8 @@ var gl = canvas.gl; var node = Node(gl,options); canvas.nodes[canvas.nodes.length] = node; - scale = 1 / (xmax - xmin); - node["shaderName"] = "colored"; + scale = 1; + node["shaderName"] = "Colored"; node["shader"] = gl["shaders"][node["shaderName"]]; node["lineWidth"] = options.getfieldvalue('linewidth',1); node["scale"] = [scale, scale, scale * matrixscale]; Index: ../trunk-jpl/src/m/plot/webgl.js =================================================================== --- ../trunk-jpl/src/m/plot/webgl.js (revision 21137) +++ ../trunk-jpl/src/m/plot/webgl.js (revision 21138) @@ -1,8 +1,10 @@ /*This is where we have all our webgl relevant functionality for the plotting routines: */ + //{{{ Canvas Initialization function initCanvas(options) { //Initialize open Gl for each canvas, if needed: - var canvas=document.getElementById(options.getfieldvalue('canvasid')); + canvas = document.getElementById(options.getfieldvalue('canvasid')); + //var canvas = document.getElementById(options.getfieldvalue('canvasid')); if (!canvas.initialized) { canvas.gl = initWebGL(canvas,options); canvas.nodes = []; @@ -29,7 +31,10 @@ gl.depthFunc(gl.LEQUAL); // Enable color blending/overlay gl.enable(gl.BLEND); - + // Enable face culling + gl.enable(gl.CULL_FACE); + gl.cullFace(gl.FRONT); + // Load shaders and store them in gl object gl.shaders = loadShaders(gl); @@ -40,6 +45,7 @@ canvas.zoom = clamp(options.getfieldvalue('zoom',1.0), canvas.zoomBounds[0], canvas.zoomBounds[1]); canvas.zoomLast = canvas.zoom; canvas.cameraMatrix = mat4.create(); + canvas.vInverseMatrix = mat4.create(); canvas.translation = options.getfieldvalue('origin',[0,0,0.0]); canvas.viewPanning = options.getfieldvalue('viewpanning','off') == 'on'; canvas.view = options.getfieldvalue('view',[0,90]); //0 azimuth - up is north, 90 elevation - looking straight down @@ -78,7 +84,7 @@ function Node(gl,options) { //{{{ //Returns a Node object that contains default display states for webgl object return {buffers:[], - shader:gl.shaders["colored"], + shader:gl.shaders["Colored"], draw:null, hideOcean:false, level:0, @@ -94,7 +100,7 @@ rotation:vec3.fromValues(-90, 0, 0), scale:vec3.fromValues(1, 1, 1), modelMatrix:mat4.create(), - shaderName:"colored", + shaderName:"Colored", drawOrder:0, maskEnabled:false, maskHeight:150.0, @@ -145,90 +151,11 @@ //}}} //{{{ Shader Loading function loadShaders(gl) { //{{{ - var shaderNames = ["colored", "unlit_textured"]; shaders = {}; - shaders["colored"] = {loaded:false, vsh:{}, fsh:{}}; - //basic phong shader - shaders["colored"] = new Shader('\ - precision highp float;\ - attribute vec3 a_vertex;\ - attribute vec4 a_color;\ - uniform mat4 u_mvp;\ - uniform float u_alpha;\ - varying vec4 v_color;\ - void main() {\ - gl_PointSize = 3.0;\ - gl_Position = u_mvp * vec4(a_vertex.xyz, 1.0);\ - v_color = vec4(a_color.xyz, u_alpha);\ - }\ - ', '\ - precision mediump float;\ - varying vec4 v_color;\ - void main() {\ - gl_FragColor = v_color;\ - }\ - '); - - shaders["unlit_textured"] = new Shader('\ - precision highp float;\ - attribute vec3 a_vertex;\ - attribute vec2 a_coord;\ - uniform mat4 u_mvp;\ - varying vec2 v_coord;\ - varying float v_z;\ - void main() {\ - gl_PointSize = 3.0;\ - gl_Position = u_mvp * vec4(a_vertex.xyz, 1.0);\ - v_coord = a_coord;\ - v_z = a_vertex.z;\ - }\ - ', '\ - precision mediump float;\ - varying vec2 v_coord;\ - varying float v_z;\ - uniform sampler2D u_texture;\ - uniform float u_alpha;\ - uniform bool u_maskEnabled;\ - uniform float u_maskHeight;\ - uniform vec4 u_maskColor;\ - void main() {\ - if (u_maskEnabled && (v_z < u_maskHeight)) {\ - gl_FragColor = vec4(u_maskColor.rgb, u_alpha);\ - }\ - else {\ - gl_FragColor = vec4(texture2D(u_texture, v_coord).rgb, u_alpha);\ - }\ - }\ - '); - /* - shaders["phong"] = new Shader('\ - precision highp float;\ - attribute vec3 a_vertex;\ - attribute vec3 a_normal;\ - attribute vec2 a_coord;\ - varying vec3 v_normal;\ - varying vec2 v_coord;\ - uniform mat4 u_mvp;\ - uniform mat4 u_model;\ - void main() {\ - v_coord = a_coord;\ - v_normal = (u_model * vec4(a_normal,0.0)).xyz;\ - gl_Position = u_mvp * vec4(a_vertex,1.0);\ - }\ - ', '\ - precision highp float;\ - varying vec3 v_normal;\ - varying vec2 v_coord;\ - uniform vec3 u_lightvector;\ - uniform vec4 u_color;\ - uniform sampler2D u_texture;\ - void main() {\ - vec3 N = normalize(v_normal);\ - vec4 color = u_color * texture2D( u_texture, v_coord);\ - gl_FragColor = color * max(0.0, dot(u_lightvector,N));\ - }\ - '); - */ + shaders["Colored"] = new Shader.fromURL("/js/shaders/Colored.vsh", "/js/shaders/Colored.fsh"); + shaders["Textured"] = new Shader.fromURL("/js/shaders/Textured.vsh", "/js/shaders/Textured.fsh"); + shaders["SkyFromSpace"] = new Shader.fromURL("/js/shaders/SkyFromSpace.vert", "/js/shaders/SkyFromSpace.frag"); + shaders["GroundFromSpace"] = new Shader.fromURL("/js/shaders/GroundFromSpace.vert", "/js/shaders/GroundFromSpace.frag"); return shaders; } //}}} //{{{ Interface Functions @@ -281,7 +208,7 @@ } //}}} function onZoom(ev,canvas,displaylog) { //{{{ ev.preventDefault(); - var delta = clamp(clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.zoom / 20, -1.0, 1.0); + var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.zoom / 20; canvas.zoom = clamp(canvas.zoom + delta, canvas.zoomBounds[0], canvas.zoomBounds[1]); if (displaylog) console.log(canvas.zoom); @@ -299,14 +226,14 @@ var aspectRatio = canvas.clientWidth / canvas.clientHeight; if (canvas.twod) { - mat4.ortho(pMatrix, -aspectRatio/canvas.zoom, aspectRatio/canvas.zoom, -1/canvas.zoom, 1/canvas.zoom, -1.0, 10000.0); + mat4.ortho(pMatrix, -aspectRatio*6371000.0/canvas.zoom, aspectRatio*6371000.0/canvas.zoom, -6371000.0/canvas.zoom, 6371000.0/canvas.zoom, -1.0, 10000000000.0); } else { - mat4.perspective(pMatrix, 60 * Math.PI / 180, aspectRatio, 0.001, 10000.0); + mat4.perspective(pMatrix, 60 * Math.PI / 180, aspectRatio, 1000, 10000000000.0); } //Apply worldspace translation - mat4.translate(translateMatrix, translateMatrix, [canvas.translation[0], canvas.translation[2], canvas.translation[1]]); + mat4.translate(translateMatrix, translateMatrix, [6371000.0 * canvas.translation[0], 6371000.0 * canvas.translation[2], 6371000.0 * canvas.translation[1]]); mat4.multiply(vMatrix, translateMatrix, vMatrix); //Calculate rotation around camera focal point about worldspace origin @@ -323,11 +250,14 @@ //Apply rotation and scaling transform mat4.multiply(vMatrix, rotationMatrix, vMatrix); - + //Apply screenspace translation mat4.identity(translateMatrix); - mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -1/canvas.zoom]); + mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6371000.0/canvas.zoom]); mat4.multiply(vMatrix, translateMatrix, vMatrix); + + //Calculate inverse matrices for lighting + mat4.invert(canvas.vInverseMatrix, vMatrix); //Apply projection matrix to get camera matrix mat4.multiply(canvas.cameraMatrix, pMatrix, vMatrix); @@ -340,30 +270,91 @@ if (node["texture"]) node["texture"].bind(0); if (node["disableDepthTest"]) gl.disable(gl.DEPTH_TEST); - + if (node["enableCullFace"]) gl.enable(gl.CULL_FACE); + + gl.cullFace(node["cullFace"]); gl.lineWidth(node["lineWidth"]); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + //Setup for light that originates from camera + var origin = vec3.fromValues(0, 0, 0); + var lightOrigin = vec3.fromValues(0, 0, 0); + var cameraPosition = vec3.create(); + vec3.transformMat4(origin, origin, canvas.vInverseMatrix); + vec3.normalize(lightOrigin, lightOrigin); + vec3.sub(cameraPosition, origin, node["translation"]); + cameraHeight = vec3.length(cameraPosition); + + var atm = { //Default Values + wavelength_r: 0.65, //0.65 Red wavelength (micrometers) + wavelength_g: 0.57, //0.57 Green wavelength (micrometers) + wavelength_b: 0.475, //0.475 Green wavelength (micrometers) + eSun: 100.0, //20.0 Sun intensity + kRayleigh: 0.0025, //0.0025 Rayleigh scattering amount + kMie: 0.000, //0.01 Mie scattering amount + g: -0.99, //-0.99 Mie phase asymmetry/direction factor + hdr_exposure: 0.8, //0.8 High Dynamic Range Exposure + scale: 1.25, //1.025 Scale of atmosphere. WARNING: Change atmosphereScale in applyoptions.js, and scaling constants. + scaleDepth: 0.25, //0.25 Percentage altitude at which the atmosphere's average density is found + a: -0.00287, //-0.00287 Scaling constant a + b: 0.459, //0.459 Scaling constant b + c: 3.83, //3.83 Scaling constant c + d: -6.80, //-6.80 Scaling constant d + e: 3.6, //5.25 Scaling constant e. Lower when increasing atmosphere scale. + attenuation: 0.5 //0.5 Strength of atmospheric scattering on ground shading. + }; + + 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)]; + var innerRadius = 6371000.0; + var outerRadius = innerRadius*atm.scale; + var scale = 1.0 / (outerRadius - innerRadius); + var scaleDepth = atm.scaleDepth; + node["shader"].uniforms({ - u_mvp: mvpMatrix, + m4MVP: mvpMatrix, + m4Model: node["modelMatrix"], u_texture: 0, u_alpha: node["alpha"], u_maskEnabled: node["maskEnabled"], u_maskHeight: node["maskHeight"], - u_maskColor: node["maskColor"] - }) + u_maskColor: node["maskColor"], + v3CameraPosition: origin, + v3Translate: node["translation"], + v3LightPos: lightOrigin, + v3InvWavelength: inv_wavelength4, + fOuterRadius: outerRadius, + fOuterRadius2: outerRadius * outerRadius, + fInnerRadius: innerRadius, + fInnerRadius2: innerRadius * innerRadius, + fKrESun: atm.kRayleigh * atm.eSun, + fKmESun: atm.kMie * atm.eSun, + fKr4PI: atm.kRayleigh * 4 * Math.PI, + fKm4PI: atm.kMie * 4 * Math.PI, + fScale: scale, + fScaleDepth: scaleDepth, + fScaleOverScaleDepth: scale/scaleDepth, + v3LightPosFrag: lightOrigin, + fHdrExposure: atm.hdr_exposure, + g: atm.g, + g2: atm.g * atm.g, + a: atm.a, + b: atm.b, + c: atm.c, + d: atm.d, + e: atm.e, + attenuation: atm.attenuation + }); if (node["useIndexBuffer"] == true) node["shader"].draw(node["mesh"], node["drawMode"], "indices"); else node["shader"].draw(node["mesh"], node["drawMode"]); gl.enable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); } //}}} function draw(canvas,options) { //{{{ // Ensure canvas and gl viewport sizes are the same - var displayWidth = canvas.clientWidth; - var displayHeight = canvas.clientHeight; - if (canvas.width != displayWidth || canvas.height != displayHeight) { - canvas.width = displayWidth; - canvas.height = displayHeight; + if (canvas.width != canvas.clientWidth || canvas.height != canvas.clientHeight) { + canvas.width = canvas.clientWidth; + canvas.height = canvas.clientHeight; canvas.gl.viewport(0, 0, canvas.width, canvas.height); } @@ -385,11 +376,9 @@ gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - updateCameraMatrix(canvas); - var drawPassNumber = 2; + var drawPassNumber = 3; for (var i = drawPassNumber - 1; i >= 0; i--) { for (var node in nodes) { if (nodes[node]["drawOrder"] == i) drawSceneGraphNode(canvas,nodes[node]); Index: ../trunk-jpl/src/m/plot/plot_overlay.js =================================================================== --- ../trunk-jpl/src/m/plot/plot_overlay.js (revision 21137) +++ ../trunk-jpl/src/m/plot/plot_overlay.js (revision 21138) @@ -60,8 +60,8 @@ var gl = canvas.gl; var node = Node(gl,options); canvas.nodes[canvas.nodes.length] = node; - scale = 1 / (xmax - xmin); - node["shaderName"] = "unlit_textured"; + scale = 1; + node["shaderName"] = "GroundFromSpace"; node["shader"] = gl["shaders"][node["shaderName"]]; node["scale"] = [scale, scale, scale * matrixscale]; node["translation"] = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (2 / scale)]; Index: ../trunk-jpl/src/m/plot/plot_quiver.js =================================================================== --- ../trunk-jpl/src/m/plot/plot_quiver.js (revision 21137) +++ ../trunk-jpl/src/m/plot/plot_quiver.js (revision 21138) @@ -62,8 +62,8 @@ var gl = canvas.gl; var node = Node(gl,options); canvas.nodes[canvas.nodes.length] = node; - scale = 1 / (xmax - xmin); - node["shaderName"] = "colored"; + scale = 1; + node["shaderName"] = "Colored"; node["shader"] = gl["shaders"][node["shaderName"]]; node["lineWidth"] = options.getfieldvalue('linewidth',1); node["scale"] = [scale, scale, scale * matrixscale]; Index: ../trunk-jpl/src/m/plot/plot_unit.js =================================================================== --- ../trunk-jpl/src/m/plot/plot_unit.js (revision 21137) +++ ../trunk-jpl/src/m/plot/plot_unit.js (revision 21138) @@ -57,13 +57,13 @@ zmin = zlim[0]; zmax = zlim[1]; var caxis; - + //Compute gl variables: var gl = canvas.gl; var node = Node(gl,options); canvas.nodes[canvas.nodes.length] = node; - scale = 1 / (xmax - xmin); - node["shaderName"] = "unlit_textured"; + scale = 1; + node["shaderName"] = "Textured"; node["shader"] = gl["shaders"][node["shaderName"]]; node["scale"] = [scale, scale, scale * matrixscale]; node["translation"] = [(xmin + xmax) / (-2 / scale), (ymin + ymax) / (-2 / scale), (zmin + zmax) / (2 / scale)];