2

I am trying to set up image background for my scene with globe in three.js, but unfortunately, when I did it the main object of my scene also became black (the same colour with background.

I used method:

renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });

Which makes default background transparent. And then I added image-background in CSS part.

My whole script for the scene looks like this:

        var container, stats;
        var camera, scene, renderer;
        var group;
        var mouseX = 0, mouseY = 0;

        var windowHalfX = window.innerWidth / 2;
        var windowHalfY = window.innerHeight / 2;

        init();
        animate();


        function init() {

            container = document.getElementById( 'container' );

            camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
            //closer
            camera.position.z = 500;

            scene = new THREE.Scene();

            group = new THREE.Group();
            scene.add( group );

            // earth

            var loader = new THREE.TextureLoader();
            loader.load( 'textures/mapnew1.jpg', function ( texture ) {

                var geometry = new THREE.SphereGeometry( 180, 32, 32 );

                var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
                var mesh = new THREE.Mesh( geometry, material );
                group.add( mesh );

            } );



            // shadow

            var canvas = document.createElement( 'canvas' );
            canvas.width = 128;
            canvas.height = 128;

            var context = canvas.getContext( '2d' );
            var gradient = context.createRadialGradient(
                canvas.width / 2,
                canvas.height / 2,
                0,
                canvas.width / 2,
                canvas.height / 2,
                canvas.width / 2
            );
            gradient.addColorStop( 0.1, '#000000' );
            gradient.addColorStop( 1, '#000000' );

            context.fillStyle = gradient;
            context.fillRect( 0, 0, canvas.width, canvas.height );

            var texture = new THREE.CanvasTexture( canvas );

            var geometry = new THREE.PlaneBufferGeometry( 300, 300, 3, 3 );
            var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );


            var mesh = new THREE.Mesh( geometry, material );
            mesh.position.y = - 200;
            mesh.rotation.x = - Math.PI / 2;
            group.add( mesh );


            renderer = new THREE.CanvasRenderer();
            renderer.setPixelRatio( window.devicePixelRatio );
            renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });
            renderer.setSize( window.innerWidth, window.innerHeight );
            renderer.setClearColor(0x000000, 0);
            container.appendChild( renderer.domElement );

            stats = new Stats();
            container.appendChild( stats.dom );

            document.addEventListener( 'mousemove', onDocumentMouseMove, false );

            //

            window.addEventListener( 'resize', onWindowResize, false );

        }

        function onWindowResize() {

            windowHalfX = window.innerWidth / 2;
            windowHalfY = window.innerHeight / 2;

            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();

            renderer.setSize( window.innerWidth, window.innerHeight );

        }

        function onDocumentMouseMove( event ) {

            mouseX = ( event.clientX - windowHalfX );
            mouseY = ( event.clientY - windowHalfY );

        }

        //

        function animate() {

            requestAnimationFrame( animate );

            render();
            stats.update();

        }


        function render() {

            camera.position.x += ( mouseX - camera.position.x ) * 0.08;
            camera.position.y += ( - mouseY - camera.position.y ) * 0.08;
            camera.lookAt( scene.position );

            group.rotation.y -= 0.003;

            renderer.render( scene, camera );


        }


    </script>

This is my CSS:

body {
  color: #ffffff;
  font-family:'Futura';
  font-size:20px;
  text-align: center;
  background-image: url(textures/starfield.png);
  background-color: black;
  margin: 0px;
  overflow: hidden;
}

Do you have any ideas how to fix it and make globe visible?

Thank you very much!

Pop-A-Stash
  • 6,314
  • 5
  • 20
  • 48
Elena Epstein
  • 63
  • 1
  • 7
  • Can you elaborate a little? What is the actual issue? What do you see on the screen? Also, consider creating a plunker(https://plnkr.co) with your script, HTML, and CSS so we can all be on the same page. – Pop-A-Stash Aug 01 '17 at 16:46
  • Here is a plunker with your code: https://plnkr.co/edit/i9gcDMuVAGQ5CqbVDlES?p=preview It has some errors with all available versions of THREE – Pop-A-Stash Aug 01 '17 at 16:57

3 Answers3

2

Regarding the background image, you are setting the alpha value for WebGLRenderer, which is correct. You didn't post your CSS, but ensure you're setting the background image on your container, not on the canvas.

Also, comment out this line:

renderer.setClearColor(0x000000, 0);

You don't need to set a clear color, since you are clearing to transparency, not a color. That should resolve the background image issue.

Regarding the all-black model, you need a light in your scene. Try adding this to your init method:

var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);

This will add a light source at the location of your camera (and will follow the camera as it moves).

Edit to add snippet:

var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0,
  mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

init();
animate();


function init() {

  container = document.getElementById('container');

  camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
  //closer
  camera.position.z = 500;
  
  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  scene = new THREE.Scene();

  group = new THREE.Group();
  scene.add(group);

  // earth

  var loader = new THREE.TextureLoader();
  loader.crossOrigin = '';
  loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Equirectangular_projection_SW.jpg/640px-Equirectangular_projection_SW.jpg', function(texture) {
    var geometry = new THREE.SphereGeometry(180, 32, 32);

    var material = new THREE.MeshBasicMaterial({
      map: texture,
      overdraw: 0.5
    });
    var mesh = new THREE.Mesh(geometry, material);
    group.add(mesh);

  });



  // shadow

  var canvas = document.createElement('canvas');
  canvas.width = 128;
  canvas.height = 128;

  var context = canvas.getContext('2d');
  var gradient = context.createRadialGradient(
    canvas.width / 2,
    canvas.height / 2,
    0,
    canvas.width / 2,
    canvas.height / 2,
    canvas.width / 2
  );
  gradient.addColorStop(0.1, '#000000');
  gradient.addColorStop(1, '#000000');

  context.fillStyle = gradient;
  context.fillRect(0, 0, canvas.width, canvas.height);

  var texture = new THREE.CanvasTexture(canvas);

  var geometry = new THREE.PlaneBufferGeometry(300, 300, 3, 3);
  var material = new THREE.MeshBasicMaterial({
    map: texture,
    overdraw: 0.5
  });


  var mesh = new THREE.Mesh(geometry, material);
  mesh.position.y = -200;
  mesh.rotation.x = -Math.PI / 2;
  group.add(mesh);


  renderer = new THREE.WebGLRenderer({
    antialias: false,
    alpha: true
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  //renderer.setClearColor(0x000000, 0);
  container.appendChild(renderer.domElement);

  stats = new Stats();
  container.appendChild(stats.dom);

  document.addEventListener('mousemove', onDocumentMouseMove, false);

  //

  window.addEventListener('resize', onWindowResize, false);

}

function onWindowResize() {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

function onDocumentMouseMove(event) {

  mouseX = (event.clientX - windowHalfX);
  mouseY = (event.clientY - windowHalfY);

}

//

function animate() {

  requestAnimationFrame(animate);

  render();
  stats.update();

}


function render() {

  camera.position.x += (mouseX - camera.position.x) * 0.08;
  camera.position.y += (-mouseY - camera.position.y) * 0.08;
  camera.lookAt(scene.position);

  group.rotation.y -= 0.003;

  renderer.render(scene, camera);


}
body {
  color: #ffffff;
  font-family: 'Futura';
  font-size: 20px;
  text-align: center;
  background-image: url(https://upload.wikimedia.org/wikipedia/commons/6/62/Starsinthesky.jpg);
  background-color: black;
  margin: 0px;
  overflow: hidden;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="container"></div>

three.js r86

TheJim01
  • 6,362
  • 1
  • 17
  • 44
  • Thank you very much! But unfortunately it still doesn't work :( – Elena Epstein Aug 02 '17 at 15:47
  • @ElenaEpstein You have some errors in your code (which Joel pointed out). Check your console for the errors. I've fixed them in the snippet above. The main change was removing the `CanvasRenderer`--you don't need it, since you're using `WebGLRenderer`. (If you DO need `CanvasRenderer`, then only use that, not both). – TheJim01 Aug 02 '17 at 16:25
  • Thank you very much for your help! It is all work except the thing that I cannot reference local file (file on my computer): console shows me this error: Access to Image at 'file:///Users/elenaorlova/Google%20%D0%94%D0%B8%D1%81%D0%BA/sa_html_css/examples/textures/mapnew1.jpg' from origin 'null' has been blocked by CORS policy: Invalid response. Origin 'null' is therefore not allowed access. – Elena Epstein Aug 03 '17 at 14:16
  • @ElenaEpstein This is expected, and is a security feature in your browser. Make sure you set `loader.crossOrigin = '';`. If that doesn't work, [you can override this feature for local files in Chrome](https://stackoverflow.com/questions/18586921/how-to-launch-html-using-chrome-at-allow-file-access-from-files-mode). Once your files are hosted, you won't have a problem as long as they're on the same domain. [Further reading about CORS.](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) – TheJim01 Aug 03 '17 at 15:46
2

Since a while, there is:

var texture = new THREE.TextureLoader().load( "textures/bg.jpg" );
scene.background = texture;

I'm using three.js v 0.87

edap
  • 956
  • 1
  • 9
  • 15
2

There are two ways to do it

1) Load a image using TextureLoader and set it as background. This will result into static background which may not look very realistic.

 var texture = new THREE.TextureLoader().load(
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
    );
   scene.background = texture;

2) Use skybox to load images for top, left, right bottom, front back sides. Then set them inside a cube or sphere geometry

var urls = [
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
      "https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg"
    ];

    var materialArray = [];
    for (var i = 0; i < 6; i++)
      materialArray.push(
        new THREE.MeshBasicMaterial({
          map: new THREE.TextureLoader().load(urls[i]),
          side: THREE.BackSide
        })
      );

    var skyGeometry = new THREE.SphereGeometry(400, 32, 32);
    var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
    var skybox = new THREE.Mesh(skyGeometry, skyMaterial);
    scene.add(skybox);

This will give a sphere with images as texture on backside. Just replace THREE.SphereGeometry with THREE.CubeGeometry and you can emulate envMap.

Hitesh Sahu
  • 31,496
  • 11
  • 150
  • 116