如何在react-three-fiber中实现类2D overflow-hidden的3D效果?
问题描述
我参考kprverse网站,尝试在3D模型中实现类2D的overflow-hidden效果,但使用裁剪平面(clipping plane)未能达成预期。
- 原始3D模型:

- 当前裁剪效果:

- 理想效果:仅显示红线间的模型并隐藏溢出部分,如图:

请问有更好的方法实现该效果吗?
代码示例
import * as THREE from "three"; import { useGLTF, OrbitControls, ScrollControls } from "@react-three/drei"; import React, { useRef } from "react"; import { Canvas } from "@react-three/fiber"; export const FLOOR_HEIGHT = 2.3; export const NB_FLOORS = 3; export default function TestingClipping(props) { const { nodes, materials } = useGLTF("./models/WawaOffice.glb"); const planes = useRef([ new THREE.Plane(new THREE.Vector3(-0.5, 0, 0), 1), new THREE.Plane(new THREE.Vector3(0.5, 0, 0), 1) ]); return ( <Canvas style={{ height: "100vh", width: "100vw" }} gl={{ localClippingEnabled: true }} > <ambientLight intensity={1} /> <OrbitControls enableZoom={false} enableDamping={false} /> <ScrollControls pages={3} damping={0.25}> <group scale={[1, 1, 1]}> <group {...props} dispose={null} position={[0.5, -1, -1]} rotation={[0, -Math.PI / 3, 0]} style={{ transform: "scale(0.1)" }} > <mesh geometry={nodes["01_office"].geometry}> <meshStandardMaterial {...materials["01"]} clippingPlanes={planes.current} /> </mesh> <group position={[0, 2.11, -2.23]}> <group> <mesh geometry={nodes["02_library"].geometry}> <meshStandardMaterial {...materials["02"]} clippingPlanes={planes.current} /> </mesh> </group> </group> <group position={[-1.97, 4.23, -2.2]}> <group> <mesh geometry={nodes["03_attic"].geometry}> <meshStandardMaterial {...materials["03"]} clippingPlanes={planes.current} /> </mesh> </group> </group> </group> </group> </ScrollControls> </Canvas> ); } // useGLTF.preload("./models/WawaOffice.glb");
解决方案
1. 修正裁剪平面参数
当前裁剪平面的方向和距离设置与模型空间位置不匹配,导致裁剪范围偏差,可按以下方式调整:
- 先获取模型在世界空间中的X轴范围,将平面的
constant参数(THREE.Plane的第二个参数)设为对应红线的位置值。 - 确保平面法向量方向正确:法向量指向的一侧会被裁剪,要保留中间区域,两个平面的法向量需分别指向左右外侧,示例:
const planes = useRef([ new THREE.Plane(new THREE.Vector3(1, 0, 0), 模型左侧边界X值), // 裁剪左侧外区域 new THREE.Plane(new THREE.Vector3(-1, 0, 0), -模型右侧边界X值) // 裁剪右侧外区域 ]);
2. 使用剪刀测试(ScissorTest)模拟2D裁剪
如果要完全复刻2D的overflow-hidden效果,推荐使用Three.js的剪刀测试,直接限制渲染区域在指定屏幕矩形内:
在react-three-fiber中,可通过useFrame钩子实现:
import { useFrame, useThree } from "@react-three/fiber"; export default function TestingClipping(props) { // ... 原有代码 const { gl } = useThree(); const canvas = gl.domElement; useFrame(() => { // 自定义屏幕裁剪区域,对应红线框的位置和尺寸 const clipRect = { x: 200, y: 100, width: 800, height: 600 }; // 开启剪刀测试 gl.enable(gl.SCISSOR_TEST); // 注意Three.js的坐标原点在左下角,需转换Canvas的y轴坐标 gl.scissor(clipRect.x, canvas.height - clipRect.y - clipRect.height, clipRect.width, clipRect.height); gl.viewport(clipRect.x, canvas.height - clipRect.y - clipRect.height, clipRect.width, clipRect.height); }, 1); // 设置优先级,确保在渲染前执行 // ... 模型渲染代码 }
3. 组合两种方法优化效果
如果需要同时限制3D空间范围和屏幕渲染区域,可以将裁剪平面与剪刀测试结合:先用裁剪平面过滤模型的3D溢出部分,再用剪刀测试锁定屏幕显示区域,确保最终效果完全匹配需求。
内容的提问来源于stack exchange,提问作者LY Hooi
相关产品推荐
相关产品推荐

