문제 상황
Three.js 코드를 R3F로 변환하는 중이다.
Three.js 코드는 이렇고
import * as THREE from 'three';
import {GLTFLoader} from 'GLTFLoader';
import {OrbitControls} from 'OrbitControls';
// 씬, 오브젝트, 카메라, 렌더러, 빛
const scene=new THREE.Scene();
const camera=new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
const canvas=document.getElementById('webgl');
const renderer=new THREE.WebGLRenderer({canvas:canvas});
// renderer.physicallyCorrectLights = true;
const light=new THREE.DirectionalLight("#ffffff",1);
light.position.set(0,0,13);
scene.add(light);
// 텍스쳐 로드
const textureLoader = new THREE.TextureLoader();
const wallsBaseColor = textureLoader.load('../static/img/textures/grass-seamless-texture-tileable.jpg');
const wallsNormalColor=textureLoader.load('../static/img/textures/Stylized_Grass_003_normal.jpg');
const wallsHeightColor=textureLoader.load('../static/img/textures/Stylized_Grass_003_height.png');
const wallsRoughColor=textureLoader.load('../static/img/textures/Stylized_Grass_003_roughness.jpg');
const wallsAmbientColor=textureLoader.load('../static/img/textures/Stylized_Grass_003_ambientOcclusion.jpg')
wallsBaseColor.repeat.set(8,8);
wallsBaseColor.wrapS=THREE.RepeatWrapping;
wallsBaseColor.wrapT=THREE.RepeatWrapping;
const groundBaseColor=textureLoader.load('../static/img/textures/grass-seamless-texture-tileable.jpg');
groundBaseColor.repeat.set(8,8);
groundBaseColor.wrapS=THREE.RepeatWrapping;
groundBaseColor.wrapT=THREE.RepeatWrapping;
const gltfLoader=new GLTFLoader();
// 하.. 웹브라우저 캐시 문제때문에 이전 값이 계속 로드된거였고 여기에서 삽질 엄청 함
gltfLoader.load(
'../static/img/untitled2.gltf',
(gltf)=>{
console.log("성공")
console.log(gltf.scene)
gltf.scene.traverse((child) => {
if (child.isMesh && child.material && child.material.name === 'walls') {
child.material.map = wallsBaseColor;
child.material.normalMap=wallsNormalColor;
child.material.displaceMap=wallsHeightColor;
child.material.roughnessMap=wallsRoughColor;
child.material.aoMap=wallsAmbientColor;
child.material.needsUpdate = true;
}
if(child.isMesh && child.material && child.material.name==='ground'){
child.material.map=groundBaseColor;
child.material.needsUpdate=true;
};
});
scene.add(gltf.scene)
},
(process)=>{
console.log("진행중")
console.log(process)
},
(error)=>{
console.log("에러남")
console.log(error);
}
)
const controls=new OrbitControls(camera, canvas);
controls.target.z=1;
controls.enableRotate=true;
controls.enablePan=true;
controls.enableZoom=true;
controls.enableDamping=true;
const tick=()=>{
requestAnimationFrame(tick);
controls.update();
renderer.render(scene, camera);
}
tick();
// 렌더링
renderer.setSize(window.innerWidth, window.innerHeight);
R3F 코드는 이렇다. TextureLoader대신 useTexture을 이용하여 텍스쳐 매핑을 하려고 했다.
import { useEffect } from 'react';
import { useGLTF, useTexture } from '@react-three/drei';
import { RigidBody, CuboidCollider } from '@react-three/rapier';
import { RepeatWrapping } from 'three';
const MazeModel = () => {
const { scene } = useGLTF('maze/scene.gltf');
const textures = useTexture({ map: 'maze/textures/grass-seamless-texture-tileable.jpg' });
useEffect(() => {
textures.map.repeat.set(8, 8);
textures.map.wrapS = RepeatWrapping;
textures.map.wrapT = RepeatWrapping;
scene.traverse((child) => {
if (child.isMesh && child.material) {
if (child.material.name === 'walls' || child.material.name === 'ground') {
const { material } = child;
material.map = textures.map;
material.needsUpdate = true;
}
}
});
}, [scene, textures]);
return (
<>
<RigidBody colliders="trimesh">
<primitive object={scene} />
</RigidBody>
</>
);
};
export const Floor = () => {
return (
<RigidBody type="static">
<CuboidCollider args={[10, 0, 10]}>
<mesh position={[0, 0, 0]} receiveShadow>
<boxGeometry args={[10, 0, 10]} />
<meshStandardMaterial color={'lightgray'} />
</mesh>
</CuboidCollider>
</RigidBody>
);
};
export default MazeModel;
그런데 이런 이상한 결과가 나왔다. 원래는 잔디여야하는데 세로 줄무늬 혹은 민무늬가 되어버렸다. 처음에는 gltf UV맵 때문인줄 알고 블렌더를 이용하여 UV맵을 모두 삭제했다. 그랬더니 이번엔 전체가 민무늬가 되었다. gltf 문제가 아니었다.
결론
mesh에 텍스쳐 입히기 강의를 듣고 따라한 코드라서 코드 문제가 아닐거라는 확신이 있었다. 그래서 삽질을 굉장히 오래했는데, 결국 코드 문제가 맞았다. useTexture 대신 TextureLoader을 사용하니 제대로 텍스쳐가 입혀졌다... 해결은 했으나 왜 useTexture로 하면 안되는지 이유를 못찾았다.
import { useEffect } from 'react';
import { useGLTF } from '@react-three/drei';
import { RigidBody, CuboidCollider } from '@react-three/rapier';
import { RepeatWrapping, TextureLoader } from 'three';
// const Model = ({ url, position, rotation, scale }) => {
// const { scene } = useGLTF(url, true);
// return <primitive object={scene} position={position} rotation={rotation} scale={scale} />;
// };
const MazeModel = () => {
const { scene } = useGLTF('maze/scene.gltf');
const textureLoader = new TextureLoader();
const textures = textureLoader.load('maze/textures/grass-seamless-texture-tileable.jpg');
useEffect(() => {
textures.repeat.set(8, 8);
textures.wrapS = RepeatWrapping; // 텍스처가 가로 방향으로 반복되도록 설정합니다.
textures.wrapT = RepeatWrapping; // 텍스처가 세로 방향으로 반복되도록 설정합니다.
scene.traverse((child) => {
if (child.isMesh && child.material) {
if (child.material.name === 'walls' || child.material.name === 'ground') {
const { material } = child;
material.map = textures;
material.needsUpdate = true;
}
}
});
}, [scene, textures]);
return (
<>
<RigidBody colliders="trimesh">
<primitive object={scene} />
</RigidBody>
</>
);
};
export const Floor = () => {
return (
<RigidBody type="static">
<CuboidCollider args={[10, 0, 10]}>
<mesh position={[0, 0, 0]} receiveShadow>
<boxGeometry args={[10, 0, 10]} />
<meshStandardMaterial color={'lightgray'} />
</mesh>
</CuboidCollider>
</RigidBody>
);
};
export default MazeModel;
'나도 공부한다 > R3F' 카테고리의 다른 글
파일 크기가 큰 프로젝트 최적화 (feat. GLTF 파일) (0) | 2024.04.02 |
---|