Importing a WebGL framework (PlayCanvas) into React

1.9k Views Asked by At

I am currently trying to import a webGL engine known as PlayCanvas into React.

PlayCanvas Github

Since PlayCanvas runs on JS and the code will stay in my index.html; I am having trouble understanding how it will interact with my React components.

Say I have a button component. This button will change the color of my 3d model in PlayCanvas. I would call a eventHandler function.

I will also load my assets into the PlayCanvas framework, which will be executed in the index.html file. For example...

Var vehicle = pc.loadAsset(“assets/123456/vehicle.json”)

I don't get the logic after that.

How would I link the PlayCanvas framework with my React components?

<html>
<head>
    <meta charset="utf-8">
    <title>PlayCanvas Hello Cube</title>
    <meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no' />
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
    <script src='https://code.playcanvas.com/playcanvas-stable.min.js'></script>
</head>
    <body>
        <canvas id='application'></canvas>
        <script>
            // create a PlayCanvas application
            var canvas = document.getElementById('application');
            var app = new pc.Application(canvas, { });
            app.start();

            // fill the available space at full resolution
            app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
            app.setCanvasResolution(pc.RESOLUTION_AUTO);

            // ensure canvas is resized when window changes size
            window.addEventListener('resize', function() {
                app.resizeCanvas();
            });

            // create box entity
            var cube = new pc.Entity('cube');
            cube.addComponent('model', {
                type: 'box'
            });

            // create camera entity
            var camera = new pc.Entity('camera');
            camera.addComponent('camera', {
                clearColor: new pc.Color(0.1, 0.1, 0.1)
            });

            // create directional light entity
            var light = new pc.Entity('light');
            light.addComponent('light');

            // add to hierarchy
            app.root.addChild(cube);
            app.root.addChild(camera);
            app.root.addChild(light);

            // set up initial positions and orientations
            camera.setPosition(0, 0, 3);
            light.setEulerAngles(45, 0, 0);

            // register a global update event
            app.on('update', function (deltaTime) {
                cube.rotate(10 * deltaTime, 20 * deltaTime, 30 * deltaTime);
            });
        </script>
    </body>
   

2

There are 2 best solutions below

0
On

If you feel using hooks and latest PlayCanvas, there it is

import React, {useLayoutEffect, useRef} from 'react';
import * as pc from 'playcanvas';

const Playcanvas = () => {
  const canvasRef = useRef(null);
  const appRef = useRef(null);

  useLayoutEffect(() => {
    const app = new pc.Application(canvasRef.current, {});
    app.start();

    app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
    app.setCanvasResolution(pc.RESOLUTION_AUTO);

    window.addEventListener('resize', function () {
      app.resizeCanvas();
    });

    const cube = new pc.Entity('cube');
    cube.addComponent('model', {
      type: 'box',
    });

    const camera = new pc.Entity('camera');
    camera.addComponent('camera', {
      clearColor: new pc.Color(0.1, 0.1, 0.1),
    });

    const light = new pc.Entity('light');
    light.addComponent('light');

    app.root.addChild(cube);
    app.root.addChild(camera);
    app.root.addChild(light);

    camera.setPosition(0, 0, 3);
    light.setEulerAngles(45, 0, 0);

    app.on('update', (deltaTime) => {
      cube.rotate(10 * deltaTime, 20 * deltaTime, 30 * deltaTime);
    });

    appRef.current = app;
  }, []);

  return (
    <div>
      <canvas ref={canvasRef} />
    </div>
  );
};

export default Playcanvas;
0
On

Install the entire playCanvas engine as an npm module. Then in your components you can build your app engine from there. use something like npm install playcanvas. Then you can structure something like this

import * as React from 'react'
import pc from 'playcanvas'

class App extends React.Component {
    constructor(props){
        super(props)
        this.canvas = undefined
        this.renderer = null;
    }

    componentDidMount(){
        this.canvas = this.refs.reactCanvas
        this.canvas.width = this.canvas.offsetWidth
        this.canvas.height = this.canvas.offsetHeight
        this.renderModel()
    }

    componentWillUnmount(){
        window.removeEventListener('resize', () => {
                this.renderer.resizeCanvas();
            });
    }

   renderModel = () => {
            var app = new pc.Application(this.canvas, { });
            app.start();

            // fill the available space at full resolution
            app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
            app.setCanvasResolution(pc.RESOLUTION_AUTO);

            // ensure canvas is resized when window changes size
            window.addEventListener('resize', function() {
                app.resizeCanvas();
            });



            // create box entity
            var cube = new pc.Entity('cube');
            cube.addComponent('model', {
                type: 'box'
            });

            // create camera entity
            var camera = new pc.Entity('camera');
            camera.addComponent('camera', {
                clearColor: new pc.Color(0.1, 0.1, 0.1)
            });

            // create directional light entity
            var light = new pc.Entity('light');
            light.addComponent('light');

            // add to hierarchy
            app.root.addChild(cube);
            app.root.addChild(camera);
            app.root.addChild(light);

            // set up initial positions and orientations
            camera.setPosition(0, 0, 3);
            light.setEulerAngles(45, 0, 0);

            app.on('update', function (deltaTime) {
                cube.rotate(10 * deltaTime, 20 * deltaTime, 30 * deltaTime);
            });

            this.renderer = app
    }

    clickHandler = event => {
         const { id } = event.target
         const handlers = {
           yourButtonId : () => { /** Do some stuff with playCanvas */}
         }

         handlers[id]();
    }

    render(){
        return (
          <div>
            <canvas ref="reactCanvas" id='3d-drawing-canvas'>This browser doesn't support canvas</canvas>
          <button onClick={clickHandler} id='yourButtonId' style={{position:'fixed', top: 0, left: 0}}/>
         </div>
        )
    }
}