How to create local axis in geometry in React and Babylon

I’m following this example from the documentation:

import { Vector3, MeshBuilder, Mesh, Color4 } from "@babylonjs/core";
import { useScene } from "babylonjs-hook";
import { useEffect, useRef } from "react";

type Props = {
    size: number;
    shade: number;
}

const LocalAxes = ({ size, shade }: Props) => {
    const pilot_local_axisX = useRef<Mesh | null>(null);
    const pilot_local_axisY = useRef<Mesh | null>(null);
    const pilot_local_axisZ = useRef<Mesh | null>(null);

    const local_origin = useRef<Mesh | null>(null);
    const scene = useScene();

    useEffect(() => {
        if (pilot_local_axisX.current === null
            || pilot_local_axisY.current === null
            || pilot_local_axisZ.current === null
            || scene === null
            || local_origin.current === null) {
            return;
        }

        pilot_local_axisX.current! = MeshBuilder.CreateLines("pilot_local_axisX", {
            points: [
                Vector3.Zero(), new Vector3(size, 0, 0), new Vector3(size * 0.95, 0.05 * size, 0),
                new Vector3(size, 0, 0), new Vector3(size * 0.95, -0.05 * size, 0)],
            colors: [new Color4(1, shade, shade)]

        }, scene);

        pilot_local_axisY.current! = MeshBuilder.CreateLines("pilot_local_axisY", {
            points: [
                Vector3.Zero(), new Vector3(0, size, 0), new Vector3(-0.05 * size, size * 0.95, 0),
                new Vector3(0, size, 0), new Vector3(0.05 * size, size * 0.95, 0)],
            colors: [new Color4(shade, 1, shade)]
        }, scene);

        pilot_local_axisZ.current! = MeshBuilder.CreateLines("pilot_local_axisZ", {
            points: [
                Vector3.Zero(), new Vector3(0, 0, size), new Vector3(0, -0.05 * size, size * 0.95),
                new Vector3(0, 0, size), new Vector3(0, 0.05 * size, size * 0.95)],
            colors: [new Color4(shade, shade, 1)]
        }, scene);

        local_origin.current! = MeshBuilder.CreateBox("local_origin", { size: 1 }, scene);
        pilot_local_axisX.current.parent = local_origin.current;
        pilot_local_axisY.current.parent = local_origin.current;
        pilot_local_axisZ.current.parent = local_origin.current;            

    }, [pilot_local_axisX, pilot_local_axisY, pilot_local_axisZ, scene, local_origin, size, shade])

    return (
        <>
            <box
                name="boxAxes"
                ref={local_origin}
                isVisible={false}>
            </box>

            <mesh
                name='pilot_local_axisX'
                fromInstance={pilot_local_axisX}
            >
            </mesh>

            <mesh
                name='pilot_local_axisY'
                fromInstance={pilot_local_axisY}>
            </mesh>

            <mesh
                name='pilot_local_axisZ'
                fromInstance={pilot_local_axisZ}>
            </mesh>
        </>
    );
}

export default LocalAxes;

I tried to adapt it to React but without success.
I don’t know if I’m doing this in the best way.
I also want to know how to insert it into a box component and move the box’s pivot to the corner

Adding our React master @brianzinn

1 Like

You can do it more declaratively - it’s a bit messy to create lines and attach them to a box that you make invisible (and then parent to a transform that rotates).

import React, { useRef } from 'react'
import { Engine, Scene, useScene, useBeforeRender } from 'react-babylonjs'
import { Vector3, Color3 } from '@babylonjs/core'

const size = 2;
const shade = 0;
const rpm = 5;

const ColorBox = () => {

  const centerTransform = useRef();
  useBeforeRender((scene) => {
    if (centerTransform.current !== null) {
      const deltaTimeInMillis = scene.getEngine().getDeltaTime();
      centerTransform.current.rotation.y += ((rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000));
    }
  })

  return (<transformNode ref={centerTransform} name="transform-node">
    <lines
      name="red-line"
      points={
        [
          new Vector3.Zero(),
          new Vector3(size, 0, 0),
          new Vector3(size * 0.95, 0.05 * size, 0),
          new Vector3(size, 0, 0),
          new Vector3(size * 0.95, -0.05 * size, 0)
        ]
      }
      color={new Color3(1, shade, shade)}
    />
    <lines
      name="green-line"
      points={
        [
          new Vector3.Zero(),
          new Vector3(0, size, 0),
          new Vector3(-0.05 * size, size * 0.95, 0),
          new Vector3(0, size, 0),
          new Vector3(0.05 * size, size * 0.95, 0)
        ]
      }
      color={new Color3(shade, 1, shade)}
    />
    <lines
      name="blue-line"
      points={
        [
          new Vector3.Zero(),
          new Vector3(0, 0, size),
          new Vector3(0, -0.05 * size, size * 0.95),
          new Vector3(0, 0, size),
          new Vector3(0, 0.05 * size, size * 0.95)
        ]
      }
      color={new Color3(shade, shade, 1)}
    />
    <box
      name="color-box"
      faceColors={[
        Color3.Blue(),
        Color3.Red(),
        Color3.Green(),
        Color3.White(),
        Color3.Yellow(),
        Color3.Black()
      ]}
    ></box>
  </transformNode>)
}

You’ve likely noticed the lines are WHITE instead of coloured properly :man_facepalming: . That’s actually a bug that I just found - yay!! I have the code generation written that anything MeshBuilder returns is a Mesh, while there is actually a LinesMesh, GroundMesh and TrailMesh, so I will need to add a check on the createXXX method return type in the generator to have the renderer update those new properties. Not sure when that will get done - there are a few escape hatches for you to write that yourself!

1 Like

@brianzinn thanks for your example, however I am getting an error, I am working with typescript.
Here is the playground

Can I add this component as a child of my box with the parent property? Or if I put it in the box as well as a material it will already become a child?

hi @JRobsonGomes

  1. You have colors instead of color and it’s a Color3 not a Color4[].
  2. useRef<T>() wants a type.

Lastly the scale is really off, so you’ll need to zoom in or change line thickness. Here is a tip - use 1 unit as 1 meter - this is I think the best way to scale everything you are doing. That will serve you well if you get into VR and also some things like raycasting default to 100, so you may get confused with those large distances. If you upgrade 'react-babylonjs` to version 3.0.14 (and lines color is fixed) and put this as LocalAxes.ts then your example will work:

import { Vector3, Color3, Color4, TransformNode } from '@babylonjs/core'
import { useBeforeRender } from 'react-babylonjs';
import { useRef } from 'react';

const size = 2;
const shade = 0;
const rpm = 5;

const LocalAxes = () => {

    const centerTransform = useRef<TransformNode | null>(null);
    useBeforeRender((scene) => {
        if (centerTransform.current !== null) {
            const deltaTimeInMillis = scene.getEngine().getDeltaTime();
            centerTransform.current!.rotation.y += ((rpm / 60) * Math.PI * 2 * (deltaTimeInMillis / 1000));
        }
    })

    return (<transformNode ref={centerTransform} name="transform-node">
        <lines
            name="red-line"
            points={
                [
                    Vector3.Zero(),
                    new Vector3(size, 0, 0),
                    new Vector3(size * 0.95, 0.05 * size, 0),
                    new Vector3(size, 0, 0),
                    new Vector3(size * 0.95, -0.05 * size, 0)
                ]
            }
            color={new Color3(1, shade, shade)}
        />
        <lines
            name="green-line"
            points={
                [
                    Vector3.Zero(),
                    new Vector3(0, size, 0),
                    new Vector3(-0.05 * size, size * 0.95, 0),
                    new Vector3(0, size, 0),
                    new Vector3(0.05 * size, size * 0.95, 0)
                ]
            }
            color={new Color3(shade, 1, shade)}
        />
        <lines
            name="blue-line"
            points={
                [
                    Vector3.Zero(),
                    new Vector3(0, 0, size),
                    new Vector3(0, -0.05 * size, size * 0.95),
                    new Vector3(0, 0, size),
                    new Vector3(0, 0.05 * size, size * 0.95)
                ]
            }
            color={new Color3(shade, shade, 1)}
        />
        <box
            name="color-box"
            faceColors={[
                new Color4(0, 0, 1),//Azul
                new Color4(1, 0, 0),//Vermelho
                new Color4(0, 0.5, 0),//Verde
                new Color4(1, 1, 1),//Branco
                new Color4(1, 1, 0),//Amarelo
                new Color4(0, 0, 0)//Preto
            ]}
        ></box>
    </transformNode>);
}

export default LocalAxes;
1 Like

Hi @brianzinn
I used the attribute colors = {[new Color4 (1, shade, shade)]} because react says
The property 'color' does not exist in type '{addInstance ?: any; addLODLevel ?: any; computeBonesUsingShaders ?: boolean | undefined; delayLoadingFile ?: string | undefined; delayLoadState ?: number | undefined; instances ?: InstancedMesh [] | undefined; ... 12 more ...; setVerticesData ?: any; } & ... 5 more ... & BabylonNode <...> '. Did you mean 'colors'? Ts (2322)

But as you said there is a bug:

You’ve likely noticed the lines are WHITE instead of coloured properly

Is it possible to color? What alternatives do I have to make the colored lines, if it is not possible I would like to just write the letters corresponding to the axes. This would help me a lot to identify the axes.

Gratitude :pray:

Ah yes, now I understand @brianzinn. I did that and now there is the color property, disregard my message above.

Speaking of updating, it would be very useful to include this zoom feature, do you intend?

mention me when it’s merged and I can run a code generation on the 5.0 branch. if there are no breaking changes with 5.0 then I can update the main branch or otherwise will do a minor update and beta.

1 Like

1 - I don’t know how to merge, I’m really a beginner.
But it is an incredible feature and very useful, if you do an update it will be much appreciated.

2 - The feature that changes the line thickness according to the zoom of the mouse, applied in the Component “LocalAxes” example of this question is very good, why does it not happen in the lines of the box?

You can’t merge - it’s an open PR that has not yet been accepted to the project.
I don’t understand about the line thickness - i didn’t see it as a property.

What I meant is that in the “LocalAxes” component of our example, the axes lines appear thinner when zooming in and wider in zooming out. Why doesn’t this happen with box line thicknesses?

If you are talking about edges rendering they are on a different rendering group (and have thickness), so render much different than a line. I would defer that question as a new one to the community, though. A single line should get smaller as you zoom in/out. Maybe you want to look at the Gizmo if it’s for debugging as well, but I never added native support for that.