blob: 36266d9975cc185637e38213b9471326dbfe3772 [file] [log] [blame]
<!DOCTYPE html>
<!--
/*
* Copyright (C) 2009 Apple 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:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
*/
-->
<html>
<head>
<title>Teapot (per-pixel)</title>
<script src="resources/J3DI.js"> </script>
<script src="resources/J3DIMath.js" type="text/javascript"> </script>
<script id="vshader" type="x-shader/x-vertex">
/*
Copyright (c) 2008 Seneca College
Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/)
*/
// We need to create our own light structure since we can't access
// the light() function in the 2.0 context.
struct Light
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
vec3 halfVector;
};
struct Material
{
vec4 emission;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
//
// vertex attributes
//
attribute vec4 a_vertex;
attribute vec3 a_normal;
attribute vec4 a_texCoord;
// for every model we multiply the projection, view and model matrices
// once to prevent having to do it for every vertex, however we still need
// the view matrix to calculate lighting.
uniform mat4 u_modelViewMatrix;
// we can calculate this once per model to speed up processing done on the js side.
uniform mat4 u_modelViewProjMatrix;
// matrix to transform the vertex normals
uniform mat4 u_normalMatrix;
// custom light structures need to be used since we don't have access to
// light states.
uniform Light u_light;
// material
uniform vec4 u_globalAmbientColor;
uniform Material u_frontMaterial;
uniform Material u_backMaterial;
// passed to fragment shader
varying vec4 v_diffuse, v_ambient;
varying vec3 v_normal, v_lightDir;
varying vec2 v_texCoord;
/*
Given a reference to the ambient and diffuse lighting variables,
this function will calculate how much each component contributes to the scene.
Light light - the light in view space
vec3 normal -
vec4 ambient -
vec4 diffuse -
*/
vec3 directionalLight(inout vec4 ambient, inout vec4 diffuse)
{
ambient += u_light.ambient;
diffuse += u_light.diffuse;
return normalize(vec3(u_light.position));
}
void main()
{
v_normal = normalize(u_normalMatrix * vec4(a_normal, 1)).xyz;
vec4 ambient = vec4(0.0, 0.0, 0.0, 1.0);
vec4 diffuse = vec4(0.0, 0.0, 0.0, 1.0);
vec4 specular = vec4(0.0, 0.0, 0.0, 1.0);
// place the current vertex into view space
// ecPos = eye coordinate position.
vec4 ecPos4 = u_modelViewMatrix * a_vertex;
// the current vertex in eye coordinate space
vec3 ecPos = ecPos4.xyz/ecPos4.w;
v_lightDir = directionalLight(ambient, diffuse);
v_ambient = u_frontMaterial.ambient * ambient;
v_ambient += u_globalAmbientColor * u_frontMaterial.ambient;
v_diffuse = u_frontMaterial.diffuse * diffuse;
gl_Position = u_modelViewProjMatrix * a_vertex;
v_texCoord = a_texCoord.st;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
struct Light
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
vec4 position;
vec3 halfVector;
};
struct Material
{
vec4 emission;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
uniform sampler2D u_sampler2d;
uniform Light u_light;
uniform Material u_frontMaterial;
uniform Material u_backMaterial;
varying vec4 v_diffuse, v_ambient;
varying vec3 v_normal, v_lightDir;
varying vec2 v_texCoord;
void main()
{
vec4 color = v_diffuse;
vec3 n = normalize(v_normal);
Light light = u_light;
vec3 lightDir = v_lightDir;
float nDotL = max(dot(n, lightDir), 0.0);
if (nDotL > 0.0) {
color = vec4(color.rgb * nDotL, color.a);
float nDotHV = max(dot(n, light.halfVector), 0.0);
vec4 specular = u_frontMaterial.specular * light.specular;
color += vec4(specular.rgb * pow(nDotHV, u_frontMaterial.shininess), specular.a);
}
gl_FragColor = color + v_ambient;
}
</script>
<script>
function setDirectionalLight(ctx, program, eyeVector, direction, ambient, diffuse, specular)
{
var lightString = "u_light.";
ctx.uniform4f(ctx.getUniformLocation(program, lightString+"ambient"),
ambient[0], ambient[1], ambient[2], ambient[3]);
ctx.uniform4f(ctx.getUniformLocation(program, lightString+"diffuse"),
diffuse[0], diffuse[1], diffuse[2], diffuse[3]);
ctx.uniform4f(ctx.getUniformLocation(program, lightString+"specular"),
specular[0], specular[1], specular[2], specular[3]);
ctx.uniform4f(ctx.getUniformLocation(program, lightString+"position"),
direction[0], direction[1], direction[2], direction[3]);
// compute the half vector
var halfVector = [ eyeVector[0] + direction[0], eyeVector[1] + direction[1], eyeVector[2] + direction[2] ];
var length = Math.sqrt(halfVector[0] * halfVector[0] +
halfVector[1] * halfVector[1] +
halfVector[2] * halfVector[2]);
if (length == 0)
halfVector = [ 0, 0, 1 ];
else {
halfVector[0] /= length;
halfVector[1] /= length;
halfVector[2] /= length;
}
ctx.uniform3f(ctx.getUniformLocation(program, lightString+"halfVector"),
halfVector[0], halfVector[1], halfVector[2]);
}
function setMaterial(ctx, program, emission, ambient, diffuse, specular, shininess)
{
var matString = "u_frontMaterial.";
ctx.uniform4f(ctx.getUniformLocation(program, matString+"emission"),
emission[0], emission[1], emission[2], emission[3]);
ctx.uniform4f(ctx.getUniformLocation(program, matString+"ambient"),
ambient[0], ambient[1], ambient[2], ambient[3]);
ctx.uniform4f(ctx.getUniformLocation(program, matString+"diffuse"),
diffuse[0], diffuse[1], diffuse[2], diffuse[3]);
ctx.uniform4f(ctx.getUniformLocation(program, matString+"specular"),
specular[0], specular[1], specular[2], specular[3]);
ctx.uniform1f(ctx.getUniformLocation(program, matString+"shininess"), shininess);
}
function init()
{
var gl = initWebGL("example", "vshader", "fshader",
[ "a_normal", "a_texCoord", "a_vertex"],
[ 0, 0, 0, 1 ], 10000);
gl.uniform1i(gl.getUniformLocation(gl.program, "u_sampler2d"), 0);
gl.uniform4f(gl.getUniformLocation(gl.program, "u_globalAmbientColor"), 0.2, 0.2, 0.2, 1);
setDirectionalLight(gl, gl.program,
[ 0, 0, 1 ], // eyeVector
[0, 0, 1, 1], // position
[0.1, 0.1, 0.1, 1], // ambient
[1, 1, 1, 1], // diffuse
[1, 1, 1, 1]); // specular
setMaterial(gl, gl.program,
[ 0, 0, 0, 0 ], // emission
[ 0.1, 0.1, 0.1, 1 ], // ambient
[ 0.8, 0.2, 0, 1 ], // diffuse
[ 0, 0, 1, 1 ], // specular
32); // shininess
obj = loadObj(gl, "resources/teapot.obj");
mvMatrix = new J3DIMatrix4();
normalMatrix = new J3DIMatrix4();
return gl;
}
width = -1;
height = -1;
loaded = false;
function reshape(ctx)
{
var canvas = document.getElementById('example');
if (canvas.width == width && canvas.height == height)
return;
width = canvas.width;
height = canvas.height;
ctx.viewport(0, 0, width, height);
ctx.perspectiveMatrix = new J3DIMatrix4();
ctx.perspectiveMatrix.perspective(30, width/height, 1, 10000);
ctx.perspectiveMatrix.lookat(0,0,50, 0, 0, 0, 0, 1, 0);
}
function drawPicture(ctx)
{
var startRenderTime = new Date().getTime();
reshape(ctx);
ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT);
if (!loaded && obj.loaded) {
loaded = true;
ctx.enableVertexAttribArray(0);
ctx.enableVertexAttribArray(1);
ctx.enableVertexAttribArray(2);
ctx.bindBuffer(ctx.ARRAY_BUFFER, obj.vertexObject);
ctx.vertexAttribPointer(2, 3, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ARRAY_BUFFER, obj.normalObject);
ctx.vertexAttribPointer(0, 3, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ARRAY_BUFFER, obj.texCoordObject);
ctx.vertexAttribPointer(1, 2, ctx.FLOAT, false, 0, 0);
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
}
if (!loaded)
return;
// generate the model-view matrix
mvMatrix.makeIdentity();
mvMatrix.rotate(10, 1,0,0);
mvMatrix.rotate(currentAngle, 0, 1, 0);
mvMatrix.setUniform(ctx, ctx.getUniformLocation(ctx.program, "u_modelViewMatrix"), false);
// construct the normal matrix from the model-view matrix
normalMatrix.load(mvMatrix);
normalMatrix.invert();
normalMatrix.transpose();
normalMatrix.setUniform(ctx, ctx.getUniformLocation(ctx.program, "u_normalMatrix"), false);
// Construct the model-view * projection matrix and pass it in
var mvpMatrix = new J3DIMatrix4();
mvpMatrix.load(ctx.perspectiveMatrix);
mvpMatrix.multiply(mvMatrix);
mvpMatrix.setUniform(ctx, ctx.getUniformLocation(ctx.program, "u_modelViewProjMatrix"), false);
ctx.drawElements(ctx.TRIANGLES, obj.numIndices, ctx.UNSIGNED_SHORT, 0);
ctx.flush();
framerate.snapshot();
currentAngle += incAngle;
if (currentAngle > 360)
currentAngle -= 360;
}
function start()
{
var c = document.getElementById("example");
var w = Math.floor(window.innerWidth * 0.9);
var h = Math.floor(window.innerHeight * 0.9);
c.width = w;
c.height = h;
var ctx = init();
currentAngle = 0;
incAngle = 0.2;
framerate = new Framerate("framerate");
var f = function() { drawPicture(ctx) };
setInterval(f, 10);
}
</script>
<style type="text/css">
canvas {
border: 2px solid black;
}
</style>
</head>
<body onload="start()">
<canvas id="example">
There is supposed to be an example drawing here, but it's not important.
</canvas>
<div id="framerate"></div>
</body>
</html>