mylingo3d
Version:
Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor
119 lines (102 loc) • 4.11 kB
text/typescript
import { createEffect } from "@lincode/reactivity"
import * as THREE from "three"
//@ts-ignore
import { ProgressiveLightMap } from "three/examples/jsm/misc/ProgressiveLightMap"
import Octahedron from "../display/primitives/Octahedron"
import Plane from "../display/primitives/Plane"
import { onBeforeRender } from "../events/onBeforeRender"
import { getCameraRendered } from "../states/useCameraRendered"
import { getRenderer } from "../states/useRenderer"
// ShadowMap + LightMap Res and Number of Directional Lights
const shadowMapRes = 512,
lightMapRes = 1024,
lightCount = 8
let object: any = new THREE.Mesh(),
lightOrigin: any = null
const dirLights: any = [],
lightmapObjects: any = []
const blurEdges = true
const blendWindow = 200
const lightRadius = 50
const ambientWeight = 0.5
// directional lighting "origin"
lightOrigin = new THREE.Group()
lightOrigin.position.set(60, 150, 100)
// create 8 directional lights to speed up the convergence
for (let l = 0; l < lightCount; l++) {
const dirLight = new THREE.DirectionalLight(0xffffff, 1.0 / lightCount)
dirLight.name = "Dir. Light " + l
dirLight.position.set(200, 200, 200)
dirLight.castShadow = true
// dirLight.shadow.camera.near = 100
// dirLight.shadow.camera.far = 5000
dirLight.shadow.camera.right = 150
dirLight.shadow.camera.left = -150
dirLight.shadow.camera.top = 150
dirLight.shadow.camera.bottom = -150
dirLight.shadow.mapSize.width = shadowMapRes
dirLight.shadow.mapSize.height = shadowMapRes
lightmapObjects.push(dirLight)
dirLights.push(dirLight)
}
const ground = new Plane()
ground.rotationX = -90
ground.scale = 100
ground.y = -50
const groundMesh = ground.object3d
// const groundMesh = new THREE.Mesh(
// new THREE.PlaneGeometry(999 * scaleDown, 999 * scaleDown),
// new THREE.MeshStandardMaterial({ color: 0xffffff, depthWrite: true })
// )
lightmapObjects.push(groundMesh)
object = new Octahedron().object3d
object.traverse(function (child: any) {
if (child.isMesh) {
child.material = new THREE.MeshStandardMaterial()
lightmapObjects.push(child)
}
})
const lightTarget = new THREE.Group()
lightTarget.position.set(0, 20, 0)
for (let l = 0; l < dirLights.length; l++) {
dirLights[l].target = lightTarget
}
object.add(lightTarget)
createEffect(() => {
const renderer = getRenderer()
if (!renderer) return
const camera = getCameraRendered()
const progressiveSurfacemap = new ProgressiveLightMap(renderer, lightMapRes)
progressiveSurfacemap.addObjectsToLightMap(lightmapObjects)
const handle = onBeforeRender(() => {
progressiveSurfacemap.update(camera, blendWindow, blurEdges)
if (!progressiveSurfacemap.firstUpdate)
progressiveSurfacemap.showDebugLightmap(true)
// Manually Update the Directional Lights
for (let l = 0; l < dirLights.length; l++) {
// Sometimes they will be sampled from the target direction
// Sometimes they will be uniformly sampled from the upper hemisphere
if (Math.random() > ambientWeight) {
dirLights[l].position.set(
lightOrigin.position.x + Math.random() * lightRadius,
lightOrigin.position.y + Math.random() * lightRadius,
lightOrigin.position.z + Math.random() * lightRadius
)
} else {
// Uniform Hemispherical Surface Distribution for Ambient Occlusion
const lambda = Math.acos(2 * Math.random() - 1) - 3.14159 / 2.0
const phi = 2 * 3.14159 * Math.random()
dirLights[l].position.set(
Math.cos(lambda) * Math.cos(phi) * 300 + object.position.x,
Math.abs(Math.cos(lambda) * Math.sin(phi) * 300) +
object.position.y +
20,
Math.sin(lambda) * 300 + object.position.z
)
}
}
})
return () => {
handle.cancel()
}
}, [getRenderer, getCameraRendered])