Created
November 15, 2012 12:36
-
-
Save mrdoob/4078432 to your computer and use it in GitHub Desktop.
Prettier Minecraft Vertex Colors AO.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>three.js webgl - geometry - minecraft - ao</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> | |
<style> | |
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 } | |
</style> | |
</head> | |
<body> | |
<div id="container"><br /><br /><br /><br /><br />Generating world...</div> | |
<div id="info"> | |
<a href="http://threejs.org" 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) | |
</div> | |
<script src="../build/three.min.js"></script> | |
<script src="js/controls/FirstPersonControls.js"></script> | |
<script src="js/ImprovedNoise.js"></script> | |
<script src="js/Detector.js"></script> | |
<script src="js/libs/stats.min.js"></script> | |
<script> | |
if ( ! Detector.webgl ) { | |
Detector.addGetWebGLMessage(); | |
document.getElementById( 'container' ).innerHTML = ""; | |
} | |
var fogExp2 = true; | |
var container, stats; | |
var camera, controls, scene, renderer; | |
var mesh, mat; | |
var worldWidth = 200, worldDepth = 200, | |
worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2, | |
data = generateHeight( worldWidth, worldDepth ); | |
var clock = new THREE.Clock(); | |
init(); | |
animate(); | |
function init() { | |
container = document.getElementById( 'container' ); | |
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 20000 ); | |
camera.position.y = getY( worldHalfWidth, worldHalfDepth ) * 100 + 100; | |
controls = new THREE.FirstPersonControls( camera ); | |
controls.movementSpeed = 1000; | |
controls.lookSpeed = 0.125; | |
controls.lookVertical = true; | |
controls.constrainVertical = true; | |
controls.verticalMin = 1.1; | |
controls.verticalMax = 2.2; | |
scene = new THREE.Scene(); | |
scene.fog = new THREE.FogExp2( 0xffffff, 0.00015 ); | |
// sides | |
var light = new THREE.Color( 0xffffff ); | |
var shadow = new THREE.Color( 0x404040 ); | |
var pxGeometry = new THREE.PlaneGeometry( 100, 100 ); | |
pxGeometry.faces[ 0 ].materialIndex = 1; | |
pxGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; | |
pxGeometry.applyMatrix( new THREE.Matrix4().makeRotationY( Math.PI / 2 ) ); | |
pxGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 50, 0, 0 ) ); | |
var nxGeometry = new THREE.PlaneGeometry( 100, 100 ); | |
nxGeometry.faces[ 0 ].materialIndex = 1; | |
nxGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; | |
nxGeometry.applyMatrix( new THREE.Matrix4().makeRotationY( - Math.PI / 2 ) ); | |
nxGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( - 50, 0, 0 ) ); | |
var pyGeometry = new THREE.PlaneGeometry( 100, 100, 2, 2 ); | |
pyGeometry.faces[ 0 ].materialIndex = 0; | |
pyGeometry.faces[ 0 ].vertexColors = [ light, light, light, light ]; | |
pyGeometry.faces[ 1 ].materialIndex = 0; | |
pyGeometry.faces[ 1 ].vertexColors = [ light, light, light, light ]; | |
pyGeometry.faces[ 2 ].materialIndex = 0; | |
pyGeometry.faces[ 2 ].vertexColors = [ light, light, light, light ]; | |
pyGeometry.faces[ 3 ].materialIndex = 0; | |
pyGeometry.faces[ 3 ].vertexColors = [ light, light, light, light ]; | |
pyGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); | |
pyGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 50, 0 ) ); | |
var pzGeometry = new THREE.PlaneGeometry( 100, 100 ); | |
pzGeometry.faces[ 0 ].materialIndex = 1; | |
pzGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; | |
pzGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0, 50 ) ); | |
var nzGeometry = new THREE.PlaneGeometry( 100, 100 ); | |
nzGeometry.faces[ 0 ].materialIndex = 1; | |
nzGeometry.faces[ 0 ].vertexColors = [ light, shadow, shadow, light ]; | |
nzGeometry.applyMatrix( new THREE.Matrix4().makeRotationY( Math.PI ) ); | |
nzGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0, -50 ) ); | |
// | |
var geometry = new THREE.Geometry(); | |
var dummy = new THREE.Mesh(); | |
for ( var z = 0; z < worldDepth; z ++ ) { | |
for ( var x = 0; x < worldWidth; x ++ ) { | |
var h = getY( x, z ); | |
dummy.position.x = x * 100 - worldHalfWidth * 100; | |
dummy.position.y = h * 100; | |
dummy.position.z = z * 100 - worldHalfDepth * 100; | |
var px = getY( x + 1, z ); | |
var nx = getY( x - 1, z ); | |
var pz = getY( x, z + 1 ); | |
var nz = getY( x, z - 1 ); | |
var pxpz = getY( x + 1, z + 1 ); | |
var nxpz = getY( x - 1, z + 1 ); | |
var pxnz = getY( x + 1, z - 1 ); | |
var nxnz = getY( x - 1, z - 1 ); | |
dummy.geometry = pyGeometry; | |
var colors = dummy.geometry.faces[ 0 ].vertexColors; | |
colors[ 0 ] = nx > h || nz > h || nxnz > h ? shadow : light; | |
colors[ 1 ] = nx > h ? shadow : light; | |
colors[ 3 ] = nz > h ? shadow : light; | |
var colors = dummy.geometry.faces[ 1 ].vertexColors; | |
colors[ 0 ] = nz > h ? shadow : light; | |
colors[ 2 ] = px > h ? shadow : light; | |
colors[ 3 ] = px > h || nz > h || pxnz > h ? shadow : light; | |
var colors = dummy.geometry.faces[ 2 ].vertexColors; | |
colors[ 0 ] = nx > h ? shadow : light; | |
colors[ 1 ] = nx > h || pz > h || nxpz > h ? shadow : light; | |
colors[ 2 ] = pz > h ? shadow : light; | |
var colors = dummy.geometry.faces[ 3 ].vertexColors; | |
colors[ 1 ] = pz > h ? shadow : light; | |
colors[ 2 ] = px > h || pz > h || pxpz > h ? shadow : light; | |
colors[ 3 ] = px > h ? shadow : light; | |
THREE.GeometryUtils.merge( geometry, dummy ); | |
if ( ( px != h && px != h + 1 ) || x == 0 ) { | |
dummy.geometry = pxGeometry; | |
var colors = dummy.geometry.faces[ 0 ].vertexColors; | |
colors[ 0 ] = pxpz > px && x > 0 ? shadow : light; | |
colors[ 3 ] = pxnz > px && x > 0 ? shadow : light; | |
THREE.GeometryUtils.merge( geometry, dummy ); | |
} | |
if ( ( nx != h && nx != h + 1 ) || x == worldWidth - 1 ) { | |
dummy.geometry = nxGeometry; | |
var colors = dummy.geometry.faces[ 0 ].vertexColors; | |
colors[ 0 ] = nxnz > nx && x < worldWidth - 1 ? shadow : light; | |
colors[ 3 ] = nxpz > nx && x < worldWidth - 1 ? shadow : light; | |
THREE.GeometryUtils.merge( geometry, dummy ); | |
} | |
if ( ( pz != h && pz != h + 1 ) || z == worldDepth - 1 ) { | |
dummy.geometry = pzGeometry; | |
var colors = dummy.geometry.faces[ 0 ].vertexColors; | |
colors[ 0 ] = nxpz > pz && z < worldDepth - 1 ? shadow : light; | |
colors[ 3 ] = pxpz > pz && z < worldDepth - 1 ? shadow : light; | |
THREE.GeometryUtils.merge( geometry, dummy ); | |
} | |
if ( ( nz != h && nz != h + 1 ) || z == 0 ) { | |
dummy.geometry = nzGeometry; | |
var colors = dummy.geometry.faces[ 0 ].vertexColors; | |
colors[ 0 ] = pxnz > nz && z > 0 ? shadow : light; | |
colors[ 3 ] = nxnz > nz && z > 0 ? shadow : light; | |
THREE.GeometryUtils.merge( geometry, dummy ); | |
} | |
} | |
} | |
var textureGrass = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass.png' ); | |
textureGrass.magFilter = THREE.NearestFilter; | |
textureGrass.minFilter = THREE.LinearMipMapLinearFilter; | |
var textureGrassDirt = THREE.ImageUtils.loadTexture( 'textures/minecraft/grass_dirt.png' ); | |
textureGrassDirt.magFilter = THREE.NearestFilter; | |
textureGrassDirt.minFilter = THREE.LinearMipMapLinearFilter; | |
var material1 = new THREE.MeshLambertMaterial( { map: textureGrass, ambient: 0xbbbbbb, vertexColors: THREE.VertexColors } ); | |
var material2 = new THREE.MeshLambertMaterial( { map: textureGrassDirt, ambient: 0xbbbbbb, vertexColors: THREE.VertexColors } ); | |
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( [ material1, material2 ] ) ); | |
scene.add( mesh ); | |
var ambientLight = new THREE.AmbientLight( 0xcccccc ); | |
scene.add( ambientLight ); | |
var directionalLight = new THREE.DirectionalLight( 0xffffff, 2 ); | |
directionalLight.position.set( 1, 1, 0.5 ).normalize(); | |
scene.add( directionalLight ); | |
renderer = new THREE.WebGLRenderer( { clearColor: 0xffffff } ); | |
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 ); | |
// | |
window.addEventListener( 'resize', onWindowResize, false ); | |
} | |
function onWindowResize() { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
controls.handleResize(); | |
} | |
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 ) | 0; | |
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 ) | 0; | |
} | |
// | |
function animate() { | |
requestAnimationFrame( animate ); | |
render(); | |
stats.update(); | |
} | |
function render() { | |
controls.update( clock.getDelta() ); | |
renderer.render( scene, camera ); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment