mirror of
https://github.com/wahyd4/three.js.git
synced 2026-08-16 16:36:04 +10:00
Code is still rough around edges (it can be made nicer), though it should already produce one-to-one results with ubershader. Side-effect is that scene is no longer required as WebGLRenderer constructor parameter. Shader programs are now constructed upon first frame render and only then scene lights are examined.
939 lines
24 KiB
HTML
939 lines
24 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<title>three.js - 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 {
|
|
font-family:monospace;
|
|
font-size:13px;
|
|
|
|
text-align:center;
|
|
background:rgb(100,0,0);
|
|
color:#fff;
|
|
padding:1em;
|
|
|
|
width:475px;
|
|
margin:5em auto 0;
|
|
|
|
display:none;
|
|
}
|
|
#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>
|
|
|
|
<center>
|
|
<div id="oldie">
|
|
Sorry, your browser doesn't support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">WebGL</a><br/>
|
|
<br/>
|
|
Please try in
|
|
<a href="http://www.chromium.org/getting-involved/dev-channel">Chrome 9+</a> /
|
|
<a href="http://www.mozilla.com/en-US/firefox/all-beta.html">Firefox 4+</a> /
|
|
<a href="http://nightly.webkit.org/">Safari OSX 10.6+</a>
|
|
</div>
|
|
</center>
|
|
|
|
<script type="text/javascript" src="js/Stats.js"></script>
|
|
<script type="text/javascript" src="js/ImprovedNoise.js"></script>
|
|
|
|
<script type="text/javascript" src="../build/Three.js"></script>
|
|
<script type="text/javascript" src="../src/extras/GeometryUtils.js"></script>
|
|
<script type="text/javascript" src="../src/extras/primitives/Cube.js"></script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
if ( !is_browser_compatible() ) {
|
|
|
|
document.getElementById( "oldie" ).style.display = "block";
|
|
|
|
}
|
|
|
|
var fogExp2 = true;
|
|
|
|
var container, stats;
|
|
|
|
var camera, scene, renderer;
|
|
|
|
var mesh;
|
|
|
|
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();
|
|
setInterval( loop, 1000 / 60 );
|
|
|
|
|
|
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;
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
canvas.loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
canvas.loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
|
|
|
|
}
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
canvas.loaded = true;
|
|
|
|
return new THREE.MeshLambertMaterial( { map: new THREE.Texture( canvas, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
|
|
|
|
}
|
|
|
|
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 () { this.loaded = true; 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 loop() {
|
|
|
|
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);
|
|
stats.update();
|
|
|
|
}
|
|
|
|
function is_browser_compatible() {
|
|
|
|
// WebGL support
|
|
|
|
try { var test = new Float32Array(1); } catch(e) { return false; }
|
|
|
|
// Web workers
|
|
|
|
return !!window.Worker;
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|