summaryrefslogtreecommitdiffstats
path: root/o3d/samples/o3d-webgl-samples
diff options
context:
space:
mode:
authorpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-12 21:00:00 +0000
committerpetersont@google.com <petersont@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-12 21:00:00 +0000
commite512583b79e366db399a6566964412bb6e5af823 (patch)
treee15e3c05e273a0366caf2fcbc5689ae377b3e877 /o3d/samples/o3d-webgl-samples
parenta37a999f87eed77b08e7e1b6bdb86d406f31ea9b (diff)
downloadchromium_src-e512583b79e366db399a6566964412bb6e5af823.zip
chromium_src-e512583b79e366db399a6566964412bb6e5af823.tar.gz
chromium_src-e512583b79e366db399a6566964412bb6e5af823.tar.bz2
Added textures, texture samplers and render targets to o3d-webgl. Also fixed bugs, added calls to parent class constructor to classes that didn't have them before, added a few demos to exhibit/test textures and render surfaces.
Review URL: http://codereview.chromium.org/856004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41482 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/samples/o3d-webgl-samples')
-rw-r--r--o3d/samples/o3d-webgl-samples/hellocube-colors.html343
-rw-r--r--o3d/samples/o3d-webgl-samples/hellocube-textures.html433
-rw-r--r--o3d/samples/o3d-webgl-samples/shadow-map.html636
3 files changed, 1412 insertions, 0 deletions
diff --git a/o3d/samples/o3d-webgl-samples/hellocube-colors.html b/o3d/samples/o3d-webgl-samples/hellocube-colors.html
new file mode 100644
index 0000000..2af5699
--- /dev/null
+++ b/o3d/samples/o3d-webgl-samples/hellocube-colors.html
@@ -0,0 +1,343 @@
+<!--
+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.
+-->
+
+<!--
+This sample creates an O3D area with a spinning cube. The user
+can change the color of the cube by clicking on one of the buttons that appear
+at the bottom of the page. This sample demonstrates how to use O3D Params
+to change the values of uniform parameters used by shaders.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Hello Square Colors: Getting started with O3D, take 2.
+</title>
+<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.rendergraph');
+
+// Events
+// Run the init() function once the page has finished loading.
+// Run the uninit() function when the page has is unloaded.
+window.onload = init;
+window.onunload = uninit;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_pack;
+var g_client;
+var g_clock = 0;
+var g_timeMult = 1;
+var g_finished = false; // for selenium testing
+
+var g_cubeTransform;
+var g_cubeColorParam;
+
+/**
+ * Changes the color of the cube.
+ * @param red red component of the color
+ * @param green green component of the color
+ * @param blue blue component of the color
+ */
+function changeColor(red, green, blue) {
+ // Set the rgb color values and alpha = 1
+ g_cubeColorParam.value = [red, green, blue, 1];
+}
+
+/**
+ * Creates an O3D shape representing a cube. The shape consists of
+ * a single primitive with eight vertices and 12 triangles (two for each face
+ * of the cube).
+ * @param {o3d.Material} material the material used by the primitive.
+ * @return {o3d.Shape} The Shape object created.
+ */
+function createCube(material) {
+ // Create a Shape object for the mesh.
+ var cubeShape = g_pack.createObject('Shape');
+
+ // Create the Primitive that will contain the geometry data for
+ // the cube.
+ var cubePrimitive = g_pack.createObject('Primitive');
+
+ // Create a StreamBank to hold the streams of vertex data.
+ var streamBank = g_pack.createObject('StreamBank');
+
+ // Assign the material that was passed in to the primitive.
+ cubePrimitive.material = material;
+
+ // Assign the Primitive to the Shape.
+ cubePrimitive.owner = cubeShape;
+
+ // Assign the StreamBank to the Primitive.
+ cubePrimitive.streamBank = streamBank;
+
+ // The cube is made of 12 triangles. There's eight vertices in total which
+ // are shared between the face triangles.
+ cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
+ cubePrimitive.numberPrimitives = 12; // 12 triangles
+ cubePrimitive.numberVertices = 8; // 8 vertices in total
+
+ // Generate the draw element for the cube primitive.
+ cubePrimitive.createDrawElement(g_pack, null);
+
+ // Create a javascript array that stores the X, Y and Z coordinates of each
+ // of the 8 corners of the cube.
+ var positionArray = [
+ -0.5, -0.5, 0.5, // vertex 0
+ 0.5, -0.5, 0.5, // vertex 1
+ -0.5, 0.5, 0.5, // vertex 2
+ 0.5, 0.5, 0.5, // vertex 3
+ -0.5, 0.5, -0.5, // vertex 4
+ 0.5, 0.5, -0.5, // vertex 5
+ -0.5, -0.5, -0.5, // vertex 6
+ 0.5, -0.5, -0.5 // vertex 7
+ ];
+
+ // The following array defines how vertices are to be put together to form
+ // the triangles that make up the cube's faces. In the index array, every
+ // three elements define a triangle. So for example vertices 0, 1 and 2
+ // make up the first triangle, vertices 2, 1 and 3 the second one, etc.
+ var indicesArray = [
+ 0, 1, 2, // face 1
+ 2, 1, 3,
+ 2, 3, 4, // face 2
+ 4, 3, 5,
+ 4, 5, 6, // face 3
+ 6, 5, 7,
+ 6, 7, 0, // face 4
+ 0, 7, 1,
+ 1, 7, 3, // face 5
+ 3, 7, 5,
+ 6, 0, 4, // face 6
+ 4, 0, 2
+ ];
+
+ // Create buffers containing the vertex data.
+ var positionsBuffer = g_pack.createObject('VertexBuffer');
+ var positionsField = positionsBuffer.createField('FloatField', 3);
+ positionsBuffer.set(positionArray);
+
+ var indexBuffer = g_pack.createObject('IndexBuffer');
+ indexBuffer.set(indicesArray);
+
+ // Associate the positions Buffer with the StreamBank.
+ streamBank.setVertexStream(
+ g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
+ 0, // semantic index: First (and only) position stream
+ positionsField, // field: the field this stream uses.
+ 0); // start_index: How many elements to skip in the
+ // field.
+
+ // Associate the triangle indices Buffer with the primitive.
+ cubePrimitive.indexBuffer = indexBuffer;
+
+ return cubeShape;
+}
+
+/**
+ * This method gets called every time O3D renders a frame. Here's where
+ * we update the cube's transform to make it spin.
+ * @param {o3d.RenderEvent} renderEvent The render event object that gives
+ * us the elapsed time since the last time a frame was rendered.
+ */
+function renderCallback(renderEvent) {
+ g_clock += renderEvent.elapsedTime * g_timeMult;
+ // Rotate the cube around the Y axis.
+ g_cubeTransform.identity();
+ g_cubeTransform.rotateY(2.0 * g_clock);
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.webgl.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D, creates the cube and sets up the transform and
+ * render graphs.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Initializes global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_client = o3dElement.client;
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up a perspective projection.
+ viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree fov.
+ g_client.width / g_client.height,
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ [0, 1, 5], // eye
+ [0, 0, 0], // target
+ [0, 1, 0]); // up
+
+ // Create an Effect object and initialize it using the shaders from the
+ // text area.
+ var cubeEffect = g_pack.createObject('Effect');
+ var vertexShaderString = document.getElementById('vshader').value;
+ var pixelShaderString = document.getElementById('pshader').value;
+ cubeEffect.loadVertexShaderFromString(vertexShaderString);
+ cubeEffect.loadPixelShaderFromString(pixelShaderString);
+
+ // Create a Material for the mesh.
+ var cubeMaterial = g_pack.createObject('Material');
+
+ // Set the material's drawList.
+ cubeMaterial.drawList = viewInfo.performanceDrawList;
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shaders to use.
+ cubeMaterial.effect = cubeEffect;
+
+ // Create an O3D Param on the material for every uniform used by the
+ // shader.
+ cubeEffect.createUniformParameters(cubeMaterial);
+
+ // Get the color parameter from the material and set its value to red.
+ g_cubeColorParam = cubeMaterial.getParam('color');
+ g_cubeColorParam.value = [1, 0, 0, 1];
+
+ // Create the Shape for the cube mesh and assign its material.
+ var cubeShape = createCube(cubeMaterial);
+
+ // Create a new transform and parent the Shape under it.
+ g_cubeTransform = g_pack.createObject('Transform');
+ g_cubeTransform.addShape(cubeShape);
+
+ // Parent the cube's transform to the client root.
+ g_cubeTransform.parent = g_client.root;
+
+ // Set our render callback for animation.
+ // This sets a function to be executed every time a frame is rendered.
+ g_client.setRenderCallback(renderCallback);
+
+ g_finished = true; // for selenium testing.
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function uninit() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+
+</script>
+</head>
+<body>
+<h1>Hello Square: Colors</h1>
+This example shows how to use parameters to the color output of a shader.
+<br/>
+
+
+<!-- Start of O3D plugin -->
+<div id="o3d" width="600px" height="600px"></div>
+<!-- End of O3D plugin -->
+
+<form name="default_form" action="#" method="get">
+ <p>
+ Change color:
+ <input type="button" value="Red" onclick="changeColor(1,0,0);" />
+ <input type="button" value="Green" onclick="changeColor(0,1,0);" />
+ <input type="button" value="Blue" onclick="changeColor(0,0,1);" />
+ <input type="button" value="Yellow" onclick="changeColor(1,1,0);" />
+ <input type="button" value="Cyan" onclick="changeColor(0,1,1);" />
+ <input type="button" value="Purple" onclick="changeColor(1,0,1);" />
+ <input type="button" value="White" onclick="changeColor(1,1,1);" />
+ </p>
+</form>
+
+<!-- Don't render the textarea -->
+<div style="display:none">
+<!-- Start of effect -->
+<textarea id="vshader">
+ // World View Projection matrix that will transform the input vertices
+ // to screen space.
+ uniform mat4 worldViewProjection;
+
+ // input parameters for our vertex shader
+ attribute vec4 position;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ // Multiply the vertex positions by the worldViewProjection matrix to
+ // transform them to screen space.
+ gl_Position = worldViewProjection * position;
+ }
+
+</textarea>
+<textarea id="pshader">
+ // Color to draw with.
+ uniform vec4 color;
+
+ /**
+ * This pixel shader just returns the color red.
+ */
+ void main() {
+ gl_FragColor = color;
+ }
+
+ // Here we tell our effect file *which* functions are
+ // our vertex and pixel shaders.
+</textarea>
+<!-- End of effect -->
+</div>
+</body>
+</html>
diff --git a/o3d/samples/o3d-webgl-samples/hellocube-textures.html b/o3d/samples/o3d-webgl-samples/hellocube-textures.html
new file mode 100644
index 0000000..0c20cf4
--- /dev/null
+++ b/o3d/samples/o3d-webgl-samples/hellocube-textures.html
@@ -0,0 +1,433 @@
+<!--
+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.
+-->
+
+<!--
+This sample creates an O3D area with a textured cube in the middle. The
+user can specify the URL where the texture image will be picked from.
+This sample is a simple demonstration of texture usage in O3D.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Hello Square Textures: Getting started with O3D, take 3.
+</title>
+<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.rendergraph');
+o3djs.require('o3djs.io');
+
+// Events
+// Run the init() function once the page has finished loading.
+// Run the uninit() function when the page is unloaded.
+window.onload = init;
+window.onunload = uninit;
+
+// global variables
+var g_o3d;
+var g_math;
+var g_pack;
+var g_client;
+var g_cubeTransform;
+var g_sampler;
+var g_clock = 0;
+var g_timeMult = 1;
+var g_finished = false; // for selenium testing
+var g_textureLoadDenied = false; // also for selenium testing
+
+/**
+ * Creates an O3D shape representing a cube.
+ * @param {o3d.Material} material the material used by the primitive.
+ * @return {o3d.Shape} The Shape object created.
+ */
+function createCube(material) {
+ // Create a Shape object for the mesh.
+ var cubeShape = g_pack.createObject('Shape');
+
+ // Create the Primitive that will contain the geometry data for
+ // the cube.
+ var cubePrimitive = g_pack.createObject('Primitive');
+
+ // Create a StreamBank to hold the streams of vertex data.
+ var streamBank = g_pack.createObject('StreamBank');
+
+ // Assign the material that was passed in to the primitive.
+ cubePrimitive.material = material;
+
+ // Assign the Primitive to the Shape.
+ cubePrimitive.owner = cubeShape;
+
+ // Assign the StreamBank to the Primitive.
+ cubePrimitive.streamBank = streamBank;
+
+ // The cube is made of 12 triangles (6 faces x 2 triangles per face)
+ cubePrimitive.primitiveType = g_o3d.Primitive.TRIANGLELIST;
+ cubePrimitive.numberPrimitives = 12; // 12 triangles
+
+ // Vertices used by each triangle must specify both a position and texture
+ // coordinates. We cannot share vertices between adjacent cube faces since
+ // while their positions are the same, their texture coordinates are
+ // different. We therefore create 24 vertices, 4 for each of the cube's
+ // six faces.
+ cubePrimitive.numberVertices = 24;
+
+ // Generate the draw element for the cube primitive.
+ cubePrimitive.createDrawElement(g_pack, null);
+
+ // Create a javascript array that stores the X, Y and Z coordinates of each
+ // of the 24 vertices used by the cube.
+ var positionArray = [
+ -0.5, -0.5, 0.5,
+ 0.5, -0.5, 0.5,
+ 0.5, 0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ 0.5, 0.5, 0.5,
+ 0.5, 0.5, -0.5,
+ -0.5, 0.5, -0.5,
+ -0.5, 0.5, -0.5,
+ 0.5, 0.5, -0.5,
+ 0.5, -0.5, -0.5,
+ -0.5, -0.5, -0.5,
+ -0.5, -0.5, -0.5,
+ 0.5, -0.5, -0.5,
+ 0.5, -0.5, 0.5,
+ -0.5, -0.5, 0.5,
+ 0.5, -0.5, 0.5,
+ 0.5, -0.5, -0.5,
+ 0.5, 0.5, -0.5,
+ 0.5, 0.5, 0.5,
+ -0.5, -0.5, -0.5,
+ -0.5, -0.5, 0.5,
+ -0.5, 0.5, 0.5,
+ -0.5, 0.5, -0.5
+ ];
+
+ // The following array stores the texture coordinates (u, v) for each vertex.
+ // These coordinates are used by the shader when displaying the texture image
+ // on the mesh triangles.
+ var texCoordsArray = [
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1,
+ 0, 0,
+ 1, 0,
+ 1, 1,
+ 0, 1
+ ];
+
+ // The following array defines how vertices are to be put together to form
+ // the triangles that make up the cube's faces. In the index array, every
+ // three elements define a triangle. So for example vertices 0, 1 and 2
+ // make up the first triangle, vertices 0, 2 and 3 the second one, etc.
+ var indicesArray = [
+ 0, 1, 2,
+ 0, 2, 3,
+ 4, 5, 6,
+ 4, 6, 7,
+ 8, 9, 10,
+ 8, 10, 11,
+ 12, 13, 14,
+ 12, 14, 15,
+ 16, 17, 18,
+ 16, 18, 19,
+ 20, 21, 22,
+ 20, 22, 23
+ ];
+
+ // Create buffers containing the vertex data.
+ var positionsBuffer = g_pack.createObject('VertexBuffer');
+ var positionsField = positionsBuffer.createField('FloatField', 3);
+ positionsBuffer.set(positionArray);
+
+ var texCoordsBuffer = g_pack.createObject('VertexBuffer');
+ var texCoordsField = texCoordsBuffer.createField('FloatField', 2);
+ texCoordsBuffer.set(texCoordsArray);
+
+ var indexBuffer = g_pack.createObject('IndexBuffer');
+ indexBuffer.set(indicesArray);
+
+ // Associate the positions buffer with the StreamBank.
+ streamBank.setVertexStream(
+ g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions
+ 0, // semantic index: First (and only) position stream
+ positionsField, // field: the field this stream uses.
+ 0); // start_index: How many elements to skip in the
+ // field.
+
+ // Associate the texture coordinates buffer with the primitive.
+ streamBank.setVertexStream(
+ g_o3d.Stream.TEXCOORD, // semantic
+ 0, // semantic index
+ texCoordsField, // field
+ 0); // start_index
+
+ // Associate the triangle indices Buffer with the primitive.
+ cubePrimitive.indexBuffer = indexBuffer;
+
+ return cubeShape;
+}
+
+/**
+ * This method gets called every time O3D renders a frame. Here's where
+ * we update the cube's transform to make it spin.
+ * @param {o3d.RenderEvent} renderEvent The render event object that gives
+ * us the elapsed time since the last time a frame was rendered.
+ */
+function renderCallback(renderEvent) {
+ g_clock += renderEvent.elapsedTime * g_timeMult;
+ // Rotate the cube around the Y axis.
+ g_cubeTransform.identity();
+ g_cubeTransform.rotateY(2.0 * g_clock);
+}
+
+/**
+ * Creates the client area.
+ */
+function init() {
+ o3djs.webgl.makeClients(initStep2);
+}
+
+/**
+ * Initializes O3D, creates the quad and sets up the transform and
+ * render graphs.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function initStep2(clientElements) {
+ // Set the texture URL.
+ path = '../assets/texture_b3.jpg';
+ var url = document.getElementById("url").value = path;
+
+ // Initialize global variables and libraries.
+ var o3dElement = clientElements[0];
+ g_client = o3dElement.client;
+ g_o3d = o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+
+ // Create the render graph for a view.
+ var viewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_client.renderGraphRoot);
+
+ // Set up a perspective projection.
+ viewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree fov.
+ g_client.width / g_client.height,
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ viewInfo.drawContext.view = g_math.matrix4.lookAt(
+ [0, 1, 5], // eye
+ [0, 0, 0], // target
+ [0, 1, 0]); // up
+
+ // Create an Effect object and initialize it using the shaders from the
+ // text area.
+ var cubeEffect = g_pack.createObject('Effect');
+ var vertexShaderString = document.getElementById('vshader').value;
+ var pixelShaderString = document.getElementById('pshader').value;
+ cubeEffect.loadVertexShaderFromString(vertexShaderString);
+ cubeEffect.loadPixelShaderFromString(pixelShaderString);
+
+ // Create a Material for the mesh.
+ var cubeMaterial = g_pack.createObject('Material');
+
+ // Set the material's drawList.
+ cubeMaterial.drawList = viewInfo.performanceDrawList;
+
+ // Apply our effect to this material. The effect tells the 3D hardware
+ // which shaders to use.
+ cubeMaterial.effect = cubeEffect;
+
+ // Create an O3D Param on the material for every uniform used by the
+ // shader.
+ cubeEffect.createUniformParameters(cubeMaterial);
+
+ // Get the material's sampler parameter so that we can set the texture value
+ // to it.
+ var samplerParam = cubeMaterial.getParam('texSampler0');
+
+ // Create a Sampler object and set the min filtering to ANISOTROPIC. This
+ // will improve the quality of the rendered texture when viewed at an angle.
+ g_sampler = g_pack.createObject('Sampler');
+ g_sampler.minFilter = g_o3d.Sampler.ANISOTROPIC;
+ g_sampler.maxAnisotropy = 4;
+ samplerParam.value = g_sampler;
+
+ // Create the Shape for the cube mesh and assign its material.
+ var cubeShape = createCube(cubeMaterial);
+
+ // Create a new transform and parent the Shape under it.
+ g_cubeTransform = g_pack.createObject('Transform');
+ g_cubeTransform.addShape(cubeShape);
+
+ // Note that we don't parent the transform until the texture is
+ // succesfully loaded because we don't want the system
+ // to try the draw the shape without its required texture.
+
+ // Set our render callback for animation.
+ // This sets a function to be executed every time a frame is rendered.
+ g_client.setRenderCallback(renderCallback);
+
+ // Set the initial texture.
+ changeTexture();
+}
+
+/**
+ * Fetches the bitmap pointed to by the URL supplied by the user, creates
+ * an O3D Texture object with it updates the Sampler used by the material
+ * to point to the newly created texture.
+ */
+function changeTexture() {
+ var textureUrl = document.getElementById('url').value;
+ o3djs.io.loadTexture(g_pack, textureUrl, function(texture, exception) {
+ // Remove the currently used texture from the pack so that when it's not
+ // referenced anymore, it can get destroyed.
+ if (g_sampler.texture)
+ g_pack.removeObject(g_sampler.texture);
+
+ // Because the loading is asynchronous an exception is not thrown but is
+ // instead passed on failure.
+ if (exception) {
+ g_sampler.texture = null;
+
+ g_textureLoadDenied = true; // for selenium testing.
+ } else {
+ // Set the texture on the sampler object to the newly created texture
+ // object returned by the request.
+ g_sampler.texture = texture;
+
+ // We can now safely add the cube transform to the root of the
+ // scenegraph since it now has a valid texture. If the transform
+ // is already parented under the root, the call will have no effect.
+ g_cubeTransform.parent = g_client.root;
+
+ g_finished = true; // for selenium testing.
+ }
+ });
+}
+
+/**
+ * Removes any callbacks so they don't get called after the page has unloaded.
+ */
+function uninit() {
+ if (g_client) {
+ g_client.cleanup();
+ }
+}
+
+</script>
+</head>
+<body>
+<h1>Hello Cube: Textures</h1>
+This example shows how texture map a cube using an image fetched from a URL.
+<br/>
+
+
+<!-- Start of O3D plugin -->
+<div id="o3d" width="600px" height="600px"></div>
+<!-- End of O3D plugin -->
+<br />
+Image URL: <input type="text" id="url" size="100">
+<input type="button" id="updateButton" onclick="changeTexture();" value="Update Texture"><BR>
+
+<!-- Don't render the textarea -->
+<div style="display:none">
+<!-- Start of effect -->
+<textarea id="vshader">
+ // World View Projection matrix that will transform the input vertices
+ // to screen space.
+ uniform mat4 worldViewProjection;
+
+ // input parameters for our vertex shader
+ attribute vec4 position;
+ attribute vec2 texCoord0;
+
+ varying vec2 uvs;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ // Multiply the vertex positions by the worldViewProjection matrix to
+ // transform them to screen space.
+ gl_Position = worldViewProjection * position;
+ uvs = texCoord0;
+ }
+
+</textarea>
+<textarea id="pshader">
+
+ // Color to draw with.
+ uniform sampler2D texSampler0;
+
+ varying vec2 uvs;
+
+ /**
+ * This pixel shader just returns the color red.
+ */
+ void main() {
+ gl_FragColor = texture2D(texSampler0, uvs);
+ }
+</textarea>
+<!-- End of effect -->
+</div>
+</body>
+</html>
diff --git a/o3d/samples/o3d-webgl-samples/shadow-map.html b/o3d/samples/o3d-webgl-samples/shadow-map.html
new file mode 100644
index 0000000..2bf81cc
--- /dev/null
+++ b/o3d/samples/o3d-webgl-samples/shadow-map.html
@@ -0,0 +1,636 @@
+<!--
+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.
+-->
+
+<!--
+This sample uses a custom render graph to implement a basic shadow map
+algorithm.
+
+The technique works by rendering the scene in two passes. The first pass
+renders the geometry in the scene with a shader that colors each pixel a shade
+of gray representing how far the rendered point is from the light source. That
+image, the shadow map, is rendered to a texture, and then the second (visible)
+render pass samples it to determine which points in the scene are in shaodow.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>
+Shadow Mapping
+</title>
+<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.util');
+o3djs.require('o3djs.math');
+o3djs.require('o3djs.rendergraph');
+o3djs.require('o3djs.primitives');
+o3djs.require('o3djs.effect');
+o3djs.require('o3djs.debug');
+o3djs.require('o3djs.material');
+
+// The initClient() function runs when the page has finished loading.
+window.onload = initClient;
+
+// global variables
+var g_o3dElement;
+var g_client;
+var g_o3d;
+var g_math;
+var g_pack;
+var g_colorViewInfo;
+var g_shadowViewInfo;
+var g_shadowTexture;
+var g_shadowMaterial;
+var g_colorEffect;
+var g_shadowSampler;
+var g_lightViewProjection;
+var g_lightFrustumTransform;
+var g_globalParams = { };
+var g_viewFromLight = false;
+
+var g_renderSurfaceSet;
+var g_colorPassRenderRoot;
+
+var g_lightWorldPos = [5, 10, 0];
+var g_lightColor = [1, 1, 1, 1];
+var g_eyePosition = [1, 6, 20];
+var g_targetPosition = [0, 2, 0];
+
+// constants.
+var SHADOW_MAP_WIDTH = 512;
+var SHADOW_MAP_HEIGHT = 512;
+
+var g_finished = false; // for selenium testing.
+
+
+/**
+ * Creates the client area.
+ */
+function initClient() {
+ o3djs.webgl.makeClients(main, 'FloatingPointTextures', true);
+}
+
+
+/**
+ * Initializes global variables, positions camera, draws shapes.
+ * @param {Array} clientElements Array of o3d object elements.
+ */
+function main(clientElements) {
+ // Init global variables.
+ initGlobals(clientElements);
+
+ // Set up the rendergraph.
+ initRenderGraph();
+
+ // Load effects, bind material parameters.
+ initMaterials();
+
+ // Add the shapes to the transform graph.
+ createShapes();
+
+ // Set up the view and projection transformations for the camera.
+ updateCamera();
+
+ // Init global parameters. initGlobalParams() searches all materials in order
+ // to bind parameters, so it must be called after initMaterials()
+ initGlobalParams();
+
+ // Set the view and projection transformations for the light.
+ updateLightMatrix();
+
+ // Create the light that gets drawn.
+ createLightShape();
+
+ // Execute keyPressed() when we detect a keypress on the window or
+ // on the o3d object.
+ window.document.onkeypress = keyPressed;
+ g_o3dElement.onkeypress = keyPressed;
+
+ //toggleView();
+
+ g_finished = true; // for selenium testing.
+}
+
+
+/**
+ * Initializes global variables and libraries.
+ */
+function initGlobals(clientElements) {
+ g_o3dElement = clientElements[0];
+ g_client = g_o3dElement.client;
+ g_o3d = g_o3dElement.o3d;
+ g_math = o3djs.math;
+
+ // Create a pack to manage the objects created.
+ g_pack = g_client.createPack();
+}
+
+
+/**
+ * Sets up the render graph. Builds a basic view for the camera and the light
+ * point of view, arranges for the view from the light to be rendered to a
+ * texture for the shadow map. Unlike the basic render graph created by the
+ * the utility function o3djs.rendergraph.createBasicView, to render the shadow
+ * map and then render the scene, we need two subtrees of the render graph, one
+ * for shadow map render pass and one to draw the scene.
+ */
+function initRenderGraph() {
+ // The children of any one node in the render graph get traversed in order by
+ // priority. Here, we're forcing the shadow map to get rendered first by
+ // by giving its render root lower priority.
+ var shadowPassRenderRoot = g_pack.createObject('RenderNode');
+ shadowPassRenderRoot.priority = 0;
+
+ g_colorPassRenderRoot = g_pack.createObject('RenderNode');
+ g_colorPassRenderRoot.priority = 1;
+
+ g_colorPassRenderRoot.parent = g_client.renderGraphRoot;
+
+ // Create the texture that will store the depth information.
+ g_shadowTexture = g_pack.createTexture2D(SHADOW_MAP_WIDTH,
+ SHADOW_MAP_HEIGHT,
+ g_o3d.Texture.ABGR32F,
+ 1,
+ true);
+ var renderSurface = g_shadowTexture.getRenderSurface(0);
+
+ // Create the depth-stencil buffer required when rendering the teapot.
+ var depthSurface = g_pack.createDepthStencilSurface(SHADOW_MAP_WIDTH,
+ SHADOW_MAP_HEIGHT);
+
+ shadowPassRenderRoot.parent = g_client.renderGraphRoot;
+
+ g_renderSurfaceSet = g_pack.createObject('RenderSurfaceSet');
+ g_renderSurfaceSet.renderSurface = renderSurface;
+ g_renderSurfaceSet.renderDepthStencilSurface = depthSurface;
+
+ g_renderSurfaceSet.parent = shadowPassRenderRoot;
+
+ // Create a render sub-graph for the shadow map generation.
+ g_shadowViewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_renderSurfaceSet,
+ [1, 1, 1, 1]);
+
+ // Create a render sub-graph for the regular pass.
+ g_colorViewInfo = o3djs.rendergraph.createBasicView(
+ g_pack,
+ g_client.root,
+ g_colorPassRenderRoot,
+ [0, 0, 0, 1]);
+}
+
+
+/**
+ * Switches between the camera and light point of view.
+ */
+function toggleView() {
+ if (g_viewFromLight) {
+ g_shadowViewInfo.root.parent = g_renderSurfaceSet;
+ g_colorPassRenderRoot.parent = g_client.renderGraphRoot;
+ g_viewFromLight = false;
+ } else {
+ g_shadowViewInfo.root.parent = g_client.renderGraphRoot;
+ g_colorPassRenderRoot.parent = null;
+ g_viewFromLight = true;
+ }
+}
+
+/**
+ * Creates a material to be put on all shapes in the scene for the shadow pass,
+ * and loads effects for materials in the scene. Other materials are created
+ * on the fly as the shapes are created.
+ */
+function initMaterials() {
+ var colorVertexShader = document.getElementById('colorVertexShader').text;
+ var colorPixelShader = document.getElementById('colorPixelShader').text;
+
+ g_colorEffect = g_pack.createObject('Effect');
+ g_colorEffect.loadVertexShaderFromString(colorVertexShader);
+ g_colorEffect.loadPixelShaderFromString(colorPixelShader);
+
+ var shadowVertexShader = document.getElementById('shadowVertexShader').text;
+ var shadowPixelShader = document.getElementById('shadowPixelShader').text;
+
+ g_shadowMaterial = g_pack.createObject('Material');
+ g_shadowMaterial.drawList = g_shadowViewInfo.performanceDrawList;
+
+ var shadowEffect = g_pack.createObject('Effect');
+ shadowEffect.loadVertexShaderFromString(shadowVertexShader);
+ shadowEffect.loadPixelShaderFromString(shadowPixelShader);
+
+ g_shadowMaterial.effect = shadowEffect;
+ shadowEffect.createUniformParameters(g_shadowMaterial);
+
+ g_shadowSampler = g_pack.createObject('Sampler');
+ g_shadowSampler.texture = g_shadowTexture;
+ g_shadowSampler.minFilter = g_o3d.Sampler.POINT;
+ g_shadowSampler.magFilter = g_o3d.Sampler.POINT;
+ g_shadowSampler.mipFilter = g_o3d.Sampler.POINT;
+ g_shadowSampler.addressModeU = g_o3d.Sampler.BORDER;
+ g_shadowSampler.addressModeV = g_o3d.Sampler.BORDER;
+ g_shadowSampler.borderColor = [1, 1, 1, 1];
+
+}
+
+
+/**
+ * Sets up reasonable view and projection matrices.
+ */
+function updateCamera() {
+ // Set up a perspective transformation for the projection.
+ g_colorViewInfo.drawContext.projection = g_math.matrix4.perspective(
+ g_math.degToRad(30), // 30 degree frustum.
+ g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
+ 1, // Near plane.
+ 5000); // Far plane.
+
+ // Set up our view transformation to look towards the world origin where the
+ // cube is located.
+ g_colorViewInfo.drawContext.view = g_math.matrix4.lookAt(
+ g_eyePosition, // eye
+ g_targetPosition, // target
+ [0, 1, 0]); // up
+}
+
+
+/**
+ * Computes the view and projection matrices from the point of view of the
+ * light. Sets the lightViewProjection parameter so the color shader can access
+ * it.
+ */
+function updateLightMatrix() {
+ // The perspective projection matrix for the light.
+ var lightProjection = g_math.matrix4.perspective(
+ g_math.degToRad(45), // 45 degree fov.
+ SHADOW_MAP_WIDTH / SHADOW_MAP_HEIGHT, // Aspect ratio.
+ 4, // Near plane.
+ 20); // Far plane.
+
+ var adjustedProjection =
+ [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 2, 0], [0, 0, -1, 1]];
+ o3d.Transform.compose(
+ adjustedProjection, lightProjection, adjustedProjection);
+
+ // Make the light point toward the origin
+ var lightView = g_math.matrix4.lookAt(
+ g_lightWorldPos, // light
+ [0, 0, 0], // target
+ [1, 0, 0]); // up
+
+ g_lightViewProjection = g_math.matrix4.composition(
+ lightProjection, lightView);
+
+ g_shadowViewInfo.drawContext.projection = lightProjection;
+ g_shadowViewInfo.drawContext.view = lightView;
+ g_globalParams.lightViewProjection.value = g_lightViewProjection;
+}
+
+
+/**
+ * Creates shapes using the primitives utility library, and adds them to the
+ * transform graph at the root node.
+ */
+function createShapes() {
+ // A green phong-shaded material for the cube.
+ var cubeMaterial = createColorMaterial([0.2, 0.5, 0, 1]);
+
+ // The cube shape.
+ var cube = o3djs.primitives.createCube(
+ g_pack,
+ cubeMaterial,
+ 2); // The length of each side of the cube.
+
+ // A red phong-shaded material for the sphere.
+ var sphereMaterial = createColorMaterial([0.7, 0.2, 0.1, 1]);
+
+ // The sphere shape.
+ var sphere = o3djs.primitives.createSphere(
+ g_pack, sphereMaterial, 0.5, 50, 50);
+
+ // A blue phong-shaded material for the plane.
+ var planeMaterial = createColorMaterial([0, 0.3, 0.5, 1]);
+
+ // The plane shape.
+ var plane = o3djs.primitives.createPlane(
+ g_pack,
+ planeMaterial,
+ 20, // Width.
+ 20, // Depth.
+ 1, // Horizontal subdivisions.
+ 1); // Vertical subdivisions.
+
+ // Associate to each shape, a translation vector.
+ var transformTable = [
+ {shape: cube, translation: [0, 1, 0]},
+ {shape: sphere, translation: [0.5, 2.5, 0]},
+ {shape: plane, translation: [0, 0, 0]}
+ ];
+
+ // Add the shapes to the transform graph with the translation.
+ var modelRoot = g_pack.createObject('Transform');
+ modelRoot.parent = g_client.root;
+ for (var tt = 0; tt < transformTable.length; ++tt) {
+ var transform = g_pack.createObject('Transform');
+ transform.addShape(transformTable[tt].shape);
+ // The shadow material is bound to a DrawList in the subtree of the
+ // rendergraph that handles the shadow map generation, so it gets drawn in
+ // that render pass only.
+ transformTable[tt].shape.createDrawElements(g_pack, g_shadowMaterial);
+
+ transform.translate(transformTable[tt].translation);
+ transform.parent = modelRoot;
+ }
+}
+
+
+/**
+ * Creates the wireframe frustum showing the shadow map's render volume.
+ */
+function createLightShape() {
+ var inverseMatrix = g_math.matrix4.inverse(g_lightViewProjection);
+
+/*
+ // Scale and translate a cube of side length 2 to get a box
+ // that extends from [-1, -1, 0] to [1, 1, 1].
+ var shape = o3djs.debug.createLineCube(
+ g_pack,
+ o3djs.material.createConstantMaterial(g_pack,
+ g_colorViewInfo,
+ [1, 0, 0, 1]),
+ 2,
+ g_math.matrix4.compose(
+ g_math.matrix4.translation([0, 0, 0.5]),
+ g_math.matrix4.scaling([1, 1, 0.5])));*/
+
+ g_lightFrustumTransform = g_pack.createObject('Transform');
+ g_lightFrustumTransform.localMatrix = inverseMatrix;
+ g_lightFrustumTransform.parent = g_client.root;
+ //g_lightFrustumTransform.addShape(shape);
+}
+
+
+/**
+ * Creates a Phong-shaded, shadowed material based on the given color.
+ */
+function createColorMaterial(baseColor) {
+ var material = g_pack.createObject('Material');
+ material.drawList = g_colorViewInfo.performanceDrawList;
+
+ material.effect = g_colorEffect;
+ g_colorEffect.createUniformParameters(material);
+
+ material.getParam('shadowMapSampler').value = g_shadowSampler;
+
+ material.getParam('ambient').value = g_math.mulScalarVector(0.1, baseColor);
+ material.getParam('diffuse').value = g_math.mulScalarVector(0.8, baseColor);
+ material.getParam('specular').value = [1, 1, 1, 1];
+ material.getParam('shininess').value = 20;
+
+ return material;
+}
+
+/**
+ * Binds params for light position, light color and the light view-projection
+ * matrix to all materials in the scene where they apply.
+ */
+function initGlobalParams() {
+ var paramSpec = {
+ 'lightColor': 'ParamFloat4',
+ 'lightWorldPos': 'ParamFloat3',
+ 'lightViewProjection': 'ParamMatrix4'};
+
+ g_globalParams = o3djs.material.createParams(g_pack, paramSpec);
+ o3djs.material.bindParams(g_pack, g_globalParams);
+
+ g_globalParams.lightWorldPos.value = g_lightWorldPos;
+ g_globalParams.lightColor.value = g_lightColor;
+}
+
+
+/**
+ * The keyboard event handler.
+ */
+function keyPressed(event) {
+ var keyChar = String.fromCharCode(o3djs.event.getEventKeyChar(event));
+ keyChar = keyChar.toLowerCase();
+
+ var delta = 0.2;
+ switch(keyChar) {
+ case 'a':
+ moveLight([-delta, 0, 0]);
+ break;
+ case 'd':
+ moveLight([delta, 0, 0]);
+ break;
+ case 's':
+ moveLight([0, -delta, 0]);
+ break;
+ case 'w':
+ moveLight([0, delta, 0]);
+ break;
+ case 'i':
+ moveLight([0, 0, delta]);
+ break;
+ case 'o':
+ moveLight([0, 0, -delta]);
+ break;
+
+ case ' ':
+ toggleView();
+ break;
+ }
+}
+
+/**
+ * Moves the light by the given vector delta, and updates params so the light
+ * draws in the right spot and the shadows move.
+ */
+function moveLight(delta) {
+ g_lightWorldPos = g_math.addVector(g_lightWorldPos, delta);
+ g_globalParams.lightWorldPos.value = g_lightWorldPos;
+ updateLightMatrix();
+ g_lightFrustumTransform.localMatrix =
+ g_math.matrix4.inverse(g_lightViewProjection);
+}
+
+
+</script>
+
+
+
+<script id="shadowVertexShader" type="text/glsl">
+ /**
+ * This shader is for the effect applied in the first render pass, when the
+ * shadow map is created. The scene is rendered from the perspective of the
+ * light, the grayscale value of each pixel in the rendered image represents
+ * how far away the rendered point is from the light (the lighter, the
+ * farther) This image gets rendered to a texture, and that texture gets
+ * sampled in the second render pass, when the geometry is drawn to the
+ * screen.
+ */
+ attribute vec4 position;
+ uniform mat4 worldViewProjection;
+
+ varying vec4 vposition;
+
+ void main() {
+ vposition = worldViewProjection * position;
+ gl_Position = vposition;
+ }
+</script>
+<script id="shadowPixelShader" type="text/glsl">
+ varying vec4 vposition;
+
+ void main() {
+ vec4 color;
+ vec3 q = vposition.xyz / vposition.w;
+
+ float depth = 0.5*(q.z + 1.0);
+ color.r = fract(16777216.0 * depth);
+ color.g = fract(65536.0 * depth);
+ color.b = fract(256.0 * depth);
+ color.a = depth;
+
+ gl_FragColor = color;
+ }
+</script>
+
+
+<script id="colorVertexShader" type="text/glsl">
+ attribute vec4 position;
+ attribute vec3 normal;
+
+ uniform mat4 worldViewProjection;
+ uniform mat4 world;
+ uniform mat4 worldInverseTranspose;
+ uniform mat4 lightViewProjection;
+
+ varying vec4 vposition;
+ varying vec3 vnormal;
+ varying vec4 vprojTextureCoords;
+ varying vec4 vworldPosition;
+
+ /**
+ * The vertex shader simply transforms the input vertices to screen space.
+ */
+ void main() {
+ vworldPosition = world * position;
+ vnormal = vec3(worldInverseTranspose * vec4(normal, 0));
+ vposition = worldViewProjection * position;
+ vprojTextureCoords = lightViewProjection * world * position;
+ gl_Position = vposition;
+ }
+</script>
+<script id="colorPixelShader" type="text/glsl">
+ uniform vec4 ambient;
+ uniform vec4 diffuse;
+ uniform vec4 specular;
+ uniform float shininess;
+
+ varying vec4 vposition;
+ varying vec4 vworldPosition;
+ varying vec3 vnormal;
+ varying vec4 vprojTextureCoords;
+
+ uniform sampler2D shadowMapSampler;
+
+ uniform vec3 lightWorldPos;
+ uniform mat4 viewInverse;
+
+ vec3 lighting(vec3 position, vec3 normal, vec4 pigment, vec4 specular, float shininess) {
+ vec3 l = normalize(vec3(lightWorldPos) - position); // Toward light.
+ vec3 n = normalize(normal); // Normal.
+ vec3 v = normalize(vec3(viewInverse * vec4(0,0,0,1)) - position); // Toward eye.
+ vec3 r = normalize(-reflect(v, n));
+
+ return clamp(dot(n,l), 0.0, 1.0) * diffuse.rgb +
+ 0.2 * specular.rgb * pow(max(dot(l, r), 0.0), shininess);
+ }
+
+ void main() {
+ vec3 outColor = ambient.rgb;
+ vec4 projCoords = vprojTextureCoords;
+
+ // Convert texture coords to [0, 1] range.
+ projCoords /= projCoords.w;
+ projCoords.x = 0.5 * projCoords.x + 0.5;
+ projCoords.y = 0.5 * projCoords.y + 0.5;
+ projCoords.z = 0.5 * projCoords.z + 0.5;
+
+ float depth = projCoords.z;
+
+ float light;
+
+ // If the rednered point is farther from the light than the distance encoded
+ // in the shadow map, we give it a light coefficient of 0.
+ vec4 color = texture2D(shadowMapSampler, projCoords.xy);
+
+ light = (color.a +
+ color.b / 256.0 +
+ color.g / 65536.0 +
+ color.r / 16777216.0) + 0.008 > depth ? 1.0 : 0.0;
+
+ // Make the illuninated area a round spotlight shape just for fun.
+ // Comment this line out to see just the shadows.
+ light *= 1.0 - smoothstep(0.45, 0.5,
+ length(projCoords.xy - vec2(0.5, 0.5)));
+
+ outColor += light * lighting(
+ vec3(vworldPosition),
+ vnormal,
+ diffuse,
+ specular,
+ shininess);
+
+ gl_FragColor = vec4(outColor, 1.0);
+ }
+</script>
+
+
+
+</head>
+<body>
+<h1>Shadow Maps</h1>
+This sample implements a basic shadow map.
+<br/>
+<!-- Start of O3D plugin -->
+<div id="o3d" width="800px" height="600px"></div>
+<!-- End of O3D plugin -->
+Use A, S, D, W, I and O to move the light.
+Press spacebar to see the shadow map.
+</body>
+</html>