EDIT: Following gaitat\'s suggestion for a fix, I got a new error: now the box doesn\'t show up at all. I\'ve written a new question to demonstrate this error.
I have a
So, the code turned out to contain three errors, as each pointed out by Falk Thiele and 2pha/gaitat in the follow up question that I posted:
'A Cross-origin resource sharing' (CORS) issue, promting the following error in Firebug:
SecurityError: The operation is insecure.
gl.texImage2D.apply( gl, arguments );
Quoting from Falk Thiele this error is fixed by setting the CrossOrigin attribute to empty:
var loader = new THREE.TextureLoader();
loader.crossOrigin = "";
loader.load(
"http://mrdoob.github.io/three.js/examples/textures/crate.gif",
function( texture ) {
//...
},
function () {}, // onProgress function
function ( error ) { console.log( error ) } // onError function
);
Oddly, one can also get a CORS-error (in Chrome) when loading the crate.gif
texture locally. This happens if one includes the loader.crossOrigin = "";
line. Thus it seems this line should only be used if one is certain that the origin is indeed of cross site origin.
The scene
is only being rendered once, and this one rendering happens before the texture has been loaded. This is because the TextureLoader.load()
call works asynchronously, thus letting the later code line renderer.render( scene, camera );
execute before the calling of load
has finished.
The script failed to work in Chrome, for two reasons: First the CORS-problem described above, and second, the script for some reason failing to load the THREE library (Uncaught ReferenceError: THREE is not defined
). I don't know why THREE failed to load in Chrome, but in the error corrected code (seen below, and also here) the error no longer appears, so for now the cause remains unknown.
Finally, I have made a JS fiddle demonstrating the running code.
Here is the error corrected code snippet with errors 1, 2 and 3 no longer present:
"use strict";
// make DOM elements:
var container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
container.appendChild( info );
// a 'Box2' geometry instance: (see geometry implementation below)
var myBox2geom = new THREE.BoxGeometry( 100, 100, 100, 10, 10, 10 ); // args: x,y,z-dimensions and width of their segments
// create scene:
var scene = new THREE.Scene();
// make a corresponding 'Box2' mesh:
var loader = new THREE.TextureLoader();
loader.crossOrigin = "";
loader.load("http://mrdoob.github.io/three.js/examples/textures/crate.gif",
function ( texture ) {
texture.minFilter = THREE.NearestFilter;
var material = new THREE.MeshLambertMaterial( { map: texture, side: THREE.DoubleSide } );
var myBox2mesh = new THREE.Mesh(myBox2geom, material);
// add mesh to scene:
scene.add( myBox2mesh );
},
function () {}, // onProgress function
function ( error ) { console.log( error ) } // no error gets logged
);
// make light:
var light = new THREE.PointLight( 0xffffff );
light.position.set(100, 200, 300);
light.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( light );
// make camera:
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.x = 100;
camera.position.y = 200;
camera.position.z = 300;
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( camera );
// make renderer:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// aaaand render, continuously!
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
THREE.Box2Geometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
THREE.Geometry.call( this );
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
this.widthSegments = widthSegments || 1;
this.heightSegments = heightSegments || 1;
this.depthSegments = depthSegments || 1;
var constructee = this; // constructee = the instance currently being constructed by the Box2Geometry constructor
var width_half = width / 2; // width = the distance along x in the absolute 3D space
var height_half = height / 2; // height = the distance along y in the absolute 3D space
var depth_half = depth / 2; // depth = the distance along z in the absolute 3D space
buildPlane( 'z', 'y', -1, -1, depth, height, width_half, 0 ); // px
buildPlane( 'z', 'y', 1, -1, depth, height, -width_half, 1 ); // nx
buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py
buildPlane( 'x', 'z', 1, -1, width, depth, -height_half, 3 ); // ny
buildPlane( 'x', 'y', 1, -1, width, height, depth_half, 4 ); // pz
buildPlane( 'x', 'y', -1, -1, width, height, -depth_half, 5 ); // nz
function buildPlane( u, v, uDir, vDir, uDist, vDist, wDist_half, materialIndex ) {
var w, iu, iv,
segU = constructee.widthSegments, // number of segments along u // width = x
segV = constructee.heightSegments, // number of segments along v // height = y
uDist_half = uDist / 2, // the extent of the plane along u, divided by two
vDist_half = vDist / 2, // the extent of the plane along v, divided by two
offset = constructee.vertices.length;
if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {
w = 'z';
} else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {
w = 'y';
segV = constructee.depthSegments;
} else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {
w = 'x';
segU = constructee.depthSegments;
}
var segUi = segU + 1, // i = inc = incremented (by one)
segVi = segV + 1, // i = inc = incremented (by one)
segmentDist_u = uDist / segU,
segmentDist_v = vDist / segV,
normal = new THREE.Vector3();
normal[ w ] = wDist_half > 0 ? 1 : -1;
for ( iv = 0; iv < segVi; iv++ ) {
for ( iu = 0; iu < segUi; iu++ ) {
var vertex = new THREE.Vector3();
vertex[ u ] = ( iu * segmentDist_u - uDist_half ) * uDir;
vertex[ v ] = ( iv * segmentDist_v - vDist_half ) * vDir;
vertex[ w ] = wDist_half;
constructee.vertices.push( vertex );
}
}
for ( iv = 0; iv < segV; iv++ ) {
for ( iu = 0; iu < segU; iu++ ) {
var a = iu + segUi * iv;
var b = iu + segUi * ( iv + 1 );
var c = ( iu + 1 ) + segUi * ( iv + 1 );
var d = ( iu + 1 ) + segUi * iv;
var uva = new THREE.Vector2( iu / segU, 1 - iv / segV );
var uvb = new THREE.Vector2( iu / segU, 1 - ( iv + 1 ) / segV );
var uvc = new THREE.Vector2( ( iu + 1 ) / segU, 1 - ( iv + 1 ) / segV );
var uvd = new THREE.Vector2( ( iu + 1 ) / segU, 1 - iv / segV );
var face1 = new THREE.Face3( a + offset, b + offset, d + offset );
face1.normal.copy( normal );
face1.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
face1.materialIndex = materialIndex;
constructee.faces.push( face1 );
constructee.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
var face2 = new THREE.Face3( b + offset, c + offset, d + offset );
face2.normal.copy( normal );
face2.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
face2.materialIndex = materialIndex;
constructee.faces.push( face2 );
constructee.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
}
}
}
this.mergeVertices();
};
THREE.Box2Geometry.prototype = Object.create( THREE.Geometry.prototype );
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<body>
<script src="https://raw.githubusercontent.com/mrdoob/three.js/master/build/three.js"></script>
<script src="main3.js"></script>
</body>
</html>
EDIT: A fourth type of error that can cause a texture to go white (if it is emissive on its own) or black (if it isn't) is if there are no lights, or the lights aren't being added to the scene, or the lights are pointing in the wrong direction (tip: use light.lookAt()
) or the lights are too far away from the mesh.
EDIT 2: A fifth reason is if the face normals aren't pointing outwards from the geometry. See the question three.js: custom geometry wont be textured for details.
If you want to be sure that your texture is loaded you need to use the THREE.Textureloader()
.onLoad()
function.
Here is how your example would work:
// make DOM elements:
var container = document.createElement( 'div' );
document.body.appendChild( container );
var scene = new THREE.Scene();
// a 'Box2' geometry instance: (see geometry implementation below)
var myBox2geom = new THREE.BoxGeometry( 100, 100, 100, 10, 10, 10 ); // args: x,y,z-dimensions and width of their segments
// instantiate a loader
var loader = new THREE.TextureLoader();
// load a resource
loader.load(
'crate.gif', // resource URL
function ( texture ) {
texture.minFilter = THREE.NearestFilter;
var material = new THREE.MeshLambertMaterial( { map: texture } );
var myBox2mesh = new THREE.Mesh(myBox2geom, material);
// add mesh to scene:
scene.add( myBox2mesh );
},
);
// make light:
var light = new THREE.PointLight( 0xffffff );
light.position.set(100, 200, 300);
light.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene.add( light );
// make camera:
var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 100, 200, 300 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
// make renderer:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
animate();
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}