图形绘制
Orillusion
提供了 @orillusion/graphic 扩展包,主要用于对具有实时变化的点、线、面、体的绘制,使用特定的方法创建出一个动态网格,统一管理并参与到引擎渲染管线中去,性能高效、使用方便。
目前提供三个模块来创建高性能图形数据:
Graphic3D
: 提供基础的线条制能力,常用于绘制辅助线等。Graphic3DMesh
渲染器:在同一个渲染器中批量创建出一组Mesh
克隆体,可以自由定义调整每个克隆体的Transform
、Texture
以及Material
,组合出高自由度的图形和动画。Shape3D
渲染器: 创建复杂的自定义Shape3D
对象,例如EllipseShape3D
、RoundRectShape3D
、CircleShape3D
等。对于拥有可持续绘制功能的Shape3D
,比如Path2DShape3D
、Path3DShape3D
,参照了 CanvasPath 中的API设计来实现,让开发者能借鉴和沿用自己熟悉的开发方式进行图形绘制工作。
安装
跟引擎方法一致,我们可以通过 NPM
和 CDN
链接两种方式来引入图形插件:
1. 通过 NPM
包安装
npm install @orillusion/core --save
npm install @orillusion/graphic --save
import { Engine3D } from "@orillusion/core"
import { Graphic3D, Shape3D } from "@orillusion/graphic"
2. 通过 CDN
链接引入
推荐使用 ESModule
构建版本
<script type="module">
import { Engine3D } from "https://unpkg.com/@orillusion/core/dist/orillusion.es.js"
import { Graphic3D, Shape3D } from "https://unpkg.com/@orillusion/graphic/dist/graphic.es.js"
</script>
或通过 <script>
加载构建 UMD
版本,在全局 Orillusion
变量中获取 Shape3D
模块:
<script src="https://unpkg.com/@orillusion/core/orillusion.umd.js"></script>
<script src="https://unpkg.com/@orillusion/stats/dist/graphic.umd.js"></script>
<script>
const { Engine3D, Graphic3D, Shape3D } = Orillusion
</script>
Graphic3D
通过创建一个 Graphic3D
对象统一绘制场景中的图形,目前提供 drawLines
,drawBox
,drawCircle
三种 API
快捷创建不同的线段组合。
基本方法
import {Graphic3D} from '@orillusion/graphic'
// ...
// 创建一个 Graphic3D 对象
let graphic3D = new Graphic3D();
// 添加到场景中
scene.addChild(graphic3D);
// 使用 graphic3D 统一绘制线段
// line - (uid, [start1, end1, start2, end2, ...], color)
graphic3D.drawLines('line', [new Vector3(0, 0, 0), new Vector3(0, 10, 0)], new Color(1, 0, 0));
// box - (uid, center, size, color)
graphic3D.drawBox('box', new Vector3(-5, -5, -5), new Vector3(5, 5, 5), new Color(0, 1, 0));
// circle - (uid, center, radius, segments, up, color)
graphic3D.drawCircle('circle', new Vector3(-15, -5, -5), 5, 15, Vector3.X_AXIS, new Color(0, 0, 1));
import { Object3D, Scene3D, Engine3D, Vector3, Color, AnimationCurve, Keyframe, View3D, AtmosphericComponent, CameraUtil, HoverCameraController, DirectLight, KelvinUtil, MeshRenderer, BoxGeometry, LitMaterial } from '@orillusion/core';
import { Graphic3D, Graphic3DLineRenderer } from '@orillusion/graphic';
import { Stats } from '@orillusion/stats';
import * as dat from 'dat.gui';
class GraphicLine {
scene: Scene3D;
view: View3D;
graphic3D: Graphic3D;
async run() {
await Engine3D.init();
// init Scene3D
this.scene = new Scene3D();
this.scene.exposure = 1;
this.scene.addComponent(Stats);
// init sky
let atmosphericSky: AtmosphericComponent;
atmosphericSky = this.scene.addComponent(AtmosphericComponent);
atmosphericSky.exposure = 1.0;
// init Camera3D
let camera = CameraUtil.createCamera3DObject(this.scene);
camera.perspective(60, Engine3D.aspect, 1, 5000);
// init Camera Controller
let hoverCtrl = camera.object3D.addComponent(HoverCameraController);
hoverCtrl.setCamera(-30, -15, 100);
// init View3D
let view = new View3D();
view.scene = this.scene;
view.camera = camera;
// add a Graphic3D
this.graphic3D = new Graphic3D();
this.scene.addChild(this.graphic3D);
// create direction light
let lightObj3D = new Object3D();
lightObj3D.x = 0;
lightObj3D.y = 30;
lightObj3D.z = -40;
lightObj3D.rotationX = 20;
lightObj3D.rotationY = 160;
lightObj3D.rotationZ = 0;
let light = lightObj3D.addComponent(DirectLight);
light.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
light.intensity = 30;
this.scene.addChild(light.object3D);
// relative light to sky
atmosphericSky.relativeTransform = light.transform;
Engine3D.startRenderView(view);
this.view = view;
await this.initScene();
}
async initScene() {
this.graphic3D.drawLines('line1', [Vector3.ZERO, new Vector3(0, 10, 0)], new Color().hexToRGB(Color.RED));
let animCurve = new AnimationCurve();
animCurve.addKeyFrame(new Keyframe(0, 0.5));
animCurve.addKeyFrame(new Keyframe(0.15, -0.2));
animCurve.addKeyFrame(new Keyframe(0.22, 0.4));
animCurve.addKeyFrame(new Keyframe(0.34, 0.2));
animCurve.addKeyFrame(new Keyframe(0.65, -0.2));
animCurve.addKeyFrame(new Keyframe(1, 0.9));
let lines: Vector3[] = [];
for (let i = 0; i < 100; i++) {
let y = animCurve.getValue(i / (100 - 1)) * 10;
lines.push(new Vector3(i, y, 0));
}
this.graphic3D.drawLines('line2', lines, new Color().hexToRGB(Color.RED));
this.graphic3D.drawBox('box1', new Vector3(-5, -5, -5), new Vector3(5, 5, 5), new Color().hexToRGB(Color.GREEN));
this.graphic3D.drawCircle('Circle1', new Vector3(-15, -5, -5), 5, 15, Vector3.X_AXIS, new Color().hexToRGB(Color.GREEN));
this.graphic3D.drawCircle('Circle2', new Vector3(-15, -5, -5), 5, 15, Vector3.Y_AXIS, new Color().hexToRGB(Color.GREEN));
this.graphic3D.drawCircle('Circle3', new Vector3(-15, -5, -5), 5, 15, Vector3.Z_AXIS, new Color().hexToRGB(Color.GREEN));
{
let obj = new Object3D();
let mr = obj.addComponent(MeshRenderer);
mr.geometry = new BoxGeometry(5, 5, 5);
mr.material = new LitMaterial();
this.scene.addChild(obj);
}
let gui = new dat.GUI();
let btn = {'depthTest': true}
gui.add(btn, 'depthTest').onChange(v=>{
this.graphic3D.getComponents(Graphic3DLineRenderer).forEach(mr=>{
mr.materials[0].depthCompare = v ? 'less' : 'always'
})
})
}
}
new GraphicLine().run();
Graphic3DMesh
渲染器
通过 Graphic3DMesh.draw()
快速创建一个 Graphic3DMeshRenderer
实例,该对象可视为多个克隆 Geometry
的集合体,对于这个集合体中每一个对象都可以设置位置和贴图,通过组合达到想要的视觉效果。
参数概览
参数 | 描述 |
---|---|
scene | 在指定Scene3D中创建 |
geo | 指定网格数据源 |
texture | 贴图列表(使用下标进行索引) |
count | 指定一个渲染器能够支持的克隆集合体的最大数量(选择合适的数值将会提高性能) |
TIP
geo
一般输入一个简单的 PlaneGeometry
作为模型源即可,通过不同的贴图来表现不同的外观。理论上你可以传入的任何模型源来创作。例如传入一个 BoxGeometry
类型的模型,即可获得由许多方块组合成的图形,创建像素风格的场景,或者模拟体素的渲染。
修改
Transform
: 对特定下标的(index)单元修改其旋转、缩放、位置。
取得Graphic3DMeshRenderer
所属的object3Ds
,使用数组的下标(index)获得对应的Object3D
,对Object3D
的Transform
修改即可同步至目标单元。修改
Texture
: 调用函数setTextureID
,指定修改特定下标(index)单元对应的贴图下标(textureIndex),贴图从Graphic3DMeshRenderer
初始化参数的texture中获取。修改
Material
: 在Graphic3DMeshRenderer
类中开放有一些列命名为类似setTextureID
这样的API。第一个参数为指定设置的目标单元,第二个接口为设置的相关参数。开发者可以通过这样的API,修改修改图形的内容。例如Color、UV、Emissive等数据。
使用示例
import { Object3D, Scene3D, Engine3D, BitmapTexture2DArray, BitmapTexture2D, PlaneGeometry, Vector3, Matrix4, Time, BlendMode, Color, ColorUtil } from "@orillusion/core";
import { Graphic3D, Graphic3DMesh, Graphic3DMeshRenderer } from '@orillusion/graphic';
// 加载贴图列表
let textureArray = [];
textureArray.push(await Engine3D.res.loadTexture("path/to/texture.png") as BitmapTexture2D);
let bitmapTexture2DArray = new BitmapTexture2DArray(textureArray[0].width, textureArray[0].height, textureArray.length);
bitmapTexture2DArray.setTextures(textureArray);
// 使用Plane作为网格克隆数据源
let geometry = new PlaneGeometry(1, 1, 1, 1, Vector3.Z_AXIS);
// 在当前场景中,使用 plane 作为克隆数据源,创建一个 Graphic3DMeshRenderer 实例,该实例最大支持 100 个克隆对象。
let mr:Graphic3DMeshRenderer = Graphic3DMesh.draw(scene, geometry, bitmapTexture2DArray, 100);
// 修改材质球属性
mr.material.blendMode = BlendMode.ADD;
mr.material.transparent = true;
mr.material.depthWriteEnabled = false;
mr.material.useBillboard = true;
// 拿到每个克隆体单元所对应的Object3D对象,修改该 Object3D 的 Transform 属性,即可同步修改目标克隆体 Transform。
// 同样的操作,放在引擎的主update函数里,则可每帧修改以驱动动画效果。
let parts = mr.object3Ds;
for (let i = 0; i < 100; i++) {
const element = parts[i];
// set texture index from textureArray
mr.setTextureID(i, 0);
// update transform
element.transform.x = 1;
element.transform.scaleX = 1;
element.transform.rotationX = 0;
// ...
}
import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, UnLitTexArrayMaterial, BitmapTexture2DArray, BitmapTexture2D, PlaneGeometry, Vector3, Matrix4, Time, BlendMode, Color } from '@orillusion/core';
import { Stats } from '@orillusion/stats';
import { Graphic3DMesh, Graphic3DMeshRenderer } from '@orillusion/graphic';
class Sample_GraphicMesh {
private scene: Scene3D;
private parts: Object3D[];
private width: number;
private height: number;
private cafe: number = 47;
private view: View3D;
graphicMeshRenderer: Graphic3DMeshRenderer;
constructor() {}
async run() {
Matrix4.maxCount = 500000;
Matrix4.allocCount = 500000;
await Engine3D.init({beforeRender: ()=> this.update()});
Engine3D.setting.render.debug = true;
Engine3D.setting.shadow.shadowBound = 5;
this.scene = new Scene3D();
this.scene.addComponent(Stats);
let sky = this.scene.addComponent(AtmosphericComponent);
sky.enable = false;
let camera = CameraUtil.createCamera3DObject(this.scene);
camera.perspective(60, Engine3D.aspect, 1, 5000.0);
camera.object3D.addComponent(HoverCameraController).setCamera(30, 0, 120);
this.view = new View3D();
this.view.scene = this.scene;
this.view.camera = camera;
Engine3D.startRenderView(this.view);
await this.initScene();
}
async initScene() {
let texts:any[] = [];
texts.push((await Engine3D.res.loadTexture('https://cdn.orillusion.com/textures/128/star_0008.png')) as BitmapTexture2D);
let bitmapTexture2DArray = new BitmapTexture2DArray(texts[0].width, texts[0].height, texts.length);
bitmapTexture2DArray.setTextures(texts);
let mat = new UnLitTexArrayMaterial();
mat.baseMap = bitmapTexture2DArray;
mat.name = 'LitMaterial';
{
this.width = 15;
this.height = 15;
let geometry = new PlaneGeometry(1, 1, 1, 1, Vector3.Z_AXIS);
this.graphicMeshRenderer = Graphic3DMesh.draw(this.scene, geometry, bitmapTexture2DArray, this.width * this.height);
this.parts = this.graphicMeshRenderer.object3Ds;
this.graphicMeshRenderer.material.blendMode = BlendMode.ADD;
this.graphicMeshRenderer.material.transparent = true;
this.graphicMeshRenderer.material.depthWriteEnabled = false;
this.graphicMeshRenderer.material.useBillboard = true;
for (let i = 0; i < this.width * this.height; i++) {
const element = this.parts[i];
this.graphicMeshRenderer.setTextureID(i, 0);
element.transform.scaleX = 5.5;
element.transform.scaleY = 5.5;
element.transform.scaleZ = 5.5;
}
}
}
update(){
if (this.parts) {
let len = this.parts.length;
for (let i = 0; i < len; i++) {
const element = this.parts[i];
let tmp = this.sphericalFibonacci(i, len);
tmp.scaleBy(Math.sin(i + Time.frame * 0.01) * this.cafe);
element.transform.localPosition = tmp;
}
}
}
public madfrac(A: number, B: number): number {
return A * B - Math.floor(A * B);
}
public sphericalFibonacci(i: number, n: number): Vector3 {
const PHI = Math.sqrt(5.0) * 0.5 + 0.5;
let phi = 2.0 * Math.PI * this.madfrac(i, PHI - 1);
let cosTheta = 1.0 - (2.0 * i + 1.0) * (1.0 / n);
let sinTheta = Math.sqrt(Math.max(Math.min(1.0 - cosTheta * cosTheta, 1.0), 0.0));
return new Vector3(Math.cos(phi) * sinTheta, Math.sin(phi) * sinTheta, cosTheta);
}
}
new Sample_GraphicMesh().run();
更多
Graphic3D
API 用法请参考 GraphicMesh 示例代码。
Shape3D
渲染器
通过 Shape3DMaker
创建一个 Shape3DRenderer
渲染器,它可以持有和维护一个 Shape3D
数据集。每个Shape3D是被定义好的各种各样的形状,例如 EllipseShape3D
、RoundRectShape3D
、CircleShape3D
等等。其中 Path2DShape3D
和 Path3DShape3D
拥有更加丰富的API,可以帮你组合绘制出复杂的图形。
参数 | 描述 |
---|---|
name | 名称,用于标识Shape3DRenderer |
scene | 指定 Shape3DRenderer 放入到哪个 scene 中 |
textureList | 贴图列表,使用 index 进行索引 |
maxNodeCount | 指定渲染器支持最多 Shape3D 的数量 |
triangleEachNode | 指定每个 Shape3D 平均拥有的三角形的数量 |
渲染器参照
CanvasPath
中的API设计来实现,让开发者能沿用和借鉴自己熟悉的开发方式进行3D绘制工作。渲染器的 2D 绘制部分指的是在XZ
平面中绘制点、线、面。同时对每个单元仍然可以通过Transform
独立控制。而在 3D 空间中绘制图形,则需使用Path3DShape3D
即可开始具有Y轴高程数据的图形绘制。
基础属性
引擎内置了很多基础图形,都继承于 Shape3D
类,主要包含以下属性:
属性名称 | 描述 |
---|---|
lineColor | 绘制线条时加成的颜色 |
fillColor | 绘制填充区域时加成的颜色 |
lineTextureID | 设定绘制线条时采用的贴图 |
fillTextureID | 设定绘制填充区域时采用的贴图 |
fillRotation | 设置填充区域,使用贴图的旋转角度 |
shapeOrder | 设置每个Shape的层级(消除zFighting,每个 Shape3DRenderer 可以设定 zFighting 最大范围,根据这个范围和Shape3D的数量,得到每个Shape3D拥有的偏移量) |
points3D | 预留外部传入关键点的集合 |
isClosed | 图形首尾首尾封闭 |
fill | 图形是否填充 |
lineWidth | 绘制线条的宽度 |
lineUVRect | UV数据:xy分别对应线条贴图的offset、zw对应贴图数据的缩放 |
fillUVRect | UV数据:xy分别对应填充区域贴图的offset、zw对应贴图数据的缩放 |
uvSpeed | UV数据:xy分别填充区域贴图的uv移动速度;zw对应线条绘制时贴图数据的uv移动速度 |
内置图形
和 CanvasPath
的 API 类似,引擎目前提供一下几种 Shape3D
的子类/派生类:
图形名称 | 描述 |
---|---|
CircleShape3D | 圆形、圆弧 |
CurveShape3D | 拥有2个锚点控制的贝塞尔曲线 |
EllipseShape3D | 椭圆 |
LineShape3D | 折线 |
Path2DShape3D | 在xz平面绘制线条路径 |
Path3DShape3D | 在3D空间内绘制线条路径 |
QuadraticCurveShape3D | 拥有1个锚点控制的贝塞尔曲线 |
RoundRectShape3D | 矩形、圆角矩形 |
内置方法
通过 Shape3DMaker
的实例,我们可以调用以下几种方法获得对应的特定图形:
函数名称 | 图形类型 |
---|---|
ellipse | EllipseShape3D |
arc | CircleShape3D |
line | LineShape3D |
quadraticCurve | QuadraticCurveShape3D |
curve | CurveShape3D |
path2D | Path2DShape3D |
path3D | Path3DShape3D |
rect | RoundRectShape3D |
roundRect | RoundRectShape3D |
TIP
所有 2D 图形,例如 path2D
将会忽略 Y
轴数据,图形将被展开在 XZ
平面
除此之外,我们还可以通过 Shape3DRenderer
对 Shape3D
进行增删改操作:
函数名称 | 描述 |
---|---|
createShape | 指定Shape3D的类型,在渲染器中创建Shape3D实例 |
removeShape | 删除一个Shape3D实例 |
getShapeObject3D | 通过Shape3D的实例的shapeIndex属性,获得对应的Object3D。供后续修改Transform使用 |
使用示例
import { Object3D, Scene3D, Engine3D, BitmapTexture2DArray, BitmapTexture2D, PlaneGeometry, Vector3, Matrix4, Time, BlendMode, Color,ColorUtil } from "@orillusion/core";
import { CircleShape3D, EllipseShape3D, Shape3DMaker, Shape3D } from "@orillusion/graphic";
// 加载贴图列表
let textureArray = [];
textureArray.push(await Engine3D.res.loadTexture("path/to/texture.png") as BitmapTexture2D);
let bitmapTexture2DArray = new BitmapTexture2DArray(textureArray[0].width, textureArray[0].height, textureArray.length);
bitmapTexture2DArray.setTextures(textureArray);
//在当前场景中,创建一个Shape3DRenderer实例
maker = Shape3DMaker.makeRenderer(`path`, bitmapTexture2DArray, scene);
maker.renderer.material.doubleSide = true;
//创建一个基于XZ平面的Circle,其半径为5、圆心为(0, 0)
let circle:CircleShape3D = maker.arc(5, 0, 0);
circle.lineWidth = 1; //线条宽度为1
circle.segment = 16; //该圆弧将会使用16条线段拟合
circle.fill = true; //设置是否填充
circle.line = true; //设置是否画线描边
circle.uvSpeed = new Vector4(0, 0, 0, Math.random() - 0.5).multiplyScalar(0.005); //设置UV滚动速度
circle.fillColor = Color.randomRGB(); //设置填充色加成
circle.lineColor = Color.randomRGB(); //设置线条描边色加成
circle.startAngle = 30; //设置圆弧起始角度
circle.endAngle = 240; //设置圆弧结束角度
// 将对circle的控制脚本放在引擎的主循环中,则可驱动动画效果
上述代码展示绘制一个独立圆形/圆弧,采用创建
CircleShape3D
的实例的方法。你也可以通过创建通用Path2DShape3D
实例,然后调用其arc()
函数获得。
import { Object3D, Scene3D, Engine3D, AtmosphericComponent, CameraUtil, HoverCameraController, View3D, DirectLight, KelvinUtil, BitmapTexture2DArray, BitmapTexture2D, Matrix4, Color, LineJoin, Vector4, Object3DUtil, AxisObject } from '@orillusion/core';
import { Stats } from '@orillusion/stats';
import { Shape3DMaker, Shape3D, CircleArcType, CircleShape3D } from '@orillusion/graphic';
import * as dat from 'dat.gui';
/**
* This example shows how to use Shape2D to draw various different paths on xz plane.
*
* @export
* @class Sample_Shape3DPath2D
*/
class Sample_Shape3DPath2D {
lightObj3D: Object3D;
scene: Scene3D;
view: View3D;
async run() {
Matrix4.maxCount = 10000;
Matrix4.allocCount = 10000;
await Engine3D.init({ beforeRender: () => this.update() });
Engine3D.setting.render.debug = true;
Engine3D.setting.shadow.shadowBound = 5;
this.scene = new Scene3D();
this.scene.addComponent(Stats);
let sky = this.scene.addComponent(AtmosphericComponent);
let camera = CameraUtil.createCamera3DObject(this.scene);
camera.perspective(60, Engine3D.aspect, 1, 5000.0);
camera.object3D.addComponent(HoverCameraController).setCamera(0, -60, 60);
this.view = new View3D();
this.view.scene = this.scene;
this.view.camera = camera;
Engine3D.startRenderView(this.view);
await this.initScene();
this.scene.addChild(new AxisObject(10, 0.1));
sky.relativeTransform = this.lightObj3D.transform;
}
async initScene() {
{
/******** light *******/
this.lightObj3D = new Object3D();
this.lightObj3D.rotationX = 21;
this.lightObj3D.rotationY = 108;
this.lightObj3D.rotationZ = 10;
let directLight = this.lightObj3D.addComponent(DirectLight);
directLight.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
directLight.castShadow = false;
directLight.intensity = 20;
this.scene.addChild(this.lightObj3D);
await this.addNode();
}
{
let floor = Object3DUtil.GetSingleCube(100, 0.1, 100, 0.2, 0.2, 0.2);
floor.y = -0.2;
this.scene.addChild(floor);
}
}
private maker: Shape3DMaker;
private async addNode() {
let textureArray:any[] = [];
textureArray.push((await Engine3D.res.loadTexture('https://cdn.orillusion.com/textures/128/vein_0013.png')) as BitmapTexture2D);
textureArray.push((await Engine3D.res.loadTexture('https://cdn.orillusion.com/textures/128/vein_0014.png')) as BitmapTexture2D);
let bitmapTexture2DArray = new BitmapTexture2DArray(textureArray[0].width, textureArray[0].height, textureArray.length);
bitmapTexture2DArray.setTextures(textureArray);
this.maker = Shape3DMaker.makeRenderer(`path`, bitmapTexture2DArray, this.scene);
this.maker.renderer.material.doubleSide = true;
this.createPath();
}
private createPath(): Shape3D {
let circle = this.maker.arc(20, 0, 360, undefined);
circle.lineWidth = 2;
circle.segment = 40;
circle.fill = true;
circle.line = true;
circle.isClosed = false;
circle.lineUVRect.z = 0.5;
circle.lineUVRect.w = 0.5;
circle.fillUVRect.z = 0.1;
circle.fillUVRect.w = 0.1;
circle.fillTextureID = 0;
circle.lineTextureID = 1;
circle.lineColor = Color.random();
circle.uvSpeed = new Vector4(0, 0, 0, Math.random() - 0.5).multiplyScalar(0.005);
const GUIHelp = new dat.GUI();
this.renderCircle(GUIHelp, circle, 5, false);
return circle;
}
update() {}
renderCircle(GUIHelp: dat.GUI, shape: CircleShape3D, maxSize: number, open: boolean = true, name?: string) {
name ||= 'Circle3D_' + shape.shapeIndex;
GUIHelp.addFolder(name);
GUIHelp.add(shape, 'radius', 0, maxSize, 0.1);
GUIHelp.add(shape, 'segment', 0, 100, 1);
GUIHelp.add(shape, 'startAngle', 0, 360, 1);
GUIHelp.add(shape, 'endAngle', 0, 360, 1);
let arcType = {};
arcType['sector'] = CircleArcType.Sector;
arcType['moon'] = CircleArcType.Moon;
GUIHelp.add({ arcType: shape.arcType }, 'arcType', arcType).onChange((v) => {
shape.arcType = Number.parseInt(v);
});
this.renderCommonShape3D(GUIHelp, shape, maxSize);
}
renderCommonShape3D(GUIHelp: dat.GUI, shape: Shape3D, maxSize: number, uvMin: number = 0.01, uvMax: number = 1.0) {
GUIHelp.add(shape, 'line');
GUIHelp.add(shape, 'fill');
GUIHelp.add(shape, 'isClosed');
GUIHelp.add(shape, 'lineWidth', 0, maxSize, 0.01);
GUIHelp.add(shape, 'fillRotation', -Math.PI, Math.PI, 0.01);
this.renderVec4(GUIHelp, 'FillUVRect.', shape, 'fillUVRect', 0, 10, 0.01);
this.renderVec4(GUIHelp, 'LineUVRect.', shape, 'lineUVRect', 0, 10, 0.01);
this.renderVec4(GUIHelp, 'UVSpeed.', shape, 'uvSpeed', -0.01, 0.01, 0.0001);
GUIHelp.add(shape, 'lineTextureID', 0, 1, 1);
GUIHelp.add(shape, 'fillTextureID', 0, 1, 1);
}
renderVec4(GUIHelp: dat.GUI, label: string, target: Object, key: string, min: number, max: number, step: number = 0.01) {
let components = ['x', 'y', 'z', 'w'];
let data = {} as any;
let vec4: Vector4 = target[key];
for (let component of components) {
data[label + component] = vec4[component];
GUIHelp.add(data, label + component, min, max, step).onChange((v) => {
vec4[component] = v;
target[key] = vec4;
});
}
}
}
new Sample_Shape3DPath2D().run();
更多
Shape3D
API 用法请参考 Shape3D 示例代码。