#javascript #reactjs #three.js #react-three-fiber
#javascript #reactjs #three.js #реакция-три волокна
Вопрос:
В настоящее время я новичок и изучаю three.js . И я использую react-three-fiber
, чтобы это произошло с помощью React, но я наткнулся на проблему. Однако модель не может получить какую-либо тень от другой модели. Я пытался использовать obj.castShadow = true
и obj.receiveShadow = true
для одного из объектов принимающей теневой модели как для родительского, так и для дочерних объектов, но это не показывает никакой разницы. Есть ли какой-либо способ отбросить тень на другую модель?
И тень .. это кажется очень грубым. Есть ли какой-нибудь способ сгладить это?
Вот моя песочница:
https://codesandbox.io/s/modest-newton-np1sw
Код:
import React, { Suspense, useMemo, useState } from "react";
import { Canvas } from "react-three-fiber";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
import { OrbitControls} from "drei";
import { Mesh } from "three";
import billboard from "../assets/models/billboard.obj";
import bridge from "../assets/models/bridge.obj";
const Model = ({ modelPath }) => {
const [obj, setObj] = useState();
useMemo(() => new OBJLoader().load(modelPath, setObj), [modelPath]);
if (obj) {
obj.castShadow = true;
obj.traverse((children) => {
if (children instanceof Mesh) {
children.castShadow = true;
}
});
}
return obj ? <primitive object={obj} /> : null;
};
const ShadowedModel = ({ modelPath }) => {
const [obj, setObj] = useState();
useMemo(() => new OBJLoader().load(modelPath, setObj), [modelPath]);
if (obj) {
obj.castShadow = true;
obj.receiveShadow = true;
obj.traverse((children) => {
if (children instanceof Mesh) {
children.castShadow = true;
children.receiveShadow = true;
}
});
}
return obj ? <primitive object={obj} /> : null;
};
const Lights = () => {
return (
<>
<ambientLight intensity={0.1} />
<spotLight
castShadow
position={[-50, 50, 20]}
intensity={0.5}
shadow-mapSize-shadowMapWidth={2048}
shadow-mapSize-shadowMapHeight={2048}
shadow-camera-left={-50}
shadow-camera-right={50}
shadow-camera-top={-50}
shadow-camera-bottom={50}
/>
<pointLight position={[10, -10, -20]} intensity={0.3} />
<pointLight position={[0, 10, 5]} intensity={0.3} />
<spotLight intensity={1} position={[0, 1000, 0]} />
</>
);
};
const Billboard = () => {
return (
<mesh
castShadow
position={[-15, 5, -35]}
scale={[0.05, 0.05, 0.05]}
rotation={[0, 20, 0]}
>
<Model modelPath={billboard} />
</mesh>
);
};
const Bridge = () => {
return (
<mesh
castShadow
receiveShadow
position={[10, -40, -80]}
// position={[-80, -40, -150]}
scale={[0.15, 0.15, 0.15]}
rotation={[0, 10.2, 0]}
>
<ShadowedModel modelPath={bridge} />
</mesh>
);
};
const Shadow = () => {
return (
<group>
<mesh
receiveShadow
rotation={[-Math.PI / 2, 0, 0]}
position={[-20, -32, -40]}
>
<planeBufferGeometry attach="geometry" args={[500, 500]} />
<meshLambertMaterial attach="material" color={"lightblue"} />
</mesh>
</group>
);
};
const MegatronModel = () => {
return (
<>
<Canvas
shadowMap
colorManagement
camera={{ position: [0, 0, 5], fov: 60 }}
>
<OrbitControls
enablePan={Boolean("Pan", true)}
enableZoom={Boolean("Zoom", true)}
enableRotate={Boolean("Rotate", true)}
/>
<Shadow />
<Suspense fallback={null}>
<Bridge />
</Suspense>
<Billboard />
<Lights />
</Canvas>
</>
);
};
export default MegatronModel;
Любая помощь будет оценена.
Большое вам спасибо.
Ответ №1:
Ваша модель действительно получает тени. Проблема в том, что у вас есть несколько PointLight
s с полной интенсивностью, которые вымывают все в белый цвет. Даже затененные области становятся белыми. Смотрите здесь, я отключил все ваши PointLight
s и сохранил только прожектор и окружающий свет, чтобы вы снова могли видеть тени:
Я рекомендую вам использовать как можно меньше источников света, чтобы сделать рендеринг менее ресурсоемким. Добавление такого количества источников света может снизить частоту кадров, перегреть ноутбуки и разрядить аккумулятор на мобильных телефонах. Для довольно реалистичной настройки освещения мне нравится использовать светильник с одной полусферой и направленным светом, как в этой демонстрации. Полушарие создает ощущение, что сверху исходит атмосферный свет, а снизу — отраженный свет земли.
Что касается пикселизированных теней, вы используете большую карту 2048×2048, но она разбросана по слишком большой области. Я вижу, что вы пытаетесь установить left, right, top, bottom
расстояния, но они применимы только к DirectionalLight, в котором используется ортогональная камера. Свойства Left, right, top и bottom не применяются к SpotLight, который использует перспективную камеру. Если вы хотите сделать Spotlight shadowmap более узким, используйте .angle
свойство.
Комментарии:
1. Большое вам спасибо! Я потратил часы, чтобы выяснить, что происходит, но оказывается, это просто глупая ошибка, которую я совершил. Думаю, мне нужно пересмотреть и узнать гораздо больше из документации. Еще раз, спасибо!