ThreeJS Highlight/Projector
ThreeJS Highlight/Projector
我如何在平面顶部的 3d 对象下添加 2d 精灵以显示我的对象是 highlighted/selected?
此外,在不平坦的地形上我该怎么做?
我附上了一张示例图片以更好地解释我的问题:
我不确定使用 sprite 是个好主意。
正如你所说的不平坦的地形,最好使用不平坦的东西。例如,带有 material 和 .alphaMap
.
的球体或圆柱体
我们需要一些东西 ring-like 来实现 selection 的效果。
假设您选择了球体,那么您可以从文件或从 canvas:
动态创建的纹理中设置其 material 的 alphaMap
// alpha texture
var canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 128;
var ctx = canvas.getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 0, 128);
gradient.addColorStop(0.35, "black");
gradient.addColorStop(0.475, "white");
gradient.addColorStop(0.525, "white");
gradient.addColorStop(0.65, "black");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 128, 128);
var alphaTexture = new THREE.Texture(canvas);
alphaTexture.needsUpdate = true;
关于.alphaMap
:
alpha 贴图是一种灰度纹理,可控制整个表面的不透明度(黑色:完全透明;白色:完全不透明)。默认为空。
仅使用纹理的颜色,如果存在则忽略 alpha 通道。对于 RGB 和 RGBA 纹理,由于在 DXT-compressed 和未压缩的 RGB 565 格式中为绿色提供了额外的精度,WebGL 渲染器将在对该纹理进行采样时使用绿色通道。 Luminance-only 和 luminance/alpha 纹理也将按预期工作。
这就是我们只有黑白照片的原因。
让我们创建一个最简单的 NPC 对象,它带有一个黄色圆环,表示我们的 NPC 是 selected:
var npc = function() {
var geom = new THREE.SphereGeometry(4, 4, 2);
geom.translate(0, 4, 0);
var mesh = new THREE.Mesh(geom, new THREE.MeshLambertMaterial({
color: Math.random() * 0xffffff
}));
// highlighter
geom.computeBoundingSphere();
var sphereGeom = new THREE.SphereGeometry(geom.boundingSphere.radius, 32, 24);
var sphereMat = new THREE.MeshBasicMaterial({
color: "yellow", // yellow ring
transparent: true, // to make our alphaMap work, we have to set this parameter to `true`
alphaMap: alphaTexture
});
var sphere = new THREE.Mesh(sphereGeom, sphereMat);
sphere.visible = false;
mesh.add(sphere);
mesh.userData.direction = new THREE.Vector3(Math.random() - 0.5, 0, Math.random() - 0.5).normalize();
mesh.userData.speed = Math.random() * 5 + 5;
mesh.position.set(
Math.random() * (worldWidth - 10) - (worldWidth - 10) * 0.5,
10,
Math.random() * (worldDepth - 10) - (worldDepth - 10) * 0.5
);
scene.add(mesh);
return mesh;
}
剩下的就没那么难了。
我们需要一组 NPC,我们将检查它们的交集
var npcs = [];
for (var i = 0; i < 10; i++) {
npcs.push(npc());
}
然后在 mousedown
事件中我们将 select 我们的 NPC(取自 interactive cubes 示例并根据我们的需要进行修改):
window.addEventListener('mousedown', onMouseDown, false);
function onMouseDown(event) {
if (event.button != 2) return;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
selector.setFromCamera( mouse, camera );
var intersects = selector.intersectObjects( npcs );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.children[0].visible = INTERSECTED.selected;
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.selected = INTERSECTED.children[0].visible;
INTERSECTED.children[0].visible = true;
}
} else {
if ( INTERSECTED ) INTERSECTED.children[0].visible = INTERSECTED.selected;
INTERSECTED = null;
}
}
jsfiddle 例子。在这里您可以使用鼠标右键 select 个对象。
我如何在平面顶部的 3d 对象下添加 2d 精灵以显示我的对象是 highlighted/selected?
此外,在不平坦的地形上我该怎么做?
我附上了一张示例图片以更好地解释我的问题:
我不确定使用 sprite 是个好主意。
正如你所说的不平坦的地形,最好使用不平坦的东西。例如,带有 material 和 .alphaMap
.
我们需要一些东西 ring-like 来实现 selection 的效果。
假设您选择了球体,那么您可以从文件或从 canvas:
动态创建的纹理中设置其 material 的alphaMap
// alpha texture
var canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 128;
var ctx = canvas.getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 0, 128);
gradient.addColorStop(0.35, "black");
gradient.addColorStop(0.475, "white");
gradient.addColorStop(0.525, "white");
gradient.addColorStop(0.65, "black");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 128, 128);
var alphaTexture = new THREE.Texture(canvas);
alphaTexture.needsUpdate = true;
关于.alphaMap
:
alpha 贴图是一种灰度纹理,可控制整个表面的不透明度(黑色:完全透明;白色:完全不透明)。默认为空。 仅使用纹理的颜色,如果存在则忽略 alpha 通道。对于 RGB 和 RGBA 纹理,由于在 DXT-compressed 和未压缩的 RGB 565 格式中为绿色提供了额外的精度,WebGL 渲染器将在对该纹理进行采样时使用绿色通道。 Luminance-only 和 luminance/alpha 纹理也将按预期工作。
这就是我们只有黑白照片的原因。
让我们创建一个最简单的 NPC 对象,它带有一个黄色圆环,表示我们的 NPC 是 selected:
var npc = function() {
var geom = new THREE.SphereGeometry(4, 4, 2);
geom.translate(0, 4, 0);
var mesh = new THREE.Mesh(geom, new THREE.MeshLambertMaterial({
color: Math.random() * 0xffffff
}));
// highlighter
geom.computeBoundingSphere();
var sphereGeom = new THREE.SphereGeometry(geom.boundingSphere.radius, 32, 24);
var sphereMat = new THREE.MeshBasicMaterial({
color: "yellow", // yellow ring
transparent: true, // to make our alphaMap work, we have to set this parameter to `true`
alphaMap: alphaTexture
});
var sphere = new THREE.Mesh(sphereGeom, sphereMat);
sphere.visible = false;
mesh.add(sphere);
mesh.userData.direction = new THREE.Vector3(Math.random() - 0.5, 0, Math.random() - 0.5).normalize();
mesh.userData.speed = Math.random() * 5 + 5;
mesh.position.set(
Math.random() * (worldWidth - 10) - (worldWidth - 10) * 0.5,
10,
Math.random() * (worldDepth - 10) - (worldDepth - 10) * 0.5
);
scene.add(mesh);
return mesh;
}
剩下的就没那么难了。 我们需要一组 NPC,我们将检查它们的交集
var npcs = [];
for (var i = 0; i < 10; i++) {
npcs.push(npc());
}
然后在 mousedown
事件中我们将 select 我们的 NPC(取自 interactive cubes 示例并根据我们的需要进行修改):
window.addEventListener('mousedown', onMouseDown, false);
function onMouseDown(event) {
if (event.button != 2) return;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
selector.setFromCamera( mouse, camera );
var intersects = selector.intersectObjects( npcs );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.children[0].visible = INTERSECTED.selected;
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.selected = INTERSECTED.children[0].visible;
INTERSECTED.children[0].visible = true;
}
} else {
if ( INTERSECTED ) INTERSECTED.children[0].visible = INTERSECTED.selected;
INTERSECTED = null;
}
}
jsfiddle 例子。在这里您可以使用鼠标右键 select 个对象。