Item shader with roughness

This commit is contained in:
bmathews 2025-11-14 23:59:35 -08:00
parent aaecdc95b9
commit bbc113f35a
2 changed files with 70 additions and 6 deletions

View file

@ -1,8 +1,11 @@
import { Suspense } from "react";
import { useGLTF, useTexture } from "@react-three/drei";
import { BASE_URL, shapeTextureToUrl, shapeToUrl } from "../loaders";
import { setupColor } from "../textureUtils";
import { filterGeometryByVertexGroups, getHullBoneIndices } from "../meshUtils";
import {
createAlphaAsRoughnessMaterial,
setupAlphaAsRoughnessTexture,
} from "../shaderMaterials";
import { MeshStandardMaterial } from "three";
const FALLBACK_URL = `${BASE_URL}/black.png`;
@ -21,11 +24,15 @@ export function ShapeTexture({
material?: MeshStandardMaterial;
}) {
const url = shapeTextureToUrl(material.name, FALLBACK_URL);
const texture = useTexture(url, (texture) => setupColor(texture));
material.map = texture;
material.side = 2;
material.transparent = true;
return <primitive object={material} attach="material" />;
const texture = useTexture(url, (texture) =>
setupAlphaAsRoughnessTexture(texture)
);
// Create or reuse shader material that uses alpha channel as roughness
const shaderMaterial = createAlphaAsRoughnessMaterial();
shaderMaterial.map = texture;
return <primitive object={shaderMaterial} attach="material" />;
}
export function ShapeModel({ shapeName }: { shapeName: string }) {

57
src/shaderMaterials.ts Normal file
View file

@ -0,0 +1,57 @@
import {
MeshStandardMaterial,
Texture,
RepeatWrapping,
LinearFilter,
LinearMipmapLinearFilter,
SRGBColorSpace,
} from "three";
// Shared shader modification function to avoid duplication
const alphaAsRoughnessShaderModifier = (shader: any) => {
// Modify fragment shader to extract alpha channel as roughness after map is sampled
// We need to intercept after diffuseColor is set from the map
shader.fragmentShader = shader.fragmentShader.replace(
"#include <roughness_fragment>",
`
#include <roughness_fragment>
// Override roughness with map alpha channel if map exists
#ifdef USE_MAP
roughnessFactor = texture2D(map, vMapUv).a * 1;
#endif
`
);
};
/**
* Configures a texture for use with alpha-as-roughness materials
* @param texture - The texture to configure
*/
export function setupAlphaAsRoughnessTexture(texture: Texture) {
texture.wrapS = texture.wrapT = RepeatWrapping;
texture.colorSpace = SRGBColorSpace;
texture.flipY = false;
texture.anisotropy = 16;
texture.generateMipmaps = true;
texture.minFilter = LinearMipmapLinearFilter;
texture.magFilter = LinearFilter;
texture.needsUpdate = true;
}
/**
* Creates a reusable shader-enhanced material that treats alpha as roughness
* The same material instance can be used with different textures by setting the `map` property
* @returns A pre-configured MeshStandardMaterial with the shader modifier attached
*/
export function createAlphaAsRoughnessMaterial() {
const material = new MeshStandardMaterial({
side: 2, // DoubleSide
metalness: 0.0,
roughness: 1.0,
});
// Attach shader modifier (will be applied when shader is compiled)
material.onBeforeCompile = alphaAsRoughnessShaderModifier;
return material;
}