i met my challenge

master
howard 2021-04-10 01:45:15 -07:00
parent 1af670fde9
commit 0ae39d196a
10 changed files with 291 additions and 192 deletions

View File

@ -9,7 +9,7 @@ import Stats from './stats.module.js';
import { add3DPoint } from './datums'
import { extrude } from './extrude'
import { onHover, onPick } from './mouseEvents';
import { _vec2, _vec3, color, awaitSelection } from './shared'
import { _vec2, _vec3, color, awaitSelection, ptObj} from './shared'
import {AxesHelper} from './axes'
@ -38,7 +38,7 @@ export class Scene {
this.rect = this.canvas.getBoundingClientRect().toJSON()
this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas });
this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas, antialias:true });
const size = 1;
const near = 0;
@ -66,13 +66,23 @@ export class Scene {
this.obj3d.add(helpersGroup);
for (let i=0; i<4;i ++) {
const freePt = ptObj()
freePt.matrixAutoUpdate = false
freePt.material.size=8
freePt.visible = false
freePt.depthTest = false
helpersGroup.add(freePt);
}
this.fptIdx = 0;
this.fptObj = {}
this.axes = new AxesHelper(this.camera.zoom)
this.axes.visible = false
helpersGroup.add(this.axes);
const planeGeom = new THREE.PlaneGeometry(5, 5)
const pxy = new THREE.Mesh(
@ -88,6 +98,7 @@ export class Scene {
);
pxy.userData.type = 'plane'
pxy.layers.enable(1)
pxy.add(
new THREE.LineSegments(
@ -109,7 +120,7 @@ export class Scene {
const intensity = 1;
const intensity = 0.5;
const light1 = new THREE.DirectionalLight(color.lighting, intensity);
light1.position.set(10, 10, 10);
this.obj3d.add(light1);
@ -122,6 +133,8 @@ export class Scene {
this.render = render.bind(this);
this.addSketch = addSketch.bind(this);
this.extrude = extrude.bind(this);
@ -208,6 +221,45 @@ export class Scene {
console.log('fireed')
}
subtract (m1, m2) {
let bspA = CSG.fromMesh(m1)
let bspB = CSG.fromMesh(m2)
m1.traverse(e=>e.layers.disable(0))
m2.traverse(e=>e.layers.disable(0))
// m1.visible = false
// m2.visible = false
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
let bspResult = bspA.subtract(bspB)
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
let mesh = CSG.toMesh(bspResult, m1.matrix, m1.material)
mesh.userData.type = 'mesh'
mesh.name = `${m1.name}-${m2.name}`
const edges = new THREE.EdgesGeometry( mesh.geometry, 15 );
edges.type = 'BufferGeometry'
edges.parameters = undefined
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x000000 } ) );
line.userData.type = 'line'
// const vertices = new THREE.Points( edges, new THREE.PointsMaterial({ color: 0x000000, size:4}) );
const vertices = new THREE.Points( edges, new THREE.PointsMaterial() );
vertices.userData.type = 'point'
vertices.layers.enable(1)
mesh.add(line)
mesh.add(vertices)
sc.obj3d.add(mesh)
return mesh
}
}
@ -299,12 +351,7 @@ async function addSketch() {
}
window.sc = new Scene(store)
// sc.loadState()
sc.loadState()
// sc.camera.layers.enable(1)
// rc.layers.set(1)

View File

@ -152,6 +152,7 @@ class Sketch {
this.setDimLines()
this.obj3d.traverse(e=>e.layers.enable(0))
this.scene.axes.matrix = this.obj3d.matrix
this.scene.axes.visible = true
@ -164,6 +165,7 @@ class Sketch {
this.canvas.removeEventListener('pointermove', this.onHover)
this.store.dispatch({ type: 'exit-sketch' })
this.labelContainer.innerHTML = ""
this.obj3d.traverse(e=>e.layers.disable(0))
this.scene.axes.visible = false
}

View File

@ -4,8 +4,6 @@ import { color } from './shared'
const lineMaterial = new THREE.LineBasicMaterial({
linewidth: 2,
color: color.dimension,
opacity: 0.2,
transparent: true,
})
@ -26,7 +24,7 @@ export async function drawDimension() {
const line = new THREE.LineSegments(
new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute(3 * 8, 3)
new THREE.Float32BufferAttribute(Array(3 * 8).fill(-0.001), 3)
),
lineMaterial.clone()
);

View File

@ -77,23 +77,43 @@ export function extrude(sketch) {
const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
const material = new THREE.MeshPhongMaterial({
const material = new THREE.MeshLambertMaterial({
// const material = new THREE.MeshPhongMaterial({
color: color.mesh,
emissive: color.emissive,
// flatShading:true,
});
const mesh = new THREE.Mesh(geometry, material)
mesh.name = 'm' + id++
mesh.userData.type = 'mesh'
mesh.layers.enable(1)
for (let i = 0; i < offSetPts.length; i += 2) {
if (
offSetPts[i] == offSetPts[i - 2] &&
offSetPts[i + 1] == offSetPts[i - 1]
) continue;
mesh.add(
ptObj([offSetPts[i], offSetPts[i + 1], 8])
)
}
const edges = new THREE.EdgesGeometry( geometry, 15 );
edges.type = 'BufferGeometry'
edges.parameters = undefined
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x000000 } ) );
line.userData.type = 'line'
const vertices = new THREE.Points( edges, new THREE.PointsMaterial() );
vertices.userData.type = 'point'
vertices.layers.enable(1)
mesh.add(line)
mesh.add(vertices)
// for (let i = 0; i < offSetPts.length; i += 2) {
// if (
// offSetPts[i] == offSetPts[i - 2] &&
// offSetPts[i + 1] == offSetPts[i - 1]
// ) continue;
// mesh.add(
// ptObj([offSetPts[i], offSetPts[i + 1], 0], false),
// ptObj([offSetPts[i], offSetPts[i + 1], 8], false),
// )
// }
mesh.matrixAutoUpdate = false;
@ -103,7 +123,6 @@ export function extrude(sketch) {
this.render()
// sketch.visible = false

View File

@ -1,6 +1,9 @@
import * as THREE from '../node_modules/three/src/Three';
import { raycaster, color, hoverColor } from './shared';
let ptLoc
export function onHover(e) {
if (this.mode || e.buttons) return
@ -12,95 +15,98 @@ export function onHover(e) {
this.camera
);
let hoverPts;
let idx = []
if (this.obj3d.userData.type == 'sketch') {
hoverPts = raycaster.intersectObjects([...this.obj3d.children[1].children, ...this.obj3d.children])
if (hoverPts.length) {
let minDist = Infinity;
for (let i = 0; i < hoverPts.length; i++) {
if (!hoverPts[i].distanceToRay) continue;
if (hoverPts[i].distanceToRay < minDist - 0.0001) {
minDist = hoverPts[i].distanceToRay
idx = [i]
} else if (Math.abs(hoverPts[i].distanceToRay - minDist) < 0.0001) {
idx.push(i)
}
}
// console.log(hoverPts, idx)
if (!idx.length) idx.push(0)
}
} else {
// hoverPts = raycaster.intersectObjects(this.obj3d.children)
if (this.obj3d.userData.type != 'sketch') {
raycaster.layers.set(1)
hoverPts = raycaster.intersectObjects(this.obj3d.children, true)
} else {
raycaster.layers.set(0)
hoverPts = raycaster.intersectObjects([...this.obj3d.children[1].children, ...this.obj3d.children])
}
let idx = []
if (hoverPts.length) {
// console.log(hoverPts)
// for (let i = 0; i < hoverPts.length; i++) {
// const obj = hoverPts[i].object
// if (['point', 'plane'].includes(obj.userData.type)) {
// idx.push(i)
// break;
// }
// }
let minDist = Infinity;
for (let i = 0; i < hoverPts.length; i++) {
if (!hoverPts[i].distanceToRay) continue;
if (hoverPts[i].distanceToRay < minDist - 0.0001) {
minDist = hoverPts[i].distanceToRay
idx = [i]
if (this.obj3d.userData.type != 'sketch') break
minDist = hoverPts[i].distanceToRay
} else if (Math.abs(hoverPts[i].distanceToRay - minDist) < 0.0001) {
idx.push(i)
}
}
if (!idx.length) {
const obj = hoverPts[0].object
if (obj.userData.type == "mesh" && obj.visible) {
idx.push(0)
} else if (['point', 'plane'].includes(obj.userData.type)) {
idx.push(0)
}
}
}
if (idx.length) { // after filtering, if hovered objs still exists
}
if (idx.length) { // after filtering, hovered objs still exists
if (hoverPts[idx[0]].object != this.hovered[0]) { // if the previous hovered obj is not the same as current
for (let x = 0; x < this.hovered.length; x++) {
for (let x = 0; x < this.hovered.length; x++) { // first clear old hovers that are not selected
const obj = this.hovered[x]
if (obj && !this.selected.includes(obj)) {
if (!this.selected.includes(obj)) {
if (typeof obj == 'object') {
obj.material.color.set(color[obj.userData.type])
if (this.obj3d.userData.type != 'sketch') {
if (obj.userData.type == 'mesh') {
obj.children[0].material.color.set(color['line'])
}
}
} else {
// this.obj3d.children[0].children[this.fptObj[obj]].visible = false
this.obj3d.children[0].children[0].visible = false
}
}
}
this.hovered = []
for (let x = 0; x < idx.length; x++) {
const obj = hoverPts[idx[x]].object
let obj = hoverPts[idx[x]].object
if (this.obj3d.userData.type == 'sketch') {
obj.material.color.set(hoverColor[obj.userData.type])
} else {
if (obj.userData.type == 'mesh') {
obj.children[0].material.color.set(hoverColor['line'])
} else if (obj.userData.type == 'plane') {
obj.material.color.set(hoverColor[obj.userData.type])
} else if (obj.userData.type == 'point') {
ptLoc = obj.geometry.attributes.position.array
.slice(
3 * hoverPts[idx[x]].index,
3 * hoverPts[idx[x]].index + 3
)
// const pp = this.obj3d.children[0].children[this.fptIdx % 3]
const pp = this.obj3d.children[0].children[0]
pp.geometry.attributes.position.array.set(ptLoc)
pp.matrix = obj.parent.matrix
pp.geometry.attributes.position.needsUpdate = true
pp.visible = true
obj = hoverPts[idx[x]].index
}
}
this.hovered.push(obj)
}
@ -109,11 +115,22 @@ export function onHover(e) {
}
} else { // no hovered object after filtering
if (this.hovered.length) { // if previously something was hovered, then we need to clear it
for (let x = 0; x < this.hovered.length; x++) {
const obj = this.hovered[x]
// console.log(obj, 'here')
if (!this.selected.includes(obj)) {
if (typeof obj == 'object') {
obj.material.color.set(color[obj.userData.type])
if (this.obj3d.userData.type != 'sketch') {
if (obj.userData.type == 'mesh') {
obj.children[0].material.color.set(color['line'])
}
}
} else {
// this.obj3d.children[0].children[this.fptObj[obj]].visible = false
this.obj3d.children[0].children[0].visible = false
}
}
}
this.hovered = []
@ -122,6 +139,8 @@ export function onHover(e) {
this.obj3d.dispatchEvent({ type: 'change' })
}
}
}
let draggedLabel;
@ -129,9 +148,30 @@ export function onPick(e) {
if (this.mode || e.buttons != 1) return
if (this.hovered.length) {
const obj = this.hovered[this.hovered.length - 1]
this.selected.push(this.hovered[this.hovered.length - 1])
if (this.obj3d.userData.type != 'sketch') {
if (typeof obj == 'object') {
if (obj.userData.type == "mesh") {
obj.material.color.set(hoverColor[obj.userData.type])
}
} else {
const pp = this.obj3d.children[0].children[this.fptIdx % 3 + 1]
const p0 = this.obj3d.children[0].children[0]
pp.geometry.attributes.position.array.set(p0.geometry.attributes.position.array)
pp.matrix = p0.matrix
pp.geometry.attributes.position.needsUpdate = true
pp.visible = true
this.fptObj[obj] = this.fptIdx
this.fptIdx++
}
}
if (typeof this.hovered[0] == 'object') {
switch (this.hovered[0].userData.type) {
case 'dimension':
const idx = this.obj3d.children[1].children.indexOf(this.hovered[0])
@ -157,12 +197,21 @@ export function onPick(e) {
default:
break;
}
}
} else {
for (let x = 0; x < this.selected.length; x++) {
const obj = this.selected[x]
if (typeof obj == 'object') {
obj.material.color.set(color[obj.userData.type])
if (this.obj3d.userData.type != 'sketch' && obj.userData.type == 'mesh') {
obj.children[0].material.color.set(color['line'])
}
} else {
this.obj3d.children[0].children[this.fptObj[obj] + 1].visible = false
}
}
this.obj3d.children[0].children[0].visible = false
this.obj3d.dispatchEvent({ type: 'change' })
this.selected = []
}

View File

@ -60,6 +60,14 @@ body {
}
.btn-green {
cursor: pointer;
@apply fill-current
bg-transparent text-gray-700
hover:bg-gray-300 hover:text-green-200;
}
.tooltip {
position: fixed;
display: block;

View File

@ -58,7 +58,7 @@ export class DepTree {
this.allIds.splice(spliceIdx, 1)
const deletedObj = sc.obj3d.children.splice(spliceIdx + 4, 1)[0]
const deletedObj = sc.obj3d.children.splice(spliceIdx + 4, 1)[0] // first 4 elements are non geom
deletedObj.traverse((obj)=>{
if (obj.geometry) obj.geometry.dispose()

View File

@ -43,7 +43,7 @@ export const NavBar = () => {
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
// console.log('here')
const [m1, m2] = sc.selected
const mesh = subtract(m1, m2)
const mesh = sc.subtract(m1, m2)
console.log(mesh, 'meshres')
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
@ -68,29 +68,3 @@ export const NavBar = () => {
}
</div>
}
const subtract = (m1, m2) => {
// //Create a bsp tree from each of the meshes
// console.log(sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh'), "wtf")
let bspA = BoolOp.fromMesh(m1)
let bspB = BoolOp.fromMesh(m2)
m1.visible = false
m2.visible = false
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
let bspResult = bspA.subtract(bspB)
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
let meshResult = BoolOp.toMesh(bspResult, m1.matrix, m1.material)
meshResult.userData.type = 'mesh'
meshResult.name = `${m1.name}-${m2.name}`
sc.obj3d.add(meshResult)
return meshResult
}

View File

@ -4,6 +4,7 @@ import React, { useReducer } from 'react';
import { useDispatch, useSelector } from 'react-redux'
import { MdEdit, MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md'
import { FaCube, FaEdit } from 'react-icons/fa'
export const Tree = () => {
const treeEntries = useSelector(state => state.treeEntries)
@ -17,6 +18,12 @@ export const Tree = () => {
}
const treeIcons = {
'mesh': FaCube,
'sketch': FaEdit
}
const TreeEntry = ({ entId }) => {
const treeEntries = useSelector(state => state.treeEntries.byId)
@ -28,18 +35,30 @@ const TreeEntry = ({ entId }) => {
entry = treeEntries[entId]
if (entId[0] == "s") {
if (treeEntries[entId].obj3d) {
obj3d = treeEntries[entId].obj3d
} else {
obj3d = treeEntries[entId]
}
console.log(obj3d.userData.type)
let Icon = treeIcons[obj3d.userData.type]
const [_, forceUpdate] = useReducer(x => x + 1, 0);
const vis = obj3d.visible
// const vis = obj3d.visible
const vis = obj3d.layers.mask&1
return <div className='bg-gray-50 flex justify-between w-full'>
<div className="btn-light"
return <div className='btn-light select-none flex justify-start w-full h-7 items-center text-sm'
onDoubleClick={() => {
activeSketchId && treeEntries[activeSketchId].deactivate()
entry.activate()
sc.clearSelection()
sc.activeSketch = entry;
}}
>
<Icon className='h-full w-auto p-1.5' />
<div className="btn-light pl-1"
onPointerEnter={() => {
if (entId[0] == 'm') {
// entry.material.color.set(color.hover)
@ -64,46 +83,31 @@ const TreeEntry = ({ entId }) => {
>
{entId}
</div>
<div className='flex'>
<div className='btn-light'
onClick={() => {
activeSketchId && treeEntries[activeSketchId].deactivate()
entry.activate()
sc.clearSelection()
sc.activeSketch = entry;
}}
>
<MdEdit />
</div>
<div className='flex h-full ml-auto'>
<div className='btn-light'
<MdDelete className='btn-green h-full w-auto p-1.5'
onClick={() => {
dispatch({ type: 'delete-node', id: entId })
}}
>
<MdDelete />
</div>
/>
{
vis ?
<div className='btn-light'
<MdVisibility className='btn-green h-full w-auto p-1.5'
onClick={() => {
obj3d.visible = false;
obj3d.traverse((e)=>e.layers.disable(0))
sc.render()
forceUpdate()
}}
>
<MdVisibility />
</div>
/>
:
<div className='btn-light'
<MdVisibilityOff className='btn-green h-full w-auto p-1.5'
onClick={() => {
obj3d.visible = true;
obj3d.traverse((e)=>e.layers.enable(0))
sc.render()
forceUpdate()
}}
>
<MdVisibilityOff />
</div>
/>
}
</div>

View File

@ -12,20 +12,16 @@ raycaster.params.Points.threshold = 0.1;
const color = {
// background:0xdae1e7,
background:0xffffff,
// background:0xbbbbbb,
background:0xdae1e7,
lighting: 0xFFFFFF,
emissive: 0x072534,
hover: 0x00ff00,
point: 0x555555, //points
line: 0x555555, //lines
mesh: 0x156289, //mesh:
line: 0x000000, //lines
mesh: 0x9DCFED, //mesh:
dimension: 0x0000ff, //
// plane: 0xdaacac, //
// planeBorder: 0xc59797, //
plane: 0x88adcd, //
planeBorder: 0xa7cae8, //
}
@ -34,7 +30,7 @@ const hoverColor = {
hover: 0x00ff00,
point: 0x00ff00, //points
line: 0x00ff00, //lines
mesh: 0x00ff00, //mesh:
mesh: 0xFAB601, //mesh:
dimension: 0x00ff00, //
plane: 0x005dff, //
}
@ -52,7 +48,7 @@ const pointMaterial = new THREE.PointsMaterial({
})
const ptObj = (n) => {
const ptObj = (n, visibility = true) => {
const ret = new THREE.Points(
new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute(n || 3, 3)
@ -61,6 +57,7 @@ const ptObj = (n) => {
);
ret.name = "p" + id++
ret.userData.type = 'point'
ret.visible = visibility
return ret
}
@ -145,6 +142,7 @@ async function awaitSelection(...criteria) {
return null
}
window.rc = raycaster
export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, hoverColor, ptObj, lineObj, awaitSelection }