From 52a32aee359f2e32f77f0bd98597a501ad8a7cc2 Mon Sep 17 00:00:00 2001 From: Brian Peiris <brianpeiris@gmail.com> Date: Thu, 1 Nov 2018 18:07:11 -0700 Subject: [PATCH] Fix avatar hover effect. Use a sweeping gradient effect --- src/components/hover-visuals.js | 17 ++++++++++++---- src/components/hoverable-visuals.js | 16 ++++++++++++++- src/components/media-loader.js | 19 +++++++++++++----- src/components/player-info.js | 3 ++- src/hub.html | 6 ++---- src/utils/media-highlight-frag.glsl | 30 ++++++++++++++--------------- src/utils/media-utils.js | 6 +++++- 7 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/components/hover-visuals.js b/src/components/hover-visuals.js index 775f51dca..0e34b061e 100644 --- a/src/components/hover-visuals.js +++ b/src/components/hover-visuals.js @@ -4,6 +4,10 @@ * @component hover-visuals */ AFRAME.registerComponent("hover-visuals", { + schema: { + hand: { type: "string" }, + controller: { type: "selector" } + }, init: function() { // uniforms are set from the component responsible for loading the mesh. this.uniforms = null; @@ -12,15 +16,20 @@ AFRAME.registerComponent("hover-visuals", { remove() { this.interactorTransform = null; }, - tick(time) { + tick() { if (!this.uniforms) return; this.el.object3D.matrixWorld.toArray(this.interactorTransform); + const hovering = this.data.controller.components["super-hands"].state.has("hover-start"); for (const uniform of this.uniforms) { - uniform.hubs_HighlightInteractorOne.value = !!this.el.components["super-hands"].state.has("hover-start"); - uniform.hubs_InteractorOneTransform.value = this.interactorTransform; - uniform.hubs_Time.value = time; + if (this.data.hand === "left") { + uniform.hubs_HighlightInteractorOne.value = hovering; + uniform.hubs_InteractorOneTransform.value = this.interactorTransform; + } else { + uniform.hubs_HighlightInteractorTwo.value = hovering; + uniform.hubs_InteractorTwoTransform.value = this.interactorTransform; + } } } }); diff --git a/src/components/hoverable-visuals.js b/src/components/hoverable-visuals.js index 0728c95bd..9f70e7b92 100644 --- a/src/components/hoverable-visuals.js +++ b/src/components/hoverable-visuals.js @@ -8,12 +8,17 @@ AFRAME.registerComponent("hoverable-visuals", { cursorController: { type: "selector" } }, init: function() { - // uniforms are set from the component responsible for loading the mesh. + // uniforms and boundingSphere are set from the component responsible for loading the mesh. this.uniforms = null; + this.boundingSphere = new THREE.Sphere(); + this.interactorOneTransform = []; this.interactorTwoTransform = []; + this.sweepParams = []; }, remove() { + this.uniforms = null; + this.boundingBox = null; this.interactorOneTransform = null; this.interactorTwoTransform = null; }, @@ -42,7 +47,16 @@ AFRAME.registerComponent("hoverable-visuals", { interactorTwo.matrixWorld.toArray(this.interactorTwoTransform); } + if (interactorOne || interactorTwo) { + const worldY = this.el.object3D.matrixWorld.elements[13]; + const scaledRadius = this.el.object3D.scale.y * this.boundingSphere.radius; + this.sweepParams[0] = worldY - scaledRadius; + this.sweepParams[1] = worldY + scaledRadius; + } + for (const uniform of this.uniforms) { + uniform.hubs_EnableSweepingEffect.value = true; + uniform.hubs_SweepParams.value = this.sweepParams; uniform.hubs_HighlightInteractorOne.value = !!interactorOne; uniform.hubs_InteractorOneTransform.value = this.interactorOneTransform; uniform.hubs_HighlightInteractorTwo.value = !!interactorTwo; diff --git a/src/components/media-loader.js b/src/components/media-loader.js index aac091576..6545ca9f7 100644 --- a/src/components/media-loader.js +++ b/src/components/media-loader.js @@ -19,6 +19,8 @@ const fetchMaxContentIndex = url => { return fetch(url).then(r => parseInt(r.headers.get("x-max-content-index"))); }; +const boundingBox = new THREE.Box3(); + AFRAME.registerComponent("media-loader", { schema: { src: { type: "string" }, @@ -102,13 +104,19 @@ AFRAME.registerComponent("media-loader", { delete this.showLoaderTimeout; }, - onMediaLoaded() { - this.clearLoadingTimeout(); - if (this.el.components["hoverable-visuals"]) { - this.el.components["hoverable-visuals"].uniforms = injectCustomShaderChunks(this.el.object3D); + setupHoverableVisuals() { + const hoverableVisuals = this.el.components["hoverable-visuals"]; + if (hoverableVisuals) { + hoverableVisuals.uniforms = injectCustomShaderChunks(this.el.object3D); + boundingBox.setFromObject(this.el.object3DMap.mesh); + boundingBox.getBoundingSphere(hoverableVisuals.boundingSphere); } }, + onMediaLoaded() { + this.setupHoverableVisuals(); + }, + async update(oldData) { try { const { src } = this.data; @@ -174,9 +182,10 @@ AFRAME.registerComponent("media-loader", { this.el.addEventListener( "model-loaded", () => { - this.onMediaLoaded(); + this.clearLoadingTimeout(); this.hasBakedShapes = !!(this.el.body && this.el.body.shapes.length > (this.shapeAdded ? 1 : 0)); this.setShapeAndScale(this.data.resize); + this.setupHoverableVisuals(); addAnimationComponents(this.el); }, { once: true } diff --git a/src/components/player-info.js b/src/components/player-info.js index 612386b41..7c5cbd89e 100644 --- a/src/components/player-info.js +++ b/src/components/player-info.js @@ -35,8 +35,9 @@ AFRAME.registerComponent("player-info", { modelEl.setAttribute("gltf-model-plus", "src", this.data.avatarSrc); } + const uniforms = injectCustomShaderChunks(this.el.object3D); this.el.querySelectorAll("[hover-visuals]").forEach(el => { - el.components["hover-visuals"].uniforms = injectCustomShaderChunks(this.el.object3D); + el.components["hover-visuals"].uniforms = uniforms; }); } }); diff --git a/src/hub.html b/src/hub.html index 462512136..b3935f397 100644 --- a/src/hub.html +++ b/src/hub.html @@ -377,7 +377,6 @@ missOpacity: 0.1; curveShootingSpeed: 12;" haptic-feedback - hover-visuals body="type: static; shape: none;" mixin="controller-super-hands" controls-shape-offset @@ -404,7 +403,6 @@ missOpacity: 0.1; curveShootingSpeed: 12;" haptic-feedback - hover-visuals body="type: static; shape: none;" mixin="controller-super-hands" controls-shape-offset @@ -438,11 +436,11 @@ </template> <template data-name="LeftHand"> - <a-entity bone-visibility></a-entity> + <a-entity bone-visibility hover-visuals="hand: left; controller: #player-left-controller"></a-entity> </template> <template data-name="RightHand"> - <a-entity bone-visibility></a-entity> + <a-entity bone-visibility hover-visuals="hand: right; controller: #player-right-controller"></a-entity> </template> </a-entity> diff --git a/src/utils/media-highlight-frag.glsl b/src/utils/media-highlight-frag.glsl index e47db1ac0..c953d39ab 100644 --- a/src/utils/media-highlight-frag.glsl +++ b/src/utils/media-highlight-frag.glsl @@ -15,24 +15,22 @@ if (hubs_HighlightInteractorOne || hubs_HighlightInteractorTwo) { dist2 = distance(hubs_WorldPosition, ip); } + float size = hubs_SweepParams.t - hubs_SweepParams.s; + float line = mod(hubs_Time / 3000.0 * size, size * 2.0) + hubs_SweepParams.s - size / 2.0; + float ratio = 0.0; + if (hubs_EnableSweepingEffect && hubs_WorldPosition.y < line) { + // Highlight with an sweeping gradient + ratio = max(0.0, 1.0 - (line - hubs_WorldPosition.y) / size * 3.0); + } + float pulse = sin(hubs_Time / 1000.0) + 1.0; - float spacing = 0.5; - float line = spacing * pulse - spacing / 2.0; - float lineWidth= 0.01; - float mody = mod(hubs_WorldPosition.y, spacing); - - if (-lineWidth + line < mody && mody < lineWidth + line) { - // Highlight with an animated line effect - ratio = 0.5; - } else { - // Highlight with a gradient falling off with distance. - if (hubs_HighlightInteractorOne) { - ratio = -min(1.0, pow(dist1 * (9.0 + 3.0 * pulse), 3.0)) + 1.0; - } - if (hubs_HighlightInteractorTwo) { - ratio += -min(1.0, pow(dist2 * (9.0 + 3.0 * pulse), 3.0)) + 1.0; - } + // Highlight with a gradient falling off with distance. + if (hubs_HighlightInteractorOne) { + ratio += -min(1.0, pow(dist1 * (9.0 + 3.0 * pulse), 3.0)) + 1.0; + } + if (hubs_HighlightInteractorTwo) { + ratio += -min(1.0, pow(dist2 * (9.0 + 3.0 * pulse), 3.0)) + 1.0; } ratio = min(1.0, ratio); diff --git a/src/utils/media-utils.js b/src/utils/media-utils.js index c192c1110..7db272e7e 100644 --- a/src/utils/media-utils.js +++ b/src/utils/media-utils.js @@ -140,7 +140,7 @@ export const addMedia = (src, template, contentOrigin, resolve = false, resize = }; export function injectCustomShaderChunks(obj) { - const vertexRegex = /\bbegin_vertex\b/; + const vertexRegex = /\bskinning_vertex\b/; const fragRegex = /\bgl_FragColor\b/; const materialsSeen = new Set(); @@ -157,6 +157,8 @@ export function injectCustomShaderChunks(obj) { shader.uniforms.hubs_InteractorOneTransform = { value: [] }; shader.uniforms.hubs_InteractorTwoTransform = { value: [] }; shader.uniforms.hubs_InteractorTwoPos = { value: [] }; + shader.uniforms.hubs_EnableSweepingEffect = { value: false }; + shader.uniforms.hubs_SweepParams = { value: [] }; shader.uniforms.hubs_HighlightInteractorOne = { value: false }; shader.uniforms.hubs_HighlightInteractorTwo = { value: false }; shader.uniforms.hubs_Time = { value: 0 }; @@ -182,6 +184,8 @@ export function injectCustomShaderChunks(obj) { const findex = flines.findIndex(line => fragRegex.test(line)); flines.splice(findex + 1, 0, mediaHighlightFrag); flines.unshift("varying vec3 hubs_WorldPosition;"); + flines.unshift("uniform bool hubs_EnableSweepingEffect;"); + flines.unshift("uniform vec2 hubs_SweepParams;"); flines.unshift("uniform bool hubs_HighlightInteractorOne;"); flines.unshift("uniform mat4 hubs_InteractorOneTransform;"); flines.unshift("uniform bool hubs_HighlightInteractorTwo;"); -- GitLab