diff options
-rw-r--r-- | o3d/DEPS | 2 | ||||
-rw-r--r-- | o3d/core/cross/gl/renderer_gl.cc | 5 | ||||
-rw-r--r-- | o3d/samples/MANIFEST | 1 | ||||
-rw-r--r-- | o3d/samples/o3djs/debug.js | 24 | ||||
-rwxr-xr-x | o3d/samples/shadow-map.html | 627 | ||||
-rw-r--r-- | o3d/tests/selenium/sample_list.txt | 1 |
6 files changed, 655 insertions, 5 deletions
@@ -2,7 +2,7 @@ vars = { "chromium_trunk": "http://src.chromium.org/svn/trunk", "nixysa_rev": "28", - "o3d_code_rev": "95", + "o3d_code_rev": "96", } deps = { diff --git a/o3d/core/cross/gl/renderer_gl.cc b/o3d/core/cross/gl/renderer_gl.cc index 8638607..dbd34fd 100644 --- a/o3d/core/cross/gl/renderer_gl.cc +++ b/o3d/core/cross/gl/renderer_gl.cc @@ -1567,6 +1567,11 @@ bool RendererGL::SaveScreen(const String& file_name) { MakeCurrentLazy(); Bitmap::Ref bitmap = Bitmap::Ref(new Bitmap(service_locator())); bitmap->Allocate(Texture::ARGB8, width(), height(), 1, false); + + // Note: glReadPixels captures the alpha component of the frame buffer as well + // as the color components, the browser usually ignores the alpha channel when + // drawing to the screen, so unless the alpha is 1, the png image generated + // might exhibit suprise translucency. ::glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap->image_data()); bool result = bitmap->SaveToPNGFile((file_name + ".png").c_str()); diff --git a/o3d/samples/MANIFEST b/o3d/samples/MANIFEST index ef3a61c..72145b8 100644 --- a/o3d/samples/MANIFEST +++ b/o3d/samples/MANIFEST @@ -283,6 +283,7 @@ shaders/texture-only.shader shaders/toon.shader shaders/vertex-color.shader shaders/yuv2rgb.shader +shadow-map.html simpleviewer/assets/cube.o3dtgz simpleviewer/simpleviewer.html trends/assets/clouds.jpg diff --git a/o3d/samples/o3djs/debug.js b/o3d/samples/o3djs/debug.js index 9589c50..2f4be54 100644 --- a/o3d/samples/o3djs/debug.js +++ b/o3d/samples/o3djs/debug.js @@ -263,6 +263,25 @@ o3djs.debug.VertexInfo.prototype.Offset = { }; /** + * Computes the number of vertices in this vertex info. + * @return {number} The number of vertices. + */ +o3djs.debug.VertexInfo.prototype.numVertices = function() { + return this.vertices.length / 3; +}; + + +/** + * Given the number of a vertex returns the index in the array where + * the coordinates of that vertex vertexIndex. + * @param {number} vertexNumber The vertex number. + * @return {number} The index where that vertex begins. + */ +o3djs.debug.VertexInfo.prototype.vertexIndex = function(vertexNumber) { + return vertexNumber * 3; +} + +/** * Adds a vertex. * @param {number} positionX The x position of the vertex. * @param {number} positionY The y position of the vertex. @@ -298,6 +317,7 @@ o3djs.debug.VertexInfo.prototype.createShape = function( this.indices); }; + /** * Reorients the vertex positions of this vertexInfo by the * given matrix. In other words it multiplies each vertex by the @@ -306,10 +326,6 @@ o3djs.debug.VertexInfo.prototype.createShape = function( */ o3djs.debug.VertexInfo.prototype.reorient = function(matrix) { var math = o3djs.math; - // Assume if it has a length it's not a Matrix4 - if (matrix.length) { - matrix = math.matrix4.copy(matrix); - } var numVerts = this.numVertices(); for (var v = 0; v < numVerts; ++v) { var index = this.vertexIndex(v); diff --git a/o3d/samples/shadow-map.html b/o3d/samples/shadow-map.html new file mode 100755 index 0000000..a7bb6e9 --- /dev/null +++ b/o3d/samples/shadow-map.html @@ -0,0 +1,627 @@ +<!-- +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="o3djs/base.js"></script> +<script type="text/javascript"> +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_shadowColorEffect; +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.util.makeClients(main, 'FloatingPointTextures'); +} + + +/** + * 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; + + 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() { + // 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, g_pack); + + // Create the depth-stencil buffer required when rendering the teapot. + var depthSurface = g_pack.createDepthStencilSurface(SHADOW_MAP_WIDTH, + SHADOW_MAP_HEIGHT); + + // 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; + + shadowPassRenderRoot.parent = g_client.renderGraphRoot; + g_colorPassRenderRoot.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() { + g_shadowMaterial = g_pack.createObject('Material'); + g_shadowMaterial.drawList = g_shadowViewInfo.performanceDrawList; + + var shadowEffect = g_pack.createObject('Effect'); + var shadowEffectString = document.getElementById('shadowShader').text; + shadowEffect.loadFromFXString(shadowEffectString); + g_shadowMaterial.effect = shadowEffect; + shadowEffect.createUniformParameters(g_shadowMaterial); + + g_shadowColorEffect = g_pack.createObject('Effect'); + var colorEffectString = document.getElementById('shadowColorShader').text; + g_shadowColorEffect.loadFromFXString(colorEffectString); + + 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. + + // 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 = createShadowColorMaterial([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 = createShadowColorMaterial([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 = createShadowColorMaterial([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 createShadowColorMaterial(baseColor) { + var material = g_pack.createObject('Material'); + material.drawList = g_colorViewInfo.performanceDrawList; + + material.effect = g_shadowColorEffect; + g_shadowColorEffect.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 = 80; + + 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="shadowShader" type="text/O3DShader"> + /** + * 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. + */ + + // The light's wvp matrix + float4x4 worldViewProjection : WorldViewProjection; + + // Input parameters for our vertex shader. + struct VertexShaderInput { + float4 position : POSITION; + }; + + // Input parameters for our pixel shader. + struct PixelShaderInput { + float4 position : POSITION; + float2 depth : TEXCOORD0; + }; + + /** + * The vertex shader simply transforms the input vertices to screen space. + */ + PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + PixelShaderInput output; + // Render from the light's perspective. + output.position = mul(input.position, worldViewProjection); + output.depth = output.position.zw; + return output; + } + + /** + * The pixel shader returns a shade of gray. The lighter the shade the + * farther that fragment is from the light. + */ + float4 pixelShaderFunction(PixelShaderInput input): COLOR { + // Pixels in the shadowmap store the pixel depth from the light's + // perspective in normalized device coordinates. + return float4(input.depth.x / input.depth.y); + } + + // #o3d VertexShaderEntryPoint vertexShaderFunction + // #o3d PixelShaderEntryPoint pixelShaderFunction + // #o3d MatrixLoadOrder RowMajor +</script> + + +<script id="shadowColorShader" type="text/O3DShader"> + /** + * This shader is for the effect applied in the second render pass when the + * shadowed shapes are drawn to the screen. In the pixel shader, the distance + * from the rendered point to the camera is compared to the distance encoded + * in the shadow map. If the distance is much greater, the rendered point is + * considered to be in shadow and is given a light coefficient of 0. + */ + + float4x4 world : World; + float4x4 worldViewProjection : WorldViewProjection; + float4x4 worldInverseTranspose : WorldInverseTranspose; + float4x4 viewInverse : ViewInverse; + float4x4 lightViewProjection; + sampler shadowMapSampler; + + // Parameters for the phong shader. + uniform float3 lightWorldPos; + uniform float4 lightColor; + uniform float4 ambient; + uniform float4 diffuse; + uniform float4 specular; + uniform float shininess; + + // input parameters for our vertex shader + struct VertexShaderInput { + float4 position : POSITION; + float3 normal : NORMAL; + }; + + // input parameters for our pixel shader + struct PixelShaderInput { + float4 position : POSITION; + float4 projTextureCoords : TEXCOORD0; + float4 worldPosition : TEXCOORD1; + float3 normal : TEXCOORD2; + }; + + PixelShaderInput vertexShaderFunction(VertexShaderInput input) { + PixelShaderInput output; + + // Transform to homogeneous clip space. + output.position = mul(input.position, worldViewProjection); + + // Compute the projective texture coordinates to project the shadow map + // onto the scene. + float4x4 worldLightViewProjection = mul(world, lightViewProjection); + output.projTextureCoords = mul(input.position, worldLightViewProjection); + output.worldPosition = mul(input.position, world); + output.normal = mul(float4(input.normal, 0), worldInverseTranspose).xyz; + + return output; + } + + float4 pixelShaderFunction(PixelShaderInput input): COLOR { + float3 surfaceToLight = normalize(lightWorldPos - input.worldPosition); + float3 surfaceToView = normalize(viewInverse[3].xyz - input.worldPosition); + float3 normal = normalize(input.normal); + float3 halfVector = normalize(surfaceToLight + surfaceToView); + float4 litResult = lit(dot(normal, surfaceToLight), + dot(normal, halfVector), shininess); + float4 outColor = ambient; + float4 projCoords = input.projTextureCoords; + + // Convert texture coords to [0, 1] range. + projCoords.xy /= projCoords.w; + projCoords.x = 0.5 * projCoords.x + 0.5; + projCoords.y = -0.5 * projCoords.y + 0.5; + + // Compute the pixel depth for shadowing. + float depth = projCoords.z / projCoords.w; + + // If the rednered point is farter from the light than the distance encoded + // in the shadow map, we give it a light coefficient of 0. + float light = tex2D(shadowMapSampler, projCoords.xy).r + 0.008 > depth; + + // Make the illuninated area a round spotlight shape just for fun. + // Comment this line out to see just the shadows. + light *= 1 - smoothstep(0.45, 0.5, length(projCoords - float2(0.5, 0.5))); + + outColor += light * lightColor * + (diffuse * litResult.y + specular * litResult.z); + return outColor; + } + + // #o3d VertexShaderEntryPoint vertexShaderFunction + // #o3d PixelShaderEntryPoint pixelShaderFunction + // #o3d MatrixLoadOrder RowMajor +</script> + + +</head> +<body> +<h1>Shadow Maps</h1> +This sample implements a basic shadow map. +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 600px; 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> diff --git a/o3d/tests/selenium/sample_list.txt b/o3d/tests/selenium/sample_list.txt index de0f665..6a8dc5d 100644 --- a/o3d/tests/selenium/sample_list.txt +++ b/o3d/tests/selenium/sample_list.txt @@ -101,6 +101,7 @@ medium simpletexture screenshot pdiff_threshold(5100) medium skinning screenshot pdiff_threshold(500) medium sobel screenshot pdiff_threshold(1400) medium stencil_example screenshot(0) screenshot(100) screenshot(7777) pdiff_threshold(4800) pdiff_threshold_win(20800) +medium shadow-map screenshot pdiff_threshold(10000) small texturesamplers screenshot pdiff_threshold(32200) pdiff_threshold_win(37100) medium tutorial-primitive screenshot pdiff_threshold(1200) pdiff_threshold_mac(10400) large vertex-shader screenshot timeout(45000) pdiff_threshold(1400) except(*iexplore) |