Skip to content
This repository has been archived by the owner on Jun 10, 2022. It is now read-only.

Commit

Permalink
Add box and capsule primitive geometries to gltf-gen (#481)
Browse files Browse the repository at this point in the history
* Add a box gltf primitive generator

* Add capsule prim, docstrings

* Fix linting issues
  • Loading branch information
stevenvergenz authored Feb 10, 2020
1 parent a5d57b7 commit eda59af
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 11 deletions.
30 changes: 22 additions & 8 deletions packages/functional-tests/src/tests/gltf-gen-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ export default class GltfGenTest extends Test {
public async run(root: MRE.Actor): Promise<boolean> {
this.assets = new MRE.AssetContainer(this.app.context);

const spherePrim = new GltfGen.Sphere(0.5);
spherePrim.material = new GltfGen.Material({
const mat = new GltfGen.Material({
baseColorFactor: new MRE.Color4(1, 1, 1, 0.7),
baseColorTexture: new GltfGen.Texture({
source: new GltfGen.Image({
Expand All @@ -33,16 +32,31 @@ export default class GltfGenTest extends Test {
}),
alphaMode: GltfGen.AlphaMode.Blend
});

const sphere = new GltfGen.Node({
name: 'sphere',
mesh: new GltfGen.Mesh({ name: 'sphere', primitives: [new GltfGen.Sphere(0.5, 36, 18, mat)] }),
translation: new MRE.Vector3(1, 0, 0)
});

const box = new GltfGen.Node({
name: 'box',
mesh: new GltfGen.Mesh({ name: 'box', primitives: [new GltfGen.Box(0.9, 0.9, 0.9, mat)] }),
translation: new MRE.Vector3(0, 0, 0)
});

const capsule = new GltfGen.Node({
name: 'capsule',
mesh: new GltfGen.Mesh({ name: 'capsule', primitives: [new GltfGen.Capsule(0.3, 1, 36, 18, 0.35, mat)] }),
translation: new MRE.Vector3(-1, 0, 0)
});

const gltfFactory = new GltfGen.GltfFactory([new GltfGen.Scene({
nodes: [new GltfGen.Node({
mesh: new GltfGen.Mesh({
primitives: [spherePrim]
})
})]
nodes: [sphere, box, capsule]
})]);

MRE.Actor.CreateFromGltf(this.assets, {
uri: Server.registerStaticBuffer('sphere.glb', gltfFactory.generateGLTF()),
uri: Server.registerStaticBuffer('test.glb', gltfFactory.generateGLTF()),
actor: {
parentId: root.id,
transform: {
Expand Down
102 changes: 102 additions & 0 deletions packages/gltf-gen/src/geometry/box.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { Material, MeshPrimitive, Vertex } from '..';
import { Vector2, Vector3 } from '@microsoft/mixed-reality-extension-sdk';

/**
* A MeshPrimitive prepopulated with box vertices and triangles
*/
export class Box extends MeshPrimitive {
/**
* Build a box geometry
* @param width The size of the box along the X axis
* @param height The size of the box along the Y axis
* @param depth The size of the box along the Z axis
* @param material An initial material to apply to the box
*/
public constructor(width: number, height: number, depth: number, material: Material = null) {
super({material});

// make geo corners
const extent = new Vector3(width / 2, height / 2, depth / 2);
const pxpypz = extent.clone();
const pxpynz = extent.multiplyByFloats(1, 1, -1);
const pxnypz = extent.multiplyByFloats(1, -1, 1);
const pxnynz = extent.multiplyByFloats(1, -1, -1);
const nxpypz = extent.multiplyByFloats(-1, 1, 1);
const nxpynz = extent.multiplyByFloats(-1, 1, -1);
const nxnypz = extent.multiplyByFloats(-1, -1, 1);
const nxnynz = extent.multiplyByFloats(-1, -1, -1);

// make normal vectors
const right = Vector3.Right();
const left = Vector3.Left();
const up = Vector3.Up();
const down = Vector3.Down();
const forward = Vector3.Forward();
const backward = Vector3.Backward();

// make UV corners
const uvTopLeft = new Vector2(0, 0);
const uvTopRight = new Vector2(1, 0);
const uvBottomLeft = new Vector2(0, 1);
const uvBottomRight = new Vector2(1, 1);

// make right face
let io = this.vertices.length;
this.vertices.push(
new Vertex({ position: nxpynz, normal: right, texCoord0: uvTopLeft }),
new Vertex({ position: nxpypz, normal: right, texCoord0: uvTopRight }),
new Vertex({ position: nxnynz, normal: right, texCoord0: uvBottomLeft }),
new Vertex({ position: nxnypz, normal: right, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);

// make left face
io = this.vertices.length;
this.vertices.push(
new Vertex({ position: pxpypz, normal: left, texCoord0: uvTopLeft }),
new Vertex({ position: pxpynz, normal: left, texCoord0: uvTopRight }),
new Vertex({ position: pxnypz, normal: left, texCoord0: uvBottomLeft }),
new Vertex({ position: pxnynz, normal: left, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);

// make top face
io = this.vertices.length;
this.vertices.push(
new Vertex({ position: pxpypz, normal: up, texCoord0: uvTopLeft }),
new Vertex({ position: nxpypz, normal: up, texCoord0: uvTopRight }),
new Vertex({ position: pxpynz, normal: up, texCoord0: uvBottomLeft }),
new Vertex({ position: nxpynz, normal: up, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);

// make bottom face
io = this.vertices.length;
this.vertices.push(
new Vertex({ position: pxnynz, normal: down, texCoord0: uvTopLeft }),
new Vertex({ position: nxnynz, normal: down, texCoord0: uvTopRight }),
new Vertex({ position: pxnypz, normal: down, texCoord0: uvBottomLeft }),
new Vertex({ position: nxnypz, normal: down, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);

// make forward face
io = this.vertices.length;
this.vertices.push(
new Vertex({ position: nxpypz, normal: forward, texCoord0: uvTopLeft }),
new Vertex({ position: pxpypz, normal: forward, texCoord0: uvTopRight }),
new Vertex({ position: nxnypz, normal: forward, texCoord0: uvBottomLeft }),
new Vertex({ position: pxnypz, normal: forward, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);

// make backward face
io = this.vertices.length;
this.vertices.push(
new Vertex({ position: pxpynz, normal: backward, texCoord0: uvTopLeft }),
new Vertex({ position: nxpynz, normal: backward, texCoord0: uvTopRight }),
new Vertex({ position: pxnynz, normal: backward, texCoord0: uvBottomLeft }),
new Vertex({ position: nxnynz, normal: backward, texCoord0: uvBottomRight }));
this.triangles.push(io + 1, io + 0, io + 3, io + 0, io + 2, io + 3);
}
}
111 changes: 111 additions & 0 deletions packages/gltf-gen/src/geometry/capsule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*!
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/

import { Material, MeshPrimitive, Vertex } from '..';
import { Vector2, Vector3 } from '@microsoft/mixed-reality-extension-sdk';

/**
* A MeshPrimitive prepopulated with capsule vertices and triangles
*/
export class Capsule extends MeshPrimitive {
/**
* Generate a new capsule geometry, long axis aligned to local Y.
* @param radius The radius of the capsule.
* @param height The height of the capsule including end caps. Must be at least 2 * radius.
* @param longLines The number of polar vertex rings (running the length of the capsule).
* @param latLines The number of equatorial vertex rings (not counting poles) per cap.
* @param capUvFraction The amount of texture space the end caps should occupy.
* @param material An initial material to apply to the capsule.
*/
public constructor(
radius: number, height: number, longLines = 12, latLines = 8, capUvFraction = 0.2, material: Material = null
) {
super({ material });
height = Math.max(height, radius * 2);

const theta = 2 * Math.PI / longLines; // the angle between longitude lines
const phi = Math.PI / (2 * latLines); // the angle between latitude lines
const topCap = 0, botCap = 1; // vert indices for poles

// create poles
this.vertices.push(
new Vertex({
position: new Vector3(0, height / 2, 0),
normal: Vector3.Up(),
texCoord0: new Vector2(0.5, 0)
}),
new Vertex({
position: new Vector3(0, -height / 2, 0),
normal: Vector3.Down(),
texCoord0: new Vector2(0.5, 1)
}),
);

// start striping longitude lines, starting at +X
for (let s = 0; s <= longLines; s++) {
// create end caps, starting at the ring one out from the pole
for (let r = 1; r <= latLines; r++) {
const radial = radius * Math.sin(r*phi);

// create verts
this.vertices.push(
new Vertex({
position: new Vector3(
radial * Math.cos(s * theta),
height / 2 - radius * (1 - Math.cos(r * phi)),
radial * Math.sin(s * theta)),
normal: new Vector3(
Math.cos(s * theta),
1 - Math.cos(r * phi),
Math.sin(s * theta)),
texCoord0: new Vector2(1 - s / longLines, r / latLines * capUvFraction)
}),
new Vertex({
position: new Vector3(
radial * Math.cos(s * theta),
-height / 2 + radius * (1 - Math.cos(r * phi)),
radial * Math.sin(s * theta)),
normal: new Vector3(
Math.cos(s * theta),
-1 + Math.cos(r * phi),
Math.sin(s * theta)),
texCoord0: new Vector2(1 - s / longLines, 1 - (r / latLines * capUvFraction))
})
);

// find the vertex indices of the four corners of the quad completed by the latest vertex
const topS1R1 = this.vertices.length - 2, topS1R0 = this.vertices.length - 4;
const botS1R1 = this.vertices.length - 1, botS1R0 = this.vertices.length - 3;
const topS0R1 = topS1R1 - 2 * latLines, topS0R0 = topS1R0 - 2 * latLines;
const botS0R1 = botS1R1 - 2 * latLines, botS0R0 = botS1R0 - 2 * latLines;

// create faces
if(s > 0 && r === 1) {
this.triangles.push(
topCap, topS1R1, topS0R1,
botCap, botS0R1, botS1R1
);
} else if (s > 0) {
this.triangles.push(
topS1R0, topS1R1, topS0R0,
topS0R0, topS1R1, topS0R1,
botS0R1, botS1R1, botS0R0,
botS0R0, botS1R1, botS1R0
);
}
}

// create long sides
const topS1 = this.vertices.length - 2, topS0 = topS1 - 2 * latLines;
const botS1 = this.vertices.length - 1, botS0 = botS1 - 2 * latLines;
if (s > 0) {
this.triangles.push(
topS0, topS1, botS1,
botS0, topS0, botS1
);
}
}
}
}
2 changes: 2 additions & 0 deletions packages/gltf-gen/src/geometry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
*/

export * from './sphere';
export * from './box';
export * from './capsule';
1 change: 1 addition & 0 deletions packages/gltf-gen/src/geometry/sphere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class Sphere extends MeshPrimitive {
* @param radius The radius of the generated sphere
* @param longLines The number of polar vertex rings
* @param latLines The number of equatorial vertex rings (not counting poles)
* @param material An initial material to apply to the sphere
*/
public constructor(radius: number, longLines = 12, latLines = 8, material: Material = null) {
super({material});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { Client, ClientDesyncPreprocessor, MissingRule, Rules, SyncActor } from '..';
import { Guid, Message, newGuid } from '../../..';
import { Message, newGuid } from '../../..';
import { log } from '../../../log';
import * as Protocols from '../../../protocols';
import * as Payloads from '../../../types/network/payloads';
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/types/runtime/appearance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License.
*/

import { Actor, GroupMask, Mesh } from '.';
import { Actor, GroupMask } from '.';
import { Guid, ZeroGuid } from '../..';

export interface AppearanceLike {
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/types/runtime/assets/material.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License.
*/

import { Asset, AssetContainer, AssetLike, Texture } from '.';
import { Asset, AssetContainer, AssetLike } from '.';
import { Actor, Guid, ZeroGuid } from '../../..';
import { Color3, Color4, Color4Like, Vector2, Vector2Like } from '../../../math';
import { observe } from '../../../utils/observe';
Expand Down

0 comments on commit eda59af

Please sign in to comment.