110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
import type { MeshStandardMaterial } from "three";
|
|
|
|
import type {
|
|
AdvancedRenderingSettings,
|
|
AdvancedRenderingWhiteboxBevelSettings
|
|
} from "../document/world-settings";
|
|
|
|
const WHITEBOX_BEVEL_MIN_DETERMINANT = 1e-5;
|
|
const WHITEBOX_BEVEL_MAX_EDGE_WIDTH = 0.49;
|
|
|
|
type WhiteboxBevelCompileShader = Parameters<
|
|
MeshStandardMaterial["onBeforeCompile"]
|
|
>[0];
|
|
type WhiteboxBevelCompileRenderer = Parameters<
|
|
MeshStandardMaterial["onBeforeCompile"]
|
|
>[1];
|
|
|
|
function formatShaderFloat(value: number) {
|
|
return value.toFixed(4);
|
|
}
|
|
|
|
export function shouldApplyWhiteboxBevel(
|
|
settings: Pick<AdvancedRenderingSettings, "enabled" | "whiteboxBevel">
|
|
): boolean {
|
|
return (
|
|
settings.enabled &&
|
|
settings.whiteboxBevel.enabled &&
|
|
settings.whiteboxBevel.edgeWidth > 0 &&
|
|
settings.whiteboxBevel.normalStrength > 0
|
|
);
|
|
}
|
|
|
|
export function applyWhiteboxBevelToMaterial(
|
|
material: MeshStandardMaterial,
|
|
settings: AdvancedRenderingWhiteboxBevelSettings
|
|
) {
|
|
const edgeWidth = Math.min(
|
|
Math.max(settings.edgeWidth, 0),
|
|
WHITEBOX_BEVEL_MAX_EDGE_WIDTH
|
|
);
|
|
const normalStrength = Math.max(settings.normalStrength, 0);
|
|
const shaderKey = `whitebox-bevel:${formatShaderFloat(edgeWidth)}:${formatShaderFloat(normalStrength)}`;
|
|
|
|
material.onBeforeCompile = (
|
|
shader: WhiteboxBevelCompileShader,
|
|
_renderer: WhiteboxBevelCompileRenderer
|
|
) => {
|
|
shader.vertexShader = shader.vertexShader
|
|
.replace(
|
|
"#include <common>",
|
|
`#include <common>
|
|
attribute vec2 faceUv;
|
|
varying vec2 vWhiteboxFaceUv;`
|
|
)
|
|
.replace(
|
|
"#include <uv_vertex>",
|
|
`#include <uv_vertex>
|
|
vWhiteboxFaceUv = faceUv;`
|
|
);
|
|
|
|
shader.fragmentShader = shader.fragmentShader
|
|
.replace(
|
|
"#include <common>",
|
|
`#include <common>
|
|
varying vec2 vWhiteboxFaceUv;`
|
|
)
|
|
.replace(
|
|
"#include <normal_fragment_maps>",
|
|
`#include <normal_fragment_maps>
|
|
vec2 whiteboxFaceUv = clamp(vWhiteboxFaceUv, 0.0, 1.0);
|
|
float whiteboxBevelLeft = 1.0 - smoothstep(0.0, ${formatShaderFloat(edgeWidth)}, whiteboxFaceUv.x);
|
|
float whiteboxBevelRight = 1.0 - smoothstep(0.0, ${formatShaderFloat(edgeWidth)}, 1.0 - whiteboxFaceUv.x);
|
|
float whiteboxBevelBottom = 1.0 - smoothstep(0.0, ${formatShaderFloat(edgeWidth)}, whiteboxFaceUv.y);
|
|
float whiteboxBevelTop = 1.0 - smoothstep(0.0, ${formatShaderFloat(edgeWidth)}, 1.0 - whiteboxFaceUv.y);
|
|
float whiteboxBevelMask = max(max(whiteboxBevelLeft, whiteboxBevelRight), max(whiteboxBevelBottom, whiteboxBevelTop));
|
|
vec3 whiteboxFacePosition = -vViewPosition;
|
|
vec3 whiteboxDpdx = dFdx(whiteboxFacePosition);
|
|
vec3 whiteboxDpdy = dFdy(whiteboxFacePosition);
|
|
vec2 whiteboxDuvdx = dFdx(whiteboxFaceUv);
|
|
vec2 whiteboxDuvdy = dFdy(whiteboxFaceUv);
|
|
float whiteboxDeterminant = whiteboxDuvdx.x * whiteboxDuvdy.y - whiteboxDuvdx.y * whiteboxDuvdy.x;
|
|
|
|
if (whiteboxBevelMask > 0.0 && abs(whiteboxDeterminant) > ${WHITEBOX_BEVEL_MIN_DETERMINANT.toFixed(5)}) {
|
|
vec3 whiteboxTangent = normalize(
|
|
(whiteboxDpdx * whiteboxDuvdy.y - whiteboxDpdy * whiteboxDuvdx.y) /
|
|
whiteboxDeterminant
|
|
);
|
|
vec3 whiteboxBitangent = normalize(
|
|
(-whiteboxDpdx * whiteboxDuvdy.x + whiteboxDpdy * whiteboxDuvdx.x) /
|
|
whiteboxDeterminant
|
|
);
|
|
|
|
whiteboxTangent = normalize(whiteboxTangent - normal * dot(normal, whiteboxTangent));
|
|
whiteboxBitangent = normalize(whiteboxBitangent - normal * dot(normal, whiteboxBitangent));
|
|
|
|
vec3 whiteboxBevelDirection =
|
|
whiteboxTangent * (whiteboxBevelRight - whiteboxBevelLeft) +
|
|
whiteboxBitangent * (whiteboxBevelTop - whiteboxBevelBottom);
|
|
vec3 whiteboxBeveledNormal = normalize(
|
|
normal + whiteboxBevelDirection * ${formatShaderFloat(normalStrength)}
|
|
);
|
|
normal = normalize(mix(normal, whiteboxBeveledNormal, whiteboxBevelMask));
|
|
}`
|
|
);
|
|
};
|
|
|
|
material.customProgramCacheKey = () => shaderKey;
|
|
material.needsUpdate = true;
|
|
}
|