Files
three.js/examples/webgl_geometry_minecraft_ao.html
T
alteredq 3e2f4f7cc5 Merged with mrdoob's branch.
Also got uqbiquity working and fixed ugly globals bug in WebGLRenderer. Again we missed it because of consistent naming ;)
2011-02-24 01:31:33 +01:00

924 lines
23 KiB
HTML

<!DOCTYPE HTML>
<html lang="en">
<head>
<title>three.js webgl - geometry - minecraft - ao</title>
<meta charset="utf-8">
<style type="text/css">
body {
color: #61443e;
font-family:Monospace;
font-size:13px;
text-align:center;
/* background-color: #bfd1e5; */
background-color: #ffffff;
margin: 0px;
overflow: hidden;
}
a { color: #a06851; }
#info {
position: absolute;
top: 0px; width: 100%;
padding: 5px;
}
#oldie {
background:rgb(100,0,0) !important;
color:#fff !important;
margin-top:10em !important;
}
#oldie a { color:#fff }
button { border:0; background:rgba(0,0,0,0.5); color:orange; cursor:pointer }
button:hover { color:gold }
</style>
</head>
<body>
<div id="container"><br /><br /><br /><br /><br />Generating world...</div>
<div id="info">
<a href="http://github.com/mrdoob/three.js" target="_blank">three.js</a> - <a href="http://www.minecraft.net/" target="_blank">minecraft</a> demo [ambient occlusion]. featuring <a href="http://painterlypack.net/" target="_blank">painterly pack</a><br />(left click: forward, right click: backward)
<br/><br/>
<button id="bt">texture</button>
<button id="bao">ao</button>
<button id="baot">texture + ao</button>
</div>
<script type="text/javascript" src="../build/Three.js"></script>
<script type="text/javascript" src="js/ImprovedNoise.js"></script>
<script type="text/javascript" src="js/Detector.js"></script>
<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
<script type="text/javascript" src="js/Stats.js"></script>
<script type="text/javascript">
if ( ! Detector.webgl ) {
Detector.addGetWebGLMessage();
document.getElementById( 'container' ).innerHTML = "";
}
var fogExp2 = true;
var container, stats;
var camera, scene, renderer;
var mesh;
var mat;
var worldWidth = 128, worldDepth = 128,
worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2,
data = generateHeight( worldWidth, worldDepth );
var mouseX = 0, mouseY = 0,
lat = 0, lon = 0, phy = 0, theta = 0;
var direction = new THREE.Vector3(),
moveForward = false, moveBackward = false, moveLeft = false, moveRight = false;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById( 'container' );
if( fogExp2 )
camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 20000 );
else
camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 7500 );
camera.target.position.z = - 100;
camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100;
camera.target.position.y = camera.position.y;
scene = new THREE.Scene();
if( fogExp2 )
scene.fog = new THREE.FogExp2( 0xffffff, 0.00025 );
else
scene.fog = new THREE.Fog( 0xffffff, - 1000, 7500 );
var debug_texture = false,
debug_numbers = false,
debug_corner_colors = false,
strength = 2,
textures = { side: 'textures/minecraft/grass_dirt.png',
top: 'textures/minecraft/grass.png',
bottom: 'textures/minecraft/dirt.png'
},
m_aot = generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors ),
m_ao = generateMegamaterialAO( textures, strength, true, debug_numbers, debug_corner_colors ),
m_t = generateMegamaterialPlain( textures ),
//m_d = generateMegamaterialDebug(),
mat = generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors ),
materials = [ mat, mat, mat, mat, mat, mat ];
var i, j, x, z, h, h2, uv,
px, nx, pz, nz, sides,
right, left, bottom, top,
nright, nleft, nback, nfront,
nleftup, nrightup, nbackup, nfrontup,
nrb, nrf, nlb, nlf,
nrbup, nrfup,
face_px, face_nx, face_py, face_ny, face_pz, face_nz,
ti, ri, li, bi, fi, ci, mi, mm, column, row,
cube,
unit = 1/16 * 0.95, padding = 1/16 * 0.025, p, s, t, hash, N = -1,
// map of UV indices for faces of partially defined cubes
uv_index_map = {
0: { px: N, nx: N, py: 0, ny: N, pz: N, nz: N },
1: { px: N, nx: N, py: 0, ny: N, pz: N, nz: 1 },
2: { px: N, nx: N, py: 0, ny: N, pz: 1, nz: N },
3: { px: N, nx: N, py: 0, ny: N, pz: 1, nz: 2 },
4: { px: N, nx: 0, py: 1, ny: N, pz: N, nz: N },
5: { px: N, nx: 0, py: 1, ny: N, pz: N, nz: 2 },
6: { px: N, nx: 0, py: 1, ny: N, pz: 2, nz: N },
7: { px: N, nx: 0, py: 1, ny: N, pz: 2, nz: 3 },
8: { px: 0, nx: N, py: 1, ny: N, pz: N, nz: N },
9: { px: 0, nx: N, py: 1, ny: N, pz: N, nz: 2 },
10: { px: 0, nx: N, py: 1, ny: N, pz: 2, nz: N },
11: { px: 0, nx: N, py: 1, ny: N, pz: 2, nz: 3 },
12: { px: 0, nx: 1, py: 2, ny: N, pz: N, nz: N },
13: { px: 0, nx: 1, py: 2, ny: N, pz: N, nz: 3 },
14: { px: 0, nx: 1, py: 2, ny: N, pz: 3, nz: N },
15: { px: 0, nx: 1, py: 2, ny: N, pz: 3, nz: 4 }
},
// all possible combinations of corners and sides
// mapped to mixed tiles
// (including corners overlapping sides)
// (excluding corner alone and sides alone)
// looks ugly, but allows to squeeze all
// combinations for one texture into just 3 rows
// instead of 16
mixmap = {
"1_1": 0,
"1_3": 0,
"1_9": 0,
"1_11": 0,
"1_4": 1,
"1_6": 1,
"1_12": 1,
"1_14": 1,
"2_2": 2,
"2_3": 2,
"2_6": 2,
"2_7": 2,
"2_8": 3,
"2_9": 3,
"2_12": 3,
"2_13": 3,
"4_1": 4,
"4_5": 4,
"4_9": 4,
"4_13": 4,
"4_2": 5,
"4_6": 5,
"4_10": 5,
"4_14": 5,
"8_4": 6,
"8_5": 6,
"8_6": 6,
"8_7": 6,
"8_8": 7,
"8_9": 7,
"8_10": 7,
"8_11": 7,
"1_5": 8,
"1_7": 8,
"1_13": 8,
"1_15": 8,
"2_10": 9,
"2_11": 9,
"2_14": 9,
"2_15": 9,
"4_3": 10,
"4_7": 10,
"4_11": 10,
"4_15": 10,
"8_12": 11,
"8_13": 11,
"8_14": 11,
"8_15": 11,
"5_1": 12,
"5_3": 12,
"5_7": 12,
"5_9": 12,
"5_11": 12,
"5_13": 12,
"5_15": 12,
"6_2": 13,
"6_3": 13,
"6_6": 13,
"6_7": 13,
"6_10": 13,
"6_11": 13,
"6_14": 13,
"6_15": 13,
"9_4": 14,
"9_5": 14,
"9_6": 14,
"9_7": 14,
"9_12": 14,
"9_13": 14,
"9_14": 14,
"9_15": 14,
"10_8": 15,
"10_9": 15,
"10_10": 15,
"10_11": 15,
"10_12": 15,
"10_13": 15,
"10_14": 15,
"10_15": 15
},
tilemap = {},
top_row_corners = 0,
top_row_mixed = 1,
top_row_sides = 2,
sides_row = 3,
bottom_row = 4,
geometry = new THREE.Geometry();
// mapping from 256 possible corners + sides combinations
// into 3 x 16 tiles
for ( i = 0; i < 16; i++ ) {
for ( j = 0; j < 16; j++ ) {
mm = i + "_" + j;
if ( i == 0 )
row = top_row_corners;
else if ( mixmap[ mm ] != undefined )
row = top_row_mixed;
else
row = top_row_sides;
tilemap[ mm ] = row;
}
}
function setUVTile( face, s, t ) {
var j, uv = cube.uvs[ face ];
for ( j = 0; j < uv.length; j++ ) {
uv[ j ].u += s * (unit+2*padding);
uv[ j ].v += t * (unit+2*padding);
}
}
for ( z = 0; z < worldDepth; z ++ ) {
for ( x = 0; x < worldWidth; x ++ ) {
h = getY( x, z );
// direct neighbors
h2 = getY( x - 1, z );
nleft = h2 == h || h2 == h + 1;
h2 = getY( x + 1, z );
nright = h2 == h || h2 == h + 1;
h2 = getY( x, z + 1 );
nback = h2 == h || h2 == h + 1;
h2 = getY( x, z - 1 );
nfront = h2 == h || h2 == h + 1;
// corner neighbors
nrb = getY( x - 1, z + 1 ) == h && x > 0 && z < worldDepth - 1 ? 1 : 0;
nrf = getY( x - 1, z - 1 ) == h && x > 0 && z > 0 ? 1 : 0;
nlb = getY( x + 1, z + 1 ) == h && x < worldWidth - 1 && z < worldDepth - 1 ? 1 : 0;
nlf = getY( x + 1, z - 1 ) == h && x < worldWidth - 1 && z > 0 ? 1 : 0;
// up neighbors
nleftup = getY( x - 1, z ) > h && x > 0 ? 1 : 0;
nrightup = getY( x + 1, z ) > h && x < worldWidth - 1 ? 1 : 0;
nbackup = getY( x, z + 1 ) > h && z < worldDepth - 1 ? 1 : 0;
nfrontup = getY( x, z - 1 ) > h && z > 0 ? 1 : 0;
// up corner neighbors
nrbup = getY( x - 1, z + 1 ) > h && x > 0 && z < worldDepth - 1 ? 1 : 0;
nrfup = getY( x - 1, z - 1 ) > h && x > 0 && z > 0 ? 1 : 0;
nlbup = getY( x + 1, z + 1 ) > h && x < worldWidth - 1 && z < worldDepth - 1 ? 1 : 0;
nlfup = getY( x + 1, z - 1 ) > h && x < worldWidth - 1 && z > 0 ? 1 : 0;
// textures
ti = nleftup * 8 + nrightup * 4 + nfrontup * 2 + nbackup * 1;
ri = nrf * 8 + nrb * 4 + 1;
li = nlb * 8 + nlf * 4 + 1;
bi = nrb * 8 + nlb * 4 + 1;
fi = nlf * 8 + nrf * 4 + 1;
ci = nlbup * 8 + nlfup * 4 + nrbup * 2 + nrfup * 1;
// cube sides
px = nx = pz = nz = 0;
px = !nleft || x == 0 ? 1 : 0;
nx = !nright || x == worldWidth - 1 ? 1 : 0;
pz = !nback || z == worldDepth - 1 ? 1 : 0;
nz = !nfront || z == 0 ? 1 : 0;
sides = { px: px, nx: nx, py: true, ny: false, pz: pz, nz: nz };
cube = new Cube( 100, 100, 100, 1, 1, materials, false, sides );
// set UV tiles
for ( i = 0; i < cube.uvs.length; i++ ) {
uv = cube.uvs[ i ];
for ( j = 0; j < uv.length; j++ ) {
p = uv[j].u == 0 ? padding : -padding;
uv[j].u = uv[j].u * unit + p;
p = uv[j].v == 0 ? padding : -padding;
uv[j].v = uv[j].v * unit + p;
}
}
hash = px * 8 + nx * 4 + pz * 2 + nz;
face_px = uv_index_map[ hash ].px;
face_nx = uv_index_map[ hash ].nx;
face_py = uv_index_map[ hash ].py;
face_ny = uv_index_map[ hash ].ny;
face_pz = uv_index_map[ hash ].pz;
face_nz = uv_index_map[ hash ].nz;
if( face_px != N ) setUVTile( face_px, ri, sides_row );
if( face_nx != N ) setUVTile( face_nx, li, sides_row );
if( face_py != N ) {
mm = ti + "_" + ci;
switch ( tilemap[ mm ] ) {
case top_row_sides: column = ti; break;
case top_row_corners: column = ci; break;
case top_row_mixed: column = mixmap[ mm ]; break;
}
setUVTile( face_py, column, tilemap[ mm ] );
}
if( face_ny != N ) setUVTile( face_ny, 0, bottom_row );
if( face_pz != N ) setUVTile( face_pz, bi, sides_row );
if( face_nz != N ) setUVTile( face_nz, fi, sides_row );
mesh = new THREE.Mesh( cube );
mesh.position.x = x * 100 - worldHalfWidth * 100;
mesh.position.y = h * 100;
mesh.position.z = z * 100 - worldHalfDepth * 100;
GeometryUtils.merge( geometry, mesh );
}
}
geometry.sortFacesByMaterial();
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
scene.addObject( mesh );
var ambientLight = new THREE.AmbientLight( 0xcccccc );
scene.addLight( ambientLight );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
directionalLight.position.x = 1;
directionalLight.position.y = 1;
directionalLight.position.z = 0.5;
directionalLight.position.normalize();
scene.addLight( directionalLight );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.innerHTML = "";
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
document.addEventListener( 'keydown', onDocumentKeyDown, false );
document.addEventListener( 'keyup', onDocumentKeyUp, false );
document.getElementById( "bao" ).addEventListener( "click", function() { mat.map = m_ao.map; }, false );
document.getElementById( "baot" ).addEventListener( "click", function() { mat.map = m_aot.map; }, false );
document.getElementById( "bt" ).addEventListener( "click", function() { mat.map = m_t.map; }, false );
}
function generateMegamaterialAO( textures, strength, debug_texture, debug_numbers, debug_corner_colors ) {
var count = 0,
tex_side = loadTexture( textures.side, function() { count++; generateTexture() } ),
tex_top = loadTexture( textures.top, function() { count++; generateTexture() } ),
tex_bottom = loadTexture( textures.bottom, function() { count++; generateTexture() } ),
canvas = document.createElement( 'canvas' ),
ctx = canvas.getContext( '2d' ),
size = 256, tile = 16;
canvas.width = canvas.height = size;
var texture = new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter );
function generateTexture() {
if( count == 3 ) {
for( var i = 0; i < 16; i++ ) {
drawAOCorners( ctx, tex_top, 0, i, i, tile, strength, debug_texture, debug_numbers, debug_corner_colors );
drawAOMixed ( ctx, tex_top, 1, i, i, tile, strength, debug_texture, debug_numbers, debug_corner_colors );
drawAOSides ( ctx, tex_top, 2, i, i, tile, strength, debug_texture, debug_numbers );
drawAOSides ( ctx, tex_side, 3, i, i, tile, strength, debug_texture, debug_numbers );
drawAOSides ( ctx, tex_bottom, 4, i, i, tile, strength, debug_texture, debug_numbers );
}
texture.needsUpdate = true;
}
}
return new THREE.MeshLambertMaterial( { map: texture } );
}
function generateMegamaterialPlain( textures ) {
var count = 0,
tex_side = loadTexture( textures.side, function() { count++; generateTexture() } ),
tex_top = loadTexture( textures.top, function() { count++; generateTexture() } ),
tex_bottom = loadTexture( textures.bottom, function() { count++; generateTexture() } ),
canvas = document.createElement( 'canvas' ),
ctx = canvas.getContext( '2d' ),
size = 256, tile = 16;
canvas.width = canvas.height = size;
var texture = new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter );
function generateTexture() {
if( count == 3 ) {
var i, sx;
for( i = 0; i < 16; i++ ) {
sx = i * tile;
drawBase( ctx, tex_top, sx, 0 * tile, tile, false );
drawBase( ctx, tex_top, sx, 1 * tile, tile, false );
drawBase( ctx, tex_top, sx, 2 * tile, tile, false );
drawBase( ctx, tex_side, sx, 3 * tile, tile, false );
drawBase( ctx, tex_bottom, sx, 4 * tile, tile, false );
}
texture.needsUpdate = true;
}
}
return new THREE.MeshLambertMaterial( { map: texture } );
}
function generateMegamaterialDebug() {
var canvas = document.createElement( 'canvas' ),
ctx = canvas.getContext( "2d" ),
size = 256, tile = 16,
i, j, h, s;
canvas.width = size;
canvas.height = size;
ctx.textBaseline = "top";
ctx.font = "8pt arial";
for ( i = 0; i < tile; i++ ) {
for ( j = 0; j < tile; j++ ) {
h = i * tile + j;
ctx.fillStyle = "hsl(" + h + ",90%, 50%)";
ctx.fillRect( i * tile, j * tile, tile, tile );
drawHex( ctx, h, i * tile + 2, j * tile + 2 );
}
}
var texture = new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter );
texture.needsUpdate = true;
return new THREE.MeshLambertMaterial( { map: texture } );
}
function drawHex( ctx, n, x, y ) {
ctx.fillStyle = "black";
ctx.font = "8pt arial";
ctx.textBaseline = "top";
var s = n.toString( 16 );
s = n < 16 ? "0" + s : s;
ctx.fillText( s, x, y );
}
function drawBase( ctx, image, sx, sy, tile, debug_texture ) {
if ( debug_texture ) {
ctx.fillStyle = "#888";
ctx.fillRect( sx, sy, tile, tile );
} else {
ctx.drawImage( image, sx, sy, tile, tile );
}
}
function drawCorner( ctx, sx, sy, sa, ea, color, step, n ) {
for( var i = 0; i < n; i++ ) {
ctx.strokeStyle = color + step * ( n - i ) + ")";
ctx.beginPath();
ctx.arc( sx, sy, i, sa, ea, 0 ) ;
ctx.stroke();
}
}
function drawSide( ctx, sx, sy, a, b, n, width, height, color, step ) {
for( var i = 0; i < n; i++ ) {
ctx.fillStyle = color + step * ( n - i ) + ")";
ctx.fillRect( sx + a * i, sy + b * i, width, height );
}
}
function drawAOSides( ctx, image, row, column, sides, tile, strength, debug_texture, debug_numbers ) {
var sx = column * tile, sy = row * tile;
drawBase( ctx, image, sx, sy, tile, debug_texture );
drawAOSidesImp( ctx, image, row, column, sides, tile, strength );
if ( debug_numbers ) drawHex( ctx, row * tile + sides, sx + 2, sy + 2 );
}
function drawAOCorners( ctx, image, row, column, corners, tile, strength, debug_texture, debug_numbers, debug_corner_colors ) {
var sx = column * tile, sy = row * tile;
drawBase( ctx, image, sx, sy, tile, debug_texture );
drawAOCornersImp( ctx, image, row, column, corners, tile, strength, debug_corner_colors );
if ( debug_numbers ) drawHex( ctx, row * tile + corners, sx + 2, sy + 2 );
}
function drawAOMixed( ctx, image, row, column, elements, tile, strength, debug_texture, debug_numbers, debug_corner_colors ) {
var sx = column * tile, sy = row * tile,
mmap = {
0: [ 1, 1 ],
1: [ 1, 4 ],
2: [ 2, 2 ],
3: [ 2, 8 ],
4: [ 4, 1 ],
5: [ 4, 2 ],
6: [ 8, 4 ],
7: [ 8, 8 ],
8: [ 1, 5 ],
9: [ 2, 10 ],
10: [ 4, 3 ],
11: [ 8, 12 ],
12: [ 5, 1 ],
13: [ 6, 2 ],
14: [ 9, 4 ],
15: [ 10, 8 ]
};
drawBase( ctx, image, sx, sy, tile, debug_texture );
drawAOCornersImp( ctx, image, row, column, mmap[ elements ][1], tile, strength, debug_corner_colors );
drawAOSidesImp( ctx, image, row, column, mmap[ elements ][0], tile, strength );
if ( debug_numbers ) drawHex( ctx, row * tile + elements, sx + 2, sy + 2 );
}
function drawAOSidesImp( ctx, image, row, column, sides, tile, strength ) {
var sx = column * tile, sy = row * tile,
full = tile, step = 1 / full, half = full / 2 + strength,
color = "rgba(0, 0, 0, ",
left = (sides & 8) == 8,
right = (sides & 4) == 4,
bottom = (sides & 2) == 2,
top = (sides & 1) == 1;
if ( bottom ) drawSide( ctx, sx, sy, 0, 1, half, tile, 1, color, step );
if ( top ) drawSide( ctx, sx, sy + full - 1, 0, -1, half, tile, 1, color, step );
if ( left ) drawSide( ctx, sx, sy, 1, 0, half, 1, tile, color, step );
if ( right ) drawSide( ctx, sx + full - 1, sy, -1, 0, half, 1, tile, color, step );
}
function drawAOCornersImp( ctx, image, row, column, corners, tile, strength, debug_corner_colors ) {
var sx = column * tile, sy = row * tile,
full = tile, step = 1 / full, half = full / 2 + strength,
color = "rgba(0, 0, 0, ",
bottomright = (corners & 8) == 8,
topright = (corners & 4) == 4,
bottomleft = (corners & 2) == 2,
topleft = (corners & 1) == 1;
if ( topleft ) {
if ( debug_corner_colors ) color = "rgba(200, 0, 0, ";
drawCorner( ctx, sx, sy, 0, 1.57, color, step, half );
}
if ( bottomleft ) {
if ( debug_corner_colors ) color = "rgba(0, 200, 0, ";
drawCorner( ctx, sx, sy + full, 4.71, 6.28, color, step, half );
}
if ( bottomright ) {
if ( debug_corner_colors ) color = "rgba(0, 0, 200, ";
drawCorner( ctx, sx + full, sy + full, 3.14, 4.71, color, step, half );
}
if ( topright ) {
if ( debug_corner_colors ) color = "rgba(200, 0, 200, ";
drawCorner( ctx, sx + full, sy, 1.57, 3.14, color, step, half );
}
}
function loadTexture( path, callback ) {
var image = new Image();
image.onload = function () { callback(); };
image.src = path;
return image;
}
function generateHeight( width, height ) {
var data = [], perlin = new ImprovedNoise(),
size = width * height, quality = 2, z = Math.random() * 100;
for ( var j = 0; j < 4; j ++ ) {
if ( j == 0 ) for ( var i = 0; i < size; i ++ ) data[ i ] = 0;
for ( var i = 0; i < size; i ++ ) {
var x = i % width, y = ~~ ( i / width );
data[ i ] += perlin.noise( x / quality, y / quality, z ) * quality;
}
quality *= 4
}
return data;
}
function getY( x, z ) {
return ~~( data[ x + z * worldWidth ] * 0.2 );
}
function onDocumentMouseDown( event ) {
event.preventDefault();
event.stopPropagation();
switch ( event.button ) {
case 0: moveForward = true; break;
case 2: moveBackward = true; break;
}
}
function onDocumentMouseUp( event ) {
event.preventDefault();
event.stopPropagation();
switch ( event.button ) {
case 0: moveForward = false; break;
case 2: moveBackward = false; break;
}
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function onDocumentKeyDown( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/ moveForward = true; break;
case 37: /*left*/
case 65: /*A*/ moveLeft = true; break;
case 40: /*down*/
case 83: /*S*/ moveBackward = true; break;
case 39: /*right*/
case 68: /*D*/ moveRight = true; break;
}
}
function onDocumentKeyUp( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/ moveForward = false; break;
case 37: /*left*/
case 65: /*A*/ moveLeft = false; break;
case 40: /*down*/
case 83: /*S*/ moveBackward = false; break;
case 39: /*right*/
case 68: /*D*/ moveRight = false; break;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
if ( moveForward ) camera.translateZ( - 15 );
if ( moveBackward ) camera.translateZ( 15 );
if ( moveLeft ) camera.translateX( - 15 );
if ( moveRight ) camera.translateX( 15 );
lon += mouseX * 0.005;
lat -= mouseY * 0.005;
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = ( 90 - lat ) * Math.PI / 180;
theta = lon * Math.PI / 180;
camera.target.position.x = 100 * Math.sin( phi ) * Math.cos( theta ) + camera.position.x;
camera.target.position.y = 100 * Math.cos( phi ) + camera.position.y;
camera.target.position.z = 100 * Math.sin( phi ) * Math.sin( theta ) + camera.position.z;
renderer.render( scene, camera );
}
</script>
</body>
</html>