我想缓存一个帧,然后在这个帧的基础上渲染另一个场景,怎么做呢?

时间:2017-11-15 09:49:14

标签: three.js

我想缓存一个帧,然后根据这个帧渲染另一个场景,该怎么做?

我设置了两个场景,一个是物理场景,一个是光标场景,因为物理场景可能不会改变。

现在我使用2个画布,一个在顶部,并使用透明背景来解决问题。

    let canvas = document.createElement("canvas");

    canvas.style.position = "absolute"
    canvas.style.zIndex = "100px";

    canvas.style.pointerEvents = "none";

    canvas.style.width = "100%";
    canvas.style.height = "100%";

    canvas.style.left = "0px";
    canvas.style.top = "0px";

    el.appendChild(canvas);

    render = new THREE.WebGLRenderer({ canvas: canvas, clearColor: 0, alpha: true })

1 个答案:

答案 0 :(得分:2)

如果我正确理解你,你想渲染一个场景,然后在第一个场景的顶部渲染第二个场景。这实际上很容易做到,尽管你可以通过执行错误的操作轻易地导致意外结果。

首先,告诉渲染器不要自动清除缓冲区:

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

接下来,在渲染第一个场景之前,您需要手动清除缓冲区。如果你不清楚这里,那么上一张图片将保留在画布上。

renderer.clear();
renderer.render(scene1, camera1);

渲染第一个场景时,您需要确保第二个场景将在第一个场景的顶部渲染。调用renderer.clear();会导致它删除第一个场景。相反,您只想清除深度缓冲区。这将删除渲染器之前的所有深度信息,并使其在旧的像素之上绘制所有新像素。

renderer.clearDepth();
renderer.render(scene2, camera2);

无法清除深度缓冲区意味着渲染器会记住所有scene1对象的位置(空间),并且它会将scene2对象渲染为好像它们占用与{{scene1相同的空间1}}。

此时,您应该看到第一个场景呈现在第一个场景之上,并且它们都被绘制到同一个画布上。

如果您有任何疑问,或希望我扩展上述任何步骤,请在下方发表评论。

three.js r88

<强>更新

这似乎是一种hacky方式,所以如果有人有更好的想法,请加入。我在下面的代码中做的是使背景渲染为可选,并使用第一个渲染的场景作为画布背后的背景。在我的例子中,我允许背景每1~1渲染一次。仍可以requestAnimationFrame允许的完整帧速率操作红色立方体。

有几点需要注意:

如果要捕获完整渲染的图像,必须在渲染renderWithBackground === true后捕获。在所有其他情况下,画布实际上只包含scene2

的内容

此外,第一帧渲染黑色背景,我不知道为什么。我现在还没有时间继续调试它。

&#13;
&#13;
var renderer, scene1, scene2, camera1, camera2, controls, bgCube, fgCube;

var renderWithBackground = true;

var WIDTH = window.innerWidth,
  HEIGHT = window.innerHeight,
  FOV = 35,
  NEAR = 1,
  FAR = 1000;

function populateScenes() {
  var cubeGeo1 = new THREE.BoxBufferGeometry(15, 15, 15),
    cubeMat1 = new THREE.MeshPhongMaterial({
      color: "green"
    });
  bgCube = new THREE.Mesh(cubeGeo1, cubeMat1);
  scene1.add(bgCube);

  var cubeGeo2 = new THREE.BoxBufferGeometry(5, 5, 5),
    cubeMat2 = new THREE.MeshPhongMaterial({
      color: "red"
    });
  fgCube = new THREE.Mesh(cubeGeo2, cubeMat2);
  scene2.add(fgCube);
}

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

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

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

  scene1 = new THREE.Scene();
  scene2 = new THREE.Scene();

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

  camera2 = camera1.clone();
  scene2.add(camera2);

  controls = new THREE.TrackballControls(camera2, renderer.domElement);
  controls.dynamicDampingFactor = 0.5;
  controls.rotateSpeed = 3;

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

  setInterval(function() {
    renderWithBackground = true;
  }, 1000);

  resize();
  window.onresize = resize;

  populateScenes();

  animate();
}

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

function render() {
  renderer.clear();
  if (renderWithBackground) {
    renderWithBackground = false;
    renderer.render(scene1, camera1);
    document.body.style.backgroundImage = "url('" + renderer.domElement.toDataURL() + "')";
    renderer.clearDepth();
  }
  renderer.render(scene2, camera2);
}

function animate() {
  bgCube.rotation.x += 0.001;
  bgCube.rotation.y += 0.002;
  bgCube.rotation.z += 0.003;
  requestAnimationFrame(animate);
  render();
  controls.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/TrackballControls.js", function() {
      addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
        threeReady();
      })
    })
  })
})();
&#13;
&#13;
&#13;