mirror of
https://github.com/Doodle3D/Doodle3D-Core.git
synced 2024-12-22 11:03:48 +01:00
fix 3d holes
This commit is contained in:
parent
7a93b3e5c8
commit
6a54f540eb
103
src/d3/ShapeMesh.js
vendored
103
src/d3/ShapeMesh.js
vendored
@ -16,11 +16,11 @@ const MAX_HEIGHT_BASE = 5;
|
||||
const isValidNumber = (num) => typeof num === 'number' && !isNaN(num);
|
||||
|
||||
class ShapeMesh extends THREE.Object3D {
|
||||
constructor(shapeData, holes, toonShader, active) {
|
||||
constructor(shapeData, active, toonShader) {
|
||||
super();
|
||||
this.name = shapeData.UID;
|
||||
|
||||
const { sculpt, rotate, twist, height, type, transform, z, color, fill } = shapeData;
|
||||
const { sculpt, rotate, twist, height, type, transform, z, color, fill, solid } = shapeData;
|
||||
|
||||
let material;
|
||||
if (toonShader) {
|
||||
@ -40,10 +40,6 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._mesh.name = shapeData.UID;
|
||||
this.add(this._mesh);
|
||||
|
||||
this._holeMesh = new THREE.Mesh(new THREE.Geometry, material);
|
||||
this._holeMesh.name = shapeData.UID;
|
||||
this.add(this._holeMesh);
|
||||
|
||||
this._toonShader = toonShader;
|
||||
|
||||
this._shapes = [];
|
||||
@ -61,10 +57,13 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._shapeData = shapeData;
|
||||
this._color = color;
|
||||
this._fill = fill;
|
||||
|
||||
this.updatePoints(shapeData);
|
||||
|
||||
this._checkHoles(holes, active);
|
||||
this._holeMesh = new THREE.Mesh(new THREE.Geometry().fromBufferGeometry(this._mesh.geometry), material);
|
||||
this._holeMesh.name = shapeData.UID;
|
||||
this.add(this._holeMesh);
|
||||
|
||||
this.updateSolid(solid, active);
|
||||
}
|
||||
|
||||
add(object) {
|
||||
@ -74,52 +73,29 @@ class ShapeMesh extends THREE.Object3D {
|
||||
if (this.children.includes(object)) super.remove(object);
|
||||
}
|
||||
|
||||
_checkHoles(holes, active) {
|
||||
let changed = false;
|
||||
updateHoleGeometry(holes) {
|
||||
if (!this._solid || !this._fill) return false;
|
||||
if (holes === this._holes && !this._changedGeometry) return false;
|
||||
|
||||
const visible = this._shapeData.solid || active;
|
||||
if (visible !== this.visible) {
|
||||
this.visible = visible;
|
||||
changed = true;
|
||||
this._holeMesh.geometry.dispose();
|
||||
|
||||
if (holes === null) {
|
||||
this._holeMesh.geometry = new THREE.Geometry().fromBufferGeometry(this._mesh.geometry);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (active) {
|
||||
this.remove(this._holeMesh);
|
||||
this.add(this._mesh);
|
||||
}
|
||||
|
||||
holes = holes.map(hole => hole.mesh._mesh);
|
||||
const objectBoundingBox = new THREE.Box3().setFromObject(this._mesh);
|
||||
holes = holes.filter(hole => {
|
||||
const holeBoundingBox = new THREE.Box3().setFromObject(hole);
|
||||
return holeBoundingBox.intersectsBox(objectBoundingBox);
|
||||
});
|
||||
|
||||
if (holes.length === 0) {
|
||||
this.remove(this._holeMesh);
|
||||
this.add(this._mesh);
|
||||
return changed;
|
||||
}
|
||||
// is coliding with holes
|
||||
|
||||
const objectGeometry = new THREE.Geometry().fromBufferGeometry(this._mesh.geometry);
|
||||
let objectBSP = new THREE_BSP(objectGeometry);
|
||||
objectGeometry.dispose();
|
||||
for (const hole of holes) {
|
||||
const holeGeometry = new THREE.Geometry().fromBufferGeometry(hole.geometry);
|
||||
const holeBSP = new THREE_BSP(holeGeometry);
|
||||
holeGeometry.dispose();
|
||||
objectBSP = objectBSP.subtract(holeBSP)
|
||||
}
|
||||
this._holeMesh.geometry.dispose();
|
||||
objectBSP = objectBSP.subtract(holes);
|
||||
this._holeMesh.geometry = objectBSP.toMesh().geometry;
|
||||
|
||||
this.add(this._holeMesh);
|
||||
this.remove(this._mesh);
|
||||
this._holes = holes;
|
||||
this._changedGeometry = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
update(shapeData, holes, active) {
|
||||
update(shapeData, active) {
|
||||
let changed = false;
|
||||
|
||||
if (shapeChanged(this._shapeData, shapeData)) {
|
||||
@ -152,28 +128,20 @@ class ShapeMesh extends THREE.Object3D {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (this._checkHoles(holes, active)) {
|
||||
let solidChanged = false;
|
||||
if (shapeData.solid !== this._solid || active !== this._active) {
|
||||
this.updateSolid(shapeData.solid, active);
|
||||
changed = true;
|
||||
solidChanged = true;
|
||||
}
|
||||
|
||||
this._shapeData = shapeData;
|
||||
return changed;
|
||||
}
|
||||
|
||||
setOpaque(opaque) {
|
||||
let opacity;
|
||||
if (this._shapeData.solid) {
|
||||
opacity = opaque ? 1.0 : DESELECT_TRANSPARENCY;
|
||||
} else {
|
||||
opacity = 0.0;
|
||||
}
|
||||
this._mesh.material.opacity = opacity;
|
||||
this._mesh.material.transparent = opacity !== 1;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._mesh.geometry.dispose();
|
||||
this._meshHole.geometry.dispose();
|
||||
this._holeMesh.geometry.dispose();
|
||||
}
|
||||
|
||||
updatePoints(shapeData) {
|
||||
@ -252,6 +220,23 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._color = color;
|
||||
}
|
||||
|
||||
updateSolid(solid, active) {
|
||||
this._mesh.material.opacity = solid ? 1.0 : 0.0;
|
||||
this._mesh.material.transparent = !solid;
|
||||
this.visible = solid || active;
|
||||
|
||||
if (active || !solid) {
|
||||
this.add(this._mesh);
|
||||
this.remove(this._holeMesh);
|
||||
} else {
|
||||
this.add(this._holeMesh);
|
||||
this.remove(this._mesh);
|
||||
}
|
||||
|
||||
this._solid = solid;
|
||||
this._active = active;
|
||||
}
|
||||
|
||||
_getPoint(point, heightStep, center) {
|
||||
const { scale, pos: y } = this._heightSteps[heightStep];
|
||||
|
||||
@ -326,6 +311,8 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._mesh.geometry.boundingSphere = null;
|
||||
this._mesh.geometry.computeFaceNormals();
|
||||
this._mesh.geometry.computeVertexNormals();
|
||||
|
||||
this._changedGeometry = true;
|
||||
}
|
||||
_updateSide() {
|
||||
// TODO use higher precision for export mesh
|
||||
@ -362,6 +349,8 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._heightSteps = heightSteps;
|
||||
|
||||
if (heightStepsChanged) this._updateFaces();
|
||||
|
||||
this._changedGeometry = true;
|
||||
}
|
||||
_updateFaces() {
|
||||
// TODO
|
||||
@ -483,6 +472,8 @@ class ShapeMesh extends THREE.Object3D {
|
||||
this._vertices = new Float32Array(vertexBufferLength);
|
||||
this._vertexBuffer = new THREE.BufferAttribute(this._vertices, 3);
|
||||
this._mesh.geometry.addAttribute('position', this._vertexBuffer);
|
||||
|
||||
this._changedGeometry = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
76
src/d3/ShapesManager.js
vendored
76
src/d3/ShapesManager.js
vendored
@ -1,7 +1,10 @@
|
||||
import { determineActiveShape } from '../shape/shapeDataUtils.js';
|
||||
import { determineActiveShape3d } from '../shape/shapeDataUtils.js';
|
||||
import { SHAPE_TYPE_PROPERTIES } from '../constants/shapeTypeProperties.js';
|
||||
import * as THREE from 'three';
|
||||
import ShapeMesh from './ShapeMesh.js';
|
||||
import ThreeBSP from 'three-js-csg';
|
||||
|
||||
const THREE_BSP = ThreeBSP(THREE);
|
||||
|
||||
export default class ShapesManager extends THREE.Object3D {
|
||||
constructor({ toonShader }) {
|
||||
@ -12,6 +15,9 @@ export default class ShapesManager extends THREE.Object3D {
|
||||
this._meshes = {};
|
||||
this._spaces = {};
|
||||
this.name = 'shapes-manager';
|
||||
|
||||
this._holes = new THREE_BSP(new THREE.Geometry());
|
||||
|
||||
// this._edges = {};
|
||||
}
|
||||
|
||||
@ -36,27 +42,22 @@ export default class ShapesManager extends THREE.Object3D {
|
||||
}
|
||||
}
|
||||
|
||||
let holesChanged = false;
|
||||
|
||||
// Remove removed shapes
|
||||
if (this._state) {
|
||||
for (const id in this._state.objectsById) {
|
||||
if (!state.objectsById[id]) {
|
||||
if (!this._meshes[id].mesh._shapeData.solid) holesChanged = true;
|
||||
this._handleShapeRemove(id);
|
||||
render = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const activeShapes = determineActiveShape(state);
|
||||
const ids = Object.keys(state.objectsById);
|
||||
const activeShapes = determineActiveShape3d(state);
|
||||
|
||||
const ids = Object.keys(state.objectsById).sort((a, b) => {
|
||||
const solidA = state.objectsById[a].solid;
|
||||
const solidB = state.objectsById[b].solid;
|
||||
|
||||
if (solidA === solidB) return 0;
|
||||
return solidA ? 1 : -1;
|
||||
});
|
||||
|
||||
const holes = [];
|
||||
for (let i = 0; i < ids.length; i ++) {
|
||||
const id = ids[i];
|
||||
const newShapeData = state.objectsById[id];
|
||||
@ -65,33 +66,52 @@ export default class ShapesManager extends THREE.Object3D {
|
||||
if (!SHAPE_TYPE_PROPERTIES[newShapeData.type].D3Visible) continue;
|
||||
// add new shapes
|
||||
if (!this._state || !this._state.objectsById[id]) {
|
||||
this._handleShapeAdded(newShapeData, holes, active);
|
||||
this._handleShapeAdded(newShapeData, active);
|
||||
render = true;
|
||||
if (!newShapeData.solid) holesChanged = true;
|
||||
} else {
|
||||
const { mesh } = this._meshes[id];
|
||||
if (mesh.update(newShapeData, holes, active)) {
|
||||
if (mesh.update(newShapeData, active)) {
|
||||
render = true;
|
||||
if (!newShapeData.solid || !this._state.objectsById[id].solid) holesChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (holesChanged) {
|
||||
this._holes = null;
|
||||
for (let i = 0; i < ids.length; i ++) {
|
||||
const id = ids[i];
|
||||
if (!state.objectsById[id].solid) {
|
||||
const hole = this._meshes[id].mesh._mesh;
|
||||
const holeGeometry = new THREE.Geometry().fromBufferGeometry(hole.geometry);
|
||||
const holeBSP = new THREE_BSP(holeGeometry);
|
||||
if (!this._holes) {
|
||||
this._holes = holeBSP;
|
||||
} else {
|
||||
this._holes = this._holes.union(holeBSP);
|
||||
}
|
||||
holeGeometry.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < ids.length; i ++) {
|
||||
const id = ids[i];
|
||||
const active = activeShapes[id];
|
||||
if (!active && state.objectsById[id].solid) {
|
||||
const shape = this._meshes[id].mesh;
|
||||
if (shape.updateHoleGeometry(this._holes)) {
|
||||
render = true;
|
||||
}
|
||||
}
|
||||
if (!newShapeData.solid && !active) holes.push(this._meshes[id]);
|
||||
}
|
||||
this._state = state;
|
||||
|
||||
this._state = state;
|
||||
return render;
|
||||
}
|
||||
|
||||
updateTransparent(selectedUIDs) {
|
||||
for (const UID in this._meshes) {
|
||||
const { mesh } = this._meshes[UID];
|
||||
const selected = selectedUIDs.indexOf(UID) !== -1;
|
||||
const opaque = selected || selectedUIDs.length === 0;
|
||||
|
||||
mesh.setOpaque(opaque);
|
||||
}
|
||||
}
|
||||
|
||||
getMesh(id) {
|
||||
return this._meshes[id].mesh;
|
||||
}
|
||||
|
||||
_handleShapeRemove(id) {
|
||||
@ -103,10 +123,10 @@ export default class ShapesManager extends THREE.Object3D {
|
||||
this._spaces[space].remove(mesh);
|
||||
}
|
||||
|
||||
_handleShapeAdded(shapeData, holes) {
|
||||
_handleShapeAdded(shapeData, active) {
|
||||
if (!SHAPE_TYPE_PROPERTIES[shapeData.type].D3Visible) return;
|
||||
const { space } = shapeData;
|
||||
const mesh = new ShapeMesh(shapeData, holes, this._toonShader);
|
||||
const mesh = new ShapeMesh(shapeData, active, this._toonShader);
|
||||
this._meshes[shapeData.UID] = { mesh, space };
|
||||
|
||||
this._spaces[space].add(mesh);
|
||||
|
@ -93,3 +93,18 @@ export const determineActiveShape = (state) => {
|
||||
}
|
||||
return activeShapes;
|
||||
};
|
||||
|
||||
export const determineActiveShape3d = (state) => {
|
||||
const activeTransformer = state.d2.eraser.active ||
|
||||
(state.d2.transform.active && state.d2.transform.handle !== 'dragselect') ||
|
||||
state.d3.height.active ||
|
||||
state.d3.sculpt.activeHandle !== null ||
|
||||
state.d3.twist.active;
|
||||
|
||||
const selectedObjects = state.selection.objects.map(({ id }) => id);
|
||||
const activeShapes = {};
|
||||
for (const id in state.objectsById) {
|
||||
activeShapes[id] = activeTransformer;
|
||||
}
|
||||
return activeShapes;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user