@awayjs/scene
Version:
AwayJS scene classes
631 lines (508 loc) • 17.5 kB
text/typescript
import { IMaterial, ElementsType, LineElements, ElementsBase, TriangleElements } from '@awayjs/renderer';
import { PrimitivePrefabBase } from '../prefabs/PrimitivePrefabBase';
/**
* A Cube primitive prefab.
*/
export class PrimitiveCubePrefab extends PrimitivePrefabBase {
private _width: number;
private _height: number;
private _depth: number;
private _tile6: boolean;
private _segmentsW: number;
private _segmentsH: number;
private _segmentsD: number;
/**
* Creates a new Cube object.
* @param width The size of the cube along its X-axis.
* @param height The size of the cube along its Y-axis.
* @param depth The size of the cube along its Z-axis.
* @param segmentsW The number of segments that make up the cube along the X-axis.
* @param segmentsH The number of segments that make up the cube along the Y-axis.
* @param segmentsD The number of segments that make up the cube along the Z-axis.
* @param tile6 The type of uv mapping to use. When true, a texture will be subdivided in a 2x3 grid,
* each used for a single face. When false, the entire image is mapped on each face.
*/
constructor(material: IMaterial = null, elementsType: string = 'triangle',
width: number = 100, height: number = 100,
depth: number = 100, segmentsW: number = 1,
segmentsH: number = 1, segmentsD: number = 1, tile6: boolean = true) {
super(material, elementsType);
this._width = width;
this._height = height;
this._depth = depth;
this._segmentsW = segmentsW;
this._segmentsH = segmentsH;
this._segmentsD = segmentsD;
this._tile6 = tile6;
}
/**
* The size of the cube along its X-axis.
*/
public get width(): number {
return this._width;
}
public set width(value: number) {
this._width = value;
this._pInvalidatePrimitive();
}
/**
* The size of the cube along its Y-axis.
*/
public get height(): number {
return this._height;
}
public set height(value: number) {
this._height = value;
this._pInvalidatePrimitive();
}
/**
* The size of the cube along its Z-axis.
*/
public get depth(): number {
return this._depth;
}
public set depth(value: number) {
this._depth = value;
this._pInvalidatePrimitive();
}
/**
* The type of uv mapping to use. When false, the entire image is mapped on each face.
* When true, a texture will be subdivided in a 3x2 grid, each used for a single face.
* Reading the tiles from left to right, top to bottom they represent the faces of the
* cube in the following order: bottom, top, back, left, front, right. This creates
* several shared edges (between the top, front, left and right faces) which simplifies
* texture painting.
*/
public get tile6(): boolean {
return this._tile6;
}
public set tile6(value: boolean) {
this._tile6 = value;
this._pInvalidatePrimitive();
}
/**
* The number of segments that make up the cube along the X-axis. Defaults to 1.
*/
public get segmentsW(): number {
return this._segmentsW;
}
public set segmentsW(value: number) {
this._segmentsW = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* The number of segments that make up the cube along the Y-axis. Defaults to 1.
*/
public get segmentsH(): number {
return this._segmentsH;
}
public set segmentsH(value: number) {
this._segmentsH = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* The number of segments that make up the cube along the Z-axis. Defaults to 1.
*/
public get segmentsD(): number {
return this._segmentsD;
}
public set segmentsD(value: number) {
this._segmentsD = value;
this._pInvalidatePrimitive();
this._pInvalidateUVs();
}
/**
* @inheritDoc
*/
public _pBuildGraphics(target: ElementsBase, elementsType: string): void {
let indices: Uint16Array;
let positions: ArrayBufferView;
let normals: Float32Array;
let tangents: Float32Array;
let stride: number;
let tl: number, tr: number, bl: number, br: number;
let i: number, j: number, inc: number = 0;
let vidx: number, fidx: number; // indices
let dw: number, dh: number, dd: number; // deltas
let outer_pos: number;
// half cube dimensions
const hw: number = this._width / 2;
const hh: number = this._height / 2;
const hd: number = this._depth / 2;
if (elementsType == ElementsType.TRIANGLE) {
const triangleGraphics: TriangleElements = <TriangleElements> target;
const numVertices: number = ((this._segmentsW + 1) * (this._segmentsH + 1) +
(this._segmentsW + 1) * (this._segmentsD + 1) + (this._segmentsH + 1) * (this._segmentsD + 1)) * 2;
const numIndices: number = ((this._segmentsW * this._segmentsH +
this._segmentsW * this._segmentsD + this._segmentsH * this._segmentsD) * 12);
if (numVertices == triangleGraphics.numVertices && triangleGraphics.indices != null) {
triangleGraphics.invalidateIndices();
triangleGraphics.invalidateVertices(triangleGraphics.positions);
triangleGraphics.invalidateVertices(triangleGraphics.normals);
triangleGraphics.invalidateVertices(triangleGraphics.tangents);
} else {
triangleGraphics.setIndices(new Uint16Array(numIndices));
triangleGraphics.setPositions(new Float32Array(numVertices * 3));
triangleGraphics.setNormals(new Float32Array(numVertices * 3));
triangleGraphics.setTangents(new Float32Array(numVertices * 3));
this._pInvalidateUVs();
}
indices = triangleGraphics.indices.get(triangleGraphics.numElements);
positions = triangleGraphics.positions.get(numVertices);
normals = triangleGraphics.normals.get(numVertices);
tangents = triangleGraphics.tangents.get(numVertices);
stride = triangleGraphics.concatenatedBuffer.stride / 4;
vidx = 0;
fidx = 0;
// Segment dimensions
dw = this._width / this._segmentsW;
dh = this._height / this._segmentsH;
dd = this._depth / this._segmentsD;
for (i = 0; i <= this._segmentsW; i++) {
outer_pos = -hw + i * dw;
for (j = 0; j <= this._segmentsH; j++) {
// front
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh + j * dh;
positions[vidx + 2] = -hd;
normals[vidx] = 0;
normals[vidx + 1] = 0;
normals[vidx + 2] = -1;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
// back
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh + j * dh;
positions[vidx + 2] = hd;
normals[vidx] = 0;
normals[vidx + 1] = 0;
normals[vidx + 2] = 1;
tangents[vidx] = -1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
if (i && j) {
tl = 2 * ((i - 1) * (this._segmentsH + 1) + (j - 1));
tr = 2 * (i * (this._segmentsH + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
inc += 2 * (this._segmentsW + 1) * (this._segmentsH + 1);
for (i = 0; i <= this._segmentsW; i++) {
outer_pos = -hw + i * dw;
for (j = 0; j <= this._segmentsD; j++) {
// top
positions[vidx] = outer_pos;
positions[vidx + 1] = hh;
positions[vidx + 2] = -hd + j * dd;
normals[vidx] = 0;
normals[vidx + 1] = 1;
normals[vidx + 2] = 0;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
// bottom
positions[vidx] = outer_pos;
positions[vidx + 1] = -hh;
positions[vidx + 2] = -hd + j * dd;
normals[vidx] = 0;
normals[vidx + 1] = -1;
normals[vidx + 2] = 0;
tangents[vidx] = 1;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 0;
vidx += stride;
if (i && j) {
tl = inc + 2 * ((i - 1) * (this._segmentsD + 1) + (j - 1));
tr = inc + 2 * (i * (this._segmentsD + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
inc += 2 * (this._segmentsW + 1) * (this._segmentsD + 1);
for (i = 0; i <= this._segmentsD; i++) {
outer_pos = hd - i * dd;
for (j = 0; j <= this._segmentsH; j++) {
// left
positions[vidx] = -hw;
positions[vidx + 1] = -hh + j * dh;
positions[vidx + 2] = outer_pos;
normals[vidx] = -1;
normals[vidx + 1] = 0;
normals[vidx + 2] = 0;
tangents[vidx] = 0;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = -1;
vidx += stride;
// right
positions[vidx] = hw;
positions[vidx + 1] = -hh + j * dh;
positions[vidx + 2] = outer_pos;
normals[vidx] = 1;
normals[vidx + 1] = 0;
normals[vidx + 2] = 0;
tangents[vidx] = 0;
tangents[vidx + 1] = 0;
tangents[vidx + 2] = 1;
vidx += stride;
if (i && j) {
tl = inc + 2 * ((i - 1) * (this._segmentsH + 1) + (j - 1));
tr = inc + 2 * (i * (this._segmentsH + 1) + (j - 1));
bl = tl + 2;
br = tr + 2;
indices[fidx++] = tl;
indices[fidx++] = bl;
indices[fidx++] = br;
indices[fidx++] = tl;
indices[fidx++] = br;
indices[fidx++] = tr;
indices[fidx++] = tr + 1;
indices[fidx++] = br + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tr + 1;
indices[fidx++] = bl + 1;
indices[fidx++] = tl + 1;
}
}
}
} else if (elementsType == ElementsType.LINE) {
const lineGraphics: LineElements = <LineElements> target;
const numSegments: number = this._segmentsH * 4 + this._segmentsW * 4 + this._segmentsD * 4;
positions = new Float32Array(numSegments * 6);
const thickness: Float32Array = new Float32Array(numSegments);
vidx = 0;
fidx = 0;
//front/back face
for (i = 0; i < this._segmentsH; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = i * this._height / this._segmentsH - hh;
positions[vidx++] = -hd;
positions[vidx++] = hw;
positions[vidx++] = i * this._height / this._segmentsH - hh;
positions[vidx++] = -hd;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = hh - i * this._height / this._segmentsH;
positions[vidx++] = hd;
positions[vidx++] = hw;
positions[vidx++] = hh - i * this._height / this._segmentsH;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsW; ++i) {
positions[vidx++] = i * this._width / this._segmentsW - hw;
positions[vidx++] = -hh;
positions[vidx++] = -hd;
positions[vidx++] = i * this._width / this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = -hd;
thickness[fidx++] = 1;
positions[vidx++] = hw - i * this._width / this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = hd;
positions[vidx++] = hw - i * this._width / this._segmentsW;
positions[vidx++] = hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
//left/right face
for (i = 0; i < this._segmentsH; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = i * this._height / this._segmentsH - hh;
positions[vidx++] = -hd;
positions[vidx++] = -hw;
positions[vidx++] = i * this._height / this._segmentsH - hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
positions[vidx++] = hw;
positions[vidx++] = hh - i * this._height / this._segmentsH;
positions[vidx++] = -hd;
positions[vidx++] = hw;
positions[vidx++] = hh - i * this._height / this._segmentsH;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsD; ++i) {
positions[vidx++] = hw;
positions[vidx++] = -hh;
positions[vidx++] = i * this._depth / this._segmentsD - hd;
positions[vidx++] = hw;
positions[vidx++] = hh;
positions[vidx++] = i * this._depth / this._segmentsD - hd;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i * this._depth / this._segmentsD;
positions[vidx++] = -hw;
positions[vidx++] = hh;
positions[vidx++] = hd - i * this._depth / this._segmentsD;
thickness[fidx++] = 1;
}
//top/bottom face
for (i = 0; i < this._segmentsD; ++i) {
positions[vidx++] = -hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i * this._depth / this._segmentsD;
positions[vidx++] = hw;
positions[vidx++] = -hh;
positions[vidx++] = hd - i * this._depth / this._segmentsD;
thickness[fidx++] = 1;
positions[vidx++] = -hw;
positions[vidx++] = hh;
positions[vidx++] = i * this._depth / this._segmentsD - hd;
positions[vidx++] = hw;
positions[vidx++] = hh;
positions[vidx++] = i * this._depth / this._segmentsD - hd;
thickness[fidx++] = 1;
}
for (i = 0; i < this._segmentsW; ++i) {
positions[vidx++] = hw - i * this._width / this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = -hd;
positions[vidx++] = hw - i * this._width / this._segmentsW;
positions[vidx++] = -hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
positions[vidx++] = i * this._width / this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = -hd;
positions[vidx++] = i * this._width / this._segmentsW - hw;
positions[vidx++] = hh;
positions[vidx++] = hd;
thickness[fidx++] = 1;
}
// build real data from raw data
lineGraphics.setPositions(positions);
lineGraphics.setThickness(thickness);
}
}
/**
* @inheritDoc
*/
public _pBuildUVs(target: ElementsBase, elementsType: string): void {
let i: number, j: number, index: number;
let uvs: ArrayBufferView;
let stride: number;
let u_tile_dim: number, v_tile_dim: number;
let u_tile_step: number, v_tile_step: number;
let tl0u: number, tl0v: number;
let tl1u: number, tl1v: number;
let du: number, dv: number;
let numVertices: number;
if (elementsType == ElementsType.TRIANGLE) {
numVertices = ((this._segmentsW + 1) * (this._segmentsH + 1) +
(this._segmentsW + 1) * (this._segmentsD + 1) + (this._segmentsH + 1) * (this._segmentsD + 1)) * 2;
const triangleGraphics: TriangleElements = <TriangleElements> target;
if (triangleGraphics.uvs && numVertices == triangleGraphics.numVertices) {
triangleGraphics.invalidateVertices(triangleGraphics.uvs);
} else {
triangleGraphics.setUVs(new Float32Array(numVertices * 2));
}
uvs = triangleGraphics.uvs.get(numVertices);
stride = triangleGraphics.uvs.stride;
if (this._tile6) {
u_tile_dim = u_tile_step = 1 / 3;
v_tile_dim = v_tile_step = 1 / 2;
} else {
u_tile_dim = v_tile_dim = 1;
u_tile_step = v_tile_step = 0;
}
// Create planes two and two, the same way that they were
// constructed in the buildGraphics() function. First calculate
// the top-left UV coordinate for both planes, and then loop
// over the points, calculating the UVs from these numbers.
// When tile6 is true, the layout is as follows:
// .-----.-----.-----. (1,1)
// | Bot | T | Bak |
// |-----+-----+-----|
// | L | F | R |
// (0,0)'-----'-----'-----'
index = 0;
// FRONT / BACK
tl0u = 1 * u_tile_step;
tl0v = 1 * v_tile_step;
tl1u = 2 * u_tile_step;
tl1v = 0 * v_tile_step;
du = u_tile_dim / this._segmentsW;
dv = v_tile_dim / this._segmentsH;
for (i = 0; i <= this._segmentsW; i++) {
for (j = 0; j <= this._segmentsH; j++) {
uvs[index] = (tl0u + i * du) * this._scaleU;
uvs[index + 1] = (tl0v + (v_tile_dim - j * dv)) * this._scaleV;
index += stride;
uvs[index] = (tl1u + (u_tile_dim - i * du)) * this._scaleU;
uvs[index + 1] = (tl1v + (v_tile_dim - j * dv)) * this._scaleV;
index += stride;
}
}
// TOP / BOTTOM
tl0u = 1 * u_tile_step;
tl0v = 0 * v_tile_step;
tl1u = 0 * u_tile_step;
tl1v = 0 * v_tile_step;
du = u_tile_dim / this._segmentsW;
dv = v_tile_dim / this._segmentsD;
for (i = 0; i <= this._segmentsW; i++) {
for (j = 0; j <= this._segmentsD; j++) {
uvs[index] = (tl0u + i * du) * this._scaleU;
uvs[index + 1] = (tl0v + (v_tile_dim - j * dv)) * this._scaleV;
index += stride;
uvs[index] = (tl1u + i * du) * this._scaleU;
uvs[index + 1] = (tl1v + j * dv) * this._scaleV;
index += stride;
}
}
// LEFT / RIGHT
tl0u = 0 * u_tile_step;
tl0v = 1 * v_tile_step;
tl1u = 2 * u_tile_step;
tl1v = 1 * v_tile_step;
du = u_tile_dim / this._segmentsD;
dv = v_tile_dim / this._segmentsH;
for (i = 0; i <= this._segmentsD; i++) {
for (j = 0; j <= this._segmentsH; j++) {
uvs[index] = (tl0u + i * du) * this._scaleU;
uvs[index + 1] = (tl0v + (v_tile_dim - j * dv)) * this._scaleV;
index += stride;
uvs[index] = (tl1u + (u_tile_dim - i * du)) * this._scaleU;
uvs[index + 1] = (tl1v + (v_tile_dim - j * dv)) * this._scaleV;
index += stride;
}
}
} else if (elementsType == ElementsType.LINE) {
//nothing to do here
}
}
}