Skip to main content

混合 PixiJS 和 Three.js

¥Mixing PixiJS and Three.js

在许多项目中,开发者旨在利用 3D 和 2D 图形的优势。将 Three.js 的高级 3D 渲染功能与 PixiJS 的 2D 速度和多功能性相结合,可以带来强大、无缝的体验。这些技术共同为动态和视觉上引人注目的应用创造了机会。让我们看看如何做到这一点。

¥In many projects, developers aim to harness the strengths of both 3D and 2D graphics. Combining the advanced 3D rendering capabilities of Three.js with the speed and versatility of PixiJS for 2D can result in a powerful, seamless experience. Together, these technologies create opportunities for dynamic and visually compelling applications. Lets see how to do this.

注意

本指南假设 PixiJS 将用作顶层,在 Three.js 渲染的 3D 场景上提供 UI。但是,开发者可以根据需要以任何顺序多次渲染。这种灵活性允许创建富有创意和动态的应用。

¥This guide assumes PixiJS will be used as the top layer to deliver UI over a 3D scene rendered by Three.js. However, developers can render either in any order, as many times as needed. This flexibility allows for creative and dynamic applications.


你将学到什么

¥What You’ll Learn

  • 设置 PixiJS 和 Three.js 以共享单个 WebGL 上下文。

    ¥Setting up PixiJS and Three.js to share a single WebGL context.

  • 使用 resetState 管理渲染器状态。

    ¥Using resetState to manage renderer states.

  • 使用多个渲染器时避免常见的陷阱。

    ¥Avoiding common pitfalls when working with multiple renderers.


设置

¥Setting Up

步骤 1:初始化 Three.js 渲染器和场景

¥Step 1: Initialize Three.js Renderer and Scene

Three.js 将处理 3D 渲染、dom 元素和上下文的创建。

¥Three.js will handle the 3D rendering the creation of the dom element and context.

const WIDTH = window.innerWidth;
const HEIGHT = window.innerHeight;

const threeRenderer = new THREE.WebGLRenderer({
antialias: true,
stencil: true // so masks work in pixijs
});

threeRenderer.setSize(WIDTH, HEIGHT);
threeRenderer.setClearColor(0xdddddd, 1);
document.body.appendChild(threeRenderer.domElement);

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT);
camera.position.z = 50;
scene.add(camera);

const boxGeometry = new THREE.BoxGeometry(10, 10, 10);
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x0095dd });
const cube = new THREE.Mesh(boxGeometry, basicMaterial);
cube.rotation.set(0.4, 0.2, 0);
scene.add(cube);
注意

我们使用 three.js 渲染器创建的 dom 元素和上下文传递给 pixijs 渲染器。这是确保两个渲染器使用相同 WebGL 上下文的最简单方法。如果你愿意,也可以反过来做。

¥We used the dom element and context created by the three.js renderer to pass to the pixijs renderer. This was the simplest way to ensure that the two renderers were using the same WebGL context. You could have done it the other way round if you wanted to.

步骤 2:初始化 PixiJS 渲染器和舞台

¥Step 2: Initialize PixiJS Renderer and Stage

PixiJS 将处理 2D 叠加层。

¥PixiJS will handle the 2D overlay.

const pixiRenderer = new PIXI.WebGLRenderer();

await pixiRenderer.init({
context: threeRenderer.getContext(),
width: WIDTH,
height: HEIGHT,
clearBeforeRender: false, // Prevent PixiJS from clearing the Three.js render
});

const stage = new PIXI.Container();
const amazingUI = new PIXI.Graphics()
.roundRect(20, 80, 100, 100, 5)
.roundRect(220, 80, 100, 100, 5)
.fill(0xffff00);

stage.addChild(amazingUI);

渲染循环

¥Rendering Loop

为确保渲染器之间的平滑过渡,请在每次渲染之前重置其状态:

¥To ensure smooth transitions between the renderers, reset their states before each render:

function render() {
// Render the Three.js scene
threeRenderer.resetState();
threeRenderer.render(scene, camera);

// Render the PixiJS stage
pixiRenderer.resetState();
pixiRenderer.render({ container: stage });

requestAnimationFrame(render);
}

requestAnimationFrame(render);


示例:结合 3D 和 2D 元素

¥Example: Combining 3D and 2D Elements

这是集成 PixiJS 和 Three.js 的完整示例:

¥Here’s the complete example integrating PixiJS and Three.js:



陷阱

¥Gotchas

  • 启用模板缓冲区:

    ¥Enable Stencil Buffers:

    • 创建 Three.js 渲染器时,请确保将 stencil 设置为 true。这允许 PixiJS 蒙版正常工作。

      ¥When creating the Three.js renderer, ensure stencil is set to true. This allows PixiJS masks to work correctly.

  • 保持尺寸同步:

    ¥Keep Dimensions in Sync:

    • 确保两个渲染器使用相同的 widthheight 以避免视觉不匹配 - 因此在调整一个渲染器的大小时要小心,你需要调整另一个渲染器的大小!

      ¥Ensure both renderers use the same width and height to avoid visual mismatches—so be careful when resizing one, you need to resize the other!

  • 传递 WebGL 上下文:

    ¥Pass the WebGL Context:

    • 在使用 pixiRenderer.init({ context: threeRenderer.getContext() }); 初始化期间将 WebGL 上下文从 Three.js 传递到 PixiJS。

      ¥Pass the WebGL context from Three.js to PixiJS during initialization using pixiRenderer.init({ context: threeRenderer.getContext() });.

  • 禁用渲染前清除:

    ¥Disable Clear Before Render:

    • 初始化 PixiJS 渲染器时设置 clearBeforeRender: false。这可防止 PixiJS 清除在它之前渲染的 Three.js 内容。

      ¥Set clearBeforeRender: false when initializing the PixiJS renderer. This prevents PixiJS from clearing the Three.js content that was rendered before it.

    • 或者,你可以在 pixiRenderer.render() 调用中设置 clear: false。例如 pixiRenderer.render({ container: stage, clear: false });

      ¥Alternatively you can set clear: false in the pixiRenderer.render() call. eg pixiRenderer.render({ container: stage, clear: false });.

  • 管理渲染顺序:

    ¥Manage Render Order:

    • 在此示例中,首先渲染 Three.js,然后渲染 UI 层使用 PixiJS。但是,这个顺序是灵活的。你可以根据需要渲染 pixi -> three -> pixi,只需确保在切换渲染器时重置状态即可。

      ¥In this example, Three.js is rendered first, followed by PixiJS for UI layers. However, this order is flexible. You can render pixi -> three -> pixi is you want, just make sure you reset the state when switching renderer.

  • 单独资源:

    ¥Separate Resources:

    • 请记住,PixiJS 和 Three.js 之间不共享纹理等资源。PixiJS 纹理不能直接用作 Three.js 纹理,反之亦然。

      ¥Remember that resources like textures are not shared between PixiJS and Three.js. A PixiJS texture cannot be directly used as a Three.js texture and vice versa.


结论

¥Conclusion

混合 PixiJS 和 Three.js 可以成为创建动态且具有视觉吸引力的应用的有效方法。通过仔细管理渲染循环和状态,你可以实现 3D 和 2D 层之间的无缝过渡。这种方法允许你利用两种技术的优势,创建视觉效果令人惊叹且性能卓越的应用。

¥Mixing PixiJS and Three.js can be a powerful way to create dynamic and visually appealing applications. By carefully managing the rendering loop and states, you can achieve seamless transitions between 3D and 2D layers. This approach allows you to leverage the strengths of both technologies, creating applications that are both visually stunning and performant.

此技术也可以与其他渲染器一起使用 - 只要它们有自己的重置状态的方式(主要的方式就是如此),你就可以混合它们。流行的 3D 引擎(如 Babylon.js 和 PlayCanvas)都通过各自的 API 支持状态管理,使它们与这种混合方法兼容。这使你能够灵活地选择最适合你需求的 3D 引擎,同时仍能利用 PixiJS 强大的 2D 功能。

¥This technique can be used with other renderers too - as long as they have their own way of resetting their state (which the main ones do) you can mix them. Popular 3D engines like Babylon.js and PlayCanvas both support state management through their respective APIs, making them compatible with this mixing approach. This gives you the flexibility to choose the 3D engine that best suits your needs while still leveraging PixiJS's powerful 2D capabilities.