You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARKIT开发问询:如何实现点击立方体面自动生成并贴合第二个立方体

当然可以实现!这在3D交互场景里是很常见的需求,核心思路是通过**射线检测(Raycasting)**识别你点击的立方体表面,再根据该面的法线和位置计算第二个立方体的放置坐标,让它刚好贴合。下面我用Three.js给你具体演示实现步骤——毕竟这是Web 3D开发最常用的框架,思路也适用于Unity、Unreal等其他引擎,只是API不同而已。

实现步骤详解

1. 先搭好基础场景

首先得有常规的3D场景基础组件:场景、相机、渲染器,还有第一个立方体。这部分是标准操作:

// 初始化核心组件
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 创建第一个立方体并加入场景
const cube1 = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshStandardMaterial({ color: 0x00ff00 })
);
scene.add(cube1);
camera.position.z = 5;

// 添加光源让立方体可见
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);

2. 实现点击面的检测逻辑

要监听鼠标点击事件,用射线检测来判断是否命中第一个立方体的某个面,关键是获取命中面的法线和点击点:

// 射线检测器和鼠标坐标转换工具
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

// 监听鼠标点击
window.addEventListener('click', (event) => {
  // 把浏览器鼠标坐标转成Three.js的标准化设备坐标
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

  // 更新射线的起点和方向
  raycaster.setFromCamera(mouse, camera);

  // 检测射线和第一个立方体的交集
  const intersects = raycaster.intersectObject(cube1);

  if (intersects.length > 0) {
    // 取第一个命中的面和点击点
    const hitFace = intersects[0].face;
    const hitPoint = intersects[0].point;
    // 生成第二个立方体
    spawnSecondCube(hitFace, hitPoint);
  }
});

3. 计算贴合位置并生成第二个立方体

这里的核心是让第二个立方体的中心刚好在点击面的外侧,距离等于立方体边长的一半(因为立方体原点在中心),同时让它的面和点击面平行:

function spawnSecondCube(hitFace, hitPoint) {
  const cubeSize = 1; // 和第一个立方体尺寸一致,可自行修改
  const halfSize = cubeSize / 2;

  // 把面的法线转换到世界坐标系(应对第一个立方体有旋转/缩放的情况)
  const faceNormal = hitFace.normal.clone();
  faceNormal.transformDirection(cube1.matrixWorld);

  // 计算第二个立方体的位置:点击点 + 法线方向 * 半边长
  const cube2Position = hitPoint.clone().add(faceNormal.multiplyScalar(halfSize));

  // 创建第二个立方体
  const cube2 = new THREE.Mesh(
    new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize),
    new THREE.MeshStandardMaterial({ color: 0xff0000 })
  );
  cube2.position.copy(cube2Position);

  // 让第二个立方体的面和点击面贴合:根据法线计算旋转角度
  const defaultForward = new THREE.Vector3(0, 0, 1);
  const quaternion = new THREE.Quaternion().setFromUnitVectors(defaultForward, faceNormal);
  cube2.quaternion.copy(quaternion);

  // 加入场景
  scene.add(cube2);
}

4. 启动渲染循环

最后别忘了添加渲染循环,让场景持续渲染:

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}
animate();

额外说明

  • 如果你的第一个立方体有缩放或旋转,上面的代码已经通过matrixWorld处理了法线的坐标转换,完全没问题。
  • 要是你用Unity,思路类似:用Physics.Raycast检测点击,获取RaycastHit.normal,计算位置后实例化第二个立方体即可。
  • 其他3D引擎的核心逻辑都是射线检测获取面信息 → 计算贴合位置 → 生成物体,只是具体API不同。

内容的提问来源于stack exchange,提问作者Lucian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:35:12