Improve WebGL leather material

This commit is contained in:
2026-06-06 03:00:07 +02:00
parent f634500121
commit 13f8b60e20
+53 -26
View File
@@ -175,40 +175,44 @@ const materials = {
color: 0x25130b,
map: leatherTextures.color,
normalMap: leatherTextures.normal,
normalScale: new THREE.Vector2(0.055, 0.055),
roughness: 0.72,
normalScale: new THREE.Vector2(0.07, 0.07),
roughnessMap: leatherTextures.roughness,
roughness: 0.78,
metalness: 0.02,
envMapIntensity: 0.08,
envMapIntensity: 0.1,
side: THREE.DoubleSide
}),
hingeLeather: new THREE.MeshStandardMaterial({
color: 0x32180c,
map: leatherTextures.color,
normalMap: leatherTextures.normal,
normalScale: new THREE.Vector2(0.048, 0.048),
roughness: 0.78,
normalScale: new THREE.Vector2(0.062, 0.062),
roughnessMap: leatherTextures.roughness,
roughness: 0.82,
metalness: 0.015,
envMapIntensity: 0.06,
envMapIntensity: 0.08,
side: THREE.DoubleSide
}),
spineBaseLeather: new THREE.MeshStandardMaterial({
color: 0x2a1209,
map: leatherTextures.color,
normalMap: leatherTextures.normal,
normalScale: new THREE.Vector2(0.042, 0.042),
roughness: 0.82,
normalScale: new THREE.Vector2(0.055, 0.055),
roughnessMap: leatherTextures.roughness,
roughness: 0.86,
metalness: 0.01,
envMapIntensity: 0.04,
envMapIntensity: 0.06,
side: THREE.DoubleSide
}),
coverEdge: new THREE.MeshStandardMaterial({
color: 0x5b351b,
map: leatherTextures.color,
normalMap: leatherTextures.normal,
normalScale: new THREE.Vector2(0.052, 0.052),
roughness: 0.76,
normalScale: new THREE.Vector2(0.068, 0.068),
roughnessMap: leatherTextures.roughness,
roughness: 0.8,
metalness: 0.015,
envMapIntensity: 0.05,
envMapIntensity: 0.07,
side: THREE.DoubleSide
}),
pageBlock: new THREE.MeshStandardMaterial({
@@ -252,6 +256,9 @@ const materials = {
}),
spineCloth: new THREE.MeshStandardMaterial({
color: 0x8e1d18,
normalMap: leatherTextures.normal,
normalScale: new THREE.Vector2(0.04, 0.04),
roughnessMap: leatherTextures.roughness,
roughness: 0.82,
metalness: 0,
envMapIntensity: 0.08,
@@ -1840,22 +1847,31 @@ function createLeatherTextures() {
const size = 1024;
const colorCanvas = document.createElement('canvas');
const normalCanvas = document.createElement('canvas');
const roughnessCanvas = document.createElement('canvas');
colorCanvas.width = size;
colorCanvas.height = size;
normalCanvas.width = size;
normalCanvas.height = size;
roughnessCanvas.width = size;
roughnessCanvas.height = size;
const colorContext = colorCanvas.getContext('2d');
const normalContext = normalCanvas.getContext('2d');
const roughnessContext = roughnessCanvas.getContext('2d');
const colorImage = colorContext.createImageData(size, size);
const normalImage = normalContext.createImageData(size, size);
const roughnessImage = roughnessContext.createImageData(size, size);
const heightAt = (x, y) => {
const nx = x / size;
const ny = y / size;
const longGrain = Math.sin((nx * 18 + Math.sin(ny * 18.8495559215) * 0.24) * 6.28318530718);
const crossGrain = Math.sin((ny * 42 + Math.sin(nx * 12.5663706144) * 0.16) * 6.28318530718);
const poreA = Math.sin((nx * 91 + ny * 37) * 6.28318530718);
const poreB = Math.sin((nx * 47 - ny * 83) * 6.28318530718);
return longGrain * 0.34 + crossGrain * 0.22 + poreA * poreB * 0.16;
const longGrain = Math.sin((nx * 24 + Math.sin(ny * 31.4159265359) * 0.18) * 6.28318530718);
const secondaryGrain = Math.sin((nx * 63 + ny * 9 + Math.sin(ny * 50.2654824574) * 0.1) * 6.28318530718);
const crossGrain = Math.sin((ny * 39 + Math.sin(nx * 18.8495559215) * 0.12) * 6.28318530718);
const poreA = Math.sin((nx * 137 + ny * 71) * 6.28318530718);
const poreB = Math.sin((nx * 97 - ny * 113) * 6.28318530718);
const pebble = Math.sin((nx * 181 + Math.sin(ny * 25.1327412287) * 0.22) * 6.28318530718) *
Math.sin((ny * 167 + Math.sin(nx * 37.6991118431) * 0.18) * 6.28318530718);
const pit = Math.max(0, 0.58 - Math.abs(poreA * poreB));
return longGrain * 0.22 + secondaryGrain * 0.16 + crossGrain * 0.1 + pebble * 0.18 - pit * 0.24;
};
for (let y = 0; y < size; y += 1) {
@@ -1863,34 +1879,44 @@ function createLeatherTextures() {
const wrappedX = (x + size) % size;
const wrappedY = (y + size) % size;
const height = heightAt(wrappedX, wrappedY);
const grain = THREE.MathUtils.clamp(0.54 + height * 0.22, 0, 1);
const warm = 0.82 + 0.18 * Math.sin((x * 0.07 + y * 0.013));
const grain = THREE.MathUtils.clamp(0.58 + height * 0.24, 0, 1);
const warm = 0.86 + 0.1 * Math.sin((x * 0.045 + y * 0.011)) + 0.04 * Math.sin((x * 0.009 - y * 0.031));
const index = (y * size + x) * 4;
colorImage.data[index] = Math.round(132 * grain * warm);
colorImage.data[index + 1] = Math.round(66 * grain * warm);
colorImage.data[index + 2] = Math.round(29 * grain);
colorImage.data[index] = Math.round(118 * grain * warm);
colorImage.data[index + 1] = Math.round(54 * grain * warm);
colorImage.data[index + 2] = Math.round(22 * grain);
colorImage.data[index + 3] = 255;
const hLeft = heightAt((x - 1 + size) % size, wrappedY);
const hRight = heightAt((x + 1) % size, wrappedY);
const hDown = heightAt(wrappedX, (y - 1 + size) % size);
const hUp = heightAt(wrappedX, (y + 1) % size);
const normal = new THREE.Vector3((hLeft - hRight) * 2.8, (hDown - hUp) * 2.8, 1).normalize();
const normal = new THREE.Vector3((hLeft - hRight) * 4.1, (hDown - hUp) * 4.1, 1).normalize();
normalImage.data[index] = Math.round((normal.x * 0.5 + 0.5) * 255);
normalImage.data[index + 1] = Math.round((normal.y * 0.5 + 0.5) * 255);
normalImage.data[index + 2] = Math.round((normal.z * 0.5 + 0.5) * 255);
normalImage.data[index + 3] = 255;
const fiberContrast = Math.abs(hLeft - hRight) + Math.abs(hDown - hUp);
const roughness = THREE.MathUtils.clamp(0.76 + height * 0.1 + fiberContrast * 1.4, 0.5, 0.96);
const roughnessByte = Math.round(roughness * 255);
roughnessImage.data[index] = roughnessByte;
roughnessImage.data[index + 1] = roughnessByte;
roughnessImage.data[index + 2] = roughnessByte;
roughnessImage.data[index + 3] = 255;
}
}
colorContext.putImageData(colorImage, 0, 0);
normalContext.putImageData(normalImage, 0, 0);
roughnessContext.putImageData(roughnessImage, 0, 0);
const colorTexture = new THREE.CanvasTexture(colorCanvas);
const normalTexture = new THREE.CanvasTexture(normalCanvas);
[colorTexture, normalTexture].forEach((texture) => {
const roughnessTexture = new THREE.CanvasTexture(roughnessCanvas);
[colorTexture, normalTexture, roughnessTexture].forEach((texture) => {
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2.5, 1.6);
texture.repeat.set(3.6, 2.2);
texture.anisotropy = maxTextureAnisotropy;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
@@ -1898,7 +1924,8 @@ function createLeatherTextures() {
});
colorTexture.colorSpace = THREE.SRGBColorSpace;
normalTexture.colorSpace = THREE.NoColorSpace;
return { color: colorTexture, normal: normalTexture };
roughnessTexture.colorSpace = THREE.NoColorSpace;
return { color: colorTexture, normal: normalTexture, roughness: roughnessTexture };
}
function createRoomReflectionTexture() {