UNPKG

@awayjs/scene

Version:
631 lines (508 loc) 17.5 kB
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 } } }