Skip to content

Mesh

Mesh describes the geometric information (geometry) and material information (material) of the model. 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. Geometry object, which determines the specific geometry of the object, including vertex position, topology, UV, etc.;
  2. Material object, which determines the material ball style of the object, including texture, color, transparency, etc.

Orillusion has several built-in geometry types, which can be used to create different types of mesh:

Rectangular Cuboid

BoxGeometry class provides the function of creating a rectangular box. Parameters overview:

ParameterDescription
widthThe width on the X axis. The default value is 1.
heightThe height on the Y axis. The default value is 1.
depthThe depth on the Z axis. The 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';
await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Sphere

SphereGeometry class provides the function of creating a sphere. Parameters overview:

ParameterDescription
widthSegmentsThe number of segments that make up the sphere along the width (longitude).
heightSegmentsThe number of segments that make up the sphere along the height (latitude).
phiStart(Optional) The starting angle, in radians, of the horizontal (longitude) lines.
phiLength(Optional) The central angle, in radians, of the horizontal (longitude) lines.
thetaStart(Optional) The starting angle, in radians, of the vertical (latitude) lines.
thetaLength(Optional) The central angle, in radians, of the vertical (latitude) lines.

Example:

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

let obj = new Object3D();
// Add MeshRenderer
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';
await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Cylinder

CylinderGeometry class provides the function of creating a cylinder. Parameters overview:

ParameterDescription
radiusTopTop radius. The default value is 1.
radiusBottomBottom radius. The default value is 1.
heightThe height of the cylinder. The default value is 1.
radialSegmentsThe number of subdivisions around the circumference of the circle. The default value is 8.
heightSegmentsThe number of subdivisions along the height of the cylinder. The default value is 8.
openEndedWhether the cylinder is open (with top and bottom). The default value is false.
thetaStartThe starting angle of the first segment, in radians. The default value is 0.
thetaLengthThe central angle of the circular sector, in radians. The 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';
await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Torus

TorusGeometry class provides the function of creating a Torus.

Parameters overview:

ParameterDescription
radiusThe radius of the Torus,default value 0.4
tubeThe pipe radius,default value 0.1
radialSegmentsNumber of torus segments, default value 32
tubularSegmentsNumber of pipeline segments,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 a torus 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';
await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Plane

PlaneGeometry class provides the function of creating a plane. Parameters overview:

ParameterDescription
widthThe width of the plane along the X axis. The default value is 1.
heightThe height of the plane along the Y axis. The default value is 1.
segmentWThe number of segments along the width of the plane. The default value is 1.
segmentHThe number of segments along the height of the plane. The default value is 1.
upThe direction of the plane. The 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';
await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Extruded Geometry

ExtrudeGeometry Creates extruded geometry from a path shape

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 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 extruded 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';

await Engine3D.init();
let scene3D: Scene3D = new Scene3D();
let cameraObj: Object3D = new Object3D();
let camera = cameraObj.addComponent(Camera3D);
camera.perspective(60, Engine3D.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
Engine3D.startRenderView(view);

Custom Geometry

We can customize the shape of the geometry by updating the vertices of the existing geometry’s vertexBuffer.

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 base plane geometry, easy to set size and segments
mr.geometry = new PlaneGeometry(100, 100, 100, 100);
mr.material = new LitMaterial()

// get current vertex position buffer
let posAttrData = mr.geometry.getAttribute(VertexAttributeName.position);
// you can reset all vertex position
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
}
// reuplaod the vertex buffer
mr.geometry.vertexBuffer.upload(VertexAttributeName.position, posAttrData);
// recompute normal buffer
mr.geometry.computeNormals();

We can even change the vertex buffer in the main loop every frame:

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() {
        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, Engine3D.aspect, 1, 2000);
        view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 150);

        Engine3D.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();

Extra Plugins

In addition to the commonly built-in geometries mentioned above, the engine also provides the @orillusion/geometry extension package.

We can quicklly import the geometries 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"

2D ExtrudeGeometry

Similar to but distinct from the built-in ExtrudeGeometry, this geometry class simplifies the data and supports generating spatial geometries from Shape2D

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

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, 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() {
        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, webGPUContext.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))

        Engine3D.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.multiplyScaler(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();

TextGeometry

Creating spatial text geometries from common font files such as woff,otf,ttf.

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

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, 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;
    async run() {
        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, webGPUContext.aspect, 1, 5000.0);
        view.camera.object3D.z = -15;
        view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 150);

        Engine3D.startRenderView(view);

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

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

            let font = await Engine3D.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();

TerrainGeometry

Quickly creating 3D terrain geometries through 2D heightmaps or displacement maps

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

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, 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;

    async run() {
        Engine3D.setting.shadow.autoUpdate = true;
        Engine3D.setting.shadow.updateFrameRate = 1;
        Engine3D.setting.shadow.shadowBound = 500;
        Engine3D.setting.shadow.shadowSize = 2048;

        await Engine3D.init();
        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, webGPUContext.aspect, 1, 50000.0);
        this.view.camera.object3D.z = -15;
        this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 10000);

        Engine3D.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 Engine3D.res.loadTexture('https://cdn.orillusion.com/terrain/test01/bitmap.png');
        let heightTexture = await Engine3D.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();

GrassGeometry

Creating a simulated grass terrain, combined with the GrassComponent, can mimic dynamic wind-swaying effects.

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

<
ts
import { Engine3D, View3D, Scene3D, CameraUtil, AtmosphericComponent, webGPUContext, 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;

    async run() {
        Engine3D.setting.shadow.autoUpdate = true;
        Engine3D.setting.shadow.updateFrameRate = 1;
        Engine3D.setting.shadow.shadowBound = 500;
        Engine3D.setting.shadow.shadowSize = 1024;

        await Engine3D.init();
        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, webGPUContext.aspect, 1, 5000.0);
        this.view.camera.object3D.addComponent(HoverCameraController).setCamera(35, -20, 500);

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

    private async createScene(scene: Scene3D) {
        //bitmap
        let bitmapTexture = await Engine3D.res.loadTexture('https://cdn.orillusion.com/terrain/test01/bitmap.png');
        let heightTexture = await Engine3D.res.loadTexture('https://cdn.orillusion.com/terrain/test01/height.png');
        // let grassTexture = await Engine3D.res.loadTexture('https://cdn.orillusion.com/terrain/grass/GrassThick.png');
        let gustNoiseTexture = await Engine3D.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 = 49;
        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(Engine3D.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