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:
- The
geometryobject, which determines the specific geometric shape of the object, includingvertex position,topology,UV, etc.; - The
materialobject, which determines the material style presented by the object, includingtexture,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:
| Parameter | Description |
|---|---|
| width | The width along the X axis, default value is 1. |
| height | The height along the Y axis, default value is 1. |
| depth | The depth along the Z axis, 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';
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:
| Parameter | Description |
|---|---|
| widthSegments | Number of horizontal segments of the sphere (segmented along meridians) |
| heightSegments | Number 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:
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);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:
| Parameter | Description |
|---|---|
| radiusTop | Top radius, default value is 1 |
| radiusBottom | Bottom radius, default value is 1 |
| height | Barrel height, default value is 1 |
| radialSegments | Number of subdivisions of the circular face, default value is 8 |
| heightSegments | Number of subdivisions of the barrel wall, default value is 8 |
| openEnded | Whether it is an open barrel (with top and bottom faces), default value is false |
| thetaStart | The start angle of the first segment, default value is 0 |
| thetaLength | The central angle of the circular sector, 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';
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:
| Parameter | Description |
|---|---|
| radius | Torus radius, default value 0.4 |
| tube | Tube radius, default value 0.1 |
| radialSegments | Number of subdivisions of the torus, default value 32 |
| tubularSegments | Number of subdivisions of the tube, default value 32 |
Example:
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);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:
| Parameter | Description |
|---|---|
| width | The width of the plane along the X axis. Default value is 1. |
| height | The height of the plane along the Y axis. Default value is 1. |
| segmentW | The number of width segments of the plane, default value is 1. |
| segmentH | The number of height segments of the plane, default value is 1. |
| up | The orientation of the plane, 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';
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:
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);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:
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
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:
npm install @orillusion/core --save
npm install @orillusion/geometry --saveimport { Engine3D } from "@orillusion/core"
import { TextGeometry } from "@orillusion/geometry"Or the UMD version
<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.
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
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
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
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();
