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

Commit

Permalink
Add support for texture manipulation on material assets (#164)
Browse files Browse the repository at this point in the history
* Add texture APIs

* Update material with correct patching props

* Fix patching ambiguity

* Move ZeroGuid definition

* Add material color setter
  • Loading branch information
stevenvergenz authored Feb 4, 2019
1 parent 11bd895 commit 3925f7a
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 63 deletions.
33 changes: 26 additions & 7 deletions packages/functional-tests/src/tests/asset-preload-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,24 @@ export default class AssetPreloadTest extends Test {
await delay(1000);

label.text.contents = 'Preloading assets';
const [prefabs, mats] = await Promise.all([
const [monkey, uvgrid] = await Promise.all([
this.app.context.assetManager.loadGltf('monkey', this.baseUrl + '/monkey.glb'),
this.app.context.assetManager.loadGltf('uvgrid', this.generateMaterial())
]);
label.text.contents = `Assets preloaded:
${prefabs.prefabs.count + mats.prefabs.count} prefabs, ${prefabs.materials.count + mats.materials.count} materials`;
label.text.contents = "Assets preloaded:" +
`${monkey.prefabs.count + uvgrid.prefabs.count} prefabs, ` +
`${monkey.materials.count + uvgrid.materials.count} materials, ` +
`${monkey.textures.count + uvgrid.textures.count} textures`;
await delay(1000);

const monkeyPrefab = monkey.prefabs.byIndex(0);
const monkeyMat = monkey.materials.byIndex(0);
const uvgridMat = uvgrid.materials.byIndex(0);
const uvgridTex = uvgrid.textures.byIndex(0);

label.text.contents = 'Instantiating prefabs';
const head = await MRESDK.Actor.CreateFromPrefab(this.app.context, {
prefabId: prefabs.prefabs.byIndex(0).id,
prefabId: monkeyPrefab.id,
actor: {
transform: {
position: { x: -1, y: 1, z: 0 }
Expand All @@ -60,7 +67,7 @@ ${prefabs.prefabs.count + mats.prefabs.count} prefabs, ${prefabs.materials.count
radius: 1
},
actor: {
materialId: mats.materials.byIndex(0).id,
materialId: uvgridMat.id,
transform: {
position: { x: 1, y: 1, z: 0 }
}
Expand All @@ -75,12 +82,24 @@ ${prefabs.prefabs.count + mats.prefabs.count} prefabs, ${prefabs.materials.count
actor.children.forEach(c => assignMat(c, mat));
}

assignMat(head, mats.materials.byIndex(0));
assignMat(sphere, prefabs.materials.byIndex(0));
assignMat(head, uvgridMat);
assignMat(sphere, monkeyMat);
label.text.contents = 'Materials swapped';

await delay(3000);

monkeyMat.mainTexture = uvgridTex;
uvgridMat.mainTexture = null;
label.text.contents = 'Textures swapped';

await delay(3000);

monkeyMat.mainTexture = null;
uvgridMat.mainTexture = null;
label.text.contents = 'Textures cleared';

await delay(3000);

assignMat(head, null);
assignMat(sphere, null);
label.text.contents = 'Materials cleared';
Expand Down
69 changes: 40 additions & 29 deletions packages/functional-tests/src/tests/mutable-asset-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
* Licensed under the MIT License.
*/

import * as GltfGen from '@microsoft/gltf-gen';
import * as MRESDK from '@microsoft/mixed-reality-extension-sdk';
import App from '../app';
import Server from '../server';
import delay from '../utils/delay';
import destroyActors from '../utils/destroyActors';
import Test from './test';
Expand All @@ -18,46 +20,55 @@ export default class MutableAssetTest extends Test {
public async run(): Promise<boolean> {

const assets = await this.app.context.assetManager.loadGltf(
'assets', `${this.baseUrl}/monkey.glb`);
'assets', this.generateMaterial()
);

const monkey = MRESDK.Actor.CreateFromPrefab(this.app.context, {
prefabId: assets.prefabs.byIndex(0).id,
const mat = assets.materials.byIndex(0);
const box = await MRESDK.Actor.CreatePrimitive(this.app.context, {
definition: {
shape: MRESDK.PrimitiveShape.Box,
dimensions: {x: 1, y: 1, z: 1}
},
actor: {
name: 'monkey',
name: 'box',
materialId: mat.id,
transform: {
position: { x: 0, y: 1, z: 0 }
}
}
}).value;
});

const label = MRESDK.Actor.CreateEmpty(this.app.context, {
actor: {
name: 'label',
transform: {
position: { x: 0, y: 2, z: 0 }
},
text: {
contents: 'Original (pink)'
}
}
}).value;
label.lookAt(this.user, MRESDK.LookAtMode.TargetY);

await delay(3000);
for (let i = 0; i < 64; i++) {
mat.color.copyFrom( this.fromHSV(i / 32, 1, 1) );
mat.mainTextureOffset.set(i / 32, i / 32);
mat.mainTextureScale.set(1 - i / 32, 1 - i / 32);

const material = assets.materials.byIndex(0);
const origColor = material.color.clone();
material.color.set(0, 1, 0, 1);
label.text.contents = 'Green';
await delay(100);
}

await delay(3000);
destroyActors([box]);
return true;
}

material.color.copyFrom(origColor);
label.text.contents = 'Back to original';
private generateMaterial(): string {
const material = new GltfGen.Material({
metallicFactor: 0,
baseColorTexture: new GltfGen.Texture({
source: new GltfGen.Image({
uri: `${this.baseUrl}/uv-grid.png` // alternate form (don't embed)
})
})
});
const gltfFactory = new GltfGen.GltfFactory(null, null, [material]);

await delay(3000);
return Server.registerStaticBuffer('assets.glb', gltfFactory.generateGLTF());
}

destroyActors([monkey, label]);
return true;
private fromHSV(h: number, s: number, v: number): MRESDK.Color4 {
// from wikipedia: https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
function f(n: number, k = (n + h * 6) % 6) {
return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
}
return new MRESDK.Color4(f(5), f(3), f(1), 1);
}
}
6 changes: 3 additions & 3 deletions packages/gltf-gen/src/geometry/sphere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under the MIT License.
*/

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

/**
Expand All @@ -17,8 +17,8 @@ export class Sphere extends MeshPrimitive {
* @param longLines The number of polar vertex rings
* @param latLines The number of equatorial vertex rings (not counting poles)
*/
public constructor(radius: number, longLines = 12, latLines = 8) {
super();
public constructor(radius: number, longLines = 12, latLines = 8, material: Material = null) {
super({material});

// generate north pole
const north = new Vertex({
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

// tslint:disable:variable-name

export const ZeroGuid = '00000000-0000-0000-0000-000000000000';

/** @hidden */
export const HTTPHeaders = {
SessionID: 'x-ms-mixed-reality-extension-sessionid',
Expand Down
20 changes: 18 additions & 2 deletions packages/sdk/src/math/vector2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ import { Epsilon, Matrix, Scalar, Vector3 } from '.';

// tslint:disable:member-ordering variable-name one-variable-per-declaration trailing-comma no-bitwise curly max-line-length

export interface Vector2Like {
x: number;
y: number;
}

/**
* Class representing a vector containing 2 coordinates
*/
export class Vector2 {
export class Vector2 implements Vector2Like {

// Statics

Expand Down Expand Up @@ -300,7 +305,7 @@ export class Vector2 {
return {
x: this.x,
y: this.y,
};
} as Vector2Like;
}

/**
Expand Down Expand Up @@ -656,4 +661,15 @@ export class Vector2 {
public clone(): Vector2 {
return new Vector2(this.x, this.y);
}

/**
* Updates the Vector2 from the sparsely populated value.
* @param from The sparsely populated value to read from.
*/
public copy(from: Partial<Vector2Like>): this {
if (!from) { return this; }
if (from.x !== undefined) { this.x = from.x; }
if (from.y !== undefined) { this.y = from.y; }
return this;
}
}
15 changes: 9 additions & 6 deletions packages/sdk/src/types/runtime/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
PrimitiveDefinition,
SetAnimationStateOptions
} from '../..';
import { ZeroGuid } from '../../constants';
import { log } from '../../log';
import observe from '../../utils/observe';
import readPath from '../../utils/readPath';
Expand Down Expand Up @@ -82,10 +83,10 @@ export class Actor implements ActorLike, Patchable<ActorLike> {
private _rigidBody?: RigidBody;
private _collider?: Collider;
private _text?: Text;
private _materialId?: string;
private _materialId = ZeroGuid;
// tslint:enable:variable-name

/**
/*
* PUBLIC ACCESSORS
*/

Expand Down Expand Up @@ -113,17 +114,19 @@ export class Actor implements ActorLike, Patchable<ActorLike> {
this._parentId = value;
this.actorChanged('parentId');
}

/** @returns A shared reference to this actor's material, or null if this actor has no material */
public get material() { return this._context.assetManager.assets[this._materialId] as Material; }
public set material(value) {
this.materialId = value && value.id || null;
this.materialId = value && value.id || ZeroGuid;
}
public get materialId() { return this._materialId; }
public set materialId(value) {
if (value && value.startsWith('0000')) {
value = null;
if (!value || value.startsWith('0000')) {
value = ZeroGuid;
}
if (!this.context.assetManager.assets[value]) {
value = null; // throw?
value = ZeroGuid; // throw?
}
this._materialId = value;
this.actorChanged('materialId');
Expand Down
Loading

0 comments on commit 3925f7a

Please sign in to comment.