From 1a602c5f582abc060939c7710a1040f9383033ca Mon Sep 17 00:00:00 2001 From: howard Date: Mon, 29 Mar 2021 22:13:13 -0700 Subject: [PATCH] working 3d hover --- src/Renderer.js | 71 ++--------- src/app.jsx | 43 +++++-- src/index.js | 11 +- src/mouseEvents.js | 120 ++++++++++++++++++ src/sketcher/Sketcher.js | 30 +++-- .../{pickEvents.js => sketchMouseEvents.js} | 2 +- 6 files changed, 198 insertions(+), 79 deletions(-) create mode 100644 src/mouseEvents.js rename src/sketcher/{pickEvents.js => sketchMouseEvents.js} (97%) diff --git a/src/Renderer.js b/src/Renderer.js index 8491ad8..a815b54 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,6 +1,6 @@ - + import * as THREE from '../node_modules/three/src/Three'; // import { OrbitControls } from './utils/OrbitControls' import { TrackballControls } from './utils/trackball' @@ -8,9 +8,17 @@ import { Sketcher } from './sketcher/Sketcher' import Stats from './utils/stats.module.js'; import { add3DPoint } from './datums' -import {extrude} from './sketcher/extrude' +import { extrude } from './sketcher/extrude' +import { onHover } from './mouseEvents'; +// class Scene extends THREE.Scene { + + +// constructor() { + +// } +// } export function Renderer(store) { this.store = store @@ -29,7 +37,7 @@ export function Renderer(store) { // this.scene.background = new THREE.Color(0xffffff); const helpersGroup = new THREE.Group(); - helpersGroup.name= "helpersGroup" + helpersGroup.name = "helpersGroup" this.scene.add(helpersGroup); const axesHelper = new THREE.AxesHelper(5); helpersGroup.add(axesHelper); @@ -46,8 +54,6 @@ export function Renderer(store) { controls.target.set(0, 0, 0); controls.update() - - const color = 0xFFFFFF; const intensity = 1; const light1 = new THREE.DirectionalLight(color, intensity); @@ -61,54 +67,6 @@ export function Renderer(store) { this.scene.add(ambient); - - - // this.defaultPlanes = [ - // new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), - // new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), - // new THREE.Plane(new THREE.Vector3(1, 0, 0), 0), - // ] - - // this.defaultPlanes.forEach(pl => { - // const helper = new THREE.PlaneHelper(pl, 10, 0xffffff) - // this.scene.add(helper); - // }) - - - - - - - - - const unsubscribe = store.subscribe(handleChange.bind(this)) - - let state; - function handleChange() { - let prevState = state - state = store.getState() - - // if (prevState.sketches.length < state.sketches.length) { - - - // } - - // if (state.toggle) { - // window.addEventListener('keydown', this.sketcher.onKeyPress) - // canvas.addEventListener('pointerdown', this.sketcher.onPick) - // canvas.addEventListener('pointermove', this.sketcher.onHover) - // canvas.removeEventListener('pointerdown', this.add3DPoint) - // } else { - // window.removeEventListener('keydown', this.sketcher.onKeyPress) - // canvas.removeEventListener('pointerdown', this.sketcher.onPick) - // canvas.removeEventListener('pointermove', this.sketcher.onHover) - // canvas.addEventListener('pointerdown', this.add3DPoint) - // } - - } - - - this.hovered = [] this.selected = new Set() @@ -116,7 +74,8 @@ export function Renderer(store) { this.resizeCanvas = resizeCanvas.bind(this) this.addSketch = addSketch.bind(this) this.extrude = extrude.bind(this) - // this.waitPoint = waitPoint.bind(this) + + this.onHover = onHover.bind(this); controls.addEventListener('change', this.render); controls.addEventListener('start', this.render); @@ -169,12 +128,10 @@ async function addSketch() { window.sketcher = sketcher this.render() - this.store.dispatch({ type: 'rx-sketch', obj:sketcher }) + this.store.dispatch({ type: 'rx-sketch', obj: sketcher }) } - - function getPoint(e, camera) { const mouse = new THREE.Vector2( (e.clientX / window.innerWidth) * 2 - 1, diff --git a/src/app.jsx b/src/app.jsx index 4986660..2eb1e27 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import './app.scss' import { Provider, useDispatch, useSelector } from 'react-redux' @@ -12,25 +12,52 @@ export const Root = ({ store }) => ( ); + + +function treeId2Obj(id) { + return renderInst.scene.getObjectById(parseInt(id.slice(1))) +} + const App = () => { const dispatch = useDispatch() const treeEntries = useSelector(state => state.treeEntries) + const activeSketch = useSelector(state => state.activeSketch) + + // const [state, setState] = useState('x') + // useEffect(()=>{ + // console.log('hereeee') + // },[state]) + + useEffect(() => { + if (!activeSketch) { + renderInst.canvas.addEventListener('pointermove', renderInst.onHover) + return () => renderInst.canvas.removeEventListener('pointermove', renderInst.onHover) + } + }, [activeSketch]) return <>
- - - - + {activeSketch ? + : + + } + + {/* */}
{treeEntries.allIds.map((entId, idx) => (
{ - renderInst.extrude(treeEntries.byId[entId]) - }} + onClick={() => { + if (activeSketch) { + treeId2Obj(activeSketch).deactivate() + } + treeId2Obj(entId).activate() + } + } >{entId}
))}
diff --git a/src/index.js b/src/index.js index caa06bc..9260e71 100644 --- a/src/index.js +++ b/src/index.js @@ -21,7 +21,14 @@ function reducer(state = {}, action) { byId: { ...state.treeEntries.byId, [id]: action.obj }, allIds: [...state.treeEntries.allIds, id] }, - env: id + } + case 'set-active-sketch': + return { + ...state, activeSketch:'s'+action.sketch.id + } + case 'exit-sketch': + return { + ...state, activeSketch:'' } case 'rx-extrusion': id = 'e' + action.mesh.id @@ -36,8 +43,6 @@ function reducer(state = {}, action) { ['s' + action.sketch.id]: id } } - case 'incsk': - return { ...state, id: _sketchID++ } default: return state } diff --git a/src/mouseEvents.js b/src/mouseEvents.js new file mode 100644 index 0000000..d1ae6dd --- /dev/null +++ b/src/mouseEvents.js @@ -0,0 +1,120 @@ +import * as THREE from 'three/src/Three'; +import {raycaster} from './utils/static'; + +export function onHover(e) { + if (this.mode || e.buttons) return + raycaster.setFromCamera( + new THREE.Vector2( + (e.clientX / window.innerWidth) * 2 - 1, + - (e.clientY / window.innerHeight) * 2 + 1 + ), + this.camera + ); + + const hoverPts = raycaster.intersectObjects(this.scene.children) + + + let idx = [] + if (hoverPts.length) { + + let minDist = Infinity; + for (let i = 0; i < hoverPts.length; i++) { + if (!hoverPts[i].distanceToRay) continue; + if (hoverPts[i].distanceToRay < minDist) { + minDist = hoverPts[i].distanceToRay + idx = [i] + } else if (hoverPts[i].distanceToRay == minDist) { + idx.push(i) + } + } + if (!idx.length) idx.push(0) + } + + if (idx.length) { + if (hoverPts[idx[0]].object != this.hovered[0]) { + + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.hovered[x] + if (obj && !this.selected.has(obj)) { + obj.material.color.set(0x555555) + } + } + this.hovered = [] + + for (let x = 0; x < idx.length; x++) { + const i = idx[x] + hoverPts[i].object.material.color.set(0x00ff00) + this.hovered.push(hoverPts[i].object) + } + + // console.log('render1') + this.render() + } + } else { + if (this.hovered.length) { + + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.hovered[x] + if (obj && !this.selected.has(obj)) { + obj.material.color.set(0x555555) + } + } + this.hovered = [] + + // console.log('render2') + this.render() + } + } +} + + +export function onPick(e) { + if (this.mode || e.buttons != 1) return + + if (this.hovered.length) { + + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.hovered[x] + this.selected.add(obj) + } + + if (this.hovered[0].type == "Points") { + this.domElement.addEventListener('pointermove', this.onDrag); + this.domElement.addEventListener('pointerup', this.onRelease) + } + } else { + for (let obj of this.selected) { + obj.material.color.set(0x555555) + } + this.dispatchEvent({ type: 'change' }) + this.selected.clear() + } +} + +export function onDrag(e) { + const mouseLoc = this.getLocation(e); + + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.hovered[x] + this.ptsBuf.set( + mouseLoc, + this.objIdx.get(obj.id) * 3 + ) + } + + this.solve() + this.dispatchEvent({ type: 'change' }) +} + + +export function onRelease() { + this.domElement.removeEventListener('pointermove', this.onDrag) + this.domElement.removeEventListener('pointerup', this.onRelease) + + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.hovered[x] + obj.geometry.computeBoundingSphere() + } + +} + diff --git a/src/sketcher/Sketcher.js b/src/sketcher/Sketcher.js index 219ae10..299669f 100644 --- a/src/sketcher/Sketcher.js +++ b/src/sketcher/Sketcher.js @@ -3,7 +3,7 @@ import * as THREE from '../../node_modules/three/src/Three'; import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEvents' -import { onHover, onDrag, onPick, onRelease } from './pickEvents' +import { onHover, onDrag, onPick, onRelease } from './sketchMouseEvents' import { addDimension, setCoincident } from './constraintEvents' import { get3PtArc } from './sketchArc' import { extrude } from './extrude' @@ -18,6 +18,7 @@ class Sketcher extends THREE.Group { constructor(camera, domElement, store) { super() this.name = "sketch" + this.matrixAutoUpdate = false; this.camera = camera; this.domElement = domElement; this.store = store; @@ -43,7 +44,17 @@ class Sketcher extends THREE.Group { this.c_id = 0; this.constraintsBuf = new Float32Array(this.max_constraints * 6).fill(NaN) + this.bindHandlers() + + this.selected = new Set() + this.hovered = [] + this.mode = "" + this.subsequent = false; + } + + + bindHandlers() { this.drawOnClick1 = drawOnClick1.bind(this); this.drawPreClick2 = drawPreClick2.bind(this); this.drawOnClick2 = drawOnClick2.bind(this); @@ -54,21 +65,21 @@ class Sketcher extends THREE.Group { this.onRelease = onRelease.bind(this); this.onKeyPress = this.onKeyPress.bind(this); - - this.matrixAutoUpdate = false; - this.selected = new Set() - this.hovered = [] - this.mode = "" - this.subsequent = false; } - - activate() { window.addEventListener('keydown', this.onKeyPress) this.domElement.addEventListener('pointerdown', this.onPick) this.domElement.addEventListener('pointermove', this.onHover) + this.store.dispatch({ type: 'set-active-sketch', sketch: this }) + } + + deactivate() { + window.removeEventListener('keydown', this.onKeyPress) + this.domElement.removeEventListener('pointerdown', this.onPick) + this.domElement.removeEventListener('pointermove', this.onHover) + this.store.dispatch({ type: 'exit-sketch' }) } @@ -224,7 +235,6 @@ class Sketcher extends THREE.Group { } - updatePointsBuffer(startingIdx = 0) { for (let i = startingIdx; i < this.children.length; i++) { const obj = this.children[i] diff --git a/src/sketcher/pickEvents.js b/src/sketcher/sketchMouseEvents.js similarity index 97% rename from src/sketcher/pickEvents.js rename to src/sketcher/sketchMouseEvents.js index 3c7c669..97d4dff 100644 --- a/src/sketcher/pickEvents.js +++ b/src/sketcher/sketchMouseEvents.js @@ -1,4 +1,4 @@ -import * as THREE from '../../node_modules/three/src/Three'; +import * as THREE from 'three/src/Three'; import {raycaster} from '../utils/static'; export function onHover(e) {