Three.js:如何向OBJ对象添加贴图以获得照片级逼真的金属材质



对于一个小项目,我想在Three.js 3D场景中为OBJ对象添加不同的贴图,以获得逼真的金属效果。不幸的是,我有一些问题。

以一种有效的方式直接在这里嵌入代码是行不通的。所以我创建了这个模板:https://codepen.io/Anna_B/pen/NWroEMP

如果在THREE.MeshStandardMaterial下添加envMapsmaproughnessMap,则材质应与此处类似。

我试着这样写:

import * as THREE from "https://threejs.org/build/three.module.js";
import {
OBJLoader
} from "https://threejs.org/examples/jsm/loaders/OBJLoader.js";
var container;
var camera, scene, renderer;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

const textureLoader = new TextureLoader();
const envMaps = (function() {
const path = '../../examples/textures/cube/SwedishRoyalCastle/';
const format = '.jpg';
const urls = [
path + 'px' + format, path + 'nx' + format,
path + 'py' + format, path + 'ny' + format,
path + 'pz' + format, path + 'nz' + format
];
const reflectionCube = cubeTextureLoader.load(urls);
reflectionCube.format = RGBFormat;
const refractionCube = cubeTextureLoader.load(urls);
refractionCube.mapping = CubeRefractionMapping;
refractionCube.format = RGBFormat;
return {
none: null,
reflection: reflectionCube,
refraction: refractionCube
};
})();

const roughnessMaps = (function() {
const bricks = textureLoader.load('../../examples/textures/brick_roughness.jpg');
bricks.wrapT = RepeatWrapping;
bricks.wrapS = RepeatWrapping;
bricks.repeat.set(9, 1);
return {
none: null,
bricks: bricks
};
})();

var object;
init();
animate();
function init() {
container = document.createElement("div");
container.className = "object";
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
2000
);
camera.position.z = 250;
// scene
scene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add(ambientLight);
var pointLight = new THREE.PointLight(0xffffff, 2);
pointLight.position.set(100, 100, 50);
camera.add(pointLight);
scene.add(camera);
// manager
function loadModel() {
object.traverse(function(child) {
//This allow us to check if the children is an instance of the Mesh constructor
if (child instanceof THREE.Mesh) {
child.material = new THREE.MeshStandardMaterial({
color: "#555",
roughness: 0.1,
metalness: 0.4,
texture: textureLoader,
envMap: envMaps,
roughnessMaps: roughnessMap
});
child.material.flatShading = false;
//Sometimes there are some vertex normals missing in the .obj files, ThreeJs will compute them
}
});
object.position.y = -90;
scene.add(object);
}
var manager = new THREE.LoadingManager(loadModel);
manager.onProgress = function(item, loaded, total) {
console.log(item, loaded, total);
};
// model
function onProgress(xhr) {
if (xhr.lengthComputable) {
var percentComplete = (xhr.loaded / xhr.total) * 100;
console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
}
}
function onError() {}
var loader = new OBJLoader(manager);
loader.load(
"https://threejs.org/examples/models/obj/female02/female02.obj",
function(obj) {
object = obj;
},
onProgress,
onError
);
//
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
document.addEventListener("mousemove", onDocumentMouseMove, false);
//
window.addEventListener("resize", onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseMove(event) {
mouseX = (event.clientX - windowHalfX) / 2;
mouseY = (event.clientY - windowHalfY) / 2;
}
//
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (-mouseY - camera.position.y) * 0.05;
camera.lookAt(scene.position);
renderer.render(scene, camera);
}

我认为有些地方完全不对劲。如果有人能帮我就太好了!我会非常感激的!!

如果您正在寻找一个ThreeJS工具来实验金属效果,请尝试。。。

https://threejs.org/examples/webgl_materials_displacementmap.html

它包括一组控件,可以轻松调整关键的网格材料参数,并立即查看影响。在使用此工具后,在您的特定示例中,我为网格材质提供了以下参数,使对象具有非常逼真的金属效果,并将对象的颜色更改为"#88f";蓝色色调。。。

THREE.MeshStandardMaterial({
color: "#88f",
metalness: 1,
roughness: 0.37,
aoMapIntensity: 1.0,
ambientIntensity: 0.42,
envMapIntensity: 2.2,
displacementScale: 2.1,
normalScale: 1
});

显然,你必须使用上述工具进行实验,才能获得你想要的特定金属效果。希望这能帮助你的努力。。。

编辑环境贴图功能取决于最终反射或折射到对象上的环境图像。代码笔示例似乎缺少这个关键元素(即THREE.CubeTextureLoader()(。根据问题中的代码,它似乎最初改编自https://threejs.org/examples/#webgl_materials_cubemap,我认为它具有所需环境地图概念的必要元素。使用ThreeJS示例作为基线,并将female02.obj模型注入场景中,我们得出…

<!DOCTYPE html>
<html lang="en">
<head>
<title>Adapted from "three.js webgl - materials - cube reflection / refraction [Walt]"</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Adapted from "cube mapping demo."<br />
Texture by <a href="http://www.humus.name/index.php?page=Textures" target="_blank" rel="noopener">Humus</a>
</div>
<script type="module">
import * as THREE from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';
import { OBJLoader } from 'https://threejs.org/examples/jsm/loaders/OBJLoader.js';
let container;
let camera, scene, renderer;
let pointLight;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.z = 2000;
//cubemap
const path = 'https://threejs.org/examples/textures/cube/SwedishRoyalCastle/';
const format = '.jpg';
const urls = [
path + 'px' + format, path + 'nx' + format,
path + 'py' + format, path + 'ny' + format,
path + 'pz' + format, path + 'nz' + format
];
const reflectionCube = new THREE.CubeTextureLoader().load( urls );
const refractionCube = new THREE.CubeTextureLoader().load( urls );
refractionCube.mapping = THREE.CubeRefractionMapping;
scene = new THREE.Scene();
scene.background = reflectionCube;
//lights
const ambient = new THREE.AmbientLight( 0xffffff );
scene.add( ambient );
pointLight = new THREE.PointLight( 0xffffff, 2 );
scene.add( pointLight );
//materials
const cubeMaterial3 = new THREE.MeshLambertMaterial( { color: 0xff6600, envMap: reflectionCube, combine: THREE.MixOperation, reflectivity: 0.3 } );
const cubeMaterial2 = new THREE.MeshLambertMaterial( { color: 0xffee00, envMap: refractionCube, refractionRatio: 0.95 } );
const cubeMaterial1 = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: reflectionCube } );
//models
const objLoader = new OBJLoader();
objLoader.setPath( 'https://threejs.org/examples/models/obj/female02/' );
objLoader.load( 'female02.obj', function ( object ) {

object.scale.multiplyScalar( 10 );
object.position.y = - 1200;
object.children.forEach( mesh => { mesh.material = cubeMaterial1 } );
scene.add( object );

let object2 = object.clone();
object2.position.x = -900;
object2.children.forEach( mesh => { mesh.material = cubeMaterial2 } );
scene.add( object2 );

let object3 = object.clone();
object3.position.x = +900;
object3.children.forEach( mesh => { mesh.material = cubeMaterial3 } );
scene.add( object3 );

} );
//renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//controls
const controls = new OrbitControls( camera, renderer.domElement );
controls.enableZoom = false;
controls.enablePan = false;
controls.minPolarAngle = Math.PI / 4;
controls.maxPolarAngle = Math.PI / 1.5;
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>

请注意,female02.obj由十几个网格组成,因此对象必须是cloned(),然后为每个单独的网格设置网格材质。

最新更新