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:
Geometry
object, which determines the specific geometry of the object, includingvertex position
,topology
,UV
, etc.;Material
object, which determines the material ball style of the object, includingtexture
,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:
Parameter | Description |
---|---|
width | The width on the X axis. The default value is 1. |
height | The height on the Y axis. The default value is 1. |
depth | The depth on the Z axis. The default value is 1. |
Example:
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);
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:
Parameter | Description |
---|---|
widthSegments | The number of segments that make up the sphere along the width (longitude). |
heightSegments | The 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:
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);
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:
Parameter | Description |
---|---|
radiusTop | Top radius. The default value is 1. |
radiusBottom | Bottom radius. The default value is 1. |
height | The height of the cylinder. The default value is 1. |
radialSegments | The number of subdivisions around the circumference of the circle. The default value is 8. |
heightSegments | The number of subdivisions along the height of the cylinder. The default value is 8. |
openEnded | Whether the cylinder is open (with top and bottom). The default value is false. |
thetaStart | The starting angle of the first segment, in radians. The default value is 0. |
thetaLength | The central angle of the circular sector, in radians. The default value is Math.PI * 2. |
Example:
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);
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:
Parameter | Description |
---|---|
radius | The radius of the Torus,default value 0.4 |
tube | The pipe radius,default value 0.1 |
radialSegments | Number of torus segments, default value 32 |
tubularSegments | Number of pipeline segments,default value 32 |
Example:
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);
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:
Parameter | Description |
---|---|
width | The width of the plane along the X axis. The default value is 1. |
height | The height of the plane along the Y axis. The default value is 1. |
segmentW | The number of segments along the width of the plane. The default value is 1. |
segmentH | The number of segments along the height of the plane. The default value is 1. |
up | The direction of the plane. The default value is Vector3.Y_AXIS. |
Example:
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);
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:
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);
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:
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:
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:
npm install @orillusion/core --save
npm install @orillusion/geometry --save
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
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
.
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
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.
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();