Skip to content

网格

mesh 描述了模型的几何信息(geometry)和材质信息(material)。如果你想用一个 Object3D 对象展示一个3D的模型,那么它必须添加 MeshRenderer 组件,它主要包含两个属性:

  1. geometry 对象,它决定了物体具体的几何形状,包括顶点位置拓扑UV等;
  2. material 对象,它决定了物体呈现的材质球样式,包括贴图颜色透明度等属性。

Orillusion 内置了几种常见的几何体,可以很方便的创建不同的 mesh类型:

长方体

BoxGeometry 类提供长方体创建功能。 参数概览:

参数描述
widthX轴上面的宽度,默认值为1。
heighty轴上面的高度,默认值为1。
depthZ轴上面的深度,默认值为1。

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置组件 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)

球体

SphereGeometry 类提供球体创建功能。 参数概览:

参数描述
widthSegments球体水平分段数(沿着经线分段)
heightSegments球体垂直分段数(沿着纬线分段)
phiStart(可选)指定水平(经线)起始角度
phiLength(可选)指定水平(经线)扫描角度的大小球体赤道线的弧长
thetaStart(可选)指定垂直(纬线)起始角度
thetaLength(可选)指定垂直(纬线)扫描角度大小

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置组件 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)

圆柱体

CylinderGeometry 类提供圆柱体创建功能。

参数概览:

参数描述
radiusTop顶部半径,默认值为1
radiusBottom底部半径,默认值为1
height桶高度,默认值为1
radialSegments圆面细分数量,默认值为8
heightSegments桶壁细分数量,默认值为8
openEnded是否开放的桶(有上下底),默认值为false
thetaStart第一个分段的起始角度,默认值为0
thetaLength圆形扇区的中心角,默认值为Math.PI * 2

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置组件 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)

圆环

TorusGeometry 类提供圆柱体创建功能。

参数概览:

参数描述
radius圆环半径,默认值0.4
tube管道半径,默认值0.1
radialSegments圆环细分数量,默认值32
tubularSegments管道细分数量,默认值32

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置组件 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)

平面

PlaneGeometry 类提供平面创建功能。

参数概览:

参数描述
width平面沿着X轴的宽度。默认值是1。
height平面沿着Y轴的高度。默认值是1。
segmentW平面的宽度分段数,默认值是1。
segmentH平面的高度分段数,默认值是1。
up平面朝向,默认值是Vector3.Y_AXIS。

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置组件 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)

挤压缓冲几何体

ExtrudeGeometry 类提供从一个形状路径中挤压出一个几何体的功能。

使用示例:

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

let conduitObject3D = new Object3D();
// 添加 MeshRenderer 组件
let mr = conduitObject3D.addComponent(MeshRenderer);
// 创建自定义形状
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);
}
// 创建自定义路径
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);
}
// 创建 Extrude Geometry
mr.geometry = new ExtrudeGeometry().build(shape, true, curve, 0.2);

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

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

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)

自定义几何体

我们可以通过更新现有的几何体的顶点 vertexBuffer 来自定义几何体的形状

使用示例:

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

let obj = new Object3D();
// 添加 MeshRenderer 组件
let mr = obj.addComponent(MeshRenderer);
// 设置一个平面作为基础, 定义大小和分段数量
mr.geometry = new PlaneGeometry(100, 100, 100, 100);
mr.material = new LitMaterial()

// 获得现有顶点信息
let posAttrData = mr.geometry.getAttribute(VertexAttributeName.position);
// 重写所有顶点 xyz 坐标
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
}
// 更新顶点信息
mr.geometry.vertexBuffer.upload(VertexAttributeName.position, posAttrData);
// 重新计算法向量
mr.geometry.computeNormals();

我们甚至可以在主循环中每帧更改顶点信息

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()