mirror of
https://github.com/wahyd4/three.js.git
synced 2026-08-09 13:06:01 +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.
319 lines
7.8 KiB
HTML
319 lines
7.8 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
<title>three.js - geometry - minecraft</title>
|
|
<meta charset="utf-8">
|
|
<style type="text/css">
|
|
body {
|
|
color: #61443e;
|
|
font-family:Monospace;
|
|
font-size:13px;
|
|
text-align:center;
|
|
|
|
background-color: #bfd1e5;
|
|
margin: 0px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#info {
|
|
position: absolute;
|
|
top: 0px; width: 100%;
|
|
padding: 5px;
|
|
}
|
|
|
|
a {
|
|
|
|
color: #a06851;
|
|
}
|
|
|
|
</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. featuring <a href="http://painterlypack.net/" target="_blank">painterly pack</a><br />(left click: forward, right click: backward)</div>
|
|
|
|
<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">
|
|
|
|
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;
|
|
|
|
var windowHalfX = window.innerWidth / 2;
|
|
var windowHalfY = window.innerHeight / 2;
|
|
|
|
|
|
init();
|
|
setInterval( loop, 1000 / 60 );
|
|
|
|
|
|
function init() {
|
|
|
|
container = document.getElementById( 'container' );
|
|
|
|
camera = new THREE.Camera( 60, window.innerWidth / window.innerHeight, 1, 20000 );
|
|
camera.target.position.z = - 100;
|
|
|
|
scene = new THREE.Scene();
|
|
|
|
var grass_dirt = loadTexture( 'textures/minecraft/grass_dirt.png' ),
|
|
grass = loadTexture( 'textures/minecraft/grass.png' ),
|
|
dirt = loadTexture( 'textures/minecraft/dirt.png' );
|
|
|
|
var materials = [
|
|
|
|
grass_dirt, // right
|
|
grass_dirt, // left
|
|
grass, // top
|
|
dirt, // bottom
|
|
grass_dirt, // back
|
|
grass_dirt // front
|
|
|
|
];
|
|
|
|
var h, h2, px, nx, pz, nz, cubes = [];
|
|
|
|
for ( var i = 0; i < 16; i++ ) {
|
|
|
|
px = (i & 8) == 8;
|
|
nx = (i & 4) == 4;
|
|
pz = (i & 2) == 2;
|
|
nz = (i & 1) == 1;
|
|
cubes[ i ] = new Cube( 100, 100, 100, 1, 1, materials, false, { px: px, nx: nx, py: true, ny: false, pz: pz, nz: nz } );
|
|
|
|
}
|
|
|
|
var geometry = new THREE.Geometry();
|
|
|
|
camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100;
|
|
camera.target.position.y = camera.position.y;
|
|
|
|
for ( var z = 0; z < worldDepth; z ++ ) {
|
|
|
|
for ( var x = 0; x < worldWidth; x ++ ) {
|
|
|
|
px = nx = pz = nz = 0;
|
|
|
|
h = getY( x, z );
|
|
|
|
h2 = getY( x - 1, z );
|
|
px = ( h2 != h && h2 != h + 1 ) || x == 0 ? 1 : 0;
|
|
|
|
h2 = getY( x + 1, z );
|
|
nx = ( h2 != h && h2 != h + 1 ) || x == worldWidth - 1 ? 1 : 0;
|
|
|
|
h2 = getY( x, z + 1 );
|
|
pz = ( h2 != h && h2 != h + 1 ) || z == worldDepth - 1 ? 1 : 0;
|
|
|
|
h2 = getY( x, z - 1 );
|
|
nz = ( h2 != h && h2 != h + 1 ) || z == 0 ? 1 : 0;
|
|
|
|
mesh = new THREE.Mesh( cubes[ px * 8 + nx * 4 + pz * 2 + nz ] );
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
function generateAO( image, sides ) {
|
|
|
|
var c = document.createElement('canvas');
|
|
c.width = image.width;
|
|
c.height = image.height;
|
|
c.getContext( "2d" ).drawImage( image, 0, 0 );
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
function loadTexture( path ) {
|
|
|
|
var image = new Image();
|
|
image.onload = function () { this.loaded = true; };
|
|
image.src = path;
|
|
|
|
return new THREE.MeshLambertMaterial( { map: new THREE.Texture( image, new THREE.UVMapping(), THREE.ClampToEdgeWrapping, THREE.ClampToEdgeWrapping, THREE.NearestFilter, THREE.LinearMipMapLinearFilter ) } );
|
|
|
|
}
|
|
|
|
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: /*↑*/ moveForward = true; break;
|
|
case 40: /*↓*/ moveBackward = true; break;
|
|
|
|
case 87: /*W*/ moveForward = true; break;
|
|
case 83: /*S*/ moveBackward = true; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function onDocumentKeyUp( event ) {
|
|
|
|
switch( event.keyCode ) {
|
|
|
|
case 38: /*↑*/ moveForward = false; break;
|
|
case 40: /*↓*/ moveBackward = false; break;
|
|
|
|
case 87: /*W*/ moveForward = false; break;
|
|
case 83: /*S*/ moveBackward = false; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function loop() {
|
|
|
|
if ( moveForward ) camera.translateZ( - 15 );
|
|
if ( moveBackward ) camera.translateZ( 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();
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|