You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Three.js加载Sketchfab模型出现渲染色差的问题求助

Three.js加载Sketchfab模型出现渲染色差的问题求助

我最近在尝试展示从Sketchfab下载的模型,但用Three.js渲染出来的效果和预期的差很多,想请教下问题出在哪,是模型本身的问题还是我的Three.js代码设置有问题?

预期渲染效果

This is the expected rendering

我的Three.js渲染效果

Rendering I get

想问问怎么才能达到第一张图的效果?问题是在模型上还是我的Three.js展示方式上?

以下是我的代码:

import * as THREE from 'three'; 
import { GLTFLoader } from 'https://unpkg.com/three@0.138.3/examples/jsm/loaders/GLTFLoader.js';
import { FBXLoader } from 'https://unpkg.com/three@0.138.3/examples/jsm/loaders/FBXLoader.js';
import { OrbitControls } from 'https://unpkg.com/three@0.138.3/examples/jsm/controls/OrbitControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10000 );
camera.position.set( -50, 50, 1000 );
camera.lookAt(0, 0, 0)

const renderer = new THREE.WebGLRenderer({antialias: true, logarithmicDepthBuffer: true});
renderer.setSize( window.innerWidth, window.innerHeight);

const color = 0xFFFFFF;
const intensity = 10;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-60, 60, 1060);

// 测试立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

document.getElementById("threejsbackdrop").appendChild( renderer.domElement );
const controls = new OrbitControls( camera, renderer.domElement );
controls.update();

const loader = new GLTFLoader();
loader.load('./black_hole.glb', function ( gltf ) {
    gltf.scene.receiveShadow = true;
    scene.add( gltf.scene );
},
function ( xhr ) {
    if(( xhr.loaded / xhr.total * 100 ) == 100){
        console.log("Finished Loading!")
    }
},
function ( error ) {
    console.log(error)
    console.log( 'An error happened' );
});

function animate() {
    requestAnimationFrame( animate );
    controls.update();
    renderer.render( scene, camera );
};
animate();

我的分析和解决建议

兄弟,我看了你的问题和代码,大概率是Three.js的渲染设置没跟上,不是模型的问题~ Sketchfab的预览效果是用了专业的光照环境和渲染参数的,你的代码里很多关键设置都没做,我给你梳理下问题点和修改方案:

1. 光照系统太单薄

你只用了一盏方向光,而且没有开启阴影,Sketchfab的预览通常有丰富的环境光、补光甚至HDR环境贴图,这会直接影响材质的质感和颜色表现。

2. 渲染器缺少关键设置

你没开启阴影映射、伽马校正、色调映射,这些都是让颜色和质感贴近真实预览的核心设置。

3. 相机位置太离谱

你的相机z轴在1000的位置,离模型太远了,模型在场景里可能小到几乎看不见,这也是你觉得效果不对的原因之一。

4. 测试立方体干扰

那个绿色的小立方体没啥用,建议删掉,避免干扰你观察模型。


具体修改代码

我给你调整了代码,你可以试试:

import * as THREE from 'three'; 
import { GLTFLoader } from 'https://unpkg.com/three@0.138.3/examples/jsm/loaders/GLTFLoader.js';
import { OrbitControls } from 'https://unpkg.com/three@0.138.3/examples/jsm/controls/OrbitControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10000 );
// 调整相机位置,离模型近一点,能看清细节
camera.position.set( -50, 50, 200 );
camera.lookAt(0, 0, 0)

// 渲染器关键设置:开启阴影、伽马校正、色调映射
const renderer = new THREE.WebGLRenderer({antialias: true, logarithmicDepthBuffer: true});
renderer.setSize( window.innerWidth, window.innerHeight);
// 开启阴影映射
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 柔和阴影
// 伽马校正,让颜色更准确
renderer.outputEncoding = THREE.sRGBEncoding;
// 色调映射,模拟真实曝光
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2;

// 完善光照:添加环境光+方向光,都开启阴影
// 环境补光,让暗部不那么死黑
const ambientLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.6);
scene.add(ambientLight);

// 主方向光,调整参数并开启阴影
const dirLight = new THREE.DirectionalLight(0xffffff, 1.5);
dirLight.position.set(-60, 60, 100);
dirLight.castShadow = true;
// 设置阴影相机参数,让阴影覆盖模型范围
dirLight.shadow.camera.left = -100;
dirLight.shadow.camera.right = 100;
dirLight.shadow.camera.top = 100;
dirLight.shadow.camera.bottom = -100;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
scene.add(dirLight);

document.getElementById("threejsbackdrop").appendChild( renderer.domElement );
const controls = new OrbitControls( camera, renderer.domElement );
controls.enableDamping = true; // 让镜头移动更顺滑
controls.update();

const loader = new GLTFLoader();
loader.load('./black_hole.glb', function ( gltf ) {
    // 给模型的 mesh 开启投射和接收阴影
    gltf.scene.traverse( function( child ) {
        if ( child.isMesh ) {
            child.castShadow = true;
            child.receiveShadow = true;
        }
    });
    scene.add( gltf.scene );
},
function ( xhr ) {
    if(( xhr.loaded / xhr.total * 100 ) == 100){
        console.log("Finished Loading!")
    }
},
function ( error ) {
    console.log(error)
    console.log( 'An error happened' );
});

// 监听窗口大小变化
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
});

function animate() {
    requestAnimationFrame( animate );
    controls.update();
    renderer.render( scene, camera );
};
animate();

额外优化建议

如果想更贴近Sketchfab的效果,可以加载一张HDR环境贴图作为场景的环境贴图,代码大概是这样:

// 加载HDR环境贴图
import { RGBELoader } from 'https://unpkg.com/three@0.138.3/examples/jsm/loaders/RGBELoader.js';
new RGBELoader()
    .load('你的HDR文件路径.hdr', function ( texture ) {
        texture.mapping = THREE.EquirectangularReflectionMapping;
        scene.environment = texture;
        scene.background = texture;
    });

你可以找免费的HDR贴图网站下载合适的环境贴图,效果会提升一大截~


备注:内容来源于stack exchange,提问作者user9002871

火山引擎 最新活动