r3f-fake-lighting
v1.1.2
Published
A fake lighting system for React Three Fiber that allows GLTF models to emit and receive custom lighting
Downloads
4
Maintainers
Readme
r3f-fake-lighting
A fake lighting system for React Three Fiber that allows GLTF models to emit and receive custom lighting without using Three.js built-in lights. Features realistic shape-aware area lighting where light follows the actual geometry of emissive objects.
Features
- 🔦 Custom shader-based lighting system
- 🎨 GLTF models can emit fake light
- 🎭 GLTF models can receive fake light with proper shading
- ⚡ Supports up to 32 point lights or 8 area lights
- 🎬 Full animation support for both emitters and receivers
- 🎯 Efficient performance with custom shaders
- 🔧 Easy to integrate with existing R3F projects
- ✨ NEW: Shape-aware area lighting - light emission follows object geometry
Installation
npm install r3f-fake-lighting
# or
yarn add r3f-fake-lighting
# or
pnpm add r3f-fake-lightingQuick Start
import React, { Suspense } from 'react'
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import {
useLightManager,
LightManagerUpdater,
GLTFLightEmitter,
GLTFLightReceiver
} from 'r3f-fake-lighting'
function Scene() {
const lightManager = useLightManager()
return (
<>
{/* Required: Updates all materials each frame */}
<LightManagerUpdater lightManager={lightManager} />
<OrbitControls />
{/* GLTF model that emits light */}
<Suspense fallback={null}>
<GLTFLightEmitter
url="/models/light-source.glb"
position={[0, 2, 0]}
color="#ff0000"
intensity={3}
range={10}
lightManager={lightManager}
useAreaLight={true} // Enable shape-aware lighting
/>
</Suspense>
{/* GLTF model that receives light */}
<Suspense fallback={null}>
<GLTFLightReceiver
url="/models/scene.glb"
position={[0, 0, 0]}
lightManager={lightManager}
/>
</Suspense>
</>
)
}
export default function App() {
return (
<Canvas>
<Scene />
</Canvas>
)
}Shape-Aware Area Lighting
The library now supports realistic area lighting where light emission follows the actual shape of objects:
<GLTFLightEmitter
url="/models/neon-sign.glb"
lightManager={lightManager}
useAreaLight={true} // Enable area lighting (default: true)
sampleCount={16} // Number of surface samples (default: 16)
useLegacyPointLight={false} // Force point light mode if needed
/>How It Works
- Surface Sampling: The system samples multiple points across the emissive surface
- Geometry-Aware: Light emission follows the object's actual shape, not just a point
- Realistic Falloff: Uses proper area light calculations for natural light distribution
- Dynamic Updates: Supports animated objects with real-time surface updates
Area Light Benefits
- Realistic Emission: Light wraps around object contours naturally
- No Hotspots: Even distribution across flat surfaces like screens
- Shape Preservation: Long or curved objects emit light along their entire surface
- Soft Shadows: Natural light gradients based on surface proximity
API Reference
useLightManager()
Hook that creates and returns a light manager instance. Use this once at the top level of your scene.
const lightManager = useLightManager()<LightManagerUpdater>
Required component that updates all registered materials with light data each frame. Must be placed inside the Canvas.
Props:
lightManager(required): The light manager instance
<GLTFLightEmitter>
Component for GLTF models that emit fake light.
Props:
url(required): Path to the GLTF fileposition: Position in 3D space (default:[0, 0, 0])color: Light color (default:'#ffffff')intensity: Light intensity (default:1)range: Light range/falloff distance (default:10)lightManager(required): The light manager instanceanimationIndex: Which animation to play (default:0)fallbackComponent: Component to render if GLTF fails to loaduseAreaLight: Enable shape-aware area lighting (default:true)sampleCount: Number of surface samples for area lights (default:16)useLegacyPointLight: Force point light mode (default:false)
<GLTFLightReceiver>
Component for GLTF models that receive fake light.
Props:
url(required): Path to the GLTF fileposition: Position in 3D space (default:[0, 0, 0])lightManager(required): The light manager instanceanimationIndex: Which animation to play (default:0)fallbackComponent: Component to render if GLTF fails to load
<MockLight>
Invisible light source without any visual representation.
Props:
position(required): Position in 3D spacecolor(required): Light colorintensity(required): Light intensityrange(required): Light rangelightManager(required): The light manager instance
<FakeLightReceiverMaterialWrapper>
A React component wrapper that simplifies using the fake light receiver material with automatic prop handling and ref management.
Props:
color: Material color (string or THREE.Color, default:'#ffffff')roughness: Surface roughness (0-1, default:0.5)metalness: Metallic appearance (0-1, default:0.0)map: Diffuse texture (THREE.Texture, optional)normalMap: Normal texture (THREE.Texture, optional)roughnessMap: Roughness texture (THREE.Texture, optional)metalnessMap: Metalness texture (THREE.Texture, optional)ref: Ref callback or object to access the material instance
import { FakeLightReceiverMaterialWrapper } from 'r3f-fake-lighting'
<Box>
<FakeLightReceiverMaterialWrapper
color="#cccccc"
roughness={0.3}
metalness={0.1}
ref={(mat) => mat && lightManager.registerMaterial(mat)}
/>
</Box><fakeLightReceiverMaterial>
The raw shader material that can be used directly in JSX (requires manual uniform setting).
<Box>
<fakeLightReceiverMaterial
ref={(mat) => {
if (mat) {
mat.uniforms.color.value = new THREE.Color('#ffffff')
mat.uniforms.roughness.value = 0.5
mat.uniforms.metalness.value = 0.0
lightManager.registerMaterial(mat)
}
}}
/>
</Box>Note: For most use cases, prefer FakeLightReceiverMaterialWrapper as it handles prop updates automatically.
Advanced Usage
Manual Light Management
You can also manually control lights using the light manager API:
// Add a point light
lightManager.addLight(id, position, color, intensity, range)
// Add an area light
lightManager.addAreaLight(id, surfaceSamples, color, intensity, range)
// Update a light
lightManager.updateLight(id, { position, color, intensity, range })
// Remove a light
lightManager.removeLight(id)
// Register a material to receive lighting
lightManager.registerMaterial(material)
// Unregister a material
lightManager.unregisterMaterial(material)Custom Materials
The package exports FakeLightReceiverMaterial which you can extend or modify:
import { FakeLightReceiverMaterial } from 'r3f-fake-lighting'
// Create a custom version
const CustomMaterial = shaderMaterial(
{ ...FakeLightReceiverMaterial.uniforms },
// Your vertex shader
// Your fragment shader
)Geometry Sampling Utilities
For custom implementations:
import { sampleMeshSurface, extractEmissiveMeshes } from 'r3f-fake-lighting'
// Sample points on a mesh surface
const samples = sampleMeshSurface(mesh, 16)
// Extract all emissive meshes from a scene
const emissiveMeshes = extractEmissiveMeshes(scene)Performance Considerations
- Area Lights: Limited to 8 simultaneous area lights for performance
- Point Lights: Supports up to 32 point lights
- Surface Samples: More samples = better quality but higher GPU cost
- Materials automatically clean up when disposed
- Use
Suspenseboundaries for GLTF loading - Area lights update every frame for animated objects
Examples & Recipes
- Check the
/examplesdirectory for complete working examples - See
RECIPES.mdfor common patterns and solutions - Try the
area-lightingexample to see shape-aware lighting in action
TypeScript
This package includes TypeScript definitions. Import types directly:
import type {
LightManager,
Light,
AreaLight,
SurfaceSample,
GLTFLightReceiverProps
} from 'r3f-fake-lighting'License
MIT
