summaryrefslogtreecommitdiffstats
path: root/o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html')
-rw-r--r--o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html803
1 files changed, 803 insertions, 0 deletions
diff --git a/o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html b/o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html
new file mode 100644
index 0000000..61b9cf1
--- /dev/null
+++ b/o3d/samples/o3d-webgl-samples/trends/trends-with-particles.html
@@ -0,0 +1,803 @@
+<!--
+Copyright 2009, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<!--
+TODO:
+ O Set Sun to correct location for time.
+ O Put in moon
+ O Put in Google satellite
+ O Put in Star Shader that uses star data from a texture
+ O Add Halo
+ O Add Sun Model
+ O with glowing rays.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>
+Google Trends Visualizer
+</title>
+<style>
+ html, body {
+ border: 0;
+ margin: 0;
+ height: 100%;
+ height: 100%;
+ text-align: center;
+ }
+</style>
+</head>
+<body onload="init();" onunload="uninit();">
+<script type="text/javascript" src="../../o3d-webgl/base.js"></script>
+<script type="text/javascript" src="../../o3djs/base.js"></script>
+<script type="text/javascript" id="o3dscript">
+o3djs.base.o3d = o3d;
+o3djs.require('o3djs.webgl');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.quaternions');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.arcball');
+o3djs.require('o3djs.io');
+o3djs.require('o3djs.particles');
+
+var g = {
+ EARTH_RADIUS: 25,
+ ENERGY_WIDTH: 0.5,
+ ENERGY_HEIGHT: 10
+};
+
+g.camera = {
+ eye: [0, 0, 75],
+ target: [0, 0, 0]
+};
+
+var g_finished = false; // for selenium.
+var dragging = false;
+
+function startDragging(e) {
+ g.lastRot = g.thisRot;
+ g.aball.click([e.x, e.y]);
+ dragging = true;
+}
+
+function drag(e) {
+ if (dragging) {
+ var rotationQuat = g.aball.drag([e.x, e.y]);
+ var rot_mat = g.quaternions.quaternionToRotation(rotationQuat);
+ g.thisRot = g.math.matrix4.mul(g.lastRot, rot_mat);
+
+ var m = g.root.localMatrix;
+ g.math.matrix4.setUpper3x3(m, g.thisRot);
+ g.root.localMatrix = m;
+ }
+}
+
+function stopDragging(e) {
+ dragging = false;
+}
+
+function updateViewFromCamera() {
+ var target = g.camera.target;
+ var eye = g.camera.eye;
+ var up = [0, 1, 0];
+ g.viewInfo.drawContext.view = g.math.matrix4.lookAt(eye, target, up);
+ g.eyePosParam.value = eye;
+}
+
+function scrollMe(e) {
+ if (e.deltaY > 0) {
+ g.camera.eye[0] *= 11 / 12;
+ g.camera.eye[1] *= 11 / 12;
+ g.camera.eye[2] *= 11 / 12;
+
+ } else {
+ g.camera.eye[0] *= (1 + 1 / 12);
+ g.camera.eye[1] *= (1 + 1 / 12);
+ g.camera.eye[2] *= (1 + 1 / 12);
+ }
+ updateViewFromCamera();
+}
+
+function getURL(path) {
+ var base = window.location.href;
+ var index = base.lastIndexOf('/');
+ base = base.substring(0, index + 1);
+ return base + path;
+}
+
+function setClientSize() {
+ var newWidth = g.client.width;
+ var newHeight = g.client.height;
+
+ if (newWidth != g.o3dWidth || newHeight != g.o3dHeight) {
+ g.o3dWidth = newWidth;
+ g.o3dHeight = newHeight;
+
+ // Create a perspective projection matrix
+ g.viewInfo.drawContext.projection = g.math.matrix4.perspective(
+ g.math.degToRad(45), g.o3dWidth / g.o3dHeight, 0.1, 5000);
+
+ // Sets a new area size for arcball.
+ g.aball.setAreaSize(g.o3dWidth, g.o3dHeight);
+ }
+}
+
+function onRender() {
+ setClientSize();
+}
+
+// A geo is a float where the integer part is in degrees and the fractional
+// part is in 60ths
+function geoToRad(geo) {
+ var sign = geo >= 0 ? 1 : -1;
+ geo = Math.abs(geo);
+ var integerPart = Math.floor(geo);
+ var fractionalPart = (geo % 1) * 100;
+ fractionalPart = fractionalPart / 60;
+ return g.math.degToRad(integerPart + fractionalPart);
+}
+
+function addEnergyShard(latitude, longitude, energy, height, color) {
+ // Decide how many particles we want in this shard.
+ g.trailParameters.numParticles = Math.floor(Math.random() * 10) + 1;
+ // Set the color for the shard's particles.
+ g.trailParameters.colorMult = color;
+ // Compute a base position for the shard and a velocity for the particles.
+ var matrix = g.math.matrix4.rotationZ(geoToRad(latitude));
+ g.math.matrix4.rotateY(matrix, geoToRad(-longitude));
+ g.math.matrix4.rotateZ(matrix, g.math.degToRad(90));
+ g.shardStartPosition =
+ g.math.matrix4.transformDirection(matrix, [0, g.EARTH_RADIUS, 0]);
+ g.shardVelocity = g.math.matrix4.transformDirection(matrix, [0, 2.5, 0]);
+ // Birth the particles. NOTE: the position passed in here is overridden by
+ // our per particle function.
+ g.trail.birthParticles([0, 0, 0]);
+}
+
+function shardPerParticleFunc(particleIndex, parameters) {
+ // This function sets parameters for each individual particle that is
+ // birthed. We'll calculate these in addEneryShard so all the
+ // particles genearted come out of the same position going in the
+ // same direction
+ parameters.position = g.shardStartPosition;
+ parameters.velocity = g.shardVelocity;
+ // Pick a random time for the particle to appear.
+ parameters.startTime = Math.random() * parameters.timeRange;
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.webgl.makeClients(initStep2);
+}
+/**
+ * Initializes o3d
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ var path = window.location.href;
+ var index = path.lastIndexOf('/');
+
+ g.o3dElement = clientElements[0];
+ g.o3d = g.o3dElement.o3d;
+ g.math = o3djs.math;
+ g.quaternions = o3djs.quaternions;
+ g.client = g.o3dElement.client;
+
+ g.pack = g.client.createPack();
+
+ // Create the render graph for a view.
+ g.viewInfo = o3djs.rendergraph.createBasicView(
+ g.pack,
+ g.client.root,
+ g.client.renderGraphRoot);
+
+ // Set the background color to black.
+ g.viewInfo.clearBuffer.clearColor = [0, 0, 0, 0];
+
+ // Set states for shards.
+ g.viewInfo.zOrderedState.getStateParam('CullMode').value =
+ g.o3d.State.CULL_NONE;
+ g.viewInfo.zOrderedState.getStateParam('DestinationBlendFunction').value =
+ g.o3d.State.BLENDFUNC_ONE;
+ g.viewInfo.zOrderedState.getStateParam('ZWriteEnable').value = false;
+
+ g.viewInfo.performanceDrawPass.sortMethod = g.o3d.DrawList.BY_PRIORITY;
+
+ g.lastRot = g.math.matrix4.identity();
+ g.thisRot = g.math.matrix4.identity();
+
+ var root = g.client.root;
+
+ // Create a param for the sun and eye positions that we can bind
+ // to auto update a bunch of materials.
+ g.globalParams = g.pack.createObject('ParamObject');
+ g.sunPosParam = g.globalParams.createParam('sunPos', 'ParamFloat3');
+ g.sunPosParam.value = [1000, 200, 100];
+ g.eyePosParam = g.globalParams.createParam('eyePos', 'ParamFloat3');
+
+ updateViewFromCamera();
+
+ g.aball = o3djs.arcball.create(100, 100);
+ setClientSize();
+
+ g.client.setRenderCallback(onRender);
+
+
+ // Create Materials.
+ var effectNames = [
+ "noTexture",
+ "dayOnly",
+ "nightAndDay",
+ "mask",
+ "atmosphere"
+ ];
+ g.materials = [];
+ for (var ii = 0; ii < effectNames.length; ++ii) {
+ var effectName = effectNames[ii];
+ var effect = g.pack.createObject('Effect');
+ effect.loadFromFXString(document.getElementById(effectName).value);
+
+ // Create a Material for the effect.
+ var material = g.pack.createObject('Material');
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shader to use.
+ material.effect = effect;
+
+ // Set the material's drawList
+ material.drawList = g.viewInfo.performanceDrawList;
+
+ // This will create the effects's params on the material.
+ effect.createUniformParameters(material);
+
+ // Bind the sun position to a global value so we can easily change it
+ // globally.
+ var sunParam = material.getParam('sunPos');
+ if (sunParam) {
+ sunParam.bind(g.sunPosParam);
+ }
+
+ // Save off the material.
+ g.materials.push(material);
+ }
+ g.noTextureMaterial = g.materials[0];
+ g.dayOnlyMaterial = g.materials[1];
+ g.nightAndDayMaterial = g.materials[2];
+ g.maskMaterial = g.materials[3];
+ g.atmosphereMaterial = g.materials[4];
+
+ // create samplers
+ g.samplers = [];
+ for (var ii = 0; ii < 4; ++ii) {
+ var sampler = g.pack.createObject('Sampler');
+ g.samplers[ii] = sampler;
+ }
+
+ g.daySampler = g.samplers[0];
+ g.nightSampler = g.samplers[1];
+ g.maskSampler = g.samplers[2];
+
+ // set the material samplers.
+ g.dayOnlyMaterial.getParam('daySampler').value = g.daySampler;
+ g.nightAndDayMaterial.getParam('daySampler').value = g.daySampler;
+ g.nightAndDayMaterial.getParam('nightSampler').value = g.nightSampler;
+ g.maskMaterial.getParam('daySampler').value = g.daySampler;
+ g.maskMaterial.getParam('maskSampler').value = g.maskSampler;
+ g.maskMaterial.getParam('nightSampler').value = g.nightSampler;
+
+ // Setup counters for shard animation.
+ g.shardCounter = g.pack.createObject('SecondCounter');
+
+ // Setup counters to fade in textures.
+ g.flatToDayCounter = g.pack.createObject('SecondCounter');
+ g.flatToDayCounter.end = 1;
+ g.flatToDayCounter.multiplier = 0.5;
+ g.flatToDayCounter.countMode = g.o3d.Counter.ONCE;
+ g.flatToDayCounter.running = false;
+ g.flatToDayCounter.addCallback(1, loadNightTexture);
+ g.dayOnlyMaterial.getParam('time').bind(
+ g.flatToDayCounter.getParam('count'));
+
+ g.dayOnlyToNightCounter = g.pack.createObject('SecondCounter');
+ g.dayOnlyToNightCounter.end = 1;
+ g.dayOnlyToNightCounter.multiplier = 0.5;
+ g.dayOnlyToNightCounter.countMode = g.o3d.Counter.ONCE;
+ g.dayOnlyToNightCounter.running = false;
+ g.dayOnlyToNightCounter.addCallback(1, loadMaskTexture);
+ g.nightAndDayMaterial.getParam('time').bind(
+ g.dayOnlyToNightCounter.getParam('count'));
+
+ g.noMaskToMaskCounter = g.pack.createObject('SecondCounter');
+ g.noMaskToMaskCounter.end = 1;
+ g.noMaskToMaskCounter.multiplier = 0.5;
+ g.noMaskToMaskCounter.countMode = g.o3d.Counter.ONCE;
+ g.noMaskToMaskCounter.running = false;
+ g.maskMaterial.getParam('time').bind(
+ g.noMaskToMaskCounter.getParam('count'));
+
+ // Create a sphere at the origin for the earth.
+ var earth = o3djs.primitives.createSphere(g.pack,
+ g.noTextureMaterial,
+ 25,
+ 50,
+ 50);
+
+ // Get a the element so we can set its material later.
+ g.earthPrimitive = earth.elements[0];
+ g.atmosphereState = g.pack.createObject('State');
+ g.atmosphereState.getStateParam('AlphaBlendEnable').value = true;
+ g.atmosphereState.getStateParam('SourceBlendFunction').value =
+ g.o3d.State.BLENDFUNC_SOURCE_ALPHA;
+ g.atmosphereState.getStateParam('DestinationBlendFunction').value =
+ g.o3d.State.BLENDFUNC_INVERSE_SOURCE_ALPHA;
+ g.atmosphereState.getStateParam('ZWriteEnable').value = false;
+ g.atmosphereMaterial.state = g.atmosphereState;
+
+ g.root = g.pack.createObject('Transform');
+ g.root.parent = g.client.root;
+ g.earth = g.pack.createObject('Transform');
+ g.earth.addShape(earth);
+ g.earth.parent = g.root;
+
+ // Create a sphere at the origin for the atmosphere.
+ var atmosphere = o3djs.primitives.createSphere(g.pack,
+ g.atmosphereMaterial,
+ 26,
+ 50,
+ 50);
+ g.atmospherePrimitive = atmosphere.elements[0];
+ g.atmospherePrimitive.priority = 1;
+ g.atmosphere = g.pack.createObject('Transform');
+ g.atmosphere.addShape(atmosphere);
+ g.atmosphere.parent = g.root;
+
+ // Set shading language.
+ o3djs.particles.setLanguage('glsl');
+
+ // Make a particle system
+ g.particleSystem = o3djs.particles.createParticleSystem(
+ g.pack,
+ g.viewInfo,
+ g.shardCounter.getParam('count'),
+ g.math.pseudoRandom);
+
+ // Make a transform for the particle emitter.
+ var transform = g.pack.createObject('Transform');
+ transform.parent = g.root;
+ // Make a single pixel white texture as our particle.
+ var texture = g.pack.createTexture2D(1, 1, g.o3d.Texture.ARGB8, 1, false);
+ texture.set(0, [1, 1, 1, 1]);
+
+ // Setup some basic parameters for our particles.
+ g.trailParameters = {
+ lifeTime: 4, // each particle lasts 4 seconds
+ timeRange: 4, // The clock is modded by this so the *world* clock repeats
+ // every 4 seconds making each particle reappear
+ startSize: 0.1, // Size to start a particle
+ endSize: 0.1, // Size to end a particle
+ // (the particle lerps in side between start and end)
+ };
+
+ // Create a trail. Trails are just a particle system that lets us more
+ // easily birth individual particles.
+ g.trail = g.particleSystem.createTrail(
+ transform, // Transform for particles.
+ 10000, // Total number of particles in system. If 10001
+ // particles are birthed, the oldest particle is
+ // reused.
+ g.trailParameters, // Our static birth parameters.
+ texture, // The texture to use.
+ shardPerParticleFunc); // A function to set parameters per particle.
+ g.trail.setState(o3djs.particles.ParticleStateIds.BLEND);
+ // This ramp makes the particles full bright for 4/5ths of their lifespan
+ // and they fade out during the last 1/5th.
+ g.trail.setColorRamp(
+ [1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 1, 0]);
+
+
+ addEnergyShard(0, 0, 1, 1, [1, 1, 1, 1]);
+
+ // Honolulu, Hawaii, 21, 18, 157, 50
+ addEnergyShard(21.18, 157.50, 1, 1, [0, 1, 0, 1]);
+ // San Francisco, Calif. 37 47 122 26
+ addEnergyShard(37.47, 122.26, 1, 1, [1, 0.5, 0.5, 1]);
+
+ for (var ii = 0; ii < 24; ++ii) {
+ var longitude = Math.random() * 360;
+ var latitude = Math.random() * 360 - 180;
+ var color = [ Math.random() * 0.5 + 0.2,
+ Math.random() * 0.5 + 0.2,
+ Math.random() * 0.5 + 0.2,
+ 1 ];
+ // Make a least 1 color component full bright.
+ color[Math.floor(Math.random() * 2.99)] = 1;
+ for (var jj = 0; jj < 24; ++jj) {
+ addEnergyShard(latitude + (Math.random() - 0.5) * 10,
+ longitude + (Math.random() - 0.5) * 10,
+ 1,
+ 1,
+ color);
+ }
+ }
+
+ o3djs.event.addEventListener(g.o3dElement, 'mousedown', startDragging);
+ o3djs.event.addEventListener(g.o3dElement, 'mousemove', drag);
+ o3djs.event.addEventListener(g.o3dElement, 'mouseup', stopDragging);
+ o3djs.event.addEventListener(g.o3dElement, 'wheel', scrollMe);
+
+ loadDayTexture();
+}
+
+function loadTexture(path, callback) {
+ var url = getURL(path);
+ o3djs.io.loadTexture(g.pack, url, function(texture, exception) {
+ if (exception) {
+ alert(exception);
+ } else {
+ callback(texture);
+ }
+ });
+}
+
+function loadDayTexture() {
+ loadTexture('assets/earth.jpg', function(texture) {
+ g.daySampler.texture = texture;
+ g.earthPrimitive.material = g.dayOnlyMaterial;
+ g.flatToDayCounter.running = true;
+ });
+}
+
+function loadNightTexture() {
+ loadTexture('assets/night.jpg', function(texture) {
+ g.nightSampler.texture = texture;
+ g.earthPrimitive.material = g.nightAndDayMaterial;
+ g.dayOnlyToNightCounter.running = true;
+ });
+}
+
+function loadMaskTexture() {
+ loadTexture('assets/earth-large-with-ocean-mask.png', function(texture) {
+ g.maskSampler.texture = texture;
+ g.earthPrimitive.material = g.maskMaterial;
+ g.noMaskToMaskCounter.running = true;
+ g_finished = true; // for selenium
+ });
+}
+
+function uninit() {
+ // TODO: We should clean up any counters that have callbacks here.
+ if (g.client) {
+ g.client.cleanup();
+ }
+}
+</script>
+<!--<h1>
+Google Trends Visualizer.
+</h1>-->
+<div id="o3d" style="width:100%; height: 100%;"></div>
+<div style="display:none">
+<textarea id="noTexture" name="fx" cols="80" rows="20">
+uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform mat4 view;
+
+uniform vec3 sunPos;
+
+attribute vec4 position;
+attribute vec3 normal;
+
+varying vec4 v_pos;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+void main() {
+ gl_Position = worldViewProjection * position;
+ v_normal = (world * vec4(normal, 0)).xyz;
+ vec3 worldPos = (world * position).xyz;
+ v_sun = sunPos - worldPos;
+ v_view = (view[3].xyz- worldPos);
+ v_pos = gl_Position;
+}
+
+// #o3d SplitMarker
+
+varying vec4 v_pos;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+vec4 lit(float l, float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+
+void main() {
+ vec3 norm = normalize(v_normal);
+ vec3 sun = normalize(v_sun);
+ float light = dot(norm, sun);
+ float lightSign = sign(light);
+ float dayNight = 1.0 - sqrt(abs(light));
+ dayNight = dayNight * dayNight;
+ dayNight = (1.0 - dayNight) * lightSign;
+ dayNight = clamp(dayNight, 0.0, 1.0);
+ vec3 view = normalize(v_view);
+ vec3 r = normalize(reflect(norm, sun));
+ vec4 litR = vec4(lit(light, dot(r, view), 0.0).y);
+ vec3 day = vec3(0.5, 0.5, 1.0) * litR.y + vec3(1,1,1) * litR.z;
+ vec3 night = vec3(0.2, 0.2, 0.5);
+ gl_FragColor = vec4(mix(night, day, dayNight),1);
+}
+
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+<textarea id="dayOnly" name="fx" cols="80" rows="20">
+uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform mat4 view;
+
+uniform vec3 sunPos;
+
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord0;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+void main() {
+ gl_Position = (worldViewProjection * position);
+ v_uv = texCoord0;
+ v_normal = (world * vec4(normal, 0)).xyz;
+ vec3 worldPos = (world * position).xyz;
+ v_sun = sunPos - worldPos;
+ v_view = (view[3].xyz - worldPos);
+}
+
+// #o3d SplitMarker
+
+uniform float time;
+
+uniform sampler2D daySampler;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+vec4 lit(float l, float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+
+void main() {
+ vec3 norm = normalize(v_normal);
+ vec3 sun = normalize(v_sun);
+ float light = dot(norm, sun);
+ float lightSign = sign(light);
+ float dayNight = 1.0 - sqrt(abs(light));
+ dayNight = dayNight * dayNight;
+ dayNight = (1.0 - dayNight) * lightSign;
+ dayNight = clamp(dayNight, 0.0, 1.0);
+ vec3 view = normalize(v_view);
+ vec3 r = normalize(reflect(norm, sun));
+ vec4 litR = vec4(lit(light, dot(r, view), 0.0).y);
+ vec3 earth = texture2D(daySampler, v_uv).xyz;
+ vec3 day = mix(vec3(0.5, 0.5, 1.0), earth, time);
+ day = day * litR.y + vec3(1,1,1) * litR.z;
+ vec3 night = mix(vec3(0.2, 0.2, 0.5), earth * 0.3, time);
+ gl_FragColor = vec4(mix(night, day, dayNight),1);
+}
+
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+<textarea id="nightAndDay" name="fx" cols="80" rows="20">
+uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform mat4 view;
+
+uniform vec3 sunPos;
+
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord0;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+void main() {
+ gl_Position = worldViewProjection * position;
+ v_uv = texCoord0;
+ v_normal = (world * vec4(normal, 0)).xyz;
+ vec3 worldPos = (world * position).xyz;
+ v_sun = sunPos - worldPos;
+ v_view = (view[3].xyz - worldPos);
+}
+
+// #o3d SplitMarker
+
+uniform float time;
+
+uniform sampler2D daySampler;
+uniform sampler2D nightSampler;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+vec4 lit(float l, float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+
+void main() {
+ vec3 norm = normalize(v_normal);
+ vec3 sun = normalize(v_sun);
+ float light = dot(norm, sun);
+ float lightSign = sign(light);
+ float dayNight = 1.0 - sqrt(abs(light));
+ dayNight = dayNight * dayNight;
+ dayNight = (1.0 - dayNight) * lightSign;
+ dayNight = clamp(dayNight, 0.0, 1.0);
+ vec3 view = normalize(v_view);
+ vec3 r = normalize(reflect(norm, sun));
+ vec4 litR = vec4(lit(light, dot(r, view), 0.0).y);
+ vec3 earth = texture2D(daySampler, v_uv).xyz;
+ vec3 day = texture2D(daySampler, v_uv).xyz;
+ vec3 night = mix(day * 0.3, texture2D(nightSampler, v_uv).xyz, time);
+ day = day * litR.y + vec3(1,1,1) * litR.z;
+ gl_FragColor = vec4(mix(night, day, dayNight),1);
+}
+
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+<!--
+This shader renders the ocean different then the non-ocean using a mask
+stored in the alpha channel of the maskSampler
+-->
+<textarea id="mask" name="fx" cols="80" rows="20">
+uniform mat4 worldViewProjection;
+uniform mat4 world;
+uniform mat4 view;
+
+uniform vec3 sunPos;
+
+attribute vec4 position;
+attribute vec3 normal;
+attribute vec2 texCoord0;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+void main() {
+ gl_Position = worldViewProjection * position;
+ v_uv = texCoord0;
+ v_normal = (world * vec4(normal, 0)).xyz;
+ vec3 worldPos = (world * position).xyz;
+ v_sun = sunPos - worldPos;
+ v_view = (view[3].xyz - worldPos);
+}
+
+// #o3d SplitMarker
+
+uniform float time;
+
+uniform sampler2D daySampler;
+uniform sampler2D nightSampler;
+uniform sampler2D maskSampler;
+
+varying vec2 v_uv;
+varying vec3 v_normal;
+varying vec3 v_sun;
+varying vec3 v_view;
+
+vec4 lit(float l, float h, float m) {
+ return vec4(1.0,
+ max(l, 0.0),
+ (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+ 1.0);
+}
+
+void main() {
+ vec3 norm = normalize(v_normal);
+ vec3 sun = normalize(v_sun);
+ float light = dot(norm, sun);
+ float lightSign = sign(light);
+ float dayNight = 1.0 - sqrt(abs(light));
+ dayNight = dayNight * dayNight;
+ dayNight = (1.0 - dayNight) * lightSign;
+ dayNight = clamp(dayNight, 0.0, 1.0);
+ vec3 view = normalize(v_view);
+ vec3 r = normalize(reflect(norm, sun));
+ vec4 litR = vec4(lit(light, dot(r, view), 0.0).y);
+ vec3 earth = texture2D(daySampler, v_uv).xyz;
+ vec4 mask = texture2D(maskSampler, v_uv);
+ vec3 day = mix(texture2D(daySampler, v_uv).xyz,
+ mask.xyz, time);
+ vec3 night = texture2D(nightSampler, v_uv).xyz;
+ day = day * litR.y + vec3(1,1,1) * litR.z * (1.0 - mask.w * time);
+ vec3 color = mix(night, day, dayNight);
+ gl_FragColor = vec4(color, 1);
+}
+
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+<textarea id="atmosphere" name="fx" cols="80" rows="20">
+uniform mat4 worldViewProjection;
+uniform mat4 worldView;
+
+attribute vec4 position;
+attribute vec3 normal;
+
+varying vec3 v_normal;
+
+void main() {
+ gl_Position = worldViewProjection * position;
+ v_normal = normalize((worldView * vec4(normal,0)).xyz);
+}
+
+// #o3d SplitMarker
+
+varying vec3 v_normal;
+
+void main() {
+ float n = 1.0 - log(2.0 * normalize(v_normal).z);
+ gl_FragColor = vec4(0.3, 0.3, 1, n * n * n * n);
+}
+
+// #o3d MatrixLoadOrder RowMajor
+</textarea>
+</div>
+</body>
+</html>
+
+