diff --git a/src/Scene.js b/src/Scene.js index f3155ea..5d2526d 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -14,6 +14,7 @@ import { onHover, onPick } from './utils/mouseEvents'; import { _vec2, _vec3, color, awaitPts } from './utils/shared' import { Vector3 } from 'three/src/Three'; import { AxesHelper } from './utils/axes' +import { Patch } from './utils/patch' import CSG from "./utils/three-csg.js" @@ -35,15 +36,20 @@ export class Scene { this.store = store; this.canvas = document.querySelector('#c'); - this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas}); - + this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas }); const size = 1; const near = 0; const far = 100; this.camera = new THREE.OrthographicCamera(-size, size, size, -size, near, far); this.camera.zoom = 0.1; - this.camera.position.set(50, 50, 50); + const cameraDist = 50 + const xzAngle = 30 * Math.PI / 180 + this.camera.position.set( + cameraDist * Math.sin(xzAngle), + cameraDist * Math.tan(30 * Math.PI / 180), + cameraDist * Math.cos(xzAngle) + ); // const controls = new OrbitControls(camera, view1Elem); const controls = new TrackballControls(this.camera, this.canvas); @@ -52,19 +58,27 @@ export class Scene { this.obj3d = new THREE.Scene() - this.obj3d.background = new THREE.Color(0x888888); + this.obj3d.background = new THREE.Color(color.background); const helpersGroup = new THREE.Group(); helpersGroup.name = "helpersGroup"; this.obj3d.add(helpersGroup); - const axesHelper = new AxesHelper(0.4); - helpersGroup.add(axesHelper); - // console.log(color) + // const axesHelper = new AxesHelper(0.4); + // helpersGroup.add(axesHelper); + + + const patch = new Patch(0.5); + helpersGroup.add(patch); + + + + const planeGeom = new THREE.PlaneGeometry(5, 5) + const pxy = new THREE.Mesh( - new THREE.PlaneGeometry(5, 5), + planeGeom, new THREE.MeshBasicMaterial({ color: color.plane, - opacity: 0.2, + opacity: 0.05, side: THREE.DoubleSide, transparent: true, depthWrite: false, @@ -72,16 +86,22 @@ export class Scene { }) ); - pxy.name = 'd' + nid++ pxy.userData.type = 'plane' - helpersGroup.add(pxy); + + pxy.add( + new THREE.LineSegments( + new THREE.EdgesGeometry(planeGeom), + new THREE.LineBasicMaterial({ color: color.planeBorder }) + ) + ) const pyz = pxy.clone().rotateY(Math.PI / 2); pyz.material = pyz.material.clone(); - const pxz = pxy.clone().rotateX(-Math.PI / 2); pxz.material = pxz.material.clone(); + + helpersGroup.add(pxy); helpersGroup.add(pyz); helpersGroup.add(pxz); @@ -173,6 +193,20 @@ export class Scene { this.store.dispatch({ type: 'restore-state', state }) } + clearSelection() { + for (let x = 0; x < this.selected.length; x++) { + const obj = this.selected[x] + obj.material.color.set(color[obj.userData.type]) + } + for (let x = 0; x < this.hovered.length; x++) { + const obj = this.selected[x] + obj.material.color.set(color[obj.userData.type]) + } + this.obj3d.dispatchEvent({ type: 'change' }) + this.selected = [] + console.log('fireed') + } + } @@ -202,7 +236,7 @@ function render() { x = (pos.x * .5 + .5) * this.canvas.clientWidth + 10; y = (pos.y * -.5 + .5) * this.canvas.clientHeight; - + // console.log(i, ele) // ele.label.style.transform = `translate(-50%, -50%) translate(${x+20}px,${y}px)`; ele.label.style.transform = `translate(0%, -50%) translate(${x}px,${y}px)`; @@ -249,7 +283,7 @@ async function addSketch() { } - + this.clearSelection() sketch.activate() this.activeSketch = sketch diff --git a/src/app.jsx b/src/app.jsx index 51d0355..d9f175c 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -66,8 +66,9 @@ const App = () => { const [_, forceUpdate] = useReducer(x => x + 1, 0); - return
-
+ return <> +
+ {/*
*/} { btnz.map(([Icon, fcn, txt], idx) => (
{ }
-
+
{treeEntries.allIds.map((entId, idx) => ( ))}
-
+ } @@ -142,6 +143,7 @@ const TreeEntry = ({ entId }) => { onClick={() => { activeSketchId && treeEntries[activeSketchId].deactivate() entry.activate() + sc.clearSelection() sc.activeSketch = entry; }} > diff --git a/src/sketcher/Sketch.js b/src/sketcher/Sketch.js index 191cc41..ba6bbda 100644 --- a/src/sketcher/Sketch.js +++ b/src/sketcher/Sketch.js @@ -8,7 +8,7 @@ import { addDimension, setCoincident } from './constraintEvents' import { get3PtArc } from './drawArc' import { _vec2, _vec3, raycaster, awaitPts } from '../utils/shared' import { replacer, reviver } from '../utils/mapJSONReplacer' -import { AxesHelper } from '../utils/axes' +import { AxesHelper } from '../utils/sketchAxes' import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension'; @@ -48,7 +48,7 @@ class Sketch { this.constraints = new Map() this.c_id = 0; - this.obj3d.add(new THREE.Group().add(new AxesHelper(2))); + this.obj3d.add(new THREE.Group().add(new AxesHelper(0.5))); this.obj3d.add(new THREE.Group()); this.obj3d.add(new THREE.Group()); @@ -133,6 +133,7 @@ class Sketch { this.canvas.addEventListener('pointerdown', this.onPick) this.canvas.addEventListener('pointermove', this.onHover) this.store.dispatch({ type: 'set-active-sketch', sketch: this.obj3d.name }) + this.setDimLines() diff --git a/src/sketcher/threetest.js b/src/sketcher/threetest.js deleted file mode 100644 index f33d7f9..0000000 --- a/src/sketcher/threetest.js +++ /dev/null @@ -1,212 +0,0 @@ - - - attribute float size; - attribute vec3 customColor; - - varying vec3 vColor; - - void main() { - - vColor = customColor; - - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - - gl_PointSize = size * ( 300.0 / -mvPosition.z ); - - gl_Position = projectionMatrix * mvPosition; - - } - - - - - uniform vec3 color; - uniform sampler2D pointTexture; - - varying vec3 vColor; - - void main() { - - gl_FragColor = vec4( color * vColor, 1.0 ); - - gl_FragColor = gl_FragColor * texture2D( pointTexture, gl_PointCoord ); - - if ( gl_FragColor.a < ALPHATEST ) discard; - - } - - - - - - - - - import * as THREE from '../build/three.module.js'; - - import Stats from './jsm/libs/stats.module.js'; - - import { BufferGeometryUtils } from './jsm/utils/BufferGeometryUtils.js'; - - let renderer, scene, camera, stats; - - let particles; - - const PARTICLE_SIZE = 20; - - let raycaster, intersects; - let pointer, INTERSECTED; - - init(); - animate(); - - function init() { - - const container = document.getElementById( 'container' ); - - scene = new THREE.Scene(); - - camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); - camera.position.z = 250; - - // - - let boxGeometry = new THREE.BoxGeometry( 200, 200, 200, 16, 16, 16 ); - - // if normal and uv attributes are not removed, mergeVertices() can't consolidate indentical vertices with different normal/uv data - - boxGeometry.deleteAttribute( 'normal' ); - boxGeometry.deleteAttribute( 'uv' ); - - boxGeometry = BufferGeometryUtils.mergeVertices( boxGeometry ); - - // - - const positionAttribute = boxGeometry.getAttribute( 'position' ); - - const colors = []; - const sizes = []; - - const color = new THREE.Color(); - - for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - - color.setHSL( 0.01 + 0.1 * ( i / l ), 1.0, 0.5 ); - color.toArray( colors, i * 3 ); - - sizes[ i ] = PARTICLE_SIZE * 0.5; - - } - - const geometry = new THREE.BufferGeometry(); - geometry.setAttribute( 'position', positionAttribute ); - geometry.setAttribute( 'customColor', new THREE.Float32BufferAttribute( colors, 3 ) ); - geometry.setAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1 ) ); - - // - - const material = new THREE.ShaderMaterial( { - - uniforms: { - color: { value: new THREE.Color( 0xffffff ) }, - pointTexture: { value: new THREE.TextureLoader().load( 'textures/sprites/disc.png' ) } - }, - vertexShader: document.getElementById( 'vertexshader' ).textContent, - fragmentShader: document.getElementById( 'fragmentshader' ).textContent, - - alphaTest: 0.9 - - } ); - - // - - particles = new THREE.Points( geometry, material ); - scene.add( particles ); - - // - - renderer = new THREE.WebGLRenderer(); - renderer.setPixelRatio( window.devicePixelRatio ); - renderer.setSize( window.innerWidth, window.innerHeight ); - container.appendChild( renderer.domElement ); - - // - - raycaster = new THREE.Raycaster(); - pointer = new THREE.Vector2(); - - // - - stats = new Stats(); - container.appendChild( stats.dom ); - - // - - window.addEventListener( 'resize', onWindowResize ); - document.addEventListener( 'pointermove', onPointerMove ); - - } - - function onPointerMove( event ) { - - pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1; - pointer.y = - ( event.clientY / window.innerHeight ) * 2 + 1; - - } - - function onWindowResize() { - - camera.aspect = window.innerWidth / window.innerHeight; - camera.updateProjectionMatrix(); - - renderer.setSize( window.innerWidth, window.innerHeight ); - - } - - function animate() { - - requestAnimationFrame( animate ); - - render(); - stats.update(); - - } - - function render() { - - particles.rotation.x += 0.0005; - particles.rotation.y += 0.001; - - const geometry = particles.geometry; - const attributes = geometry.attributes; - - raycaster.setFromCamera( pointer, camera ); - - intersects = raycaster.intersectObject( particles ); - - if ( intersects.length > 0 ) { - - if ( INTERSECTED != intersects[ 0 ].index ) { - - attributes.size.array[ INTERSECTED ] = PARTICLE_SIZE; - - INTERSECTED = intersects[ 0 ].index; - - attributes.size.array[ INTERSECTED ] = PARTICLE_SIZE * 1.25; - attributes.size.needsUpdate = true; - - } - - } else if ( INTERSECTED !== null ) { - - attributes.size.array[ INTERSECTED ] = PARTICLE_SIZE; - attributes.size.needsUpdate = true; - INTERSECTED = null; - - } - - renderer.render( scene, camera ); - - } - - \ No newline at end of file diff --git a/src/utils/mouseEvents.js b/src/utils/mouseEvents.js index d9c52c0..39fdd81 100644 --- a/src/utils/mouseEvents.js +++ b/src/utils/mouseEvents.js @@ -1,5 +1,5 @@ import * as THREE from 'three/src/Three'; -import { raycaster, color } from './shared'; +import { raycaster, color, hoverColor } from './shared'; export function onHover(e) { if (this.mode || e.buttons) return @@ -36,24 +36,30 @@ export function onHover(e) { } else { // hoverPts = raycaster.intersectObjects(this.obj3d.children) - hoverPts = raycaster.intersectObjects(this.obj3d.children,true) + hoverPts = raycaster.intersectObjects(this.obj3d.children, true) - - // for (let i = 0; i < hoverPts.length; i++) { - // const obj = hoverPts[i].object - // if (obj.userData.type == "mesh" && obj.visible || obj.userData.type == "plane") { - // idx.push(i) - // } - // } if (hoverPts.length) { - // console.log(hoverPts) - if (!idx.length) idx.push(0) + for (let i = 0; i < hoverPts.length; i++) { + const obj = hoverPts[i].object + if (['point', 'plane'].includes(obj.userData.type)) { + idx.push(i) + break; + } + } + + if (!idx.length) { + const obj = hoverPts[0].object + if (obj.userData.type == "mesh" && obj.visible) { + idx.push(0) + } else { + idx.push(0) + } + } + } - - } @@ -72,7 +78,7 @@ export function onHover(e) { for (let x = 0; x < idx.length; x++) { const obj = hoverPts[idx[x]].object - obj.material.color.set(color.hover) + obj.material.color.set(hoverColor[obj.userData.type]) this.hovered.push(obj) } @@ -81,7 +87,6 @@ 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') diff --git a/src/utils/patch.js b/src/utils/patch.js new file mode 100644 index 0000000..26d883a --- /dev/null +++ b/src/utils/patch.js @@ -0,0 +1,40 @@ +// import { LineSegments } from '../objects/LineSegments.js'; +// import { LineBasicMaterial } from '../materials/LineBasicMaterial.js'; +// import { Float32BufferAttribute } from '../core/BufferAttribute.js'; +// import { BufferGeometry } from '../core/BufferGeometry.js'; + +import { LineSegments, MeshBasicMaterial, Float32BufferAttribute, BufferGeometry, Mesh, DoubleSide } from 'three/src/Three' + +class Patch extends Mesh { + + constructor(s = 1) { + + const positions = [ + 0.5 * s, 0, 0, + 0.3 * s, 0.08*s, 0, + 0.3 * s, -0.08*s, 0 + ]; + + const geometry = new BufferGeometry(); + geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); + + + super( + geometry, + new MeshBasicMaterial({ + color: 0x0000ff, + opacity: 0.2, + side: DoubleSide, + transparent: true, + depthWrite: false, + toneMapped: false + }) + ) + + return this; + } + +} + + +export { Patch }; diff --git a/src/utils/shared.js b/src/utils/shared.js index 666b110..62ac4c9 100644 --- a/src/utils/shared.js +++ b/src/utils/shared.js @@ -12,16 +12,30 @@ raycaster.params.Points.threshold = 0.6; const color = { - hover: 0x00ff00, + background:0xbbbbbb, lighting: 0xFFFFFF, emissive: 0x072534, + + hover: 0x00ff00, point: 0x555555, //points line: 0x555555, //lines mesh: 0x156289, //mesh: dimension: 0x891d15, // - plane: 0x891d15, // + + plane: 0xdaacac, // + planeBorder: 0xc59797, // } +const hoverColor = { + hover: 0x00ff00, + point: 0x00ff00, //points + line: 0x00ff00, //lines + mesh: 0x00ff00, //mesh: + dimension: 0x00ff00, // + plane: 0xff0000, // +} + + const lineMaterial = new THREE.LineBasicMaterial({ linewidth: 2, color: color.line, @@ -129,4 +143,4 @@ async function awaitPts(...criteria) { -export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, ptObj, lineObj, awaitPts } \ No newline at end of file +export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, hoverColor, ptObj, lineObj, awaitPts } \ No newline at end of file diff --git a/src/utils/sketchAxes.js b/src/utils/sketchAxes.js new file mode 100644 index 0000000..746cde7 --- /dev/null +++ b/src/utils/sketchAxes.js @@ -0,0 +1,34 @@ +// import { LineSegments } from '../objects/LineSegments.js'; +// import { LineBasicMaterial } from '../materials/LineBasicMaterial.js'; +// import { Float32BufferAttribute } from '../core/BufferAttribute.js'; +// import { BufferGeometry } from '../core/BufferGeometry.js'; + +import { LineSegments, LineBasicMaterial, Float32BufferAttribute, BufferGeometry } from 'three/src/Three' + +class AxesHelper extends LineSegments { + + constructor(s = 1) { + + const vertices = [ + 0, 0, 0, 0.5 * s, 0, 0, + 0.5 * s, 0, 0, 0.35 * s, 0.08*s, 0, + + 0, 0, 0, 0, s, 0, + ]; + + + const geometry = new BufferGeometry(); + geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); + + const material = new LineBasicMaterial({ color: 0xff0000, toneMapped: false }); + + super(geometry, material); + + // this.type = 'AxesHelper'; + + } + +} + + +export { AxesHelper }; diff --git a/todo.txt b/todo.txt index aea9928..a8b2933 100644 --- a/todo.txt +++ b/todo.txt @@ -1,10 +1,16 @@ fix css on design tree (a lot of work) \ clear dim on exit exit sketch / rehydrate when back or after loading \\\ done + + +- select sketch for extrusion +reattaching sketch +- need to auto hide ( consume) when new boolean created \\ +- sensible default names, like extrude 1, sketch 1, leverage react for this + + boolean flesh out refresh / replace mesh / delete mesh - - need to auto hide ( consume) when new boolean created \\ - create derived part using relationship as name \\ done - - sensible default names, like extrude 1, sketch 1, leverage react for this - hidden bodies messes up hover highlight \\ fixed - add for union and intersect - auto update @@ -17,7 +23,6 @@ fix extrusion loop find dimension to origin -reattaching sketch file save stl export