I am working on creating a 3D terrain using Three.js and ImprovedNoise.js. Using the examples on the Three.js site I have managed to create what appears to be terrain but it is 2D (not expanding into the z-axis).
While trying to create this scene I ran into errors in the example code. Some things I had to change slightly to get it working, such as:
geometry.rotateX(-Math.PI)
I changed to
geometry.rotateX = -Math.PI
but one thing that was throwing an error was that THREE.CanvasTexture is not a function. CanvasTexture appears in every three.js example I can find and I can't find any documentation about it being changed. But, CanvasTexture isn't in the documentation on the three.js site so I'm assuming it's been deprecated or something.
Anyway, my problem now is that while I have yet to figure my issue out, I tried copying and pasting the example code verbatim so that I could work backwards in an attempt to understand the code better but even the example code from the three.js site comes out 2D when ran on my computer.
Below is the example code (slightly altered as to avoid the above mentioned errors):
If anyone could tell me if this works for them or what I'm missing it would be greatly appreciated.
Thank you
I'm using these libraries:
<script src="js/three.min.js"></script>
<script src="js/PointerLockControls.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/ImprovedNoise.js"></script>
<script src="js/FirstPersonControls.js"></script>
<script src="js/Detector.js"></script>
And here is the js: (the only other thing I changed was that I didn't include the stats library so the corresponding code is commented out below)
var container, stats;
var camera, controls, scene, renderer;
var mesh, texture;
var worldWidth = 256, worldDepth = 256,
worldHalfWidth = worldWidth / 2, worldHalfDepth = worldDepth / 2;
var clock = new THREE.Clock();
var helper;
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
init();
animate();
function init() {
container = document.getElementById( 'blocker' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 20000 );
scene = new THREE.Scene();
controls = new THREE.OrbitControls(camera);
controls.center.set( 0.0, 100.0, 0.0 );
controls.userPanSpeed = 100;
data = generateHeight( worldWidth, worldDepth );
controls.center.y = data[ worldHalfWidth + worldHalfDepth * worldWidth ] + 500;
camera.position.y = controls.center.y + 2000;
camera.position.x = 2000;
var geometry = new THREE.PlaneBufferGeometry( 7500, 7500, worldWidth - 1, worldDepth - 1 );
geometry.rotateX = - Math.PI / 2 ;
var vertices = geometry.attributes.position.array;
for ( var i = 0, j = 0, l = vertices.length; i < l; i ++, j += 3 ) {
vertices[ j + 1 ] = data[ i ] * 10;
}
geometry.computeFaceNormals();
texture = new THREE.Texture( generateTexture( data, worldWidth, worldDepth ) );
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;
mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: texture } ) );
scene.add( mesh );
var geometry = new THREE.CylinderGeometry( 0, 20, 100, 3 );
geometry.translate = 0, 50, 0 ;
geometry.rotateX = Math.PI / 2 ;
helper = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial() );
scene.add( helper );
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xbfd1e5 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.innerHTML = "";
container.appendChild( renderer.domElement );
container.addEventListener( 'mousemove', onMouseMove, false );
//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 );
}
function generateHeight( width, height ) {
var size = width * height, data = new Uint8Array( size ),
perlin = new ImprovedNoise(), quality = 1, z = Math.random() * 100;
for ( var j = 0; j < 4; j ++ ) {
for ( var i = 0; i < size; i ++ ) {
var x = i % width, y = ~~ ( i / width );
data[ i ] += Math.abs( perlin.noise( x / quality, y / quality, z ) * quality * 1.75 );
}
quality *= 5;
}
return data;
}
function generateTexture( data, width, height ) {
var canvas, canvasScaled, context, image, imageData,
level, diff, vector3, sun, shade;
vector3 = new THREE.Vector3( 0, 0, 0 );
sun = new THREE.Vector3( 1, 1, 1 );
sun.normalize();
canvas = document.createElement( 'canvas' );
canvas.width = width;
canvas.height = height;
context = canvas.getContext( '2d' );
context.fillStyle = '#000';
context.fillRect( 0, 0, width, height );
image = context.getImageData( 0, 0, canvas.width, canvas.height );
imageData = image.data;
for ( var i = 0, j = 0, l = imageData.length; i < l; i += 4, j ++ ) {
vector3.x = data[ j - 2 ] - data[ j + 2 ];
vector3.y = 2;
vector3.z = data[ j - width * 2 ] - data[ j + width * 2 ];
vector3.normalize();
shade = vector3.dot( sun );
imageData[ i ] = ( 96 + shade * 128 ) * ( 0.5 + data[ j ] * 0.007 );
imageData[ i + 1 ] = ( 32 + shade * 96 ) * ( 0.5 + data[ j ] * 0.007 );
imageData[ i + 2 ] = ( shade * 96 ) * ( 0.5 + data[ j ] * 0.007 );
}
context.putImageData( image, 0, 0 );
// Scaled 4x
canvasScaled = document.createElement( 'canvas' );
canvasScaled.width = width * 4;
canvasScaled.height = height * 4;
context = canvasScaled.getContext( '2d' );
context.scale( 4, 4 );
context.drawImage( canvas, 0, 0 );
image = context.getImageData( 0, 0, canvasScaled.width, canvasScaled.height );
imageData = image.data;
for ( var i = 0, l = imageData.length; i < l; i += 4 ) {
var v = ~~ ( Math.random() * 5 );
imageData[ i ] += v;
imageData[ i + 1 ] += v;
imageData[ i + 2 ] += v;
}
context.putImageData( image, 0, 0 );
return canvasScaled;
}
//
function animate() {
requestAnimationFrame( animate );
render();
//stats.update();
}
function render() {
controls.update( clock.getDelta() );
renderer.render( scene, camera );
}
function onMouseMove( event ) {
mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
// See if the ray from the camera into the world hits one of our meshes
var intersects = raycaster.intersectObject( mesh );
// Toggle rotation bool for meshes that we clicked
if ( intersects.length > 0 ) {
helper.position.set( 0, 0, 0 );
helper.lookAt( intersects[ 0 ].face.normal );
helper.position.copy( intersects[ 0 ].point );
}
}