AdvancedGroundPlugin
Advanced Ground Plugin extends the BaseGroundPlugin with additional features including planar reflections and baked shadow support. It creates a configurable ground plane that can display real-time reflections and accumulate high-quality soft shadows over multiple frames, providing a professional presentation foundation for 3D models.
The AdvancedGroundPlugin builds upon the basic ground plane functionality by adding a sophisticated reflection system using render-to-texture and an advanced shadow baking system with customizable soft shadows, automatic frustum sizing, and optional alpha vignette effects for transparent grounds.
Features
- Planar Reflections: Real-time mirror-like reflections on the ground surface
- Physical/Non-Physical Modes: Toggle between accurate and artistic reflection behavior
- Baked Soft Shadows: Multi-frame shadow accumulation for smooth, realistic shadows
- Automatic Shadow Updates: Shadows update automatically when scene changes
- Customizable Shadow Light: Randomized directional light with adjustable parameters
- Auto Frustum Sizing: Shadow map frustum automatically matches ground size
- Multiple Shadow Types: Basic, PCF, PCFSoft, and VSM shadow map types
- Alpha Vignette: Fade shadows at edges for transparent ground planes
- Shadow Smoothing: Optional blur filter for even softer shadows
- Render Target Preview: Debug shadow maps and baked shadow textures
- Inherited Features: All BaseGroundPlugin features (size, position, material, etc.)
- SSR Integration: Automatically disables screen-space reflections on ground
Installation
This plugin is part of the @threepipe/webgi-plugins package:
npm install @threepipe/webgi-pluginsBasic Setup
import {ThreeViewer, GBufferPlugin, SSAAPlugin} from 'threepipe'
import {AdvancedGroundPlugin, TemporalAAPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
msaa: true,
plugins: [GBufferPlugin, SSAAPlugin, TemporalAAPlugin]
})
// Add advanced ground with planar reflections
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
ground.groundReflection = true
ground.material.roughness = 0.2
// Load model
await viewer.load('model.glb')With this setup, the scene will have a reflective ground plane with baked soft shadows, creating a professional product visualization look.
Configuration
Ground Visibility and Transform
Control basic ground plane properties (inherited from BaseGroundPlugin):
// Visibility
ground.visible = true // Show/hide ground
ground.enabled = true // Same as visible
// Size (in scene units)
ground.size = 8 // Default, 8x8 units
ground.size = 15 // Larger ground
ground.size = 0 // Hide ground
// Vertical position
ground.yOffset = 0 // Default, at model's base
ground.yOffset = -0.5 // Lower ground
ground.yOffset = 0.1 // Raised ground
// Auto-adjust to scene
ground.autoAdjustTransform = true // Default, automatically fits under model
ground.autoAdjustTransform = false // Manual positioningThe ground automatically positions itself under the scene's bounding box when autoAdjustTransform is enabled.
Planar Reflections
Enable and configure real-time reflections:
// Enable planar reflections
ground.groundReflection = true // Enable reflections
ground.groundReflection = false // Disable (default)
// Reflection mode
ground.physicalReflections = true // Physically accurate (default)
ground.physicalReflections = false // Non-physical, artistic control
// Material roughness affects reflection blur
ground.material.roughness = 0.0 // Perfect mirror
ground.material.roughness = 0.2 // Slightly blurred
ground.material.roughness = 0.5 // More diffuse
ground.material.roughness = 1.0 // No reflections visiblePlanar reflections render the scene from a mirrored camera position into a texture, which is then applied to the ground material. The physicalReflections setting determines whether reflections follow PBR rules or use more artistic blending.
Baked Shadows
Configure the advanced shadow baking system:
// Enable/disable baked shadows
ground.bakedShadows = true // Enable (default)
ground.bakedShadows = false // Disable
// Auto-update shadows when scene changes
ground.autoBakeShadows = true // Default, automatic updates
ground.autoBakeShadows = false // Manual control
// Manually trigger shadow bake (when autoBakeShadows is false)
ground.bakeShadows()
// Shadow accumulation frames
ground.shadowBaker.maxFrameNumber = 64 // Default, 64 frames
ground.shadowBaker.maxFrameNumber = 128 // Higher quality, slower
ground.shadowBaker.maxFrameNumber = 32 // Faster, less smoothBaked shadows accumulate over multiple frames with a randomized light position, creating extremely soft and realistic shadows without the typical shadow map artifacts.
Shadow Light Configuration
Customize the virtual light used for shadow baking:
const shadowBaker = ground.shadowBaker
// Light parameters (randomized per frame)
const randomParams = shadowBaker.light.randomParams
// Focus: how centered the light randomization is (0-1)
randomParams.focus = 0.5 // Default, balanced
randomParams.focus = 0.8 // More focused, harder shadows
randomParams.focus = 0.2 // Less focused, softer shadows
// Spread: randomization amount (0-1)
randomParams.spread = 0.5 // Default
randomParams.spread = 0.8 // More spread, very soft shadows
randomParams.spread = 0.2 // Less spread, sharper shadows
// Distance scale: light distance multiplier
randomParams.distanceScale = 10 // Default
randomParams.distanceScale = 20 // Farther light, softer shadows
randomParams.distanceScale = 5 // Closer light, harder shadows
// Direction: base light direction (normalized vector)
randomParams.direction.set(0.5, -1, 0.3)
randomParams.normalDirection.set(0, -1, 0)
// Shadow radius: penumbra size
shadowBaker.light.shadowParams.radius = 1 // Default
shadowBaker.light.shadowParams.radius = 3 // Softer edges
shadowBaker.light.shadowParams.radius = 0 // Sharp edges
// Shadow bias: prevents self-shadowing artifacts
shadowBaker.light.shadowParams.bias = -0.0001 // Default
shadowBaker.light.shadowParams.bias = -0.001 // More bias if artifacts appearThese parameters control the randomized light that creates soft shadows through multi-frame accumulation.
Shadow Map Type
Choose the shadow map algorithm:
import {BasicShadowMap, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap} from 'threepipe'
// Set shadow map type
ground.shadowBaker.shadowMapType = PCFSoftShadowMap // Default, best quality
ground.shadowBaker.shadowMapType = PCFShadowMap // Good quality, faster
ground.shadowBaker.shadowMapType = VSMShadowMap // Variance shadow maps
ground.shadowBaker.shadowMapType = BasicShadowMap // Fastest, hard shadows
// Smooth the final baked shadow
ground.shadowBaker.smoothShadow = true // Default, applies blur
ground.shadowBaker.smoothShadow = false // No additional smoothingPCFSoftShadowMap provides the best quality when combined with the multi-frame accumulation.
Auto Frustum Sizing
Automatically match shadow map frustum to ground size:
// Auto-size shadow frustum to ground plane
ground.autoFrustumSize = true // Default, recommended
ground.autoFrustumSize = false // Manual control
// Manual frustum size (when autoFrustumSize is false)
ground.shadowBaker.light.shadowParams.frustumSize = 10
ground.shadowBaker.light.updateShadowParams()
ground.bakeShadows() // Rebake with new frustumAuto frustum sizing ensures the shadow map covers exactly the ground plane area, maximizing shadow map resolution efficiency.
Alpha Vignette
Fade shadows at edges for transparent/transmissive grounds:
// First make ground transparent or transmissive
ground.material.transparent = true
ground.material.opacity = 0.5
// or
ground.material.transmission = 0.8
// Enable alpha vignette (fades shadow at edges)
ground.shadowBaker.alphaVignette = true // Enable fade
ground.shadowBaker.alphaVignette = false // No fade (default)
// Vignette axis
ground.shadowBaker.alphaVignetteAxis = 'xy' // Fade on both axes (default)
ground.shadowBaker.alphaVignetteAxis = 'x' // Fade only horizontally
ground.shadowBaker.alphaVignetteAxis = 'y' // Fade only verticallyAlpha vignette creates a smooth fade at the ground edges, perfect for transparent ground planes that should blend into the background.
Shadow Map Mode
Choose how shadows are applied to the material:
// Shadow application mode
ground.shadowBaker.groundMapMode = 'aoMap' // Default, as AO
ground.shadowBaker.groundMapMode = 'map' // As diffuse map
ground.shadowBaker.groundMapMode = 'alphaMap' // As alpha mapDifferent modes affect how the baked shadow interacts with the material's other properties.
Material Configuration
Access and configure the ground material:
const material = ground.material
// Material is a PhysicalMaterial
material.color.set('#ffffff') // Ground color
material.roughness = 0.8 // Surface roughness
material.metalness = 0.5 // Metallic amount
material.transmission = 0 // Transparency
material.opacity = 1.0 // Opacity
// Add textures
material.map = await viewer.load('ground_color.jpg')
material.normalMap = await viewer.load('ground_normal.jpg')
material.roughnessMap = await viewer.load('ground_roughness.jpg')
material.setDirty()The ground uses a standard PhysicalMaterial, so all PBR properties are available.
Advanced Usage
Studio Setup with Reflections
Create a professional studio environment:
import {PCFSoftShadowMap} from 'threepipe'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
msaa: true,
rgbm: true,
plugins: [GBufferPlugin, SSAAPlugin, TemporalAAPlugin]
})
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Enable reflections with low roughness
ground.groundReflection = true
ground.physicalReflections = true
ground.material.roughness = 0.15
ground.material.metalness = 0.2
// Configure soft shadows
ground.bakedShadows = true
ground.shadowBaker.shadowMapType = PCFSoftShadowMap
ground.shadowBaker.maxFrameNumber = 128 // High quality
ground.shadowBaker.light.randomParams.focus = 0.6
ground.shadowBaker.light.randomParams.spread = 0.7
// Load environment and model
await viewer.setEnvironmentMap('studio.hdr', {setBackground: false})
await viewer.load('product.glb')Transparent Ground with Vignette
Create a ground that fades to transparent at edges:
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Make ground transparent
ground.material.transparent = true
ground.material.opacity = 0.7
ground.material.roughness = 0.3
// Enable shadow vignette
ground.bakedShadows = true
ground.shadowBaker.alphaVignette = true
ground.shadowBaker.alphaVignetteAxis = 'xy'
// Soft shadow settings
ground.shadowBaker.maxFrameNumber = 64
ground.shadowBaker.smoothShadow = trueManual Shadow Control
Take manual control of shadow baking:
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Disable auto-baking
ground.autoBakeShadows = false
// Configure shadow parameters
ground.shadowBaker.maxFrameNumber = 96
ground.shadowBaker.light.randomParams.focus = 0.7
ground.shadowBaker.light.randomParams.spread = 0.6
// Manually trigger bake when ready
function rebakeShadows() {
ground.bakeShadows()
}
// Bake after scene changes
viewer.addEventListener('sceneUpdate', () => {
setTimeout(rebakeShadows, 100) // Delay to ensure scene is settled
})Debug Shadow Maps
Preview shadow render targets:
import {RenderTargetPreviewPlugin} from 'threepipe'
const rtPreview = viewer.addPluginSync(new RenderTargetPreviewPlugin())
// Preview shadow map
rtPreview.addTarget(
() => ground.shadowBaker?.light.shadow.map,
'shadow',
false, // Not screen space
false, // Not depth
true, // Transform
(s) => s + ' = vec4(' + s + '.r/2.);' // Adjust visualization
)
// Preview baked shadow texture
rtPreview.addTarget(
() => ground.shadowBaker?.target,
'baked shadow',
false,
false,
true
)Non-Physical Reflections
Use artistic reflection control:
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
ground.groundReflection = true
ground.physicalReflections = false // Non-physical mode
// In non-physical mode, you have more artistic control
ground.material.roughness = 0.5 // Still affects reflection visibility
ground.material.opacity = 0.8 // Can blend reflections
// Perfect for artistic/stylized presentationsCustom Geometry
Replace the ground plane with custom geometry:
import {CircleGeometry} from 'threepipe'
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Create circular ground
const circleGeometry = new CircleGeometry(5, 64)
ground.setGeometry(circleGeometry)
// Enable reflections and shadows
ground.groundReflection = true
ground.bakedShadows = trueCamera Limits
Prevent camera from going below ground:
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Limit camera to stay above ground
ground.limitCameraAboveGround = true
// Works with OrbitControls3
const camera = viewer.scene.mainCamera
// Camera will not be able to move below the ground planeDepth and Tonemap Control
Configure rendering behavior:
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Render ground to depth buffer (for post-processing)
ground.renderToDepth = true // Default
ground.renderToDepth = false // Exclude from depth
// Apply tonemapping to ground
ground.tonemapGround = true // Default, tonemap with scene
ground.tonemapGround = false // No tonemapping (keeps HDR values)
// Requires GBufferPlugin to be activeIntegration with Other Plugins
With SSReflectionPlugin
The AdvancedGroundPlugin automatically manages SSReflectionPlugin:
import {SSReflectionPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
plugins: [GBufferPlugin, SSAAPlugin, SSReflectionPlugin]
})
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// When planar reflections are enabled, SSR is disabled for the ground
ground.groundReflection = true // SSR automatically disabled on ground
// When disabled, SSR works normally
ground.groundReflection = false // SSR can work on groundThis prevents conflicting reflection systems and ensures optimal performance.
With TemporalAAPlugin
Combine with temporal anti-aliasing for best quality:
import {TemporalAAPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
plugins: [GBufferPlugin, SSAAPlugin, TemporalAAPlugin]
})
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Temporal AA helps smooth both reflections and shadows
viewer.renderManager.stableNoise = trueWith BloomPlugin
Create glowing reflections:
import {BloomPlugin} from '@threepipe/webgi-plugins'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
maxHDRIntensity: 8,
plugins: [GBufferPlugin, SSAAPlugin, BloomPlugin]
})
const bloom = viewer.getPlugin(BloomPlugin)
bloom.pass.intensity = 1.5
bloom.pass.threshold = 1.0
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
ground.groundReflection = true
ground.material.roughness = 0.1
// HDR reflections will bloom on the groundPerformance Considerations
Planar Reflections
- Render Cost: Renders entire scene again from mirrored view
- Memory: Creates additional render target (default 1024x1024)
- Optimization:
- Lower reflection texture resolution for better performance
- Use higher roughness to hide lower quality
- Disable reflections on mobile devices
Baked Shadows
- Initial Cost: Takes multiple frames to accumulate (default 64)
- Runtime Cost: Minimal once baked (just texture sampling)
- Memory: One shadow map + one baked shadow texture
- Optimization:
- Reduce
maxFrameNumberfor faster accumulation - Use
BasicShadowMapfor fastest baking - Disable
autoBakeShadowsand bake manually when needed
- Reduce
Combined Features
Using both reflections and baked shadows:
- Memory: ~2-3 render targets total
- Performance: Reflection has highest cost, baked shadows are cheap
- Recommendation: Use for product visualization and static scenes
- Avoid: Real-time applications with frequent scene changes
Common Use Cases
The AdvancedGroundPlugin is ideal for:
- Product Visualization: Professional presentation with reflections and soft shadows
- Automotive: Car configurators with reflective showroom floor
- Jewelry: Highly reflective ground for gems and metals
- Architectural Viz: Polished floor materials in interior scenes
- Character Presentation: Portrait-style ground with soft shadows
- E-commerce: Product shots with professional lighting and reflections
- Marketing Materials: High-quality renders for promotional content
Troubleshooting
Reflections not visible:
- Check that
groundReflectionis true - Lower material
roughness(try 0.2 or less) - Ensure scene has objects above ground to reflect
- Check that ground is properly positioned under scene
- Verify camera can see the ground plane
Shadows not appearing:
- Ensure
bakedShadowsis true - Wait for accumulation (64 frames by default)
- Check that objects are casting shadows (
castShadow = true) - Verify shadow light parameters are reasonable
- Look for shadow frustum size issues (enable
autoFrustumSize)
Shadows too hard/soft:
- Adjust
focusandspreadinrandomParams - Modify
radiusin shadow parameters - Change
maxFrameNumber(higher = softer) - Try different
shadowMapType(PCFSoftShadowMap is softest) - Enable
smoothShadowfor additional blur
Performance issues:
- Disable reflections with
groundReflection = false - Reduce shadow
maxFrameNumber(try 32 instead of 64) - Lower reflection texture resolution (modify source code)
- Use
BasicShadowMapinstead ofPCFSoftShadowMap - Disable
autoBakeShadowsand bake manually only when needed
Reflection artifacts:
- Try toggling
physicalReflectionsmode - Adjust material
roughnessto hide artifacts - Check for camera near/far plane issues
- Ensure proper scene bounds and ground positioning
Shadow frustum too small/large:
- Enable
autoFrustumSizefor automatic sizing - Manually adjust
ground.sizeto match scene - Modify
frustumSizedirectly if needed:typescriptground.shadowBaker.light.shadowParams.frustumSize = 20 ground.shadowBaker.light.updateShadowParams() ground.bakeShadows()
Alpha vignette not working:
- Ensure material is transparent (
transparent = true) or transmissive (transmission > 0) - Check that
alphaVignetteis enabled - Verify alpha vignette axis matches your needs
- Material opacity/transmission must be less than 1.0
API Reference
See the AdvancedGroundPlugin API documentation for detailed information on all properties and methods.
Related Plugins
- BaseGroundPlugin - Basic ground plane functionality
- SSReflectionPlugin - Screen-space reflections for materials
- SSContactShadowsPlugin - Contact shadows enhancement
- BloomPlugin - HDR bloom for reflections
- TemporalAAPlugin - Temporal anti-aliasing
- GBufferPlugin - Depth buffer for various effects
