THREE.js how to make transparent front walls in 3d room model

心不动则不痛 提交于 2020-03-27 07:21:52

问题


I want to make a 3d room in three.js. I want the walls, that are in front of the camera view, to become transparent as I rotate the room.

Here is example what i need: http://jsfiddle.net/tp2f2oo4/

It seems that solution is adding THREE.BackSide to the material.

var material2 = new THREE.MeshPhongMaterial( {
    color: 0xffffff, 
    transparent: false,
    side: THREE.BackSide
} );

Indeed this works perfectly when a room acts as a single THREE.BoxGeometry, but in my case, every wall, ceiling, and floor are separate THREE.BoxGeometry objects. Is there any way to hide them or not rendering when are in front of the camera view?


回答1:


You want to hide a mesh based on some condition. This is a perfect use case for using the onBeforeRender() and onAfterRender() methods.

// callbacks
var onBeforeRender = function() {

    var v = new THREE.Vector3();

    return function onBeforeRender( renderer, scene, camera, geometry, material, group ) {

        // this is one way. adapt to your use case.
        if ( v.subVectors( camera.position, this.position ).dot( this.userData.normal ) < 0 ) {

            geometry.setDrawRange( 0, 0 ); // it is too late to set visible = false, so do this, instead

        }

    };

}();

var onAfterRender = function( renderer, scene, camera, geometry, material, group ) {

    geometry.setDrawRange( 0, Infinity );

};

// mesh
mesh = new THREE.Mesh( geometry, material );
mesh.position.set( 0, 0, 10 );
mesh.rotation.set( 0, 0, 0 );
scene.add( mesh );
mesh.userData.normal = new THREE.Vector3( 0, 0, - 1 );
mesh.onBeforeRender = onBeforeRender;
mesh.onAfterRender = onAfterRender;

fiddle: http://jsfiddle.net/3qh815xa/

three.js r.114




回答2:


You could use ray-casting to determine which walls to turn off. Basically, shoot a ray from your camera, and set the transparency of the wall it intersects.

For a simplified case, see updateWallTransparency_simple in the snippet below. It fires a ray from the center of the camera, and sets the transparency of the intersected wall.

However, you'll probably encounter a literal corner case, where you transition from one wall into the next. You can compensate for this with a second raycast, but you need to offset the two rays from the center, so they won't intersect the same wall in the case of a corner. See updateWallTransparency_corners in the snippet below for an example.

Now this is a highly simplified case. If your wall shapes are more complex, you'll need to perform further checks to see if certain walls should be hidden or not. Also, if you tip the camera too far up, you'll notice it will make the back walls hidden instead. There is a lot more to consider for this problem as a whole, but this should get you started.

var renderer, scene, camera, controls, stats;

var WIDTH = window.innerWidth,
  HEIGHT = window.innerHeight,
  FOV = 35,
  NEAR = 1,
  FAR = 1000,
  degrad = (Math.PI / 180),
  walls = [];

var raycaster = null,
  coords = null;

function updateWallTransparency_simple() {
  // reset all walls. You can optimize this by storing which ones are transparent/not
  walls.forEach(function(wall) {
    wall.material.opacity = 1;
  });

  raycaster.setFromCamera(coords, camera);
  var intersects = raycaster.intersectObjects(walls);
  if (intersects && intersects.length > 0) {
    intersects[0].object.material.opacity = 0.25;
  }
}

function updateWallTransparency_corners() {
  // reset all walls. You can optimize this by storing which ones are transparent/not
  walls.forEach(function(wall) {
    wall.material.opacity = 1;
  });

  coords.set(-0.1, 0);
  raycaster.setFromCamera(coords, camera);
  var intersects = raycaster.intersectObjects(walls);
  if (intersects && intersects.length > 0) {
    intersects[0].object.material.opacity = 0.25;
  }

  coords.set(0.1, 0);
  raycaster.setFromCamera(coords, camera);
  var intersects = raycaster.intersectObjects(walls);
  if (intersects && intersects.length > 0) {
    intersects[0].object.material.opacity = 0.25;
  }
}

function populateScene() {
  var geo = new THREE.BoxBufferGeometry(20, 20, 0.1),
    mat = new THREE.MeshPhongMaterial({
      color: "darkred",
      transparent: true,
      opacity: 1
    });
  var mesh = new THREE.Mesh(geo, mat);
  mesh.position.set(0, 0, -10);
  mesh.name = "backWall";
  scene.add(mesh);
  mesh.updateMatrixWorld(true);
  walls.push(mesh);

  mesh = new THREE.Mesh(geo, mat.clone());
  mesh.name = "frontWall";
  mesh.position.set(0, 0, 10);
  scene.add(mesh);
  mesh.updateMatrixWorld(true);
  walls.push(mesh);

  mesh = new THREE.Mesh(geo, mat.clone());
  mesh.name = "leftWall";
  mesh.position.set(-10, 0, 0);
  mesh.rotation.set(0, (Math.PI / 180) * 90, 0);
  scene.add(mesh);
  mesh.updateMatrixWorld(true);
  walls.push(mesh);

  mesh = new THREE.Mesh(geo, mat.clone());
  mesh.name = "rightWall";
  mesh.position.set(10, 0, 0);
  mesh.rotation.set(0, (Math.PI / 180) * 90, 0);
  scene.add(mesh);
  mesh.updateMatrixWorld(true);
  walls.push(mesh);

  geo = new THREE.BoxBufferGeometry(50, 0.1, 50),
    mat = new THREE.MeshPhongMaterial({
      color: "green"
    });
  mesh = new THREE.Mesh(geo, mat);
  mesh.position.set(0, -10, 0);
  mesh.name = "ground";
  scene.add(mesh);

  geo = new THREE.TorusKnotBufferGeometry(2, 0.5, 100, 16),
    mat = new THREE.MeshPhongMaterial({
      color: "blue"
    });
  mesh = new THREE.Mesh(geo, mat);
  mesh.name = "insideObject";
  scene.add(mesh);
}

function init() {
  document.body.style.backgroundColor = "lightBlue";

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

  document.body.appendChild(renderer.domElement);
  document.body.style.overflow = "hidden";
  document.body.style.margin = "0";
  document.body.style.padding = "0";

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 50;
  scene.add(camera);

  controls = new THREE.OrbitControls(camera);
  controls.enableZoom = false;
  controls.enablePan = false;
  controls.maxPolarAngle = Math.PI / 2;

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

  light = new THREE.HemisphereLight(0xffffbb, 0x00ff00, 1);
  scene.add(light);

  stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);

  resize();
  window.onresize = resize;

  populateScene();

  raycaster = new THREE.Raycaster();
  coords = new THREE.Vector3();

  animate();
}

function resize() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  if (renderer && camera && controls) {
    renderer.setSize(WIDTH, HEIGHT);
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
  }
}

function render() {
  renderer.render(scene, camera);
}

function animate() {
  requestAnimationFrame(animate);
  //updateWallTransparency_simple();
  updateWallTransparency_corners();
  render();
  stats.update();
}

function threeReady() {
  init();
}

(function() {
  function addScript(url, callback) {
    callback = callback || function() {};
    var script = document.createElement("script");
    script.addEventListener("load", callback);
    script.setAttribute("src", url);
    document.head.appendChild(script);
  }

  addScript("https://threejs.org/build/three.js", function() {
    addScript("https://threejs.org/examples/js/controls/OrbitControls.js", function() {
      addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
        threeReady();
      })
    })
  })
})();


来源:https://stackoverflow.com/questions/46238866/three-js-how-to-make-transparent-front-walls-in-3d-room-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!