All Downloads are FREE. Search and download functionalities are using the official Maven repository.

info.laht.threekt.lights.LightShadow.kt Maven / Gradle / Ivy

The newest version!
package info.laht.threekt.lights

import info.laht.threekt.cameras.Camera
import info.laht.threekt.cameras.CameraWithNearAndFar
import info.laht.threekt.cameras.OrthographicCamera
import info.laht.threekt.cameras.PerspectiveCamera
import info.laht.threekt.core.Cloneable
import info.laht.threekt.math.*
import info.laht.threekt.renderers.RenderTarget

open class LightShadow(
        val camera: CameraWithNearAndFar
) : Cloneable {

    var bias = 0f
    var radius = 1f

    var mapSize = Vector2(1024, 1024)

    var map: RenderTarget? = null
    var matrix = Matrix4()

    val frustum = Frustum()
    var viewportCount = 1
        protected set

    internal val viewports = mutableListOf(
            Vector4(0, 0, 1, 1)
    )
    internal val frameExtents = Vector2(1, 1)
    internal val projScreenMatrix = Matrix4()
    internal val lightPositionWorld = Vector3()
    internal val lookTarget = Vector3()

    open fun updateMatrices(light: Light, viewCamera: Camera, viewportIndex: Int) {
        val shadowCamera = this.camera
        val shadowMatrix = this.matrix

        lightPositionWorld.setFromMatrixPosition(light.matrixWorld)
        camera.position.copy(lightPositionWorld)

        light as LightWithTarget

        lookTarget.setFromMatrixPosition(light.target.matrixWorld)
        camera.lookAt(lookTarget)
        camera.updateMatrixWorld()

        projScreenMatrix.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse)
        this.frustum.setFromMatrix(projScreenMatrix)

        shadowMatrix.set(
                0.5f, 0.0f, 0.0f, 0.5f,
                0.0f, 0.5f, 0.0f, 0.5f,
                0.0f, 0.0f, 0.5f, 0.5f,
                0.0f, 0.0f, 0.0f, 1.0f
        )

        shadowMatrix.multiply(shadowCamera.projectionMatrix)
        shadowMatrix.multiply(shadowCamera.matrixWorldInverse)
    }

    fun copy(source: LightShadow): LightShadow {

        this.camera.copy(source.camera, true)

        this.bias = source.bias
        this.radius = source.radius

        this.mapSize.copy(source.mapSize)

        return this
    }

    override fun clone(): LightShadow {
        return LightShadow(camera).copy(this)
    }

}

class PointLightShadow : LightShadow(PerspectiveCamera(90, 1, 0.5, 500)) {

    private val cubeDirections = listOf(
            Vector3(1, 0, 0), Vector3(-1, 0, 0), Vector3(0, 0, 1),
            Vector3(0, 0, -1), Vector3(0, 1, 0), Vector3(0, -1, 0)
    )

    private val cubeUps = listOf(
            Vector3(0, 1, 0), Vector3(0, 1, 0), Vector3(0, 1, 0),
            Vector3(0, 1, 0), Vector3(0, 0, 1), Vector3(0, 0, -1)
    )

    init {

        frameExtents.set(4f, 2f)
        viewportCount = 6

        with(viewports) {
            clear()
            addAll(listOf(
                    // These viewports map a cube-map onto a 2D texture with the
                    // following orientation:
                    //
                    //  xzXZ
                    //   y Y
                    //
                    // X - Positive x direction
                    // x - Negative x direction
                    // Y - Positive y direction
                    // y - Negative y direction
                    // Z - Positive z direction
                    // z - Negative z direction

                    // positive X
                    Vector4(2, 1, 1, 1),
                    // negative X
                    Vector4(0, 1, 1, 1),
                    // positive Z
                    Vector4(3, 1, 1, 1),
                    // negative Z
                    Vector4(1, 1, 1, 1),
                    // positive Y
                    Vector4(3, 0, 1, 1),
                    // negative Y
                    Vector4(1, 0, 1, 1)
            ))

        }

    }

    override fun updateMatrices(light: Light, viewCamera: Camera, viewportIndex: Int) {

        lightPositionWorld.setFromMatrixPosition(light.matrixWorld)
        camera.position.copy(lightPositionWorld)

        lookTarget.copy(camera.position)
        lookTarget.add(cubeDirections[viewportIndex])
        camera.up.copy(cubeUps[viewportIndex])
        camera.lookAt(lookTarget)
        camera.updateMatrixWorld()

        matrix.makeTranslation(-lightPositionWorld.x, -lightPositionWorld.y, -lightPositionWorld.z)

        projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
        this.frustum.setFromMatrix(projScreenMatrix)

    }

}

class SpotLightShadow : LightShadow(PerspectiveCamera(50, 1f, 0.5f, 500f)) {

    override fun updateMatrices(light: Light, viewCamera: Camera, viewportIndex: Int) {

        light as SpotLight
        camera as PerspectiveCamera

        val fov = RAD2DEG * 2 * light.angle
        val aspect = this.mapSize.width / this.mapSize.height
        val far = if (light.distance > 0) light.distance else camera.far

        if (fov != camera.fov || aspect != camera.aspect || far != camera.far) {

            camera.fov = fov
            camera.aspect = aspect
            camera.far = far
            camera.updateProjectionMatrix()

        }

        super.updateMatrices(light, viewCamera, viewportIndex)

    }

    override fun clone(): SpotLightShadow {
        return SpotLightShadow().copy(this) as SpotLightShadow
    }

}

class DirectionalLightShadow : LightShadow(OrthographicCamera(-5f, 5f, 5f, -5f, 0.5f, 500f))




© 2015 - 2025 Weber Informatics LLC | Privacy Policy