BaseGroundPlugin
Base Ground Plugin adds a simple horizontal ground plane to the scene that automatically positions itself below the model. It provides a foundation for displaying 3D objects with proper grounding and can be extended by plugins like AdvancedGroundPlugin for more advanced features.
The plugin creates a plane mesh with a configurable PhysicalMaterial, automatically adjusts its position and scale based on the scene bounds, and provides options for camera limits, depth rendering, and tonemapping.
Features
- Auto-Positioning: Automatically positions ground below scene bounding box
- Configurable Size: Adjustable ground plane dimensions
- Height Offset: Fine-tune vertical position
- Material Access: Full control over PhysicalMaterial properties
- Camera Limits: Optional constraint to keep camera above ground
- Depth Rendering: Control whether ground appears in depth buffer
- Tonemap Control: Toggle tonemapping for the ground material
- Extensible: Base class for advanced ground plugins
- Serializable: Full state serialization support
Installation
BaseGroundPlugin is part of the core threepipe package:
npm install threepipeBasic Setup
import {ThreeViewer, BaseGroundPlugin} from 'threepipe'
const viewer = new ThreeViewer({
canvas: document.getElementById('canvas'),
msaa: true
})
// Add ground plugin
const ground = viewer.addPluginSync(new BaseGroundPlugin())
// Load model - ground will auto-position below it
await viewer.load('model.glb')The ground plane will automatically position itself below the model's bounding box.
Configuration
Visibility and Size
Control basic ground appearance:
const ground = viewer.getPlugin(BaseGroundPlugin)
// Visibility
ground.visible = true // Show ground (default)
ground.visible = false // 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 = 3 // Smaller ground
ground.size = 0 // Hide ground (alternative to visible = false)The ground plane scales uniformly in X and Z directions.
Position
Adjust the vertical position of the ground:
// Height offset (Y position relative to model bottom)
ground.yOffset = 0 // Default, at model's base
ground.yOffset = -0.5 // Lower ground (0.5 units below)
ground.yOffset = 0.1 // Raised ground (0.1 units above)The yOffset is relative to the bottom of the scene's bounding box.
Auto-Adjustment
Control automatic positioning:
// Auto-adjust ground to fit under scene
ground.autoAdjustTransform = true // Default, automatic
ground.autoAdjustTransform = false // Manual control
// When true, ground automatically:
// - Centers below the scene's bounding box
// - Updates when objects are added/removed
// - Respects the yOffset settingMaterial Configuration
Access and modify the ground material:
const material = ground.material
// Material is a PhysicalMaterial
material.color.set('#ffffff') // White ground
material.color.set('#8b8b8b') // Gray ground
material.roughness = 0.8 // Default
material.metalness = 0.5 // Default
material.opacity = 1.0
// Add textures
material.map = await viewer.load('ground_texture.jpg')
material.normalMap = await viewer.load('ground_normal.jpg')
material.roughnessMap = await viewer.load('ground_roughness.jpg')
// Must call setDirty after changes
material.setDirty()The ground uses a standard PhysicalMaterial with all PBR properties available.
Camera Limits
Prevent camera from going below ground:
// Limit camera to stay above ground
ground.limitCameraAboveGround = true // Enable limit
ground.limitCameraAboveGround = false // No limit (default)
// Only works with OrbitControls3 or three.js OrbitControls
// Camera's maxPolarAngle is set to π/2 (90°) when enabledThis is useful for architectural visualizations or when you want to prevent the camera from viewing the scene from below.
Rendering Options
Control how the ground appears in rendering buffers:
// Render to depth buffer
ground.renderToDepth = true // Default, included in depth
ground.renderToDepth = false // Excluded from depth buffer
// Apply tonemapping
ground.tonemapGround = true // Default, tonemap with scene
ground.tonemapGround = false // No tonemapping (keeps HDR values)
// Note: Both options require GBufferPlugin to be activeThese options are useful when combining with post-processing effects that rely on depth or require special handling of ground colors.
Advanced Usage
Custom Material
Replace the default material with your own:
import {PhysicalMaterial} from 'threepipe'
const ground = viewer.getPlugin(BaseGroundPlugin)
// Create custom material
const customMaterial = new PhysicalMaterial({
name: 'CustomGroundMaterial',
color: 0x3a5f0b, // Green
roughness: 0.9,
metalness: 0.0
})
// Assign to ground (via mesh.material binding)
ground.mesh.material = customMaterial
// Or access the protected _material directly
// Note: This is not recommended for general useCustom Geometry
Replace the plane with custom geometry:
import {CircleGeometry} from 'three'
const ground = viewer.getPlugin(BaseGroundPlugin)
// Create circular ground
const circleGeometry = new CircleGeometry(5, 64)
ground.setGeometry(circleGeometry)
// Ground will use the new geometry
// UV coordinates (uv2) are automatically createdManual Positioning
Take full control of ground position:
const ground = viewer.getPlugin(BaseGroundPlugin)
// Disable auto-adjustment
ground.autoAdjustTransform = false
// Access mesh directly
const mesh = ground.mesh
// Set custom position
mesh.position.set(0, -1, 0)
// Set custom rotation (ground is rotated -90° around X by default)
mesh.rotation.set(-Math.PI / 2, 0, Math.PI / 4) // 45° Z rotation
// Set custom scale
mesh.scale.set(10, 10, 1)
// Update matrices
mesh.updateMatrixWorld()Extend for Custom Ground
Create a custom ground plugin by extending BaseGroundPlugin:
import {BaseGroundPlugin, PhysicalMaterial, ThreeViewer} from 'threepipe'
class MyCustomGroundPlugin extends BaseGroundPlugin {
static readonly PluginType = 'MyCustomGroundPlugin'
// Override material creation
protected _createMaterial(material?: PhysicalMaterial): PhysicalMaterial {
if (!material) {
material = new PhysicalMaterial({
name: 'MyCustomGroundMaterial',
color: 0xff0000, // Red ground
roughness: 0.5,
metalness: 0.8
})
}
return super._createMaterial(material)
}
// Override positioning logic
protected _refreshTransform() {
const updated = super._refreshTransform()
// Add custom transform logic here
if (updated && this._mesh) {
// Custom modifications to position/rotation/scale
}
return updated
}
// Add custom functionality
onAdded(viewer: ThreeViewer) {
super.onAdded(viewer)
// Custom initialization
}
}
// Use your custom plugin
const ground = viewer.addPluginSync(new MyCustomGroundPlugin())Scene Bounds Control
Control which objects affect ground positioning:
const ground = viewer.getPlugin(BaseGroundPlugin)
// Use only model bounds (default)
ground.useModelBounds = true // Only scene.modelRoot children
// Use full scene bounds
ground.useModelBounds = false // All objects in scene
// Manually refresh ground position
ground.refreshTransform()Physics Integration
The ground is automatically configured for physics:
const ground = viewer.getPlugin(BaseGroundPlugin)
const mesh = ground.mesh
// Physics properties (already set by plugin)
console.log(mesh.userData.physicsMass) // 0 (static)
console.log(mesh.userData.physicsBodyType) // 'static'
console.log(mesh.userData.userSelectable) // false
console.log(mesh.userData.isGroundMesh) // true
// These properties are used by physics pluginsShadow Configuration
Configure shadow casting and receiving:
const ground = viewer.getPlugin(BaseGroundPlugin)
const mesh = ground.mesh
// Shadows (enabled by default)
mesh.castShadow = true // Ground casts shadows
mesh.receiveShadow = true // Ground receives shadows
// Disable shadows
mesh.castShadow = false
mesh.receiveShadow = falseUI Integration
Use with TweakpaneUiPlugin for runtime controls:
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'
const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
const ground = viewer.getPlugin(BaseGroundPlugin)
// Add ground controls to UI
ui.setupPluginUi(BaseGroundPlugin)
// Now you have interactive controls for:
// - Visible toggle
// - Size slider
// - Height (yOffset) slider
// - Render to Depth toggle
// - Tonemap Ground toggle
// - Limit Camera Above Ground toggle
// - Auto Adjust Transform toggle
// - Material properties folderExtended Plugins
BaseGroundPlugin serves as the foundation for more advanced ground plugins:
AdvancedGroundPlugin
Extends BaseGroundPlugin with planar reflections and baked shadows:
import {AdvancedGroundPlugin} from '@threepipe/webgi-plugins'
// AdvancedGroundPlugin extends BaseGroundPlugin
const ground = viewer.addPluginSync(new AdvancedGroundPlugin())
// Has all BaseGroundPlugin features plus:
ground.groundReflection = true // Planar reflections
ground.bakedShadows = true // Baked soft shadows
ground.physicalReflections = trueSee AdvancedGroundPlugin for full documentation.
ContactShadowGroundPlugin
Extends BaseGroundPlugin with contact shadow effects:
import {ContactShadowGroundPlugin} from 'threepipe'
const ground = viewer.addPluginSync(new ContactShadowGroundPlugin())
// Has all BaseGroundPlugin features plus contact shadowsSee ContactShadowGroundPlugin for full documentation.
HDRiGroundPlugin
Extends BaseGroundPlugin with ground-projected environment:
import {HDRiGroundPlugin} from 'threepipe'
const ground = viewer.addPluginSync(new HDRiGroundPlugin())
// Has all BaseGroundPlugin features plus HDRI projectionSee HDRiGroundPlugin for full documentation.
Technical Details
How It Works
- Initialization: Creates plane geometry and default PhysicalMaterial
- Scene Integration: Adds mesh to scene root on plugin addition
- Auto-Positioning: Listens to scene updates and adjusts transform
- Material Management: Tracks and manages material depth/tonemap settings
- Camera Integration: Optionally limits camera polar angle
Geometry
- Type: PlaneGeometry (1x1, subdivisions: 1x1)
- Orientation: Rotated -90° around X axis (horizontal)
- UVs: Both uv and uv2 attributes available
- Scale: Controlled by
sizeproperty
Material
- Type: PhysicalMaterial
- Default Color: White (#ffffff)
- Default Roughness: 0.8
- Default Metalness: 0.5
- Runtime Material: Marked with
userData.runtimeMaterial = true
Performance
- Minimal Impact: Single plane mesh with standard material
- Efficient Updates: Only refreshes transform when needed
- Lazy Evaluation: Transform refresh deferred to postFrame
Events
The plugin listens to:
scene.sceneUpdate- Refresh ground when scene changesscene.addSceneObject- Refresh ground when objects addedviewer.preRender- Pre-render setupviewer.postFrame- Post-frame transform updates
Common Use Cases
BaseGroundPlugin is ideal for:
- Simple Model Display: Quick ground plane for object presentation
- Base for Extensions: Foundation for custom ground plugins
- Prototyping: Fast setup without complex features
- Mobile Friendly: Lightweight ground solution
- Physics Simulations: Static ground for physics engines
- Architectural Viz: Base ground for buildings and structures
Troubleshooting
Ground not visible:
- Check
ground.visibleis true - Verify
ground.sizeis greater than 0 - Ensure scene has objects (ground auto-sizes to scene bounds)
- Check camera position can see ground plane
Ground in wrong position:
- Enable
autoAdjustTransformfor automatic positioning - Check
yOffsetvalue - Verify scene bounds are correct
- Try calling
ground.refreshTransform()manually
Ground not updating:
- Ensure
autoAdjustTransformis enabled - Check that scene events are firing
- Verify objects are properly added to scene
- Call
ground.refresh()manually if needed
Camera goes below ground:
- Enable
limitCameraAboveGround - Check that OrbitControls3 is being used
- Verify camera controls are active
Material changes not applied:
- Call
material.setDirty()after changes - Check material is properly assigned to mesh
- Verify changes to correct material instance
Ground not receiving shadows:
- Check
mesh.receiveShadowis true - Ensure lights have
castShadowenabled - Verify shadow maps are configured in viewer
API Reference
See the BaseGroundPlugin API documentation for detailed information on all properties and methods.
Related Plugins
- AdvancedGroundPlugin - Extended ground with reflections and baked shadows
- ContactShadowGroundPlugin - Ground with contact shadow effects
- HDRiGroundPlugin - Ground with environment projection
- GBufferPlugin - Required for depth and tonemap features
