Three.js中实现地球模型底部半球显示的定位问题求助
实现仅显示地球底部半球的解决方案
直接调整地球Y轴位置在透视相机下会因透视变形导致显示偏差,要精准只显示底部半球,推荐使用Three.js的**剪裁平面(Clipping Planes)**功能,通过平面切割模型保留下半部分。
具体修改步骤
- 定义剪裁平面:创建沿Y=0的平面,仅保留Y≤0的区域(地球底部半球)
- 配置地球材质:将剪裁平面加入材质的
clippingPlanes数组 - 开启渲染器局部剪裁:确保剪裁仅对目标模型生效
修改后的完整代码
'use client' import { useEffect, useRef } from 'react' import * as Three from 'three' const Earth3D = () => { const canvas = useRef<HTMLCanvasElement>(null) useEffect(() => { let mouse = { x: 0, y: 0 } let target = { x: 0, y: 0 } let requestAnimationFrame: number const scene = new Three.Scene() const clock = new Three.Clock() const textureLoader = new Three.TextureLoader() // 定义剪裁平面:保留Y≤0的地球底部半球 const clipPlane = new Three.Plane(new Three.Vector3(0, 1, 0), 0) /** * earth */ const earthObject = new Three.SphereGeometry(0.65, 64, 64) const earthTexture = textureLoader.load('/images/texture/earth-texture.jpg') const earthMaterial = new Three.MeshStandardMaterial({ map: earthTexture, // 添加剪裁平面配置 clippingPlanes: [clipPlane], clipShadows: true // 可选,优化阴影剪裁效果 }) const earth = new Three.Mesh(earthObject, earthMaterial) scene.add(earth) /** * light */ const whiteLight = new Three.PointLight(0xffffff, 8) whiteLight.position.set(-1, 0.5, 2) scene.add(whiteLight) /** * camera */ const camera = new Three.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100) camera.position.set(0, 0, 10) scene.add(camera) /** * renderer */ const renderer = new Three.WebGLRenderer({ canvas: canvas.current as HTMLCanvasElement, alpha: true }) renderer.setSize(window.innerWidth, window.innerHeight) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) // 开启局部剪裁支持,确保仅对配置了剪裁平面的模型生效 renderer.localClippingEnabled = true /** * window resize handler */ const resizeHandler = () => { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) } window.addEventListener('resize', resizeHandler) /** * window mouse move handler */ const mousemoveHandler = (e: MouseEvent) => { mouse.x = e.clientX - window.innerWidth / 2 mouse.y = e.clientY - window.innerHeight / 2 } window.addEventListener('mousemove', mousemoveHandler) /** * animating */ const tick = () => { if (window.innerWidth < 500) camera.position.setZ(3) else camera.position.setZ(2) target.x = mouse.x * 0.001 target.y = mouse.y * 0.001 earth.rotation.y = 0.5 * clock.getElapsedTime() earth.rotation.x += 0.025 * (target.y - earth.rotation.x) earth.rotation.y += 0.5 * (target.x - earth.rotation.y) renderer.render(scene, camera) requestAnimationFrame = window.requestAnimationFrame(tick) } tick() return () => { window.removeEventListener('resize', resizeHandler) window.removeEventListener('mousemove', mousemoveHandler) window.cancelAnimationFrame(requestAnimationFrame) } // eslint-disable-next-line react-hooks/exhaustive-deps }, []) return ( <div> <canvas ref={canvas} className="relative w-screen h-screen outline-0" /> </div> ) } export default Earth3D
额外调整说明
如果需要微调切割位置,可修改Plane的第二个参数:
- 设为
0.2:切割线上移0.2单位,显示更少的底部半球 - 设为
-0.2:切割线下移0.2单位,显示更多的底部区域
内容的提问来源于stack exchange,提问作者Rawand
相关产品推荐
相关产品推荐

