user134055
user134055

Reputation:

three.js: texture goes all black

I have a simple geometry for a box, that I'm trying to decorate with a texture. However, my box doesn't show at all (or perhaps it is 100% black). This current question is evolved from this question. I've updated the code to reflect the answer given by gaitat on the original question. I've written another simple test site to demonstrate this new issue. This is the content of that site:

"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:
new THREE.TextureLoader().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!
renderer.render( scene, camera );



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="main2.js"></script>
  </body>
</html>

Upvotes: 3

Views: 11343

Answers (4)

user134055
user134055

Reputation:

So, the code turned out to contain three errors, as each pointed out by Falk Thiele and 2pha/gaitat:

  1. '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.

  2. 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.

  3. 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);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>

EDIT: A fourth type of error that can cause a texture to go white (if it is emissive on its own) or go 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.

Upvotes: 7

Codertjay
Codertjay

Reputation: 997

Loadin the image from my local computer on nextjs gave me issues . A security from chrome so i had to upload the image to https://imgur.com/ and use the link and it worked. It seems mine wasnt also working with image on http connection but only https

const texture = new THREE.TextureLoader().load('https://i.imgur.com/E5ThRBu.jpeg');
    console.log(textureImage);
    this.material = new THREE.MeshBasicMaterial(
      {
        map: texture,
      })
    this.geometry = new THREE.SphereBufferGeometry(1, 30, 30);

Upvotes: 1

Thomas Amar
Thomas Amar

Reputation: 362

I had a similar effect for a different cause: I wrote black text on a transparent background and the result was a completely black cube. I solved the issue by giving my texture png file a colour instead of leaving it transparent.

Upvotes: 0

Falk Thiele
Falk Thiele

Reputation: 4494

Error console tells it is another CORS-Problem:

DOMException [SecurityError: "The operation is insecure."

Set 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
);

Upvotes: 1

Related Questions