Buckets:
| import { Vector3, Color, Vector2, Vector4, Box3, Matrix4, Frustum, Matrix3, DoubleSide } from "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 Vector3(); | |
| this.vertexNormalsModel = [new Vector3(), new Vector3(), new Vector3()]; | |
| this.vertexNormalsLength = 0; | |
| this.color = new Color(); | |
| this.material = null; | |
| this.uvs = [new Vector2(), new Vector2(), new Vector2()]; | |
| this.z = 0; | |
| this.renderOrder = 0; | |
| } | |
| } | |
| class RenderableVertex { | |
| constructor() { | |
| this.position = new Vector3(); | |
| this.positionWorld = new Vector3(); | |
| this.positionScreen = new 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 Color(), new 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 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 Vector3(), _vector4 = new Vector4(), _clipBox = new Box3(new Vector3(-1, -1, -1), new Vector3(1, 1, 1)), _boundingBox = new Box3(), _points3 = new Array(3), _viewMatrix = new Matrix4(), _viewProjectionMatrix = new Matrix4(), _modelViewProjectionMatrix = new Matrix4(), _frustum = new Frustum(), _objectPool = [], _vertexPool = [], _facePool = [], _linePool = [], _spritePool = []; | |
| function RenderList() { | |
| const normals = []; | |
| const colors = []; | |
| const uvs = []; | |
| let object = null; | |
| const normalMatrix = new 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 === 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; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| export { | |
| Projector, | |
| RenderableFace, | |
| RenderableLine, | |
| RenderableObject, | |
| RenderableSprite, | |
| RenderableVertex | |
| }; | |
| //# sourceMappingURL=Projector.js.map | |
Xet Storage Details
- Size:
- 19.3 kB
- Xet hash:
- 97436602e262df6c39189d72b7d14f57c2a445326e05f744c2af7349c43b2a23
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.