diff options
author | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 22:15:42 +0000 |
---|---|---|
committer | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-07 22:15:42 +0000 |
commit | febe2b6bfa46f46197c9fd619382f169abfe45f8 (patch) | |
tree | 9259f62eebe464f7bd8bc42b24a939760bcb8257 /o3d | |
parent | 6e10b72ac081588661dd667ec8e156149c24b96d (diff) | |
download | chromium_src-febe2b6bfa46f46197c9fd619382f169abfe45f8.zip chromium_src-febe2b6bfa46f46197c9fd619382f169abfe45f8.tar.gz chromium_src-febe2b6bfa46f46197c9fd619382f169abfe45f8.tar.bz2 |
Converted four more demo files to o3d-webgl: juggler, sobel, julia and texturesamplers.
Review URL: http://codereview.chromium.org/2690002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@49101 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/samples/o3d-webgl-samples/juggler.html | 453 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl-samples/julia.html | 285 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl-samples/sobel.html | 339 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl-samples/texturesamplers.html | 274 |
4 files changed, 1351 insertions, 0 deletions
diff --git a/o3d/samples/o3d-webgl-samples/juggler.html b/o3d/samples/o3d-webgl-samples/juggler.html new file mode 100644 index 0000000..133e6c8 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/juggler.html @@ -0,0 +1,453 @@ +<!-- +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. +--> + +<!-- +O3D Juggler +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html style="width: 100%; height: 100%;"> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> + Juggler Shader +</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.primitives'); + +// Events +// Run the init() function once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload = unload; +// global variables +var g_o3d; +var g_math; +var g_client; +var g_o3dElement; +var g_viewInfo; +var g_pack; +var g_o3dWidth = -1; +var g_o3dHeight = -1; +var g_transform; +var g_clock = 0.0; +var g_timeMult = 1; // amount to multiply elapsed time by. + // Used to make the animation run faster or slower. +var g_finished = false; // for selenium testing +var g_thetaParam; +var g_numParam; +var g_numBalls; // Must be either 3, 5, 7, or 9 for now. +var g_speedScale; // Used to make higher numbers of balls animate faster. + +/** + * Creates the client area. + */ +function init() { + o3djs.webgl.makeClients(initStep2); +} + +/** + * Initializes O3D, loads the effect, and creates the square. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initialize global variables and libraries. + g_o3dElement = clientElements[0]; + g_o3d = g_o3dElement.o3d; + g_math = o3djs.math; + g_client = g_o3dElement.client; + + // Create a g_pack to manage our resources/assets + 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, + [0, 0, 0, 1]); + + var effect = g_pack.createObject('Effect'); + effect.loadFromFXString(document.getElementById('shader').value); + + // Create a Material for the effect. + var myMaterial = g_pack.createObject('Material'); + + // Apply our effect to this material. + myMaterial.effect = effect; + + // Set the material's drawList for opaque objects. + myMaterial.drawList = g_viewInfo.performanceDrawList; + + // Create the params the effect needs on the material. + effect.createUniformParameters(myMaterial); + + // Create a square. + var myShape = o3djs.primitives.createPlane(g_pack, myMaterial, + 1, 1, 1, 1); + + // Set up the individual parameters in our effect file. + g_thetaParam = myMaterial.getParam('theta'); + g_thetaParam.value = 0.0; + g_numParam = myMaterial.getParam('num'); + updateNum(); + + // Set the position of the camera. + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 1, 0], //eye + [0, 0, 0], //target + [0, 0, -1]); //up + + // Generate the projection matrix based + // on the g_o3d plugin size by calling resize(). + resize(); + + // Now attach the square to the root of the transform graph. + g_client.root.addShape(myShape); + + toggleRenderCallback(); + + g_finished = true; // for selenium testing. +} + +function updateNum() { + var group = document.the_form.radio_group; + for (var i = 0; i < group.length; ++i) { + if (group[i].checked) { + setNumBalls(parseInt(group[i].value)); + } + } +} + +function toggleRenderCallback() { + var box = document.the_form.check_box; + if (box.checked) { + g_client.setRenderCallback(onrender); + } else { + g_client.clearRenderCallback(); + } +} + +function setNumBalls(num) { + g_numBalls = num; + g_numParam.value = g_numBalls; + g_speedScale = Math.sqrt(g_numBalls) * 5; +} + +function onrender(render_event) { + g_clock += render_event.elapsedTime * g_timeMult; + g_thetaParam.value = g_clock * g_speedScale; + + // If we don't check the size of the client area every frame we don't get a + // chance to adjust the perspective matrix fast enough to keep up with the + // browser resizing us, so onrender must call resize. + resize(); +} + + +// Generates the projection matrix based on the size of the g_o3d plugin +// and calculates the view-projection matrix. +function resize() { + var newWidth = g_client.width; + var newHeight = g_client.height; + + if (newWidth != g_o3dWidth || newHeight != g_o3dHeight) { + g_o3dWidth = newWidth; + g_o3dHeight = newHeight; + + // Determine what the size of the rendered square within the client should + // be in pixels. + var side = g_o3dWidth < g_o3dHeight ? + g_o3dWidth : g_o3dHeight; + + // Convert to the region of world space that must be enclosed by the + // orthographic projection. + var worldSize = g_math.divVectorScalar([g_o3dWidth, g_o3dHeight], side); + + // Find a projection matrix to transform from world space to screen space. + g_viewInfo.drawContext.projection = o3djs.math.matrix4.orthographic( + -0.5 * worldSize[0], 0.5 * worldSize[0], + -0.5 * worldSize[1], 0.5 * worldSize[1], + 0.5, 1.5); + } +} + +/** + * Removes any callbacks so they don't get called after the page has unloaded. + */ +function unload() { + if (g_client) { + g_client.cleanup(); + } +} +</script> +</head> +<body style="width: 95%; height: 95%;"> +<table style="width: 100%; height: 100%;"> + <tr> + <td> + <h1>Juggler</h1> + <p> + This sample displays a juggling pattern computed entirely in a shader. + <form name="the_form"> + <input type="radio" name="radio_group" value="3" + onclick=updateNum()>3 Balls + <input type="radio" name="radio_group" value="5" + onclick=updateNum()>5 Balls + <input type="radio" name="radio_group" value="7" + onclick=updateNum()>7 Balls + <input type="radio" name="radio_group" value="9" + onclick=updateNum()>9 Balls + <input type="radio" name="radio_group" value="11" checked + onclick=updateNum()>11 Balls + <input type="radio" name="radio_group" value="13" + onclick=updateNum()>13 Balls + <input type="radio" name="radio_group" value="15" + onclick=updateNum()>15 Balls + <input type="radio" name="radio_group" value="17" + onclick=updateNum()>17 Balls + <input type="checkbox" name="check_box" checked + onclick=toggleRenderCallback()>Animate + </form> + </p> + <table id="container" style="width: 100%; height: 80%;"> + <tr> + <td height="100%"> + <!-- Start of g_o3d plugin --> + <div id="o3d" style="width: 100%; height: 100%;"></div> + <!-- End of g_o3d plugin --> + </td> + </tr> + </table> + <!-- a simple way to get a multiline string --> + <textarea id="shader" name="shader" cols="80" rows="20" + style="display: none;"> +// The 4x4 world view projection matrix. +uniform mat4 worldViewProjection; + +// input parameters for our vertex shader +attribute vec4 position; +attribute vec2 texCoord0; + +// input parameters for our pixel shader +varying vec2 v_texCoord; + +/** + * vertexShaderMain - our vertex shader for the juggling texture + */ +void main() { + gl_Position = worldViewProjection * position; + v_texCoord = 4.0 * (texCoord0 - vec2(0.5, 0.5)); +} + +// #o3d SplitMarker + +varying vec2 v_texCoord; + +uniform float theta; +uniform float num; + +float length_2(vec2 v) { + return dot(v, v); +} + +// Draw the balls in a single arc. +// Returns 1 if the pixel is within a ball, 0 if it isn't, and a value in +// between for pixels right on the edge, for antialiasing. +float drawBallsInArc(float pi, + vec4 offset, + vec2 source_hand, + vec2 dest_hand, + float height_factor, + float baseline, + float ball_radius_2, + float hand_throw_offset, + vec2 Z, + float threshold) { + // Map theta from its current range of [0, 2 * num * pi) onto [0, (num - 1)) + // by scaling, adding offset, and modding, then map that to [0, 1) by scaling. + // The first mapping tells us where in the repeating cycle we are, and the + // second mapping simplifies the calculation of the parabola. + + // The vector offset is used to distinguish between balls in the same arc, but + // out of phase. At the beginning of this function, all the operations are + // vectorized to save instructions; we get to calculate 4 ball positions for + // the price of 1. + + // The reason for the (num - 1) in the expression below is that with num + // balls, each ball spends (num - 1) beats in the air, then one in the hand. + // So (num - 1) is the length of time a parabola takes. + + vec4 time = mod(theta / pi + offset, (num - 1.0)) / (num - 1.0); + float dx = dest_hand.x - source_hand.x; + vec4 x = time * dx + source_hand.x - hand_throw_offset; + vec4 y = time * (1.0 - time); + y = y * height_factor + baseline; + vec4 ZX = vec4(Z.x); + vec4 ZY = vec4(Z.y); + vec4 len_2 = (ZX - x) * (ZX - x) + (ZY - y) * (ZY - y); + + // This antialiasing fuzzes the balls just a bit larger than they would + // otherwise be. + vec4 temp = clamp((len_2 - ball_radius_2) / threshold, 0.0, 1.0); + + // One minus the product of all entries in temp. + temp.xy = temp.xy * temp.zw; + return 1.0 - temp.x * temp.y; +} + +vec4 drawAirborneBalls(float pi, + vec4 offset, + vec2 right_hand, + vec2 left_hand, + float height_factor, + float baseline, + float ball_radius_2, + float hand_swing_radius, + vec2 Z, + float threshold) { + float value = + // balls going right to left + (drawBallsInArc(pi, offset, right_hand, left_hand, height_factor, + baseline, ball_radius_2, hand_swing_radius, Z, threshold) + + // balls going left to right + drawBallsInArc(pi, offset + 1.0, left_hand, right_hand, height_factor, + baseline, ball_radius_2, -hand_swing_radius, Z, threshold)); + return vec4(value, value, value, value); +} + + +/** + * pixelShaderMain - pixel shader + */ + +void main() { + float pi = 3.14159265; + float baseline = -1.4; + vec2 right_hand = vec2(0.8, baseline); + vec2 left_hand = vec2(-0.8, baseline); + float hand_swing_radius = 0.25; + float hand_radius = 0.15; + float hand_radius_2 = hand_radius * hand_radius; + float ball_radius = 0.08; + float ball_radius_2 = ball_radius * ball_radius; + + vec4 right_hand_color = vec4(1, 0, 0, 1); + vec4 left_hand_color = vec4(0, 0, 1, 1); + vec4 background_color = vec4(0, 0, 0, 0); + + float threshold = 0.002; // Used in clamp for antialiasing. + + float height_factor = num * 0.75; + + vec2 Z = v_texCoord; + + // Coerce to the range [0, 2 * Pi * num]. + vec2 r_h = hand_swing_radius * vec2(-cos(theta), sin(theta)) + right_hand; + vec2 l_h = hand_swing_radius * vec2(-cos(theta), -sin(theta)) + left_hand; + + // Initialize color of pixel to background_color. Background color has an + // alpha of 0. Color of objects each have alpha 1, so multiplying by + // (1-alpha) before adding the color ensures that nothing gets overdrawn. + // It's kind of like a rudimentary z-buffer. + vec4 result = background_color; + + // Draw the hands. The antialiasing here fuzzes the hands just a little bit + // smaller than they would otherwise be. That's the opposite of what we do + // for the balls, just because it happens to be cheaper here to do smaller and + // cheaper in drawBallsInArc to do larger. + result += + clamp((hand_radius_2 - length_2(Z - r_h)) / threshold, 0.0, 1.0) * + (Z.y < r_h.y ? 1.0 : 0.0) * right_hand_color + + clamp((hand_radius_2 - length_2(Z - l_h)) / threshold, 0.0, 1.0) * + (Z.y < l_h.y ? 1.0 : 0.0) * left_hand_color; + // Draw the ball in the hand. There is always a ball in exactly one hand, and + // which hand that is alternates. + vec2 hand; + if (mod(floor(theta / pi), 2.0) > 0.5) { + hand = r_h; + } else { + hand = l_h; + } + + // The antialiasing here fuzzes the balls just a bit bigger than they would + // otherwise be. This is more work than making them smaller [the extra + // subtraction in the "1 - clamp..." below], but inverting it in + // drawBallsInArc would be more expensive, and they have to match so that the + // balls are all the same size. + result += (1.0 - result.a) * + (1.0 - clamp((length_2(Z - hand) - ball_radius_2) / threshold, 0.0, 1.0)); + + // Draw airborne balls. + vec4 offset = vec4(0, 2, 4, 6); + result += (1.0 - result.a) * drawAirborneBalls(pi, + offset, + right_hand, + left_hand, + height_factor, + baseline, + ball_radius_2, + hand_swing_radius, + Z, + threshold); + + // For each up-to-4 pairs of balls you want to add, increment offset by + // (8, 8, 8, 8) and call drawAirborneBalls again. + offset += 8.0; + result += (1.0 - result.a) * drawAirborneBalls(pi, + offset, + right_hand, + left_hand, + height_factor, + baseline, + ball_radius_2, + hand_swing_radius, + Z, + threshold); + + gl_FragColor = result; +} + +// #o3d MatrixLoadOrder RowMajor + </textarea> + </td> + </tr> +</table> +</body> +</html> diff --git a/o3d/samples/o3d-webgl-samples/julia.html b/o3d/samples/o3d-webgl-samples/julia.html new file mode 100644 index 0000000..30dbaf4 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/julia.html @@ -0,0 +1,285 @@ +<!-- +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. +--> + +<!-- +O3D Julia Set + +This sample draws an animated julia set in real time using +the pixel shader for the computation. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html style="width: 100%; height: 100%;"> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Julia Set Pixel Shader +</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.primitives'); + +// Events +// Run the init() function once the page has finished loading. +// unload() when the page is unloaded. +window.onload = init; +window.onunload = unload; +// global variables +var g_o3d; +var g_math; +var g_client; +var g_o3dElement; +var g_viewInfo; +var g_pack; +var g_o3dWidth = -1; +var g_o3dHeight = -1; +var g_clock = 0.0; +var g_timeMult = 1; +var g_finished = false; // for selenium testing +var g_seedParam; + +/** + * Creates the client area. + */ +function init() { + o3djs.webgl.makeClients(initStep2); +} + +/** + * Initializes o3d, loads the effect, and creates the square. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initialize global variables and libraries. + g_o3dElement = clientElements[0]; + g_o3d = g_o3dElement.o3d; + g_math = o3djs.math; + g_client = g_o3dElement.client; + + // Create a g_pack to manage our resources/assets + 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, + [0, 0, 0, 1]); + + // Load shader code from DOM and use it to build the effect. + var effect = g_pack.createObject('Effect'); + effect.loadFromFXString(document.getElementById('shader').value); + + // Create a Material for the effect. + var myMaterial = g_pack.createObject('Material'); + + // Apply our effect to this material. + myMaterial.effect = effect; + + // Set the material's drawList for opaque objects. + myMaterial.drawList = g_viewInfo.performanceDrawList; + + // create the parameters the effect needs to the material. + effect.createUniformParameters(myMaterial); + + // Create a square. + var myShape = o3djs.primitives.createPlane(g_pack, myMaterial, 1, 1, 1, 1); + + // Initialize effect parameters to something reasonable + g_seedParam = myMaterial.getParam('seed'); + g_seedParam.value = [0.2, 0.5]; + + // Put the camera somewhere where it has a good view of that square. + g_viewInfo.drawContext.view = g_math.matrix4.lookAt( + [0, 1, 0], //eye + [0, 0, 0], //target + [0, 0, -1]); //up + + // Generate the projection matrix based + // on the g_o3d plugin size by calling resize(). + resize(); + + // Now attach the square to the root of the transform graph. + g_client.root.addShape(myShape); + + g_client.setRenderCallback(onrender); + + g_finished = true; // for selenium testing. +} + + +/** + * Render callback. Walks the seed of the Julia set through + * a parametric path in the complex plane that stays + * in the neighborhood of the Mandelbrot set. + */ +function onrender(render_event) { + g_clock += render_event.elapsedTime * g_timeMult; + + var t = 0.1 * g_clock; + var x = 0.6 * Math.cos(3.0 * t) - 0.3; + var y = (0.5 * x + 1.7)*(0.2 * Math.sin(7 * t)); + + g_seedParam.value = [x, y]; + + resize(); +} + + +/** + * Generates the projection matrix based on the size of the o3d plugin and + * calculates the view-projection matrix. + */ +function resize() { + var newWidth = g_client.width; + var newHeight = g_client.height; + + if (newWidth != g_o3dWidth || newHeight != g_o3dHeight) { + g_o3dWidth = newWidth; + g_o3dHeight = newHeight; + + // Determine what the size of the rendered square within the client should + // be in pixels. + var side = g_o3dWidth < g_o3dHeight ? + g_o3dWidth : g_o3dHeight; + + // Convert to the region of world space that must be enclosed by the + // orthographic projection. + var worldSize = g_math.divVectorScalar([g_o3dWidth, g_o3dHeight], side); + + // Find a projection matrix to transform from world space to screen space. + g_viewInfo.drawContext.projection = g_math.matrix4.orthographic( + -0.5 * worldSize[0], 0.5 * worldSize[0], + -0.5 * worldSize[1], 0.5 * worldSize[1], + 0.5, 1.5); + } +} + + +/** + * Removes any callbacks so they don't get called after the page has unloaded. + */ +function unload() { + if (g_client) { + g_client.cleanup(); + } +} + + +</script> +</head> +<body style="width: 100%; height: 100%;"> +<table style="width: 100%; height: 100%;"> + <tr> + <td> + <h1>Julia Set</h1> + <p> + This sample draws an animated julia set in real time using + the pixel shader for the computation. + </p> + <table id="container" style="width: 100%; height: 80%;"> + <tr> + <td height="100%"> + <!-- Start of g_o3d plugin --> + <div id="o3d" style="width: 100%; height: 100%;"></div> + <!-- End of g_o3d plugin --> + </td> + </tr> + </table> + <!-- a simple way to get a multiline string --> + <textarea id="shader" name="shader" cols="80" rows="20" + style="display: none;"> +// The 4x4 world view projection matrix. +uniform mat4 worldViewProjection; + +// input parameters for our vertex shader +attribute vec4 position; +attribute vec2 texCoord0; + +// input parameters for our pixel shader +varying vec2 texCoord; + +/** + * vertexShaderMain - Multiplies position by world-view-projection matrix, and + * passes on texture coordinates scaled to put the origin in the center of the + * quad and reveal a nicely sized portion of the plane to show the julia set. + */ +void main() { + gl_Position = worldViewProjection * position; + texCoord = 4.0 * (texCoord0 - vec2(0.5, 0.5)); +} + + +// #o3d SplitMarker + +varying vec2 texCoord; + +// The seed for the julia set (c in the expression z(n+1) = z(n)^2+c). +uniform vec2 seed; + +/** + * pixelShaderMain - Calculates the color of the pixel by iterating on the + * formula z = z*z + seed. After some number of iterations, the magnitude of z + * determines the color. + */ +void main() { + vec2 Z = texCoord; + + // Number of iterations hardcoded here. The more iterations, the crisper the + // image. + for(int i = 0; i < 10; ++i) { + Z = vec2(Z.x * Z.x - Z.y * Z.y, 2.0 * Z.x * Z.y) + seed; + + // Some graphics cards and some software renderers don't appreciate large + // floating point values, so we clamp to prevent Z from getting that big. + if (i > 7) { + Z = clamp(Z, -25.0, 25.0); + } + } + + gl_FragColor = (1.0 - length(Z)) * vec4(0.5, 1, 2, 1); +} +// #o3d MatrixLoadOrder RowMajor + </textarea> + </td> + </tr> +</table> +</body> +</html> + + diff --git a/o3d/samples/o3d-webgl-samples/sobel.html b/o3d/samples/o3d-webgl-samples/sobel.html new file mode 100644 index 0000000..b7105d3 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/sobel.html @@ -0,0 +1,339 @@ +<!-- +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 shows how to create a Sobel edge-detect image processing shader, +using render targets. +--> +<!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> +O3D: Sobel Shader Sample +</title> +<!-- Include sample javascript library functions--> +<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.pack'); +o3djs.require('o3djs.camera'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.scene'); + +// Events +// init() once the page has finished loading. +window.onload = init; +window.onunload = uninit; + +// constants. +var RENDER_TARGET_WIDTH = 512; +var RENDER_TARGET_HEIGHT = 512; + +// global variables +var g_o3d; +var g_client; +var g_math; +var g_pack; +var g_teapotRoot; +var g_renderGraphRoot; +var g_clock = 0; +var g_timeMult = 1; +var g_finished = false; // for selenium testing + +/** + * Loads a scene into the transform graph, and prepares its elements for + * insertion into the render graph. + * @param {!o3d.Pack} pack Pack to load scene into. + * @param {string} fileName filename of the scene. + * @param {!o3d.Transform} parent parent node in the transform graph to + * which to load the scene into. + * @param {!o3djs.rendergraph.ViewInfo} viewInfo who's view and projection will + * be set from the scene after it's loaded. + */ +function loadScene(pack, fileName, parent, viewInfo) { + // Get our full path to the scene + var scenePath = o3djs.util.getCurrentURI() + fileName; + + // Load the scene given the full path, and call the callback function + // when its done loading. + o3djs.scene.loadScene(g_client, pack, parent, scenePath, callback); + + /** + * Our callback is called once the scene has been loaded into memory + * from the web or locally. + * @param {!o3d.Pack} pack The pack that was passed in above. + * @param {!o3d.Transform} parent The parent that was passed in above. + * @param {*} exception null if loading succeeded. + */ + function callback(pack, parent, exception) { + if (exception) { + alert('Could not load: ' + fileName + '\n' + exception); + return; + } + // Get a CameraInfo (an object with a view and projection matrix) + // using our javascript library function + var cameraInfo = o3djs.camera.getViewAndProjectionFromCameras( + parent, + RENDER_TARGET_WIDTH, + RENDER_TARGET_HEIGHT); + + // Copy the view and projection to the passed in viewInfo structure.. + viewInfo.drawContext.view = cameraInfo.view; + viewInfo.drawContext.projection = cameraInfo.projection; + + // Generate draw elements and setup material draw lists. + o3djs.pack.preparePack(pack, viewInfo); + + g_finished = true; // for selenium testing. + } +} + +/** + * Creates the client area. + */ +function init() { + o3djs.webgl.makeClients(initStep2); +} + +/** + * Initializes O3D and loads the scene into the transform graph. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initializes global variables and libraries. + var o3d = clientElements[0]; + g_o3d = o3d.o3d; + g_math = o3djs.math; + g_client = o3d.client; + + // Creates a pack to manage our resources/assets + g_pack = g_client.createPack(); + + // Create the texture required for the color render-target. + var texture = g_pack.createTexture2D(RENDER_TARGET_WIDTH, + RENDER_TARGET_HEIGHT, + g_o3d.Texture.XRGB8, 1, true); + + g_teapotRoot = g_pack.createObject('Transform'); + + var renderGraphRoot = g_client.renderGraphRoot; + + var renderSurfaceSet = createRenderSurfaceSet(texture); + + // Create the render graph for the teapot view, drawing the teapot into + // texture (via renderSurfaceSet). + var teapotViewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_teapotRoot, + renderSurfaceSet, + [1, 1, 1, 1]); + + var renderNode = createSobelPass(texture, g_client.renderGraphRoot); + + // Load the scene into the transform graph as a child g_teapotRoot + loadScene(g_pack, '../assets/teapot/scene.json', g_teapotRoot, teapotViewInfo); + + // Set a render callback. + g_client.setRenderCallback(onRender); +} + +function createSobelMaterial(viewInfo, kernelSize) { + var convFXString = document.getElementById('convFX').value; + var convEffect = g_pack.createObject('Effect'); + convEffect.loadFromFXString(convFXString); + + var convMaterial = g_pack.createObject('Material'); + convMaterial.drawList = viewInfo.performanceDrawList; + convMaterial.effect = convEffect; + convEffect.createUniformParameters(convMaterial); + return convMaterial; +} + +function createRenderSurfaceSet(texture) { + var renderSurface = texture.getRenderSurface(0); + + // Create the depth-stencil buffer required when rendering this pass. + var depthSurface = g_pack.createDepthStencilSurface(RENDER_TARGET_WIDTH, + RENDER_TARGET_HEIGHT); + + var renderSurfaceSet = g_pack.createObject('RenderSurfaceSet'); + renderSurfaceSet.renderSurface = renderSurface; + renderSurfaceSet.renderDepthStencilSurface = depthSurface; + renderSurfaceSet.parent = g_client.renderGraphRoot; + return renderSurfaceSet; +} + +function createSobelPass(srcTexture, renderGraphRoot) { + // Create a root Transform for the image processing scene. + var root = g_pack.createObject('Transform'); + + // Create a basic view for the image processing scene. + var viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + root, + renderGraphRoot, + [1, 1, 1, 1]); + + var material = createSobelMaterial(viewInfo); + var quadShape = o3djs.primitives.createPlane(g_pack, + material, + 2.0, + 2.0, + 1, + 1); + + // Attach the quad to the image processing scene. + root.addShape(quadShape); + + // Rotate the view so we're looking at the XZ plane (where our quad is) + // Point the camera along the -Y axis + var target = [0, -1, 0]; + // Put the camera at the origin. + var eye = [0, 0, 0]; + // Define the up-vector as +Z + var up = [0, 0, 1]; + viewInfo.drawContext.view = g_math.matrix4.lookAt(eye, target, up); + + // Create an orthographic projection. + viewInfo.drawContext.projection = g_math.matrix4.orthographic( + -1, 1, -1, 1, -1, 1); + + // Generate draw elements and setup material draw lists for the + // image processing scene. + o3djs.pack.preparePack(g_pack, viewInfo); + + setSobelParameters(material, srcTexture); + return renderGraphRoot; +} + +function setSobelParameters(material, texture) { + var imageParam = material.getParam('image'); + var imageIncrement = material.getParam('imageIncrement'); + var sampler = g_pack.createObject('Sampler'); + sampler.texture = texture; + sampler.addressModeU = g_o3d.Sampler.CLAMP; + sampler.addressModeV = g_o3d.Sampler.CLAMP; + sampler.minFilter = g_o3d.Sampler.POINT; + sampler.magFilter = g_o3d.Sampler.POINT; + sampler.mipFilter = g_o3d.Sampler.NONE; + imageParam.value = sampler; + imageIncrement.value = [1.0 / texture.width, 1.0 / texture.height]; +} + +/** + * Called every frame. + * @param {o3d.RenderEvent} renderEvent Rendering Information. + */ +function onRender(renderEvent) { + var elapsedTime = renderEvent.elapsedTime; + g_clock += elapsedTime * g_timeMult; + + g_teapotRoot.identity(); + g_teapotRoot.rotateX(g_clock); + g_teapotRoot.rotateY(g_clock * 1.3); +} + +/** + * Cleanup before exiting. + */ +function uninit() { + if (g_client) { + g_client.cleanup(); + } +} +</script> +</head> +<body> +<h1>Sobel Edge Detection Shader Example</h1> +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 512px; height: 512px;"></div> +<!-- End of O3D plugin --> +<!-- + We embed the code for our effect inside this hidden textarea. + Effects contain the functions that define + the vertex and pixel shaders used by our shape. +--> +<!-- Don't render the textarea --> +<div style="display:none"> +<textarea id="convFX" name="convFX" cols="80" rows="20"> +uniform mat4 worldViewProjection; + +attribute vec4 position; +attribute vec2 texCoord0; + +varying vec2 v_imageCoord; + +void main() { + gl_Position = worldViewProjection * position; + v_imageCoord = texCoord0; +} + +// #o3d SplitMarker +uniform sampler2D image; +uniform vec2 imageIncrement; + +varying vec2 v_imageCoord; + +float lum(vec4 c) { + return dot(c.xyz, vec3(0.3, 0.59, 0.11)); +} + +void main() { + vec2 imageCoord = v_imageCoord; + float t00 = lum(texture2D(image, imageCoord + imageIncrement * vec2(-1, -1))); + float t10 = lum(texture2D(image, imageCoord + imageIncrement * vec2( 0, -1))); + float t20 = lum(texture2D(image, imageCoord + imageIncrement * vec2( 1, -1))); + float t01 = lum(texture2D(image, imageCoord + imageIncrement * vec2(-1, 0))); + float t21 = lum(texture2D(image, imageCoord + imageIncrement * vec2( 1, 0))); + float t02 = lum(texture2D(image, imageCoord + imageIncrement * vec2(-1, 1))); + float t12 = lum(texture2D(image, imageCoord + imageIncrement * vec2( 0, 1))); + float t22 = lum(texture2D(image, imageCoord + imageIncrement * vec2( 1, 1))); + vec2 grad; + grad.x = t00 + 2.0 * t01 + t02 - t20 - 2.0 * t21 - t22; + grad.y = t00 + 2.0 * t10 + t20 - t02 - 2.0 * t12 - t22; + float len = length(grad); + gl_FragColor = vec4(len, len, len, 1.0); +} + +// #o3d MatrixLoadOrder RowMajor +</textarea> +</div> +</body> + +</html> diff --git a/o3d/samples/o3d-webgl-samples/texturesamplers.html b/o3d/samples/o3d-webgl-samples/texturesamplers.html new file mode 100644 index 0000000..13ef9c9 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/texturesamplers.html @@ -0,0 +1,274 @@ +<!-- +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. +--> + +<!-- +O3D Texture Samplers example. + +Demonstrates how to create samplers and set their various states. +--> + +<!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> +Texture Samplers +</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.material'); +o3djs.require('o3djs.event'); +o3djs.require('o3djs.io'); + +// Events +// Run the init() once the page has finished loading. +window.onload = init; + +// global variables +var g_o3d; +var g_math; +var g_client; +var g_pack; +var g_viewInfo; +var g_eye; +var g_target; +var g_up; +var g_finished = false; // for selenium testing + +function scrollMe(e) { + g_eye = g_math.mulScalarVector((e.deltaY < 0 ? 11 : 13) / 12, g_eye); + g_viewInfo.drawContext.view = g_math.matrix4.lookAt(g_eye, g_target, g_up); + // Prevents event from reaching up to the window, e.g. so page will not scroll + o3djs.event.cancel(e); +} + +/** + * Creates the client area. + */ +function init() { + o3djs.webgl.makeClients(initStep2); +} + +/** + * Initializes O3D, loads the effect, and draws the quads. + * @param {Array} clientElements Array of o3d object elements. + */ +function initStep2(clientElements) { + // Initialize global variables and libraries. + var o3dElement = clientElements[0]; + g_o3d = o3dElement.o3d; + g_math = o3djs.math; + g_client = o3dElement.client; + + // Create a pack to manage our resources/assets + 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); + + // Create our projection matrix, with a vertical field of view of 45 degrees + // a near clipping plane of 0.1 and far clipping plane of 100. + var proj_matrix = g_math.matrix4.perspective( + g_math.degToRad(45), + g_client.width / g_client.height, + 0.1, + 100); + + // Create the view matrix which tells the camera which way to point to. + g_eye = [0, 4, 0]; + g_target = [0, 0, 0]; + g_up = [0, 0, -1]; + var view_matrix = g_math.matrix4.lookAt(g_eye, g_target, g_up); + + g_viewInfo.drawContext.view = view_matrix; + g_viewInfo.drawContext.projection = proj_matrix; + + var samplers = []; + var transforms = []; + + for (var xx = 0; xx < 3; xx++) { + for (var yy = 0; yy < 2; yy++) { + var index = yy * 3 + xx; + + //Create effect for shaders. + var effect = g_pack.createObject('Effect'); + var vertexShaderString = document.getElementById('vshader').value; + var pixelShaderString = document.getElementById('pshader').value; + effect.loadVertexShaderFromString(vertexShaderString); + effect.loadPixelShaderFromString(pixelShaderString); + + // Create a new Material for the quad. + var material = g_pack.createObject('Material'); + material.drawList = g_viewInfo.performanceDrawList; + material.effect = effect; + + effect.createUniformParameters(material); + + // Create a quad and position it. + var verts = o3djs.primitives.createPlaneVertices(1, 1, 1, 1); + var texCoordStream = verts.findStream(g_o3d.Stream.TEXCOORD, 0); + // make the UVs go from 0 to 2 instead of 0 to 1 + for (var v = 0; v < texCoordStream.elements.length; ++v) { + texCoordStream.elements[v] *= 2; + } + var shape = verts.createShape(g_pack, material); + + // Make a transform for each quad. + var transform = g_pack.createObject('Transform'); + transform.translate([(xx - 1) * 1.2, 0, (0.5 - yy) * -1.2]); + transform.addShape(shape); + + + // Get the sampler on the sampler param. + var sampler = g_pack.createObject('Sampler'); + samplers[index] = sampler; + transforms[index] = transform; + material.getParam('texSampler').value = sampler; + } + } + + // Set the sampler states on each sampler. + // Looking at the generated image, the samplers correspond to the + // following quads: + // [0] [1] [2] + // [3] [4] [5] + // Sampler states not specified assume their default values which are: + // addressModeU = Sampler.WRAP + // addressModeV = Sampler.WRAP + // minFilter = Sampler.LINEAR + // magFilter = Sampler.LINEAR + // mipFilter = Sampler.POINT + // borderColor = Float4(0, 0, 0, 0) + // maxAnisotropy = 1 + + // Rotates quad and uses anisotropic filtering. + transforms[1].rotateZ(-Math.PI / 2.5); + samplers[1].addressModeU = g_o3d.Sampler.WRAP; + samplers[1].addressModeV = g_o3d.Sampler.WRAP; + samplers[1].minFilter = g_o3d.Sampler.ANISOTROPIC; + samplers[1].maxAnisotropy = 4; + + // Uses BORDER addressing mode with a red border. + samplers[2].addressModeU = g_o3d.Sampler.BORDER; + samplers[2].addressModeV = g_o3d.Sampler.BORDER; + samplers[2].borderColor = [1, 0, 0, 1]; + + // Uses POINT sampling for minification. + samplers[3].addressModeU = g_o3d.Sampler.WRAP; + samplers[3].addressModeV = g_o3d.Sampler.WRAP; + samplers[3].minFilter = g_o3d.Sampler.POINT; + + // Rotates quad and uses default (linear) filtering. + // Compare results to quad #1. + transforms[4].rotateZ(-Math.PI / 2.5); + samplers[4].addressModeU = g_o3d.Sampler.WRAP; + samplers[4].addressModeV = g_o3d.Sampler.WRAP; + samplers[4].minFilter = g_o3d.Sampler.LINEAR; + samplers[4].magFilter = g_o3d.Sampler.LINEAR; + + // Uses MIRROR addressing mode to mirror the texture on both axes. + samplers[5].addressModeU = g_o3d.Sampler.MIRROR; + samplers[5].addressModeV = g_o3d.Sampler.MIRROR; + + // Load our texture! + var url = o3djs.util.getCurrentURI() + '../assets/texture_b3.jpg'; + o3djs.io.loadTexture(g_pack, url, function(texture, exception) { + if (exception) { + alert(exception); + } else { + // Use the same texture for all the samplers. + for (var ii = 0; ii < samplers.length; ii++) { + samplers[ii].texture = texture; + } + // Parent the transforms. We do this here because until the texture + // is loaded our quads are not ready to display. + for (var ii = 0; ii < transforms.length; ii++) { + transforms[ii].parent = g_client.root; + } + g_finished = true; // for selenium testing. + } + }); + + o3djs.event.addEventListener(o3dElement, 'wheel', scrollMe); +} +</script> +</head> +<body> +<h1>Texture Sampler Example</h1> +This tutorial demonstrates various texture sampler settings. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 700px; height: 600px"></div> +<p>Scrollwheel To Zoom</p><br/> +<!-- End of O3D plugin --> + +<textarea id="vshader" style="display: none;"> +uniform mat4 worldViewProjection; + +// input parameters for our vertex shader +attribute vec4 position; +attribute vec2 texCoord0; + +// input parameters for our pixel shader +varying vec2 texCoord; + +/** + * Our vertex shader + */ +void main() { + gl_Position = worldViewProjection * position; + texCoord = texCoord0; +} +</textarea> +<textarea id="pshader" style="display: none;"> +varying vec2 texCoord; +uniform sampler2D texSampler; + +/* Given the texture coordinates, our pixel shader grabs the corresponding + * color from the texture. + */ +void main() { + gl_FragColor = texture2D(texSampler, texCoord); +} +</textarea> +</body> +</html> |