diff --git a/src/components/tools/networked-drawing.js b/src/components/tools/networked-drawing.js index 7ff84444dde720d2bd6831ef031621e012b28478..71e31c58fc8bc99776f65c05673a984bfc56cb81 100644 --- a/src/components/tools/networked-drawing.js +++ b/src/components/tools/networked-drawing.js @@ -3,55 +3,172 @@ * Networked Drawing * @component networked-drawing */ + +import SharedBufferGeometryManager from "../../vendor/sharedbuffergeometrymanager"; + AFRAME.registerComponent("networked-drawing", { - schema: {}, + schema: { + drawPoints: { default: [] }, + segments: { default: 8 }, + radius: { default: 0.02 } + }, init() { - this.points = []; - - var sampleClosedSpline = new THREE.CatmullRomCurve3([ - new THREE.Vector3(0, -40, -40), - new THREE.Vector3(0, 40, -40), - new THREE.Vector3(0, 140, -40), - new THREE.Vector3(0, 40, 40), - new THREE.Vector3(0, -40, 40) - ]); - - var params = { - scale: 0.02, - extrusionSegments: 100, - radiusSegments: 3, - closed: true, - animationView: false, - lookAhead: false, - cameraHelper: false + const material = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, color: 0xff0000 }); + + this.sharedBufferGeometryManager = new SharedBufferGeometryManager(); + this.sharedBufferGeometryManager.addSharedBuffer(0, material, THREE.TriangleStripDrawMode); + + this.lastSegments = []; + this.currentSegments = []; + for (var x = 0; x < this.data.segments; x++) { + this.lastSegments[x] = new THREE.Vector3(); + this.currentSegments[x] = new THREE.Vector3(); + } + + this.sharedBuffer = this.sharedBufferGeometryManager.getSharedBuffer(0); + this.drawing = this.sharedBuffer.getDrawing(); + let sceneEl = document.querySelector("a-scene"); + this.scene = sceneEl.object3D; + this.scene.add(this.drawing); + + this.lastPoint = new THREE.Vector3(); + this.lastPointSet = false; + this.initialized = false; + }, + + getLastPoint() { + return this.lastPoint; + }, + + startDraw: (() => { + const normal = new THREE.Vector3(); + return function(position, direction) { + this.addPoint(position, direction); + this.getNormal(position); + this.drawStart(normal, direction); + }; + })(), + + endDraw: (() => { + const endPoint = new THREE.Vector3(); + const direction = new THREE.Vector3(); + return function(position, direction) { + //add the final point and cap + this.addPoint(position, direction); + direction.copy(direction).multiplyScalar(this.data.radius); + endPoint.copy(position).add(direction); + this.drawCap(endPoint, this.currentSegments); + + //reset + this.sharedBuffer.restartPrimitive(); + this.lastPointSet = false; + this.lastSegmentsSet = false; + this.timeSinceLastDraw = 0; }; + })(), + + //add a "cap" to the start or end of a drawing + drawCap(point, segments) { + let j = 0; + for (let i = 0; i < this.data.segments * 2 - 1; i++) { + if ((i - 1) % 3 === 0) { + this.addVertex(point); + } else { + this.addVertex(segments[j % this.data.segments]); + j++; + } + } + this.sharedBuffer.update(); + }, + + //calculate the segments for a given point + addSegments(segmentsList, point, forward, up) { + const angleIncrement = Math.PI * 2 / this.data.segments; + for (let i = 0; i < this.data.segments; i++) { + const segment = segmentsList[i]; - var geometry = new THREE.TubeBufferGeometry( - sampleClosedSpline, - params.extrusionSegments, - 2, - params.radiusSegments, - params.closed - ); - - var wireframeMaterial = new THREE.MeshBasicMaterial({ - color: 0x000000, - opacity: 0.3, - wireframe: true, - transparent: true - }); - var material = new THREE.MeshLambertMaterial({ color: 0xff00ff }); - var mesh = new THREE.Mesh(geometry, material); - - var wireframe = new THREE.Mesh(geometry, wireframeMaterial); - mesh.add(wireframe); - mesh.scale.set(params.scale, params.scale, params.scale); - - this.el.object3D.add(mesh); + this.rotatePointAroundAxis(segment, point, forward, up, angleIncrement * i, this.data.radius); + } }, - play() {}, + addVertex(point) { + this.initialized = true; + this.sharedBuffer.addVertex(point.x, point.y, point.z); + }, + + //get lastSegments, draw the start cap + drawStart: (() => { + const startPoint = new THREE.Vector3(); + const inverseDirection = new THREE.Vector3(); + return function(normal, direction) { + this.addSegments(this.lastSegments, this.lastPoint, direction, normal); + + inverseDirection + .copy(direction) + .negate() + .multiplyScalar(this.data.radius); + startPoint.copy(this.lastPoint).add(inverseDirection); + + //add the first vertex of the lastSegments if this drawing has already been initialized + if (this.initialized) { + this.addVertex(this.lastSegments[0]); + } + + this.drawCap(startPoint, this.lastSegments); + + this.sharedBuffer.restartPrimitive(); + this.addVertex(this.lastSegments[0]); + }; + })(), + + //helper function to get normal of direction of drawing cross direction to camera + getNormal: (() => { + const directionToCamera = new THREE.Vector3(); + return function(normal, position, direction) { + if (this.data.camera) { + directionToCamera.subVectors(position, this.data.camera.object3D.position).normalize(); + normal.crossVectors(direction, directionToCamera); + } else { + normal.copy(this.el.object3D.up); + } + }; + })(), - pause() {} + addPoint: (() => { + const normal = new THREE.Vector3(); + return function(position, direction) { + if (this.lastPointSet) { + this.getNormal(normal, position); + + this.addSegments(this.currentSegments, position, direction, normal); + + //draw the triangle strip + for (let j = 0; j <= this.data.segments; j++) { + this.addVertex(this.lastSegments[j % this.data.segments]); + this.addVertex(this.currentSegments[j % this.data.segments]); + } + + //update the drawing + this.sharedBuffer.update(); + + //copy the currentSegments to lastSegments + for (var j = 0; j < this.data.segments; j++) { + this.lastSegments[j].copy(this.currentSegments[j]); + } + } + + this.lastPoint.copy(position); + this.lastPointSet = true; + }; + })(), + + rotatePointAroundAxis: (() => { + const calculatedDirection = new THREE.Vector3(); + return function(out, point, axis, up, angle, radius) { + calculatedDirection.copy(up); + calculatedDirection.applyAxisAngle(axis, angle); + out.copy(point).add(calculatedDirection.normalize().multiplyScalar(radius)); + }; + })() }); diff --git a/src/components/tools/pen.js b/src/components/tools/pen.js index ac9e57fb18d4ccdb381ed2c4ce49e9a31c88255a..a62981f2479a4ec2201025b933578a04feb99af9 100644 --- a/src/components/tools/pen.js +++ b/src/components/tools/pen.js @@ -5,29 +5,19 @@ const EPS = 10e-6; * @component pen */ -import SharedBufferGeometryManager from "../../vendor/sharedbuffergeometrymanager"; - AFRAME.registerComponent("pen", { schema: { - drawPoints: { default: [] }, drawFrequency: { default: 100 }, minDistanceBetweenPoints: { default: 0.05 }, defaultDirection: { default: { x: 1, y: 0, z: 0 } }, - segments: { default: 8 }, - radius: { default: 0.02 }, - debug: { default: false }, - camera: { type: "selector" } + camera: { type: "selector" }, + drawing: { type: "selector" } }, init() { this.onMouseDown = this.onMouseDown.bind(this); this.onMouseUp = this.onMouseUp.bind(this); - const material = new THREE.MeshBasicMaterial({ side: THREE.DoubleSide, color: 0xff0000 }); - - this.sharedBufferGeometryManager = new SharedBufferGeometryManager(); - this.sharedBufferGeometryManager.addSharedBuffer(0, material, THREE.TriangleStripDrawMode); - this.isDrawing = false; this.timeSinceLastDraw = 0; @@ -36,27 +26,13 @@ AFRAME.registerComponent("pen", { this.direction = new THREE.Vector3(); this.direction.copy(this.data.defaultDirection); - this.lastPoint = new THREE.Vector3(); - this.lastPointSet = false; - this.initialized = false; - - this.lastSegments = []; - this.currentSegments = []; - for (var x = 0; x < this.data.segments; x++) { - this.lastSegments[x] = new THREE.Vector3(); - this.currentSegments[x] = new THREE.Vector3(); - } + this.handleDrawingInitialized = this.handleDrawingInitialized.bind(this); - this.sharedBuffer = this.sharedBufferGeometryManager.getSharedBuffer(0); - this.drawing = this.sharedBuffer.getDrawing(); - let sceneEl = document.querySelector("a-scene"); - this.scene = sceneEl.object3D; - this.scene.add(this.drawing); + this.data.drawing.addEventListener("componentinitialized", this.handleDrawingInitialized); + }, - if (this.data.debug) { - this.debugGeometry = new THREE.SphereGeometry(0.005, 16, 16); - this.debugMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); - } + remove() { + this.data.drawing.removeEventListener("componentinitialized", this.handleDrawingInitialized); }, play() { @@ -71,174 +47,43 @@ AFRAME.registerComponent("pen", { tick(t, dt) { const currentPosition = this.el.object3D.position; + const drawing = this.currentDrawing; - if (currentPosition.distanceToSquared(this.lastPosition) > EPS) { - this.direction.subVectors(currentPosition, this.lastPoint).normalize(); + if (drawing && currentPosition.distanceToSquared(this.lastPosition) > EPS) { + this.direction.subVectors(currentPosition, drawing.getLastPoint()).normalize(); } this.lastPosition.copy(currentPosition); - if (this.isDrawing) { + if (drawing && this.isDrawing) { const time = this.timeSinceLastDraw + dt; if ( time >= this.data.drawFrequency && - this.lastPoint.distanceTo(currentPosition) >= this.data.minDistanceBetweenPoints + drawing.getLastPoint().distanceTo(currentPosition) >= this.data.minDistanceBetweenPoints ) { - this.addPoint(currentPosition); + drawing.addPoint(currentPosition, this.direction); } this.timeSinceLastDraw = time % this.data.drawFrequency; } }, + handleDrawingInitialized(e) { + if (e.detail.name === "networked-drawing") { + this.currentDrawing = this.data.drawing.components["networked-drawing"]; + } + }, + onMouseDown(e) { - if (e.button === 0) { + if (this.currentDrawing && e.button === 0) { this.isDrawing = true; - this.startDraw(); + this.currentDrawing.startDraw(this.el.object3D.position, this.direction); } }, onMouseUp(e) { - if (e.button === 0) { + if (this.currentDrawing && e.button === 0) { this.isDrawing = false; - this.endDraw(); + this.currentDrawing.endDraw(this.el.object3D.position, this.direction); } - }, - - startDraw: (() => { - const normal = new THREE.Vector3(); - return function() { - this.addPoint(this.el.object3D.position); - this.getNormal(normal, this.el.object3D.position); - this.drawStart(normal); - }; - })(), - - endDraw: (() => { - const endPoint = new THREE.Vector3(); - const direction = new THREE.Vector3(); - return function() { - //add the final point and cap - this.addPoint(this.el.object3D.position); - direction.copy(this.direction).multiplyScalar(this.data.radius); - endPoint.copy(this.el.object3D.position).add(direction); - this.drawCap(endPoint, this.currentSegments); - - //reset - this.sharedBuffer.restartPrimitive(); - this.lastPointSet = false; - this.lastSegmentsSet = false; - this.timeSinceLastDraw = 0; - // this.direction.copy(this.data.defaultDirection); - }; - })(), - - //add a "cap" to the start or end of a drawing - drawCap(point, segments) { - let j = 0; - for (let i = 0; i < this.data.segments * 2 - 1; i++) { - if ((i - 1) % 3 === 0) { - this.addVertex(point); - } else { - this.addVertex(segments[j % this.data.segments]); - j++; - } - } - this.sharedBuffer.update(); - }, - - //calculate the segments for a given point - addSegments(segmentsList, point, forward, up) { - const angleIncrement = Math.PI * 2 / this.data.segments; - for (let i = 0; i < this.data.segments; i++) { - const segment = segmentsList[i]; - - this.rotatePointAroundAxis(segment, point, forward, up, angleIncrement * i, this.data.radius); - } - }, - - addVertex(point) { - this.initialized = true; - this.sharedBuffer.addVertex(point.x, point.y, point.z); - - if (this.data.debug) { - const sphere = new THREE.Mesh(this.debugGeometry, this.debugMaterial); - this.scene.add(sphere); - sphere.position.copy(point); - } - }, - - //get lastSegments, draw the start cap - drawStart: (() => { - const startPoint = new THREE.Vector3(); - const inverseDirection = new THREE.Vector3(); - return function(normal) { - this.addSegments(this.lastSegments, this.lastPoint, this.direction, normal); - - inverseDirection - .copy(this.direction) - .negate() - .multiplyScalar(this.data.radius); - startPoint.copy(this.lastPoint).add(inverseDirection); - - //add the first vertex of the lastSegments if this drawing has already been initialized - if (this.initialized) { - this.addVertex(this.lastSegments[0]); - } - - this.drawCap(startPoint, this.lastSegments); - - this.sharedBuffer.restartPrimitive(); - this.addVertex(this.lastSegments[0]); - }; - })(), - - //helper function to get normal of direction of drawing cross direction to camera - getNormal: (() => { - const directionToCamera = new THREE.Vector3(); - return function(normal, position) { - if (this.data.camera) { - directionToCamera.subVectors(position, this.data.camera.object3D.position).normalize(); - normal.crossVectors(this.direction, directionToCamera); - } else { - normal.copy(this.el.object3D.up); - } - }; - })(), - - addPoint: (() => { - const normal = new THREE.Vector3(); - return function(position) { - if (this.lastPointSet) { - this.getNormal(normal, position); - - this.addSegments(this.currentSegments, position, this.direction, normal); - - //draw the triangle strip - for (let j = 0; j <= this.data.segments; j++) { - this.addVertex(this.lastSegments[j % this.data.segments]); - this.addVertex(this.currentSegments[j % this.data.segments]); - } - - //update the drawing - this.sharedBuffer.update(); - - //copy the currentSegments to lastSegments - for (var j = 0; j < this.data.segments; j++) { - this.lastSegments[j].copy(this.currentSegments[j]); - } - } - - this.lastPoint.copy(position); - this.lastPointSet = true; - }; - })(), - - rotatePointAroundAxis: (() => { - const calculatedDirection = new THREE.Vector3(); - return function(out, point, axis, up, angle, radius) { - calculatedDirection.copy(up); - calculatedDirection.applyAxisAngle(axis, angle); - out.copy(point).add(calculatedDirection.normalize().multiplyScalar(radius)); - }; - })() + } }); diff --git a/src/hub.html b/src/hub.html index bd31d164c9362fbcf4e6e98bf6d4bb66b042290d..3e6ee536d3ff75bc99c3f47a0eee2327bb24a498 100644 --- a/src/hub.html +++ b/src/hub.html @@ -231,7 +231,7 @@ segments-height="9" segments-width="9" event-repeater="events: raycaster-intersection, raycaster-intersection-cleared; eventSource: #cursor-controller" - pen="camera: #player-camera" + pen="camera: #player-camera; drawing: #my-first-drawing" ></a-sphere> <!-- Player Rig --> @@ -372,10 +372,10 @@ static-body="shape: none;" ></a-entity> -<!-- <a-entity - position="0 2 0" + <a-entity + id="my-first-drawing" networked-drawing - ></a-entity> --> + ></a-entity> </a-scene> <div id="ui-root"></div> diff --git a/src/hub.js b/src/hub.js index 4a3cf673e67524cdb3bb9ea2ab4620f63933fa56..38b26d245dd32124ac35e02d946b6b8f80d8c327 100644 --- a/src/hub.js +++ b/src/hub.js @@ -128,7 +128,7 @@ import { getAvailableVREntryTypes, VR_DEVICE_AVAILABILITY } from "./utils/vr-cap import ConcurrentLoadDetector from "./utils/concurrent-load-detector.js"; import "./components/tools/pen"; -// import "./components/tools/networked-drawing"; +import "./components/tools/networked-drawing"; function qsTruthy(param) { const val = qs[param]; diff --git a/src/network-schemas.js b/src/network-schemas.js index 04275d491d43f9221626cd1060614e0f5c7a2d93..b23859cc3de91ef401d6629a89ccd478ad674ceb 100644 --- a/src/network-schemas.js +++ b/src/network-schemas.js @@ -86,7 +86,8 @@ function registerNetworkSchemas() { component: "rotation", requiresNetworkUpdate: rotationRequiresUpdate }, - "scale" + "scale", + "networked-drawing" ] }); }