-
-
Notifications
You must be signed in to change notification settings - Fork 134
PhysicalMaterial: Add Heightmap support using Parallax Occlusion Mapping (POM) #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
PhysicalMaterial: Add Heightmap support using Parallax Occlusion Mapping (POM) #569
Conversation
…calMaterial Implement height-based displacement for PhysicalMaterial using Parallax Occlusion Mapping with secant refinement. Features include: - First pass = linear layer computation, second pass = secant refinement to blend layers - Distance-based LOD with smooth fade to flat UVs at configurable range - Automatic normal derivation from height gradient when no normal map Parameters: - height_texture: Texture map for height (white=raised, 50% gray=surface, black=lowered) - height_scale: Depth of height texture - height_quality: (VeryLow to VeryHigh) which controls layer count, smoothing, and render distance Performance optimizations: - Short-circuit to not apply POM to distant surfaces - Layer count scales with height_scale (depth) - pre-computated - Layer count and refinement scales with distance - #ifdef to elimate dead code paths - Use textureLod to avoid implicit LOD calculation overhead - Guards against division-by-zero
…hields/three-d into pom-to-physical-material
PhysicalMaterialBase = 0x8020 had bit 5 already set in its value. When the height texture flag (also bit 5) was OR'd onto this base, it had no effect since the bit was already 1. This caused materials with and without height textures to get the same shader ID, leading to shader cache collisions where non-height materials received height-enabled shaders.
| HeightQuality::Low => (8, 0, 8.0, 25.0), | ||
| HeightQuality::Medium => (8, 2, 10.0, 50.0), | ||
| HeightQuality::High => (12, 3, 15.0, 50.0), | ||
| HeightQuality::VeryHigh => (16, 4, 15.0, 50.0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These levels can be tuned further, this is just what made sense for me experimentally in basic manual testing.
(Rather than "Quality" we may wish to expose the underlying raw params to users, but many of the Tier-1 rendering engines like Unreal just use "Quality")
| PrefilterMaterial = 0x8080, | ||
| PhysicalMaterialBase = 0x8040, // To 0x807F (6 bits: albedo, metallic_roughness, occlusion, normal, emissive, height) | ||
| DeferredPhysicalMaterialBase = 0x8080, // To 0x80BF (6 bits: albedo, metallic_roughness, occlusion, normal, emissive, alpha_cutout) | ||
| PrefilterMaterial = 0x80C0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shift of bits is needed to accommodate the heightmap. I'm not sure the actual performance impact of going from 5 to 6 bits on PhysicalMaterial, but if this is a regression then we could make my code here a new material (POMPhysicalMaterial) instead.
|
@asny any feedback would be appreciated! 🙇♂️ Please try |
Ideas for future PR:
This PR implements height-based displacement for PhysicalMaterial using Parallax Occlusion Mapping with secant refinement. I'd be happy to add this as POMPhysicalMaterial (or ParallaxPhysicalMaterial) if you prefer, but I think there's no harm to add it just to PhysicalMaterial b/c without a heightmap the performance should be basically the same.
These pictures are flat wall meshes with textures that have a texture with a height map and normal map.
You can see how the bricks stick-out at different angles, versus standard normal+AO maps.
Features:
Parameters:
Performance optimizations:
#define USE_HEIGHT_TEXTURE-- if no heightmap is supplied, then USE_HEIGHT_TEXTURE will be false and the code/performance will be identical to the state before this PR.Re:
height_quality, you tend not to see the quality difference except up close and in extreme cases, e.g. sharp metallic edges. The higher quality levels increase the number of layers (reduces "stacked pancake" effect) and the amount of secant smoothing (reduces artifacts). Bricks, concrete, and rough surfaces generally look very good on "Low" quality.