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

Three.js自定义FlattenedSphere仍致模型悬浮,求解决方案

解决Three.js(React Three Fiber)中模型悬浮与环境球地面贴合问题

核心问题排查

你的代码存在几个关键问题导致模型悬浮效果未解决:

  1. 未在场景中渲染模型组件(Model/Model2),无法观察贴合效果
  2. 自定义FlattenedSphere的位置未对齐到地面基准平面
  3. 使用meshBasicMaterial不支持光照和阴影交互,地面视觉上不真实
  4. 接触阴影(ContactShadows)位置未匹配地面高度

分步解决方案

1. 修正场景组件,添加模型并对齐地面

在场景中加入模型组件,同时调整模型位置使其底部贴合地面:

import {
  Environment,
  OrbitControls,
  useGLTF,
  ContactShadows,
  useTexture,
} from '@react-three/drei';
import { Perf } from 'r3f-perf';
import { useEffect } from 'react';
import React, { useRef } from 'react';
import { useControls } from 'leva';
import * as THREE from 'three';
import { Model } from './Car';
import { Model2 } from './StockCar';

export const Scene = () => {
  const { camera } = useThree();

  useEffect(() => {
    camera.position.set(-18, 6, 6);
    camera.lookAt(0, 0, -10);
  }, [camera]);

  const { envMapIntensity, envMapHeight, envMapRadius, envMapScale } =
    useControls('environment map', {
      envMapIntensity: { value: 7, min: 0, max: 12 },
      envMapHeight: { value: 9, min: 0, max: 100 },
      envMapRadius: { value: 28, min: 0, max: 1000 },
      envMapScale: { value: 140, min: 0, max: 1000 },
    });

  const { z, y, x } = useControls('car poss', {
    z: { value: 0, min: -10, max: 10 },
    y: { value: 0, min: -10, max: 10 },
    x: { value: 0, min: -10, max: 10 },
  });

  const envTexture = useTexture('/32.jpg');
  const groundHeight = 10; // 统一地面高度变量

  if (envTexture) {
    envTexture.mapping = THREE.EquirectangularReflectionMapping;
  }

  return (
    <>
      <Perf position="top-left" />
      <directionalLight
        castShadow
        position={[0, 8, 0]}
        shadow-mapSize={[1024, 1024]}
        intensity={1.2}
      >
        <orthographicCamera attach="shadow-camera" args={[-10, 10, 10, -10]} />
      </directionalLight>

      <FlattenedSphere height={groundHeight} envTexture={envTexture} />

      {/* 添加模型并调整y轴位置,使其贴合地面 */}
      <Model position={[x, y + groundHeight, z]} castShadow receiveShadow />

      <OrbitControls
        enableDamping
        dampingFactor={0.05}
        rotateSpeed={0.6}
        target={[0, groundHeight, 0]} // 控制器目标对齐地面高度
        minDistance={1}
        maxDistance={3000}
        maxPolarAngle={Math.PI}
        global={false}
        cursor={false}
        snap={false}
      />

      {/* 调整接触阴影位置到地面 */}
      <ContactShadows
        position={[0, groundHeight - 0.1, 0]}
        opacity={0.6}
        scale={16}
        blur={1}
        far={10}
      />

      <axesHelper args={[5]} />
    </>
  );
};

2. 优化FlattenedSphere组件

调整位置并替换为支持光照的材质,开启阴影接收:

const FlattenedSphere = ({ height, envTexture }) => {
  const sphereRef = useRef(null);

  useEffect(() => {
    if (sphereRef.current) {
      sphereRef.current.geometry = getSize(height);
    }
  }, [height]);

  return (
    <mesh 
      ref={sphereRef} 
      scale={[1, 1, 1]}
      position={[0, height, 0]} // 将球面底部对齐到y=0基准面
      receiveShadow
    >
      {/* 使用MeshStandardMaterial实现真实光照和环境映射 */}
      <meshStandardMaterial 
        map={envTexture} 
        side={THREE.BackSide} 
        envMap={envTexture}
        envMapIntensity={0.5}
        roughness={0.3}
        metalness={0.1}
      />
    </mesh>
  );
};

3. 优化地面几何计算

确保地面顶点完全压平,避免视觉缝隙:

const getSize = (height) => {
  const geoSphere = new THREE.SphereGeometry(50, 32, 32);
  const pos = geoSphere.getAttribute('position');
  const tmp = new THREE.Vector3();

  for (let i = 0; i < pos.count; ++i) {
    tmp.fromBufferAttribute(pos, i);
    if (tmp.y < 0) {
      const y1 = (-height * 3) / 2;
      let f = tmp.y < y1 ? -height / tmp.y : 1 - (tmp.y * tmp.y) / (3 * y1 * y1);
      tmp.multiplyScalar(f);
      // 强制底部顶点贴合目标高度,消除缝隙
      if (tmp.y < -height + 0.1) tmp.y = -height;
      tmp.toArray(pos.array, 3 * i);
    }
  }
  pos.needsUpdate = true;
  geoSphere.computeVertexNormals(); // 重新计算法向量,保证光照正确

  return geoSphere;
};

关键说明

  • 模型对齐逻辑:FlattenedSphere通过position.y=height将底部对齐到y=0平面,因此模型需要将y轴位置加上groundHeight,确保底部贴合地面。若模型自身原点不在底部,需额外调整偏移量。
  • 材质选择:meshBasicMaterial不响应光照,改用meshStandardMaterial可实现环境球与模型的真实光影交互。
  • 阴影配置:给模型开启castShadow和receiveShadow,方向光开启castShadow,环境球开启receiveShadow,保证阴影正确显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 03:59:54