A-Frame:将一个实体保持在另一个实体前面并面向相机
A-Frame: keep one entity in front of another and facing camera
我想定位和旋转实体(例如 A 型框架 text entity) so that it is always just in front of another (e.g. a box), i.e. the text is positioned slightly in front of the box from the point of view of the camera, facing the camera. I can use the look-at 组件以使文本面向相机,但我不知道如何定位文本。我需要一个通用解决方案,因为框的大小和位置可能不同,所以硬编码文本的位置将不起作用。
目标是在方框前面显示工具提示之类的东西(一旦我有了基本的想法,我就会做到这一点,只有当您将鼠标悬停在方框上时,文本才会出现)。
有多种方法可以做到这一点,这里有两个想法:
1。将 HTML 元素与 3D 对象对齐
This is an amazing resource which is worth checking out (as is the entire Fundamentals manual),我在下面用到了(经过简化,希望这样思路更清晰)
想法很简单:
- 获取对象的世界位置
- 将其映射到“屏幕”(x,y) 位置
- 用 css 定位一个
<p>
元素,使用上面的 x/y 值:
p {
z-index: 10;
position: absolute;
/* let us position them inside the container */
left: 0;
/* make their default position the top left of the container */
top: 0;
cursor: pointer;
/* change the cursor to a hand when over us */
font-size: large;
user-select: none;
/* don't let the text get selected */
}
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent("foo", {
schema: {text: {default: ""}},
init: function() {
// grab the div, which will contain all <p> elements
const layoutParent = document.querySelector("#overlays")
// wait until loaded
this.el.addEventListener("loaded", evt => {
const layoutEl = document.createElement("p") // create the overlay element
layoutEl.innerHTML = this.data.text // set the inner text
layoutParent.appendChild(layoutEl) // append to the parent
// keep references to use in the "tick" function
this.layoutEl = layoutEl
this.mesh = this.el.getObject3D("mesh")
})
this.tmpV = new THREE.Vector3(0,0,0); // for later use
},
tick: function() {
// ignore if there is no mesh/text yet
if (!this.mesh || !this.layoutEl) return;
const tmpV = this.tmpV;
const canvas = this.el.sceneEl.canvas
const camera = this.el.sceneEl.camera
// get the world position
this.mesh.getWorldPosition(tmpV);
// get the normalized screen coordinate of that position
tmpV.project(camera);
// convert the normalized position to CSS coordinates
const x = (tmpV.x * .5 + .5) * canvas.clientWidth;
const y = (tmpV.y * -.5 + .5) * canvas.clientHeight;
// move the elem to that position
this.layoutEl.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
}
})
</script>
<div id="overlays">
</div>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"
foo="text: some overlay"></a-box>
</a-scene>
希望评论说清楚 - 虽然你真的应该检查 manual
2。使用 3D 文本
您可以计算 box -> camera
向量,并使用它来偏移叠加文本 - 结合 lookAt
应该会得到您正在寻找的效果。
相同想法的更简单方法是:
- 创建一个虚拟装备,它将使用
look-at
跟随相机
- 在钻机中放置一个
a-text
,将其 z 偏移框边界球体半径。
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script>
AFRAME.registerComponent("spherical-tooltip", {
schema: {
text: {
default: ""
}
},
init: function() {
this.el.addEventListener("loaded", evt => {
const mesh = this.el.getObject3D("mesh")
// the timeout is an ugly hack,
// the bounding sphere isn't set yet
setTimeout(evt => {
const bsphere = mesh.geometry.boundingSphere
// the main rig
const rig = document.createElement("a-entity");
rig.setAttribute("look-at", "[camera]")
this.el.appendChild(rig)
// setup the text, and offset the position
const tooltip = document.createElement("a-text");
tooltip.setAttribute("color", "black")
tooltip.setAttribute("value", this.data.text)
tooltip.setAttribute("align", "center")
tooltip.setAttribute("position", {x: 0, y: 0, z: bsphere.radius})
rig.appendChild(tooltip)
}, 150)
})
}
})
</script>
<a-scene>
<a-box spherical-tooltip="text: tooltip" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
</a-scene>
我想定位和旋转实体(例如 A 型框架 text entity) so that it is always just in front of another (e.g. a box), i.e. the text is positioned slightly in front of the box from the point of view of the camera, facing the camera. I can use the look-at 组件以使文本面向相机,但我不知道如何定位文本。我需要一个通用解决方案,因为框的大小和位置可能不同,所以硬编码文本的位置将不起作用。
目标是在方框前面显示工具提示之类的东西(一旦我有了基本的想法,我就会做到这一点,只有当您将鼠标悬停在方框上时,文本才会出现)。
有多种方法可以做到这一点,这里有两个想法:
1。将 HTML 元素与 3D 对象对齐
This is an amazing resource which is worth checking out (as is the entire Fundamentals manual),我在下面用到了(经过简化,希望这样思路更清晰)
想法很简单:
- 获取对象的世界位置
- 将其映射到“屏幕”(x,y) 位置
- 用 css 定位一个
<p>
元素,使用上面的 x/y 值:
p {
z-index: 10;
position: absolute;
/* let us position them inside the container */
left: 0;
/* make their default position the top left of the container */
top: 0;
cursor: pointer;
/* change the cursor to a hand when over us */
font-size: large;
user-select: none;
/* don't let the text get selected */
}
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent("foo", {
schema: {text: {default: ""}},
init: function() {
// grab the div, which will contain all <p> elements
const layoutParent = document.querySelector("#overlays")
// wait until loaded
this.el.addEventListener("loaded", evt => {
const layoutEl = document.createElement("p") // create the overlay element
layoutEl.innerHTML = this.data.text // set the inner text
layoutParent.appendChild(layoutEl) // append to the parent
// keep references to use in the "tick" function
this.layoutEl = layoutEl
this.mesh = this.el.getObject3D("mesh")
})
this.tmpV = new THREE.Vector3(0,0,0); // for later use
},
tick: function() {
// ignore if there is no mesh/text yet
if (!this.mesh || !this.layoutEl) return;
const tmpV = this.tmpV;
const canvas = this.el.sceneEl.canvas
const camera = this.el.sceneEl.camera
// get the world position
this.mesh.getWorldPosition(tmpV);
// get the normalized screen coordinate of that position
tmpV.project(camera);
// convert the normalized position to CSS coordinates
const x = (tmpV.x * .5 + .5) * canvas.clientWidth;
const y = (tmpV.y * -.5 + .5) * canvas.clientHeight;
// move the elem to that position
this.layoutEl.style.transform = `translate(-50%, -50%) translate(${x}px,${y}px)`;
}
})
</script>
<div id="overlays">
</div>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"
foo="text: some overlay"></a-box>
</a-scene>
希望评论说清楚 - 虽然你真的应该检查 manual
2。使用 3D 文本
您可以计算 box -> camera
向量,并使用它来偏移叠加文本 - 结合 lookAt
应该会得到您正在寻找的效果。
相同想法的更简单方法是:
- 创建一个虚拟装备,它将使用
look-at
跟随相机
- 在钻机中放置一个
a-text
,将其 z 偏移框边界球体半径。
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script>
AFRAME.registerComponent("spherical-tooltip", {
schema: {
text: {
default: ""
}
},
init: function() {
this.el.addEventListener("loaded", evt => {
const mesh = this.el.getObject3D("mesh")
// the timeout is an ugly hack,
// the bounding sphere isn't set yet
setTimeout(evt => {
const bsphere = mesh.geometry.boundingSphere
// the main rig
const rig = document.createElement("a-entity");
rig.setAttribute("look-at", "[camera]")
this.el.appendChild(rig)
// setup the text, and offset the position
const tooltip = document.createElement("a-text");
tooltip.setAttribute("color", "black")
tooltip.setAttribute("value", this.data.text)
tooltip.setAttribute("align", "center")
tooltip.setAttribute("position", {x: 0, y: 0, z: bsphere.radius})
rig.appendChild(tooltip)
}, 150)
})
}
})
</script>
<a-scene>
<a-box spherical-tooltip="text: tooltip" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
</a-scene>