How to render 360-degree images on three.js without noize like Panolens.js?

Ask

I am currently working on a 360-degree images project by using three.js.
When I run the following code, there is noise in the ceiling of the sphere.
Another library called Panolens doesn’t have this noise.
If you know how to solve this problem, please let me know.

Rendering image of my code(three.js) and Panolens.js

My code(three.js)

   // create scene
  scene = new THREE.Scene();

   // create camera
  camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 10);
  camera.position.set(0, 0, 0);
  scene.add(camera);

   // create geometry
  geometry = new THREE.SphereGeometry(5,60,40);
  geometry.scale(-1, 1, 1);

  // create texture
  const loader = new THREE.TextureLoader();
  loader.load("./img/test.JPG");
  material = new THREE.MeshBasicMaterial( {map: texture});

  // create sphere
  sphere = new THREE.Mesh(geometry, material);
    
  // add scene
  scene.add(sphere);   
  
  // create renderer
  renderer = new THREE.WebGLRenderer({ preserveDrawingBuffer: true});
         
  // setup renderer
  renderer.setSize(width, height);
  renderer.setClearColor({color: 0x000000});
  element = renderer.domElement;
  document.querySelector(".panorama_viewer").appendChild(element);
  renderer.render(scene, camera);
   
  // setup orbitcontrols
  setOrbitControls();
  render();

Panolens.js

URL: https://pchen66.github.io/Panolens/#Documentation

I try to run following sample code.

var panorama, viewer, container;
container = document.querySelector('#container');
panorama = new PANOLENS.ImagePanorama('./img/test.JPG');

viewer = new PANOLENS.Viewer({
  container: container
});
viewer.add(panorama);

The noise you are talking about is visible at the poles. You can also see it in this example:

You can remove the artifacts by converting equirectangular textures to the cubemap format. This happens automatically if you set the mapping property of a texture to THREE.EquirectangularReflectionMapping and assign it to Scene.background or Material.envMap.

BTW: Please do not set preserveDrawingBuffer to true unless you really need it.

Thank you very much for your quick reply!
I will try as you have taught me.

@Mugen87
The noise disappeared the way you taught me! Thank you very much!
However, I faced with another problem which I can’t use zoom in/out function. Do you know any solution to this problem?

The following example have solved problem about zoom in/out function.

My code is below.

 import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.module.js';

 let camera, scene, renderer;
 let cube, sphere, torus, material;
 let count = 0, cubeCamera1, cubeCamera2, cubeRenderTarget1, cubeRenderTarget2;
 let onPointerDownPointerX, onPointerDownPointerY, onPointerDownLon, onPointerDownLat;

 let lon = 0, lat = 0;
 let phi = 0, theta = 0;

 const textureLoader = new THREE.TextureLoader();

 textureLoader.load('./test.JPG', function ( texture ) {

   texture.encoding = THREE.sRGBEncoding;
   texture.mapping = THREE.EquirectangularReflectionMapping;

   init( texture );
   animate();

 } );

 function init( texture ) {

   renderer = new THREE.WebGLRenderer( { antialias: true } );
   renderer.setPixelRatio( window.devicePixelRatio );
   renderer.setSize( window.innerWidth, window.innerHeight );
   renderer.outputEncoding = THREE.sRGBEncoding;
   document.body.appendChild( renderer.domElement );

   scene = new THREE.Scene();
   scene.background = texture;

   camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );

   cubeRenderTarget1 = new THREE.WebGLCubeRenderTarget( 256, {
     format: THREE.RGBFormat,
     generateMipmaps: true,
     minFilter: THREE.LinearMipmapLinearFilter,
     encoding: THREE.sRGBEncoding
   } );

   cubeRenderTarget2 = new THREE.WebGLCubeRenderTarget( 256, {
     format: THREE.RGBFormat,
     generateMipmaps: true,
     minFilter: THREE.LinearMipmapLinearFilter,
     encoding: THREE.sRGBEncoding
   } );

   material = new THREE.MeshBasicMaterial( {
     envMap: cubeRenderTarget2.texture,
     combine: THREE.MultiplyOperation,
     reflectivity: 1
   } );

   document.addEventListener( 'pointerdown', onPointerDown, false );
   document.addEventListener( 'wheel', onDocumentMouseWheel, false );

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

 }

 function onWindowResized() {

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

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

}

function onPointerDown( event ) {

  event.preventDefault();

  onPointerDownPointerX = event.clientX;
  onPointerDownPointerY = event.clientY;

  onPointerDownLon = lon;
  onPointerDownLat = lat;

  document.addEventListener( 'pointermove', onPointerMove, false );
  document.addEventListener( 'pointerup', onPointerUp, false );

}

function onPointerMove( event ) {

  lon = ( event.clientX - onPointerDownPointerX ) * 0.1 + onPointerDownLon;
  lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;

}

function onPointerUp() {

  document.removeEventListener( 'pointermove', onPointerMove, false );
  document.removeEventListener( 'pointerup', onPointerUp, false );

}

function onDocumentMouseWheel( event ) {

  const fov = camera.fov + event.deltaY * 0.05;

  camera.fov = THREE.MathUtils.clamp( fov, 10, 75 );

  camera.updateProjectionMatrix();

}

function animate() {

  requestAnimationFrame( animate );
  render();

}

function render() {

  lat = Math.max( - 85, Math.min( 85, lat ) );
  phi = THREE.MathUtils.degToRad( 90 - lat );
  theta = THREE.MathUtils.degToRad( lon );

  camera.position.x = 100 * Math.sin( phi ) * Math.cos( theta );
  camera.position.y = 100 * Math.cos( -1 * phi );
  camera.position.z = 100 * Math.sin( phi ) * Math.sin( theta );
      
  camera.lookAt( scene.position );
  renderer.render( scene, camera );

}

@Mugen87
Sorry to ask many questions!

1 Like

Just add this after defining your texture:

texture.minFilter = texture.magFilter = THREE.LinearFilter;

@AlfonsoRb
Thanks give me an implementation idea!! I will try this!