Добавьте карту нормалей в ShaderMaterial
Я пытаюсь добавить несколько текстур на один и тот же объект в Three.js. У меня есть 3D-футболка и следующие элементы в формате .png для текстур футболки:
Перед, спинка и рукава футболки:
Горловина для футболки:
И карта нормалей, которая даст складки ткани:
Я использую этот код, чтобы добавить первые два изображения в качестве текстур к моему объекту, чтобы применить изображения спереди, сзади и рукавов, а также изображение шеи к моему материалу.
const loader = new THREE.TextureLoader();
function initObject() {
var texture1 = loader.load( 'img/ak-jersey-no-neck.png' );
var texture2 = loader.load( 'img/ak-only-neck.png' );
var pitchMaterialParams = {
uniforms: THREE.UniformsUtils.merge([{
texture1: null,
texture2: null,
}]),
vertexShader:
`
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader:
`
precision mediump float;
uniform sampler2D texture1;
uniform sampler2D texture2;
varying vec2 vUv;
void main() {
vec4 t1 = texture2D( texture1, vUv );
vec4 t2 = texture2D( texture2, vUv );
gl_FragColor = vec4(mix(t1.rgb, t2.rgb, t2.a), 1.0);
}
`
};
var material = new THREE.ShaderMaterial(pitchMaterialParams);
material.uniforms.texture1.value = texture1;
material.uniforms.texture2.value = texture2;
const objLoader = new OBJLoader();
objLoader.load('object.obj', (object) => {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
scene.add(object)
// console.log(object);
},
// called when loading is in progresses
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
(error) => {
console.log('An error happened');
console.log(error);
}
);
}
initObject();
С помощью этого кода две текстуры правильно применяются к моему объекту.
Я попытался добавить третью с картой нормалей, но она не смешивается правильно:
const loader = new THREE.TextureLoader();
const normalTexture = new THREE.TextureLoader().load('img/228180-NormalMap.png')
function initObject() {
var texture1 = loader.load( 'img/ak-jersey-no-neck.png' );
var texture2 = loader.load( 'img/ak-only-neck.png' );
var pitchMaterialParams = {
uniforms: THREE.UniformsUtils.merge([{
texture1: null,
texture2: null,
normalMap: null,
}]),
vertexShader:
`
varying vec2 vUv;
void main()
{
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader:
`
precision mediump float;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform sampler2D normalMap;
varying vec2 vUv;
void main() {
vec4 t1 = texture2D( texture1, vUv );
vec4 t2 = texture2D( texture2, vUv );
vec4 t3 = texture2D( normalMap, vUv );
gl_FragColor = vec4(mix(t1.rgb, t2.rgb, t3.rgb), 1.0);
}
`
};
var material = new THREE.ShaderMaterial(pitchMaterialParams);
material.uniforms.texture1.value = texture1;
material.uniforms.texture2.value = texture2;
material.uniforms.normalMap.value = normalTexture;
// material.normalMap = normalTexture;
const objLoader = new OBJLoader();
objLoader.load('object.obj', (object) => {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
scene.add(object)
// console.log(object);
},
// called when loading is in progresses
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
(error) => {
console.log('An error happened');
console.log(error);
}
);
}
initObject();
В результате получилось просто сочетание трех текстур:
Я хотел бы применить normalMap так же, как он был применен к MeshStandardMaterial, поэтому я получаю такой результат, где на футболке видны складки:
Есть ли способ объединить изображение normalMap с другими текстурами в моем ShaderMaterial, чтобы оно смешивалось, как и normalMap?