Skip to content

Mesh

mesh describes the model's geometric information (geometry) and material information (material). If you want to use an Object3D object to display a 3D model, then it must add the MeshRenderer component, which mainly contains two properties:

  1. The geometry object, which determines the specific geometric shape of the object, including vertex position, topology, UV, etc.;
  2. The material object, which determines the material style presented by the object, including texture, color, transparency, and other properties.

Orillusion has several common built-in geometries, making it easy to create different mesh types:

Box

The BoxGeometry class provides box creation functionality. Parameter overview:

ParameterDescription
widthThe width along the X axis, default value is 1.
heightThe height along the Y axis, default value is 1.
depthThe depth along the Z axis, default value is 1.

Example:

ts
import {Object3D, MeshRenderer, BoxGeometry} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set the component geometry
mr.geometry = new BoxGeometry(5,2,3);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3, AtmosphericComponent, View3D } from '@orillusion/core';
let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, 0, 15);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);
// set a box geometry
mr.geometry = new BoxGeometry(5, 2, 3);
// set a pbr lit material
mr.material = new LitMaterial();
// set location and rotation
obj.localPosition = new Vector3(0, 0, 0);
obj.localRotation = new Vector3(0, 45, 0);
scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Sphere

The SphereGeometry class provides sphere creation functionality. Parameter overview:

ParameterDescription
widthSegmentsNumber of horizontal segments of the sphere (segmented along meridians)
heightSegmentsNumber of vertical segments of the sphere (segmented along parallels)
phiStart(Optional) Specifies the horizontal (meridian) start angle
phiLength(Optional) Specifies the size of the horizontal (meridian) sweep angle, the arc length of the sphere's equator
thetaStart(Optional) Specifies the vertical (parallel) start angle
thetaLength(Optional) Specifies the size of the vertical (parallel) sweep angle

Example:

ts
import {Object3D, MeshRenderer, SphereGeometry} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set the component geometry
mr.geometry = new SphereGeometry(2, 50, 50);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, AtmosphericComponent, View3D, LitMaterial, SphereGeometry, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3 } from '@orillusion/core';
let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, 0, 15);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);
// set a box geometry
mr.geometry = new SphereGeometry(2, 50, 50);
// set a pbr lit material
mr.material = new LitMaterial();
// set location
obj.localPosition = new Vector3(0, 0, 0);
scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Cylinder

The CylinderGeometry class provides cylinder creation functionality.

Parameter overview:

ParameterDescription
radiusTopTop radius, default value is 1
radiusBottomBottom radius, default value is 1
heightBarrel height, default value is 1
radialSegmentsNumber of subdivisions of the circular face, default value is 8
heightSegmentsNumber of subdivisions of the barrel wall, default value is 8
openEndedWhether it is an open barrel (with top and bottom faces), default value is false
thetaStartThe start angle of the first segment, default value is 0
thetaLengthThe central angle of the circular sector, default value is Math.PI * 2

Example:

ts
import {Object3D, MeshRenderer, CylinderGeometry} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set the component geometry
mr.geometry = new CylinderGeometry(2, 2, 10);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, AtmosphericComponent, View3D, LitMaterial, CylinderGeometry, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3 } from '@orillusion/core';
let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, -15, 10);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);
// set a cylinder geometry
mr.geometry = new CylinderGeometry(1, 1, 1, 8, 8, false, 0, 2 * Math.PI);
// set a pbr lit material for 3 sub-geometries
let material = new LitMaterial();
mr.materials = [material, material, material];
// set location and rotation
obj.localPosition = new Vector3(0, 0, 0);
scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Torus

The TorusGeometry class provides torus creation functionality.

Parameter overview:

ParameterDescription
radiusTorus radius, default value 0.4
tubeTube radius, default value 0.1
radialSegmentsNumber of subdivisions of the torus, default value 32
tubularSegmentsNumber of subdivisions of the tube, default value 32

Example:

ts
import {Object3D, MeshRenderer, TorusGeometry} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set the component geometry
mr.geometry = new TorusGeometry(3, 1, 32, 32);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, BoxGeometry, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3, AtmosphericComponent, View3D, TorusGeometry } from '@orillusion/core';
let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, 0, 15);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);
// set a box geometry
mr.geometry = new TorusGeometry(3, 1, 32, 32);
// set a pbr lit material
mr.material = new LitMaterial();
// set location and rotation
obj.localPosition = new Vector3(0, 0, 0);
obj.localRotation = new Vector3(90, 0, 0);
scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Plane

The PlaneGeometry class provides plane creation functionality.

Parameter overview:

ParameterDescription
widthThe width of the plane along the X axis. Default value is 1.
heightThe height of the plane along the Y axis. Default value is 1.
segmentWThe number of width segments of the plane, default value is 1.
segmentHThe number of height segments of the plane, default value is 1.
upThe orientation of the plane, default value is Vector3.Y_AXIS.

Example:

ts
import {Object3D, MeshRenderer, PlaneGeometry} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set the component geometry
mr.geometry = new PlaneGeometry(100, 100, 1, 1);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, AtmosphericComponent, View3D, LitMaterial, PlaneGeometry, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3, GPUCullMode } from '@orillusion/core';
let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, -15, 80);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);
// set a plane geometry
mr.geometry = new PlaneGeometry(20, 20);
// set a pbr lit material
mr.material = new LitMaterial();
// render double side
mr.material.cullMode = GPUCullMode.none;
// set location and rotation
obj.localPosition = new Vector3(0, 0, 0);
obj.localRotation = new Vector3(0, 45, 0);
scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Extrude Geometry

The ExtrudeGeometry class provides the functionality to extrude a geometry from a shape path.

Example:

ts
import {Object3D, MeshRenderer, ExtrudeGeometry, Vector3} from '@orillusion/core';

let conduitObject3D = new Object3D();
// Add MeshRenderer component
let mr = conduitObject3D.addComponent(MeshRenderer);
// Create a custom shape
let shape: Vector3[] = [], vertexCount = 8, shapeRadius = 1
for (let i = 0; i < vertexCount; i++) {
    let angle = Math.PI * 2 * i / vertexCount;
    let point = new Vector3(Math.sin(angle), 0, Math.cos(angle)).multiplyScalar(shapeRadius);
    shape.push(point);
}
// Create a custom path
let curve: Vector3[] = [], sectionCount = 60, modelRadius = 4
for (let i = 0; i < sectionCount; i++) {
    let angle = Math.PI * 2 * i / 20;
    modelRadius += 0.1 * i / sectionCount;
    let offsetY = 0.6 - Math.sqrt(i / sectionCount);
    let point = new Vector3(Math.sin(angle), offsetY * 6, Math.cos(angle)).multiplyScalar(modelRadius);
    curve.push(point);
}
// Create Extrude Geometry
mr.geometry = new ExtrudeGeometry().build(shape, true, curve, 0.2);

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, Scene3D, Object3D, Camera3D, LitMaterial, MeshRenderer, DirectLight, HoverCameraController, Color, Vector3, AtmosphericComponent, View3D, ExtrudeGeometry, BitmapTexture2D, GPUCullMode } from '@orillusion/core';

let engine = await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, engine.aspect, 1, 5000.0);
let controller = camera.object3D.addComponent(HoverCameraController);
controller.setCamera(0, 0, 40);
scene3D.addChild(cameraObj);

let light: Object3D = new Object3D();
let component: DirectLight = light.addComponent(DirectLight);
light.rotationX = 45;
light.rotationY = 30;
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0);
component.intensity = 1;
scene3D.addChild(light);

// create a object
const obj: Object3D = new Object3D();
// add MeshRenderer to the object
let mr: MeshRenderer = obj.addComponent(MeshRenderer);

// build shape
let shape: Vector3[] = [],
    vertexCount = 8,
    shapeRadius = 1;
for (let i = 0; i < vertexCount; i++) {
    let angle = (Math.PI * 2 * i) / vertexCount;
    let point = new Vector3(Math.sin(angle), 0, Math.cos(angle)).multiplyScalar(shapeRadius);
    shape.push(point);
}
// build curve path
let curve: Vector3[] = [],
    sectionCount = 60,
    modelRadius = 4;
for (let i = 0; i < sectionCount; i++) {
    let angle = (Math.PI * 2 * i) / 20;
    modelRadius += (0.1 * i) / sectionCount;
    let offsetY = 0.6 - Math.sqrt(i / sectionCount);
    let point = new Vector3(Math.sin(angle), offsetY * 6, Math.cos(angle)).multiplyScalar(modelRadius);
    curve.push(point);
}

// build ExtrudeGeometry from shape & curve
mr.geometry = new ExtrudeGeometry().build(shape, true, curve, 0.2);
// set a pbr lit material
mr.material = new LitMaterial();
let texture = new BitmapTexture2D();
texture.addressModeU = 'repeat';
texture.addressModeV = 'repeat';
await texture.load('https://cdn.orillusion.com/textures/grid.webp');
mr.material.baseMap = texture;
mr.material.cullMode = GPUCullMode.none;

scene3D.addChild(obj);

// add an Atmospheric sky enviroment
scene3D.addComponent(AtmosphericComponent).sunY = 0.6;
// create a view with target scene and camera
let view = new View3D();
view.scene = scene3D;
view.camera = camera;
// start render
engine.startRenderView(view);

Custom Geometry

We can customize the shape of a geometry by updating the vertices vertexBuffer of an existing geometry

Example:

ts
import {Object3D, MeshRenderer, PlaneGeometry, LitMaterial, VertexAttributeName} from '@orillusion/core';

let obj = new Object3D();
// Add MeshRenderer component
let mr = obj.addComponent(MeshRenderer);
// Set a plane as the base, defining the size and number of segments
mr.geometry = new PlaneGeometry(100, 100, 100, 100);
mr.material = new LitMaterial()

// Get the existing vertex information
let posAttrData = mr.geometry.getAttribute(VertexAttributeName.position);
// Rewrite all vertex xyz coordinates
for (let i = 0, count = posAttrData.data.length / 3; i < count; i++) {
    posAttrData.data[i * 3 + 0] = Math.random(); // position x
    posAttrData.data[i * 3 + 1] = Math.random(); // position y
    posAttrData.data[i * 3 + 2] = Math.random(); // poisiton z
}
// Update the vertex information
mr.geometry.vertexBuffer.upload(VertexAttributeName.position, posAttrData);
// Recompute the normals
mr.geometry.computeNormals();

We can even change the vertex information every frame in the main loop

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { View3D, PlaneGeometry, Engine3D, Scene3D, AtmosphericComponent, CameraUtil, HoverCameraController, Object3D, DirectLight, KelvinUtil, MeshRenderer, LitMaterial, VertexAttributeName, Time } from '@orillusion/core';

// An sample of dynamically updating a geometry vertex attribute
class Smaple_VertexAnimation {
    // This geometry will dynamically update its vertex data over time
    floorGeometry: PlaneGeometry;
    scene: Scene3D;
    async run() {
        let engine = await Engine3D.init({ beforeRender: () => this.update() });

        let view = new View3D();
        view.scene = new Scene3D();
        view.scene.addComponent(AtmosphericComponent);

        this.scene = view.scene;
        view.camera = CameraUtil.createCamera3DObject(view.scene, 'camera');
        view.camera.perspective(60, engine.aspect, 1, 2000);
        view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 150);

        engine.startRenderView(view);

        this.createScene();
    }

    private createScene() {
        // add light
        let lightObj3D = new Object3D();
        let directLight = lightObj3D.addComponent(DirectLight);
        directLight.intensity = 25;
        directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
        directLight.castShadow = true;
        lightObj3D.rotationX = 53.2;
        lightObj3D.rotationY = 220;
        lightObj3D.rotationZ = 5.58;
        this.scene.addChild(lightObj3D);

        // add floor
        this.floorGeometry = new PlaneGeometry(100, 100, 199, 199);
        let floor = new Object3D();
        let renderer = floor.addComponent(MeshRenderer);
        renderer.geometry = this.floorGeometry;
        renderer.material = new LitMaterial();
        renderer.castShadow = true;
        renderer.receiveShadow = true;
        this.scene.addChild(floor);
    }

    private update() {
        if (this.floorGeometry) {
            let posAttrData = this.floorGeometry.getAttribute(VertexAttributeName.position);
            // update its vertex data over time
            let timeOffset = Time.time;
            for (let i = 0, count = posAttrData.data.length / 3; i < count; i++) {
                posAttrData.data[i * 3 + 1] = Math.sin(timeOffset * 0.01 + i * 0.25);
            }
            // position attr need to be upload
            this.floorGeometry.vertexBuffer.upload(VertexAttributeName.position, posAttrData);
            //update normals
            this.floorGeometry.computeNormals();
        }
    }
}

new Smaple_VertexAnimation().run();

Geometry Extensions

In addition to the common built-in geometries above, the engine also provides the @orillusion/geometry geometry extension package, which currently contains extensions and utility classes such as the font geometry TextGeometry, the 2D extrude geometry ExtrudeGeometry, the terrain geometry TerrainGeometry, etc.

Users can quickly introduce the geometry plugin via the NPM package:

bash
npm install @orillusion/core --save
npm install @orillusion/geometry --save
ts
import { Engine3D } from "@orillusion/core"
import { TextGeometry } from "@orillusion/geometry"

Or the UMD version

html
<script src="https://unpkg.com/@orillusion/core/dist/orillusion.umd.js"></script>
<script src="https://unpkg.com/@orillusion/geometry/dist/geometry.umd.js"></script>
<script>
  const { Engine3D, Geometry } = Orillusion
  const { ExtrudeGeometry, TextGeometry } = Geometry
</script>

2D Extrude

Similar to but different from the built-in ExtrudeGeometry, this extension class simplifies the data and supports generating spatial geometries from Shape2D planar shapes.

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, HoverCameraController, Object3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, Color, GridObject, Vector2, Vector3, Material } from "@orillusion/core";
import { Shape2D, ExtrudeGeometry, Path2D } from "@orillusion/geometry";

class Sample_ExtrudeGeometry {
    scene: Scene3D
    async run() {
        let engine = await Engine3D.init();
        let view = new View3D();
        view.scene = this.scene = new Scene3D();
        let sky = view.scene.addComponent(AtmosphericComponent);

        view.camera = CameraUtil.createCamera3DObject(view.scene);
        view.camera.perspective(60, engine.aspect, 1, 5000.0);
        view.camera.object3D.z = -15;
        view.camera.object3D.addComponent(HoverCameraController).setCamera(0, -20, 500);

        let lightObj3D = new Object3D();
        let sunLight = lightObj3D.addComponent(DirectLight);
        sunLight.intensity = 3;
        sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553);
        sunLight.castShadow = true;
        lightObj3D.rotationX = 53.2;
        lightObj3D.rotationY = 220;
        lightObj3D.rotationZ = 5.58;
        view.scene.addChild(lightObj3D);
        sky.relativeTransform = lightObj3D.transform;

        view.scene.addChild(new GridObject(1000, 100))

        engine.startRenderView(view);

        this.createShapes();
    }

    async createShapes() {
        
        // california
        {
            let points:Vector2[] = []
            points.push( new Vector2( 610, 320 ) );
            points.push( new Vector2( 450, 300 ) );
            points.push( new Vector2( 392, 392 ) );
            points.push( new Vector2( 266, 438 ) );
            points.push( new Vector2( 190, 570 ) );
            points.push( new Vector2( 190, 600 ) );
            points.push( new Vector2( 160, 620 ) );
            points.push( new Vector2( 160, 650 ) );
            points.push( new Vector2( 180, 640 ) );
            points.push( new Vector2( 165, 680 ) );
            points.push( new Vector2( 150, 670 ) );
            points.push( new Vector2( 90, 737 ) );
            points.push( new Vector2( 80, 795 ) );
            points.push( new Vector2( 50, 835 ) );
            points.push( new Vector2( 64, 870 ) );
            points.push( new Vector2( 60, 945 ) );
            points.push( new Vector2( 300, 945 ) );
            points.push( new Vector2( 300, 743 ) );
            points.push( new Vector2( 600, 473 ) );
            points.push( new Vector2( 626, 425 ) );
            points.push( new Vector2( 600, 370 ) );
            points.push( new Vector2( 610, 320 ) );

            let shape = new Shape2D(points.map(p=>p.multiplyScalar(0.25)))
            this.addShape(shape, -300, -60, 0)
        }

        // triangle
        {
            let shape = new Shape2D();
            shape.moveTo(80, 20);
            shape.lineTo(40, 80);
            shape.lineTo(120, 80);
            shape.lineTo(80, 20);

            this.addShape(shape, -180, 0, 0)
        }

        // heart
        {
            const x = 0, y = 0;
            const shape = new Shape2D()
                .moveTo( x + 25, y + 25 )
                .bezierCurveTo( x + 25, y + 25, x + 20, y, x, y )
                .bezierCurveTo( x - 30, y, x - 30, y + 35, x - 30, y + 35 )
                .bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 )
                .bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 )
                .bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y )
                .bezierCurveTo( x + 35, y, x + 25, y + 25, x + 25, y + 25 );


            this.addShape(shape, 0, 20, 0)
        }

        // square
        {
            const sqLength = 80;
            const squareShape = new Shape2D()
                .moveTo( 0, 0 )
                .lineTo( 0, sqLength )
                .lineTo( sqLength, sqLength )
                .lineTo( sqLength, 0 )
                .lineTo( 0, 0 );
            
            this.addShape(squareShape, 100, 20, 0)
        }

        // Circle
        {
            const circleRadius = 40;
            const circleShape = new Shape2D()
                .moveTo( 0, circleRadius )
                .quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 )
                .quadraticCurveTo( circleRadius, - circleRadius, 0, - circleRadius )
                .quadraticCurveTo( - circleRadius, - circleRadius, - circleRadius, 0 )
                .quadraticCurveTo( - circleRadius, circleRadius, 0, circleRadius );

            this.addShape(circleShape, 140, 150, 0)
        }

        // Fish
        {
            const x = 0, y =0;
            const fishShape = new Shape2D()
                .moveTo( x, y )
                .quadraticCurveTo( x + 50, y - 80, x + 90, y - 10 )
                .quadraticCurveTo( x + 100, y - 10, x + 115, y - 40 )
                .quadraticCurveTo( x + 115, y, x + 115, y + 40 )
                .quadraticCurveTo( x + 100, y + 10, x + 90, y + 10 )
                .quadraticCurveTo( x + 50, y + 80, x, y );

            this.addShape(fishShape, -40, 160, 0)
        }

        // holes
        {
            const sqLength = 80;
            const squareShape = new Shape2D()
                .moveTo( 0, 0 )
                .lineTo( 0, sqLength )
                .lineTo( sqLength, sqLength )
                .lineTo( sqLength, 0 )
                .lineTo( 0, 0 );

            let hole1 = new Path2D()
                .moveTo( 10, 10 )
                .lineTo( 10, 30 )
                .lineTo( 30, 30 )
                .lineTo( 30, 10 )
                .lineTo( 10, 10 );
            
            let hole2 = new Path2D()
                .moveTo( 40, 10 )
                .lineTo( 40, 30 )
                .lineTo( 60, 30 )
                .lineTo( 60, 10 )
                .lineTo( 40, 10 );
            
            squareShape.holes.push(hole1, hole2);

            this.addShape(squareShape, -150, 100, 0)
        }

    }

    matrial: LitMaterial;
    addShape(shape: Shape2D, x:number = 0, y:number = 0, z:number = 0){
        let obj = new Object3D();
        obj.localPosition = new Vector3(x, y, z)
        let mr = obj.addComponent(MeshRenderer);
        mr.geometry = new ExtrudeGeometry([shape], {
            depth: 10,
            bevelEnabled: false,
            steps: 1,
            // anchorPoint: new Vector3(0,0,0)
        });
        if(!this.matrial){
            let mat =  this.matrial = new LitMaterial();
            mat.baseColor = new Color(0.2, 0.5, 1.0);
            mat.castShadow = false;
        }
        let mats: Material[] = [];
        for (let i = 0; i < mr.geometry.subGeometries.length; i++) {
            mats.push(this.matrial);
        }
        mr.materials = mats;
        this.scene.addChild(obj);
    }
}

new Sample_ExtrudeGeometry().run();

Font Geometry

Supports creating spatial text geometries from common font files woff, otf, ttf

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, HoverCameraController, Object3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, Vector3 } from "@orillusion/core";
import { TextGeometry, FontParser } from "@orillusion/geometry";
// import { Graphic3D } from "@orillusion/graphic";

class Sample_TextGeometry {
    lightObj: Object3D;
    engine: Engine3D;
    async run() {
        this.engine = await Engine3D.init();
        let view = new View3D();
        view.scene = new Scene3D();
        let sky = view.scene.addComponent(AtmosphericComponent);

        view.camera = CameraUtil.createCamera3DObject(view.scene);
        view.camera.perspective(60, this.engine.aspect, 1, 5000.0);
        view.camera.object3D.z = -15;
        view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 150);

        this.engine.startRenderView(view);

        await this.createScene(view.scene);
        sky.relativeTransform = this.lightObj.transform;
    }

    async createScene(scene: Scene3D) {
        {
            // scene.addChild(new Graphic3D());

            let font = await this.engine.res.load("https://cdn.orillusion.com/fonts/Roboto.ttf", FontParser);

            let obj = new Object3D();
            let mr = obj.addComponent(MeshRenderer);
            mr.geometry = new TextGeometry("Hello, Orillusion!", {
                font: font, // required
                fontSize: 16, // required
                depth: 2.5,
                steps: 1,
                bevelEnabled: false,
                anchorPoint: new Vector3(0.5, 0.5, 0.5)
            });

            let mats = [];
            let mat = new LitMaterial();
            for (let i = 0; i < mr.geometry.subGeometries.length; i++) {
                mats.push(mat);
            }
            mr.materials = mats;

            scene.addChild(obj);
        }

        let lightObj3D = this.lightObj = new Object3D();
        let sunLight = lightObj3D.addComponent(DirectLight);
        sunLight.intensity = 3;
        sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553);
        sunLight.castShadow = true;
        lightObj3D.rotationX = 53.2;
        lightObj3D.rotationY = 220;
        lightObj3D.rotationZ = 5.58;
        scene.addChild(lightObj3D);
    }
}

new Sample_TextGeometry().run();

Terrain Geometry

Supports quickly creating 3D terrain geometries from a 2D height map or elevation map

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, HoverCameraController, Object3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, PostProcessingComponent, BitmapTexture2D, GlobalFog, Color } from '@orillusion/core';
import { TerrainGeometry } from '@orillusion/geometry';
import { Stats } from '@orillusion/stats';

// An sample of custom vertex attribute of geometry
class Sample_Terrain {
    view: View3D;
    post: PostProcessingComponent;
    engine: Engine3D;

    async run() {
        this.engine = await Engine3D.init({
            setting: {
                shadow: {
                    autoUpdate: true,
                    updateFrameRate: 1,
                    shadowBound: 500,
                    shadowSize: 2048
                }
            }
        });
        this.view = new View3D();
        this.view.scene = new Scene3D();
        this.view.scene.addComponent(AtmosphericComponent);
        this.view.scene.addComponent(Stats);

        this.view.camera = CameraUtil.createCamera3DObject(this.view.scene);
        this.view.camera.perspective(60, this.engine.aspect, 1, 50000.0);
        this.view.camera.object3D.z = -15;
        this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 10000);

        this.engine.startRenderView(this.view);

        this.post = this.view.scene.addComponent(PostProcessingComponent);
        let fog = this.post.addPost(GlobalFog);
        fog.start = 2000;
        fog.end = 0;
        fog.fogHeightScale = 0.116;
        fog.density = 0.094;
        fog.ins = 0.1041;
        fog.skyFactor = 0.35;
        fog.overrideSkyFactor = 0.7;

        fog.fogColor = new Color(136 / 255, 215 / 255, 236 / 255, 1);
        fog.fogHeightScale = 0.1;
        fog.falloff = 0.626;
        fog.scatteringExponent = 8;
        fog.dirHeightLine = 6.5;

        this.createScene(this.view.scene);
    }

    private async createScene(scene: Scene3D) {
        {
            let sunObj = new Object3D();
            let sunLight = sunObj.addComponent(DirectLight);
            sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553);
            sunLight.castShadow = true;
            sunLight.intensity = 4;
            sunObj.transform.rotationX = 50;
            sunObj.transform.rotationY = 50;
            scene.addChild(sunObj);
        }

        //bitmap
        let bitmapTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/test01/bitmap.png');
        let heightTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/test01/height.png');
        let terrainSizeW = 20488;
        let terrainSizeH = 20488;
        let terrainGeometry: TerrainGeometry;
        {
            let mat = new LitMaterial();
            terrainGeometry = new TerrainGeometry(terrainSizeW, terrainSizeH, 2000, 2000);
            terrainGeometry.setHeight(heightTexture as BitmapTexture2D, 5000);
            let floor = new Object3D();
            let mr = floor.addComponent(MeshRenderer);
            mr.geometry = terrainGeometry;
            mat.baseMap = bitmapTexture;
            mr.material = mat;
            scene.addChild(floor);
        }
    }
}

new Sample_Terrain().run();

Grass Geometry

Creates simulated grassland terrain, and combined with the grass component can simulate a dynamic effect of swaying in the wind

WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, HoverCameraController, Object3D, DirectLight, KelvinUtil, LitMaterial, MeshRenderer, Vector3, PostProcessingComponent, BitmapTexture2D, GlobalFog, Color } from '@orillusion/core';
import { GrassComponent, TerrainGeometry } from '@orillusion/geometry';
import { Stats } from '@orillusion/stats';
import dat from 'dat.gui';

class Sample_Grass {
    view: View3D;
    post: PostProcessingComponent;
    engine: Engine3D;

    async run() {
        this.engine = await Engine3D.init({
            setting: {
                shadow: {
                    autoUpdate: true,
                    updateFrameRate: 1,
                    shadowBound: 500,
                    shadowSize: 1024
                }
            }
        });
        this.view = new View3D();
        this.view.scene = new Scene3D();
        this.view.scene.addComponent(AtmosphericComponent);
        this.view.scene.addComponent(Stats);

        this.view.camera = CameraUtil.createCamera3DObject(this.view.scene);
        this.view.camera.enableCSM = true;
        this.view.camera.perspective(60, this.engine.aspect, 1, 5000.0);
        this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 500);

        this.engine.startRenderView(this.view);
        this.createScene(this.view.scene);
    }

    private async createScene(scene: Scene3D) {
        //bitmap
        let bitmapTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/test01/bitmap.png', undefined, undefined, 'srgb');
        let heightTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/test01/height.png');
        // let grassTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/grass/GrassThick.png');
        let gustNoiseTexture = await this.engine.res.loadTexture('https://cdn.orillusion.com/terrain/grass/displ_noise_curl_1.png');
        let sunObj = new Object3D();
        let sunLight = sunObj.addComponent(DirectLight);
        sunLight.lightColor = KelvinUtil.color_temperature_to_rgb(6553);
        sunLight.castShadow = true;
        sunLight.intensity = 10;
        sunObj.transform.rotationX = 50;
        sunObj.transform.rotationY = 50;
        scene.addChild(sunObj);

        let terrainSize = 1000;
        let size = 1000;
        let grassCount = 6795;
        // let grassCount = 10;
        let des = 1;
        let space = 2;
        let terrainGeometry: TerrainGeometry;
        {
            let mat = new LitMaterial();
            terrainGeometry = new TerrainGeometry(terrainSize, terrainSize);
            terrainGeometry.setHeight(heightTexture as BitmapTexture2D, 100);
            let floor = new Object3D();
            let mr = floor.addComponent(MeshRenderer);
            mr.geometry = terrainGeometry;
            mat.baseMap = bitmapTexture;
            mr.material = mat;
            scene.addChild(floor);
        }

        let grassCom: GrassComponent;
        {
            let grass = new Object3D();
            grassCom = grass.addComponent(GrassComponent);
            grassCom.setGrassTexture(this.engine.res.whiteTexture);
            // grassCom.setGrassTexture(grassTexture);
            grassCom.setWindNoiseTexture(gustNoiseTexture);
            grassCom.setGrass(18, 1, 5, 1, grassCount);

            let tsw = terrainSize / terrainGeometry.segmentW;
            let tsh = terrainSize / terrainGeometry.segmentH;
            let index = 0;
            terrainGeometry.greenData.forEach((data) => {
                for (let d = 0; d < des; d++) {
                    let node = grassCom.nodes[index++];
                    if (node) {
                        let px = data.x * tsw - terrainSize * 0.5 + Math.random() * space - space * 0.5;
                        let pz = data.z * tsh - terrainSize * 0.5 + Math.random() * space - space * 0.5;
                        let pos = new Vector3(px, 0, pz);

                        let tw = terrainGeometry.segmentW;
                        let th = terrainGeometry.segmentH;
                        let tx = Math.floor(((pos.x + size * 0.5) / size) * terrainGeometry.segmentW);
                        let tz = Math.floor(((pos.z + size * 0.5) / size) * terrainGeometry.segmentH);

                        if (terrainGeometry.heightData.length > tz && terrainGeometry.heightData[tz].length > tx) {
                            pos.y = terrainGeometry.heightData[tz][tx];
                        }

                        let gassSize = 0.8;
                        let scale = (Math.random() * 0.75 + 0.25) * gassSize;
                        node.localPosition = pos;
                        node.localRotation.y = Math.random() * 360;
                        node.localScale = new Vector3(scale, scale, scale);
                        node.updateWorldMatrix(true);
                    }
                }
            });
            scene.addChild(grass);
        }

        let gui = new dat.GUI()
        let dir = gui.addFolder('grass-wind')
        dir.addColor(grassCom.grassMaterial.grassBaseColor, 'rgba').name('grassBaseColor').onChange(val=>{
            let color = grassCom.grassMaterial.grassBaseColor
            color['rgba'] = val
            grassCom.grassMaterial.grassBaseColor = color
        })
        dir.addColor(grassCom.grassMaterial.grassTopColor, 'rgba').name('grassTopColor').onChange(val=>{
            let color = grassCom.grassMaterial.grassBaseColor
            color['rgba'] = val
            grassCom.grassMaterial.grassTopColor = color
        })
        dir.add(grassCom.grassMaterial.windDirection, 'x', -1.0, 1, 0.0001).onChange((v) => {
            let tv = grassCom.grassMaterial.windDirection
            tv.x = v
            grassCom.grassMaterial.windDirection = tv
        })
        dir.add(grassCom.grassMaterial.windDirection, 'y', -1.0, 1, 0.0001).onChange((v) => {
            let tv = grassCom.grassMaterial.windDirection
            tv.y = v
            grassCom.grassMaterial.windDirection = tv
        })
        dir.add(grassCom.grassMaterial, 'windPower', 0.0, 20, 0.0001)
        dir.add(grassCom.grassMaterial, 'windSpeed', 0.0, 20, 0.0001)
        dir.add(grassCom.grassMaterial, 'curvature', 0.0, 1, 0.0001)
        dir.add(grassCom.grassMaterial, 'grassHeight', 0.0, 100, 0.0001)
        dir.add(grassCom.grassMaterial, 'roughness', 0.0, 1, 0.0001)
        dir.add(grassCom.grassMaterial, 'translucent', 0.0, 1, 0.0001)
        dir.add(grassCom.grassMaterial, 'soft', 0.0, 10, 0.0001)
        dir.add(grassCom.grassMaterial, 'specular', 0.0, 10, 0.0001)
        dir.open()
    }
}

new Sample_Grass().run();

Released under the MIT License