pixi3d

repository·develop·Indexed 21 days ago

https://github.com/jnsmalm/pixi3d

A 3D rendering library built on top of PixiJS (version 2.5.0) that enables the integration of 3D content, such as glTF models, PBR, and IBL, into 2D PixiJS applications. It supports skeletal, morphing, and transformation animations, as well as point, directional, and spot lighting. Key features include ShadowCastingLight for shadows, CameraOrbitControl for interactive viewpoints, and the ability to compose 2D and 3D elements using CompositeSprite.

Tokens
12.7K
Snippets
50
Records
61
Agent score
74%

What's inside pixi3d

  1. Compose 2D and 3D elements

    develop

    Pixi3D integrates with PixiJS. You can add 2D containers on top of 3D containers or vice versa.

    Important: 2D and 3D transforms are not compatible; changing a parent's 2D transform will not affect its 3D children.

    To bridge the two:

    • Use camera.screenToWorld and camera.worldToScreen for coordinate conversion.
    • Use CompositeSprite to render a 3D object as a 2D sprite, allowing the use of standard PixiJS filters on 3D content.
    // Adding a 2D vignette on top of the 3D scene
    let vignette = app.stage.addChild(
      PIXI.Sprite.from(
        "https://raw.githubusercontent.com/jnsmalm/pixi3d-sandbox/master/assets/vignette.png"
      )
    );
    
    app.ticker.add(() => {
      Object.assign(vignette, {
        width: app.renderer.width, 
        height: app.renderer.height
      });
    });
  2. Enable shadow casting and receiving

    develop

    To use shadows, you need a shadow-casting light and objects configured to both cast and receive shadows via the renderer's pipeline.

    1. Create a shadow-casting light: Wrap an existing light with PIXI3D.ShadowCastingLight.
    2. Create a receiver: Use PIXI3D.Mesh3D.createPlane() to create a ground.
    3. Enable shadows in the pipeline: Use pipeline.enableShadows(object, shadowCastingLight) for both the caster and the receiver.
    let ground = app.stage.addChild(PIXI3D.Mesh3D.createPlane());
    ground.y = -1;
    ground.scale.set(10);
    
    let shadowCastingLight = new PIXI3D.ShadowCastingLight(app.renderer, dirLight, {
      shadowTextureSize: 512,
      quality: PIXI3D.ShadowQuality.medium
    });
    shadowCastingLight.softness = 1;
    shadowCastingLight.shadowArea = 8;
    
    let pipeline = app.renderer.plugins.pipeline;
    pipeline.enableShadows(teapot, shadowCastingLight);
    pipeline.enableShadows(ground, shadowCastingLight);
  3. Create a PixiJS application for Pixi3D

    develop

    To use Pixi3D, you must first create a PixiJS application object. This object manages the renderer, the render loop, and the canvas element. You should append the app.view to your HTML document to display the scene.

    let app = new PIXI.Application({
      resizeTo: window, 
      backgroundColor: 0xdddddd, 
      antialias: true
    });
    document.body.appendChild(app.view);
  4. Install Pixi3D using the automatic setup

    develop

    The fastest way to start a new project is using the create-pixi3d-app scaffolding tool. This creates a complete project structure with everything needed to run immediately. Requires Node.js.

    npx create-pixi3d-app@latest my-pixi3d-app
    cd my-pixi3d-app
    npm start
  5. Load a glTF 2.0 model

    develop

    Pixi3D supports the glTF 2.0 file format. Loading a model depends on the version of PixiJS you are using.

    PixiJS v5 or v6

    Use app.loader to add the asset and app.loader.load to retrieve the resources.

    PixiJS v7

    Use PIXI.Assets.load (async) to load the glTF file directly.

    // PixiJS v7 approach
    (async function load() {
      let gltf = await PIXI.Assets.load("https://raw.githubusercontent.com/jnsmalm/pixi3d-sandbox/master/assets/teapot/teapot.gltf")
      setup(gltf)
    })()
    
    function setup(gltf) {
      let teapot = app.stage.addChild(PIXI3D.Model.from(gltf));
    }
  6. Manual setup for Pixi3D

    develop

    To set up Pixi3D manually without a package manager:

    1. Download the latest version of Pixi3D.
    2. Download PixiJS (compatible with versions 5.3 and later).
    3. Create an app.js file for your logic.
    4. Create an index.html file and include the scripts in this order: pixi.js, pixi3d.js, and then your app.js.
    <!doctype html>
    <html lang="en">
    <body
      <script type="text/javascript" src="pixi.js"></script>
      <script type="text/javascript" src="pixi3d.js"></script>
      <script type="text/javascript" src="app.js"></script>
    </body>
    </html>
  7. Install Pixi3D via npm

    develop

    You can install Pixi3D as an npm package. Note that the import path depends on which version of PixiJS you are using:

    • For PixiJS v5 or v6: Import from pixi3d.
    • For PixiJS v7: Import from pixi3d/pixi7.
    npm install pixi3d
    // For PixiJS v5/v6
    import { Model } from "pixi3d";
    
    // For PixiJS v7
    import { Model } from "pixi3d/pixi7";
  8. Use StandardMaterial for PBR surfaces

    develop

    The StandardMaterial is a Physically-Based Rendering (PBR) material used to represent a wide range of surfaces. It is the default material used when loading 3D models from files. It supports properties like roughness, metalness, base color, and emissive properties, as well as various texture maps for advanced surface detail.

    Key properties include:

    • roughness: Controls surface smoothness (0 to 1).
    • metallic: Controls how metallic the surface appears (0 to 1).
    • baseColor: The primary color of the material.
    • emissive: The color emitted by the material.
    • exposure: Controls the brightness of the material.
    • unlit: If set to true, all lighting is disabled and only the base color is used.
    import { StandardMaterial } from 'pixi3d';
    import { Color } from '@pixi/core';
    
    const material = new StandardMaterial();
    material.baseColor = new Color(1, 0, 0, 1); // Red
    material.roughness = 0.5;
    material.metallic = 0.8;
    material.unlit = false;
  9. Extend the Material class for custom shaders

    develop

    To implement complex visual effects, you can extend the Material class and override the following methods:

    • createShader(mesh: Mesh3D, renderer: Renderer): Returns a MeshShader instance tailored for the specific mesh and renderer.
    • updateUniforms(mesh: Mesh3D, shader: MeshShader): A hook called every frame to update shader uniforms based on the mesh's state (position, rotation, scale, etc.).
    • isInstancingSupported(): Return true if your material implementation supports GPU instancing.
    • createInstance(): Return a new material instance optimized for instancing if supported.
  10. Create a basic Pixi3D application

    develop

    A minimal example of initializing a PixiJS application, adding a 3D cube, and setting up a light source within the PIXI3D.LightingEnvironment.

    let app = new PIXI.Application({
      backgroundColor: 0xdddddd, resizeTo: window, antialias: true
    })
    document.body.appendChild(app.view)
    
    let mesh = app.stage.addChild(PIXI3D.Mesh3D.createCube())
    
    let light = new PIXI3D.Light()
    light.position.set(-1, 0, 3)
    PIXI3D.LightingEnvironment.main.lights.push(light)
    
    let rotation = 0
    app.ticker.add(() => {
      mesh.rotationQuaternion.setEulerAngles(0, rotation++, 0)
    })
  11. Play model animations

    develop

    Pixi3D supports three types of animations found in glTF files:

    1. Skeletal: For character movement and rigging.
    2. Morphing: Per-vertex animation (e.g., facial expressions).
    3. Transformation: Moving, rotating, or scaling entire objects.

    Use the .play() method on an animation object within the model.animations array.

    setInterval(() => {
      teapot.animations.forEach((anim) => anim.play());
    }, 1500);
  12. Set up a lighting environment

    develop

    Lights illuminate objects in the scene. You can use the default PIXI3D.LightingEnvironment.main or create custom environments.

    Available light types:

    • point: Emits light in all directions from a single point.
    • directional: Emits light in one direction from an infinite distance.
    • spot: Emits light in a cone shape from a point.

    To use a light, create a PIXI3D.Light instance, set its type and intensity, and push it into the lights array of a lighting environment.

    let dirLight = new PIXI3D.Light();
    dirLight.type = "directional";
    dirLight.intensity = 0.5;
    dirLight.rotationQuaternion.setEulerAngles(45, 45, 0);
    dirLight.position.set(-4, 7, -4);
    PIXI3D.LightingEnvironment.main.lights.push(dirLight);
    
    let pointLight = new PIXI3D.Light();
    pointLight.type = "point";
    pointLight.intensity = 10;
    pointLight.position.set(1, 0, 3);
    PIXI3D.LightingEnvironment.main.lights.push(pointLight);