UNPKG

three-stdlib

Version:

stand-alone library of threejs examples

501 lines (500 loc) 19.6 kB
"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); class RenderableObject { constructor() { this.id = 0; this.object = null; this.z = 0; this.renderOrder = 0; } } class RenderableFace { constructor() { this.id = 0; this.v1 = new RenderableVertex(); this.v2 = new RenderableVertex(); this.v3 = new RenderableVertex(); this.normalModel = new THREE.Vector3(); this.vertexNormalsModel = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()]; this.vertexNormalsLength = 0; this.color = new THREE.Color(); this.material = null; this.uvs = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()]; this.z = 0; this.renderOrder = 0; } } class RenderableVertex { constructor() { this.position = new THREE.Vector3(); this.positionWorld = new THREE.Vector3(); this.positionScreen = new THREE.Vector4(); this.visible = true; } copy(vertex) { this.positionWorld.copy(vertex.positionWorld); this.positionScreen.copy(vertex.positionScreen); } } class RenderableLine { constructor() { this.id = 0; this.v1 = new RenderableVertex(); this.v2 = new RenderableVertex(); this.vertexColors = [new THREE.Color(), new THREE.Color()]; this.material = null; this.z = 0; this.renderOrder = 0; } } class RenderableSprite { constructor() { this.id = 0; this.object = null; this.x = 0; this.y = 0; this.z = 0; this.rotation = 0; this.scale = new THREE.Vector2(); this.material = null; this.renderOrder = 0; } } class Projector { constructor() { let _object, _objectCount, _objectPoolLength = 0, _vertex, _vertexCount, _vertexPoolLength = 0, _face, _faceCount, _facePoolLength = 0, _line, _lineCount, _linePoolLength = 0, _sprite, _spriteCount, _spritePoolLength = 0, _modelMatrix; const _renderData = { objects: [], lights: [], elements: [] }, _vector3 = new THREE.Vector3(), _vector4 = new THREE.Vector4(), _clipBox = new THREE.Box3(new THREE.Vector3(-1, -1, -1), new THREE.Vector3(1, 1, 1)), _boundingBox = new THREE.Box3(), _points3 = new Array(3), _viewMatrix = new THREE.Matrix4(), _viewProjectionMatrix = new THREE.Matrix4(), _modelViewProjectionMatrix = new THREE.Matrix4(), _frustum = new THREE.Frustum(), _objectPool = [], _vertexPool = [], _facePool = [], _linePool = [], _spritePool = []; function RenderList() { const normals = []; const colors = []; const uvs = []; let object = null; const normalMatrix = new THREE.Matrix3(); function setObject(value) { object = value; normalMatrix.getNormalMatrix(object.matrixWorld); normals.length = 0; colors.length = 0; uvs.length = 0; } function projectVertex(vertex) { const position = vertex.position; const positionWorld = vertex.positionWorld; const positionScreen = vertex.positionScreen; positionWorld.copy(position).applyMatrix4(_modelMatrix); positionScreen.copy(positionWorld).applyMatrix4(_viewProjectionMatrix); const invW = 1 / positionScreen.w; positionScreen.x *= invW; positionScreen.y *= invW; positionScreen.z *= invW; vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && positionScreen.y >= -1 && positionScreen.y <= 1 && positionScreen.z >= -1 && positionScreen.z <= 1; } function pushVertex(x, y, z) { _vertex = getNextVertexInPool(); _vertex.position.set(x, y, z); projectVertex(_vertex); } function pushNormal(x, y, z) { normals.push(x, y, z); } function pushColor(r, g, b) { colors.push(r, g, b); } function pushUv(x, y) { uvs.push(x, y); } function checkTriangleVisibility(v1, v2, v3) { if (v1.visible === true || v2.visible === true || v3.visible === true) return true; _points3[0] = v1.positionScreen; _points3[1] = v2.positionScreen; _points3[2] = v3.positionScreen; return _clipBox.intersectsBox(_boundingBox.setFromPoints(_points3)); } function checkBackfaceCulling(v1, v2, v3) { return (v3.positionScreen.x - v1.positionScreen.x) * (v2.positionScreen.y - v1.positionScreen.y) - (v3.positionScreen.y - v1.positionScreen.y) * (v2.positionScreen.x - v1.positionScreen.x) < 0; } function pushLine(a, b) { const v1 = _vertexPool[a]; const v2 = _vertexPool[b]; v1.positionScreen.copy(v1.position).applyMatrix4(_modelViewProjectionMatrix); v2.positionScreen.copy(v2.position).applyMatrix4(_modelViewProjectionMatrix); if (clipLine(v1.positionScreen, v2.positionScreen) === true) { v1.positionScreen.multiplyScalar(1 / v1.positionScreen.w); v2.positionScreen.multiplyScalar(1 / v2.positionScreen.w); _line = getNextLineInPool(); _line.id = object.id; _line.v1.copy(v1); _line.v2.copy(v2); _line.z = Math.max(v1.positionScreen.z, v2.positionScreen.z); _line.renderOrder = object.renderOrder; _line.material = object.material; if (object.material.vertexColors) { _line.vertexColors[0].fromArray(colors, a * 3); _line.vertexColors[1].fromArray(colors, b * 3); } _renderData.elements.push(_line); } } function pushTriangle(a, b, c, material) { const v1 = _vertexPool[a]; const v2 = _vertexPool[b]; const v3 = _vertexPool[c]; if (checkTriangleVisibility(v1, v2, v3) === false) return; if (material.side === THREE.DoubleSide || checkBackfaceCulling(v1, v2, v3) === true) { _face = getNextFaceInPool(); _face.id = object.id; _face.v1.copy(v1); _face.v2.copy(v2); _face.v3.copy(v3); _face.z = (v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z) / 3; _face.renderOrder = object.renderOrder; _vector3.subVectors(v3.position, v2.position); _vector4.subVectors(v1.position, v2.position); _vector3.cross(_vector4); _face.normalModel.copy(_vector3); _face.normalModel.applyMatrix3(normalMatrix).normalize(); for (let i = 0; i < 3; i++) { const normal = _face.vertexNormalsModel[i]; normal.fromArray(normals, arguments[i] * 3); normal.applyMatrix3(normalMatrix).normalize(); const uv = _face.uvs[i]; uv.fromArray(uvs, arguments[i] * 2); } _face.vertexNormalsLength = 3; _face.material = material; if (material.vertexColors) { _face.color.fromArray(colors, a * 3); } _renderData.elements.push(_face); } } return { setObject, projectVertex, checkTriangleVisibility, checkBackfaceCulling, pushVertex, pushNormal, pushColor, pushUv, pushLine, pushTriangle }; } const renderList = new RenderList(); function projectObject(object) { if (object.visible === false) return; if (object.isLight) { _renderData.lights.push(object); } else if (object.isMesh || object.isLine || object.isPoints) { if (object.material.visible === false) return; if (object.frustumCulled === true && _frustum.intersectsObject(object) === false) return; addObject(object); } else if (object.isSprite) { if (object.material.visible === false) return; if (object.frustumCulled === true && _frustum.intersectsSprite(object) === false) return; addObject(object); } const children = object.children; for (let i = 0, l = children.length; i < l; i++) { projectObject(children[i]); } } function addObject(object) { _object = getNextObjectInPool(); _object.id = object.id; _object.object = object; _vector3.setFromMatrixPosition(object.matrixWorld); _vector3.applyMatrix4(_viewProjectionMatrix); _object.z = _vector3.z; _object.renderOrder = object.renderOrder; _renderData.objects.push(_object); } this.projectScene = function(scene, camera, sortObjects, sortElements) { _faceCount = 0; _lineCount = 0; _spriteCount = 0; _renderData.elements.length = 0; if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld(); if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld(); _viewMatrix.copy(camera.matrixWorldInverse); _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix); _frustum.setFromProjectionMatrix(_viewProjectionMatrix); _objectCount = 0; _renderData.objects.length = 0; _renderData.lights.length = 0; projectObject(scene); if (sortObjects === true) { _renderData.objects.sort(painterSort); } const objects = _renderData.objects; for (let o = 0, ol = objects.length; o < ol; o++) { const object = objects[o].object; const geometry = object.geometry; renderList.setObject(object); _modelMatrix = object.matrixWorld; _vertexCount = 0; if (object.isMesh) { let material = object.material; const isMultiMaterial = Array.isArray(material); const attributes = geometry.attributes; const groups = geometry.groups; if (attributes.position === void 0) continue; const positions = attributes.position.array; for (let i = 0, l = positions.length; i < l; i += 3) { let x = positions[i]; let y = positions[i + 1]; let z = positions[i + 2]; const morphTargets = geometry.morphAttributes.position; if (morphTargets !== void 0) { const morphTargetsRelative = geometry.morphTargetsRelative; const morphInfluences = object.morphTargetInfluences; for (let t = 0, tl = morphTargets.length; t < tl; t++) { const influence = morphInfluences[t]; if (influence === 0) continue; const target = morphTargets[t]; if (morphTargetsRelative) { x += target.getX(i / 3) * influence; y += target.getY(i / 3) * influence; z += target.getZ(i / 3) * influence; } else { x += (target.getX(i / 3) - positions[i]) * influence; y += (target.getY(i / 3) - positions[i + 1]) * influence; z += (target.getZ(i / 3) - positions[i + 2]) * influence; } } } renderList.pushVertex(x, y, z); } if (attributes.normal !== void 0) { const normals = attributes.normal.array; for (let i = 0, l = normals.length; i < l; i += 3) { renderList.pushNormal(normals[i], normals[i + 1], normals[i + 2]); } } if (attributes.color !== void 0) { const colors = attributes.color.array; for (let i = 0, l = colors.length; i < l; i += 3) { renderList.pushColor(colors[i], colors[i + 1], colors[i + 2]); } } if (attributes.uv !== void 0) { const uvs = attributes.uv.array; for (let i = 0, l = uvs.length; i < l; i += 2) { renderList.pushUv(uvs[i], uvs[i + 1]); } } if (geometry.index !== null) { const indices = geometry.index.array; if (groups.length > 0) { for (let g = 0; g < groups.length; g++) { const group = groups[g]; material = isMultiMaterial === true ? object.material[group.materialIndex] : object.material; if (material === void 0) continue; for (let i = group.start, l = group.start + group.count; i < l; i += 3) { renderList.pushTriangle(indices[i], indices[i + 1], indices[i + 2], material); } } } else { for (let i = 0, l = indices.length; i < l; i += 3) { renderList.pushTriangle(indices[i], indices[i + 1], indices[i + 2], material); } } } else { if (groups.length > 0) { for (let g = 0; g < groups.length; g++) { const group = groups[g]; material = isMultiMaterial === true ? object.material[group.materialIndex] : object.material; if (material === void 0) continue; for (let i = group.start, l = group.start + group.count; i < l; i += 3) { renderList.pushTriangle(i, i + 1, i + 2, material); } } } else { for (let i = 0, l = positions.length / 3; i < l; i += 3) { renderList.pushTriangle(i, i + 1, i + 2, material); } } } } else if (object.isLine) { _modelViewProjectionMatrix.multiplyMatrices(_viewProjectionMatrix, _modelMatrix); const attributes = geometry.attributes; if (attributes.position !== void 0) { const positions = attributes.position.array; for (let i = 0, l = positions.length; i < l; i += 3) { renderList.pushVertex(positions[i], positions[i + 1], positions[i + 2]); } if (attributes.color !== void 0) { const colors = attributes.color.array; for (let i = 0, l = colors.length; i < l; i += 3) { renderList.pushColor(colors[i], colors[i + 1], colors[i + 2]); } } if (geometry.index !== null) { const indices = geometry.index.array; for (let i = 0, l = indices.length; i < l; i += 2) { renderList.pushLine(indices[i], indices[i + 1]); } } else { const step = object.isLineSegments ? 2 : 1; for (let i = 0, l = positions.length / 3 - 1; i < l; i += step) { renderList.pushLine(i, i + 1); } } } } else if (object.isPoints) { _modelViewProjectionMatrix.multiplyMatrices(_viewProjectionMatrix, _modelMatrix); const attributes = geometry.attributes; if (attributes.position !== void 0) { const positions = attributes.position.array; for (let i = 0, l = positions.length; i < l; i += 3) { _vector4.set(positions[i], positions[i + 1], positions[i + 2], 1); _vector4.applyMatrix4(_modelViewProjectionMatrix); pushPoint(_vector4, object, camera); } } } else if (object.isSprite) { object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); _vector4.set(_modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1); _vector4.applyMatrix4(_viewProjectionMatrix); pushPoint(_vector4, object, camera); } } if (sortElements === true) { _renderData.elements.sort(painterSort); } return _renderData; }; function pushPoint(_vector42, object, camera) { const invW = 1 / _vector42.w; _vector42.z *= invW; if (_vector42.z >= -1 && _vector42.z <= 1) { _sprite = getNextSpriteInPool(); _sprite.id = object.id; _sprite.x = _vector42.x * invW; _sprite.y = _vector42.y * invW; _sprite.z = _vector42.z; _sprite.renderOrder = object.renderOrder; _sprite.object = object; _sprite.rotation = object.rotation; _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - (_vector42.x + camera.projectionMatrix.elements[0]) / (_vector42.w + camera.projectionMatrix.elements[12]) ); _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - (_vector42.y + camera.projectionMatrix.elements[5]) / (_vector42.w + camera.projectionMatrix.elements[13]) ); _sprite.material = object.material; _renderData.elements.push(_sprite); } } function getNextObjectInPool() { if (_objectCount === _objectPoolLength) { const object = new RenderableObject(); _objectPool.push(object); _objectPoolLength++; _objectCount++; return object; } return _objectPool[_objectCount++]; } function getNextVertexInPool() { if (_vertexCount === _vertexPoolLength) { const vertex = new RenderableVertex(); _vertexPool.push(vertex); _vertexPoolLength++; _vertexCount++; return vertex; } return _vertexPool[_vertexCount++]; } function getNextFaceInPool() { if (_faceCount === _facePoolLength) { const face = new RenderableFace(); _facePool.push(face); _facePoolLength++; _faceCount++; return face; } return _facePool[_faceCount++]; } function getNextLineInPool() { if (_lineCount === _linePoolLength) { const line = new RenderableLine(); _linePool.push(line); _linePoolLength++; _lineCount++; return line; } return _linePool[_lineCount++]; } function getNextSpriteInPool() { if (_spriteCount === _spritePoolLength) { const sprite = new RenderableSprite(); _spritePool.push(sprite); _spritePoolLength++; _spriteCount++; return sprite; } return _spritePool[_spriteCount++]; } function painterSort(a, b) { if (a.renderOrder !== b.renderOrder) { return a.renderOrder - b.renderOrder; } else if (a.z !== b.z) { return b.z - a.z; } else if (a.id !== b.id) { return a.id - b.id; } else { return 0; } } function clipLine(s1, s2) { let alpha1 = 0, alpha2 = 1; const bc1near = s1.z + s1.w, bc2near = s2.z + s2.w, bc1far = -s1.z + s1.w, bc2far = -s2.z + s2.w; if (bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0) { return true; } else if (bc1near < 0 && bc2near < 0 || bc1far < 0 && bc2far < 0) { return false; } else { if (bc1near < 0) { alpha1 = Math.max(alpha1, bc1near / (bc1near - bc2near)); } else if (bc2near < 0) { alpha2 = Math.min(alpha2, bc1near / (bc1near - bc2near)); } if (bc1far < 0) { alpha1 = Math.max(alpha1, bc1far / (bc1far - bc2far)); } else if (bc2far < 0) { alpha2 = Math.min(alpha2, bc1far / (bc1far - bc2far)); } if (alpha2 < alpha1) { return false; } else { s1.lerp(s2, alpha1); s2.lerp(s1, 1 - alpha2); return true; } } } } } exports.Projector = Projector; exports.RenderableFace = RenderableFace; exports.RenderableLine = RenderableLine; exports.RenderableObject = RenderableObject; exports.RenderableSprite = RenderableSprite; exports.RenderableVertex = RenderableVertex; //# sourceMappingURL=Projector.cjs.map