threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
133 lines (111 loc) • 4.92 kB
text/typescript
import {Vector3} from 'three'
import {AGeometryGenerator} from '../AGeometryGenerator'
export interface BoxGeometryGeneratorParams {
width: number,
height: number,
depth: number,
widthSegments: number,
heightSegments: number,
depthSegments: number
}
export class BoxGeometryGenerator extends AGeometryGenerator<BoxGeometryGeneratorParams> {
constructor(type = 'box', defaultParams?: Partial<BoxGeometryGeneratorParams>) {
super(type)
if (defaultParams) Object.assign(this.defaultParams, defaultParams)
}
defaultParams: BoxGeometryGeneratorParams = {
width: 1,
height: 1,
depth: 1,
widthSegments: 1,
heightSegments: 1,
depthSegments: 1,
}
// helper variables
protected _buildPlane(state: any, u: 'x'|'y'|'z', v: 'x'|'y'|'z', w: 'x'|'y'|'z', udir: number, vdir: number, width: number, height: number, depth: number, gridX: number, gridY: number, materialIndex: number) {
const {indices, vertices, normals, uvs, numberOfVertices, groupStart, groups} = state
const segmentWidth = width / gridX
const segmentHeight = height / gridY
const widthHalf = width / 2
const heightHalf = height / 2
const depthHalf = depth / 2
const gridX1 = gridX + 1
const gridY1 = gridY + 1
let vertexCounter = 0
let groupCount = 0
const vector = new Vector3()
// generate vertices, normals and uvs
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight - heightHalf
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth - widthHalf
// set values to correct vector component
vector[ u ] = x * udir
vector[ v ] = y * vdir
vector[ w ] = depthHalf
// now apply vector to vertex buffer
vertices.push(vector.x, vector.y, vector.z)
// set values to correct vector component
vector[ u ] = 0
vector[ v ] = 0
vector[ w ] = depth > 0 ? 1 : -1
// now apply vector to normal buffer
normals.push(vector.x, vector.y, vector.z)
// uvs
uvs.push(ix / gridX)
uvs.push(1 - iy / gridY)
// counters
vertexCounter += 1
}
}
// indices
// 1. you need three indices to draw a single face
// 2. a single segment consists of two faces
// 3. so we need to generate six (2*3) indices per segment
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = numberOfVertices + ix + gridX1 * iy
const b = numberOfVertices + ix + gridX1 * (iy + 1)
const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1)
const d = numberOfVertices + (ix + 1) + gridX1 * iy
// faces
indices.push(a, b, d)
indices.push(b, c, d)
// increase counter
groupCount += 6
}
}
// add a group to the geometry. this will ensure multi material support
groups.push({start: groupStart, count: groupCount, materialIndex})
// calculate new start value for groups
state.groupStart += groupCount
// update total number of vertices
state.numberOfVertices += vertexCounter
}
protected _generateData(params: BoxGeometryGeneratorParams) {
const {width, height, depth} = params
let {widthSegments, heightSegments, depthSegments} = params
// segments
widthSegments = Math.floor(widthSegments)
heightSegments = Math.floor(heightSegments)
depthSegments = Math.floor(depthSegments)
// buffers
const state = {
indices: [],
vertices: [],
normals: [],
uvs: [],
numberOfVertices: 0,
groupStart: 0,
groups: [],
}
// build each side of the box geometry
this._buildPlane(state, 'z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0) // px
this._buildPlane(state, 'z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1) // nx
this._buildPlane(state, 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2) // py
this._buildPlane(state, 'x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3) // ny
this._buildPlane(state, 'x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4) // pz
this._buildPlane(state, 'x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5) // nz
return state
}
}