Three.js中的WebGLRenderTarget渲染目标

2025-04-27 0 562

Three.js小白的学习之路。

之前博客写过一篇使用WebGLRenderTarget离屏渲染实现不同场景之间的过渡。本篇则主要是介绍一下WebGLRenderTarget以及一些其他使用,本篇参考了Three.js的官方中有关渲染目标的讲解。

渲染目标大体上指的是可以被渲染的纹理。当它被渲染之后,你可以像使用其他纹理一样使用它。意思就是可以将渲染目标输出的纹理当做一张图片纹理去使用(浅薄理解)。

官方示例

下面贴一下官网的一个例子:

const renderTargetWidth = 512;
const renderTargetHeight = 512;

const scene = new Three.Scene();

const camera = new Three.PerspectiveCamera(
  75,
  renderTargetWidth / renderTargetHeight,
  0.1,
  10
);
camera.position.set(0, 0, 2);
camera.lookAt(0, 0, 0);

const rtScene = new Three.Scene();
rtScene.background = new Three.Color("red");

const rtCamera = new Three.PerspectiveCamera(
  75,
  renderTargetWidth / renderTargetHeight,
  0.1,
  10
);
rtCamera.position.set(0, 0, 2);
rtCamera.lookAt(0, 0, 0);

const renderTarget = new Three.WebGLRenderTarget(
  renderTargetWidth,
  renderTargetHeight
);

const ambientLight = new Three.AmbientLight(0xffffff, 1);
scene.add(ambientLight);

{
  const light = new Three.DirectionalLight(0xffffff, 1);
  light.position.set(-1, 2, 4);
  rtScene.add(light);
}

const geometry = new Three.BoxGeometry(1, 1, 1);

const makeInstance = (geo: Three.BufferGeometry, color: number, x: number) => {
  const material = new Three.MeshPhongMaterial({ color });

  const cube = new Three.Mesh(geo, material);
  rtScene.add(cube);
  cube.position.x = x;

  return cube;
};

const rtCube = [
  makeInstance(geometry, 0x44aa88, 0),
  makeInstance(geometry, 0x8844aa, -2),
  makeInstance(geometry, 0xaa88aa, 2),
];

const material = new Three.MeshPhongMaterial({
  map: renderTarget.texture,
});
const cube = new Three.Mesh(geometry, material);
scene.add(cube);

const loop = (time: number) => {
  time *= 0.0001;

  rtCube.forEach((cube, ndx) => {
    const speed = 1 + ndx * 0.1;
    const rot = time * speed;
    cube.rotation.x = rot;
    cube.rotation.y = rot;
  });

  renderer.setRenderTarget(renderTarget);
  renderer.render(rtScene, rtCamera);
  renderer.setRenderTarget(null);

  renderer.render(scene, camera);

  requestAnimationFrame((time) => {
    loop(time);
  });
};
loop(0);

代码很简单,不难理解。先看一下运行结果:

Three.js中的WebGLRenderTarget渲染目标

可以看到,图中最外层的立方体的纹理是一个由三个旋转立方体+红色背景组成的纹理。

怎么实现的呢?这就是WebGLRenderTarget的妙用之处了。

首先创建了一个renderTargetScene(rtScene)和renderTargetCamera(rtCamera),作为渲染目标所需的场景和摄像机,在生成了三个cube加入到rtScene中。

在loop循环中,并没有直接讲场景渲染到canvas中,而是加了中间一层WebGLRenderTarget。可以理解为一个以前都是直接拿钞票付款,没有中间商,现在变成了要付款,得先掏出手机,因为钱都在手机里,然后扫码付款。

手机就是WebGLRenderTarget,他将目标换一种形式保存了下来,在这里面就可以简单理解为一个图像纹理。

既然是图像,那么自然可将其作为模型的纹理贴图进行使用,因此最外层的盒子的map属性就可设置为renderTarget.texture,从而实现上述效果。

使用场景

一个就是之前提到过的离屏渲染

一个是后处理效果,如在使用辉光等后处理时,经常会导致场景变的模糊,加入一个WebGLRenderTarget可以明显改善,官方在实现相关的后处理特效时也使用了WebGLRenderTarget。

此外还可以作为3D场景中可能会用到的镜子反射(像龙骑里面一个人被困在镜子里面,只有一半身体可以看到那种)、监控画面等需要看到不是当前所能看到的场景等。

下面写一个简单的例子,车子在行驶过程中,后视镜突然变成一个别的东西(常见的鬼片里面会出现的那种,但我做的很简单很粗糙,凑活看一看):


const renderTargetWidth = 512;
const renderTargetHeight = 512;

const scene = new Three.Scene();
const camera = new Three.PerspectiveCamera(
  60,
  window.innerWidth / window.innerHeight,
  0.1,
  10
);
camera.position.set(-2.5, 1.5, -2.5);
camera.lookAt(0, 0, 0);

const rtScene = new Three.Scene();
rtScene.background = new Three.Color(0xff0000);
const rtCamera = new Three.PerspectiveCamera(
  60,
  renderTargetWidth / renderTargetHeight,
  0.1,
  10
);
rtCamera.position.set(-2.5, 1.5, -2.5);
rtCamera.lookAt(0, 0, 0);

const geo = new Three.TorusGeometry(0.5, 0.3);
const material = new Three.MeshBasicMaterial({ color: 0x00ff00 });
const torus = new Three.Mesh(geo, material);
rtScene.add(torus);

const renderTarget = new Three.WebGLRenderTarget(
  renderTargetWidth,
  renderTargetHeight
);

const wheel: Three.Mesh[] = [];
let mirror: Three.Mesh;
new GLTFLoader().load("/car.glb", (glb) => {
  const mesh = glb.scene;
  scene.add(mesh);
  mirror = mesh.getObjectByName("mirror") as Three.Mesh;
  wheel.push(mesh.getObjectByName("wheel1") as Three.Mesh);
  wheel.push(mesh.getObjectByName("wheel2") as Three.Mesh);
  wheel.push(mesh.getObjectByName("wheel3") as Three.Mesh);
  wheel.push(mesh.getObjectByName("wheel4") as Three.Mesh);

  mirror.material = new Three.MeshBasicMaterial({
      map: renderTarget.texture,
  });
});

const ambientLight = new Three.AmbientLight(0xffffff, 1);
scene.add(ambientLight);
rtScene.add(ambientLight.clone());

const wheelRotate = () => {
  wheel.forEach((item) => {
    item.rotation.z -= 0.05;
  });
};

const loop = () => {
  wheelRotate();
  torus.rotation.x += 0.01;

  renderer.setRenderTarget(renderTarget);
  renderer.render(rtScene, rtCamera);
  renderer.setRenderTarget(null);

  renderer.render(scene, camera);
  requestAnimationFrame(loop);
};

loop();

部分代码省略了,效果如下:

Three.js中的WebGLRenderTarget渲染目标

总之,WebGLRenderTarget是一个比较悬乎的概念,使用中会遇到各种各样的问题,欢迎大家一起讨论学习!

平台声明:以上文章转载于《CSDN》,文章全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,仅作参考。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_55100638/article/details/147272193

遇见资源网 前端 Three.js中的WebGLRenderTarget渲染目标 http://www.ox520.com/157303.html

常见问题

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务