-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Volumetric spotlight #15046
Draft
ademola-lou
wants to merge
7
commits into
BabylonJS:master
Choose a base branch
from
ademola-lou:master
base: master
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Volumetric spotlight #15046
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
dccfd6f
implement volumetric spotlight
ademola-lou 16a706e
Merge branch 'master' of https://github.com/BabylonJS/Babylon.js
ademola-lou f9025f9
make volumetricSpotlight a utility/helper class for spotlight
ademola-lou 23de539
fix falloff and cone look at direction
ademola-lou 73f1db5
changed name to simpleVolumetric, review requested changes
ademola-lou caedd1e
add setDepthTexture method
ademola-lou 8cc61bb
cap the bottom face of the cone
ademola-lou File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
packages/dev/core/src/Lights/simpleVolumetricSpotLight.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { SpotLight } from "./spotLight"; | ||
import { Scene } from "core/scene"; | ||
import { Axis } from "core/Maths/math.axis"; | ||
import { CreateCylinder } from "core/Meshes/Builders/cylinderBuilder"; | ||
import { Mesh } from "core/Meshes/mesh"; | ||
import { ShaderMaterial } from "core/Materials/shaderMaterial"; | ||
import "../Shaders/simpleVolumetricSpot.fragment"; | ||
import "../Shaders/simpleVolumetricSpot.vertex"; | ||
import { Observer, RenderTargetTexture, TmpVectors } from ".."; | ||
|
||
|
||
export class SimpleVolumetricSpotLight { | ||
private _diameterTop: number; | ||
private _diameterBottom: number; | ||
private _rayLength: number; | ||
private _softRadius: number; | ||
private _scene: Scene; | ||
private spotLight: SpotLight; | ||
private _volumetricMaterial: ShaderMaterial; | ||
private _lightCone: Mesh; | ||
private _observer: Observer<any>; | ||
private _depthTexture: RenderTargetTexture; | ||
|
||
constructor(spotLight: SpotLight, diameterTop: number, diameterBottom: number, rayLength: number, scene: Scene) { | ||
this.spotLight = spotLight; | ||
this._diameterTop = diameterTop; | ||
this._diameterBottom = diameterBottom; | ||
this._rayLength = rayLength; | ||
this._scene = scene; | ||
this.createSimpleVolumetricSpotLight(); | ||
|
||
this._observer = this._scene.onBeforeRenderObservable.add(() => { | ||
this._update(); | ||
}); | ||
} | ||
|
||
public get lightCone(): Mesh { | ||
return this._lightCone; | ||
} | ||
|
||
public get lightMaterial(): ShaderMaterial { | ||
return this._volumetricMaterial; | ||
} | ||
|
||
public set softRadius(value: number){ | ||
this._softRadius = value; | ||
} | ||
|
||
public set depthTexture(value: RenderTargetTexture){ | ||
this._depthTexture = value; | ||
} | ||
|
||
private createSimpleVolumetricSpotLight(){ | ||
const spotLightCone = CreateCylinder("spotLightCone", {diameterTop: this._diameterTop, diameterBottom: this._diameterBottom, height: this._rayLength, cap: Mesh.CAP_END}, this._scene); | ||
spotLightCone.rotate(Axis.X, -Math.PI / 2); | ||
spotLightCone.translate(Axis.Y, -this._rayLength / 2); //pivot at the bottom | ||
spotLightCone.bakeCurrentTransformIntoVertices(); | ||
|
||
this._volumetricMaterial = new ShaderMaterial('volumetricSpotLightMaterial', this._scene, 'simpleVolumetricSpot', { | ||
attributes: ["position", "normal"], | ||
uniforms: ["world", "worldViewProjection", "view"], | ||
needAlphaBlending: true, | ||
}); | ||
|
||
const renderer = this._scene.enableDepthRenderer(); | ||
|
||
this._depthTexture = renderer.getDepthMap(); | ||
|
||
this._updateUniforms(); | ||
|
||
spotLightCone.material = this._volumetricMaterial; | ||
this._lightCone = spotLightCone; | ||
} | ||
|
||
private _updateUniforms(){ | ||
this._volumetricMaterial.setFloat("exponent", this.spotLight.exponent); | ||
this._volumetricMaterial.setFloat("angle", this.spotLight.angle / 100) | ||
this._volumetricMaterial.setColor3("diffuse", this.spotLight.diffuse); | ||
this._volumetricMaterial.setVector3("lightPos", this.spotLight.position); | ||
this._volumetricMaterial.setFloat("intensity", this.spotLight.intensity); | ||
this._volumetricMaterial.setFloat("cameraNear", this._scene.activeCamera!.minZ); | ||
this._volumetricMaterial.setFloat("cameraFar", this._scene.activeCamera!.maxZ); | ||
this._volumetricMaterial.setFloat("softRadius", this._softRadius || 0.5); | ||
this._volumetricMaterial.setTexture("depthTexture", this._depthTexture); | ||
const resolution = TmpVectors.Vector2[0].set(this._scene.getEngine().getRenderWidth(), this._scene.getEngine().getRenderHeight()); | ||
this._volumetricMaterial.setVector2("resolution", resolution); | ||
} | ||
|
||
private _update(){ | ||
const lightPos = TmpVectors.Vector3[0].copyFrom(this.spotLight.position); | ||
const dir = TmpVectors.Vector3[1]; | ||
lightPos.subtractToRef(this.spotLight.direction, dir); | ||
|
||
const len = dir.length(); | ||
this._lightCone.lookAt(lightPos.subtract(this.spotLight.direction.normalize().scale(-len))); | ||
this._lightCone.position.copyFrom(lightPos.add(this.spotLight.direction.normalize().scale(-1/(len * this._rayLength)))); | ||
|
||
this._updateUniforms(); | ||
} | ||
|
||
public dispose(){ | ||
this._scene.onBeforeRenderObservable.remove(this._observer); | ||
this._lightCone.dispose(); | ||
this._volumetricMaterial.dispose(); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
packages/dev/core/src/Shaders/simpleVolumetricSpot.fragment.fx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
precision highp float; | ||
varying vec3 vPositionW; | ||
varying vec3 vNormalW; | ||
varying float viewZ; | ||
uniform float exponent; | ||
uniform float angle; | ||
uniform vec3 lightPos; | ||
uniform vec3 diffuse; | ||
uniform float intensity; | ||
uniform sampler2D depthTexture; | ||
uniform float cameraNear; | ||
uniform float cameraFar; | ||
uniform float softRadius; | ||
uniform vec2 resolution; | ||
|
||
float perspectiveDepthToViewZ(float depth, float near, float far) { | ||
return (near * far) / ((far - near) * depth - far); | ||
} | ||
|
||
void main() { | ||
float rayIntensity = distance(vPositionW, lightPos) / exponent; | ||
rayIntensity = 1.0 - clamp(rayIntensity, 0.0, 1.0); | ||
|
||
vec3 normal = vNormalW; | ||
normal.z = abs(normal.z); | ||
|
||
vec3 forward = vec3(0., 0., 1.0); | ||
float angleIntensity = dot(normal, forward); | ||
|
||
//smooth the intensity | ||
angleIntensity = pow(angleIntensity, angle); | ||
rayIntensity *= angleIntensity; | ||
|
||
//soft intersection | ||
vec2 uv = gl_FragCoord.xy / resolution; | ||
float d = texture2D(depthTexture, uv).r; | ||
|
||
rayIntensity *= smoothstep(0.0, 1.0, (viewZ - perspectiveDepthToViewZ(d, cameraNear, cameraFar)) / softRadius); | ||
|
||
|
||
gl_FragColor = vec4(diffuse, rayIntensity * intensity); | ||
} |
19 changes: 19 additions & 0 deletions
19
packages/dev/core/src/Shaders/simpleVolumetricSpot.vertex.fx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
precision highp float; | ||
attribute vec3 position; | ||
attribute vec3 normal; | ||
uniform mat4 worldViewProjection; | ||
uniform mat4 world; | ||
uniform mat4 view; | ||
varying vec3 vNormalW; | ||
varying vec3 vPositionW; | ||
varying float viewZ; | ||
|
||
void main() { | ||
vec4 p = vec4(position, 1.); | ||
vec3 viewPos = vec3(view * vec4(position, 1.0)); | ||
gl_Position = worldViewProjection * p; | ||
|
||
vNormalW = normalize(vec3(world * vec4(normal, 0.0))); | ||
vPositionW = vec3(world * vec4(position, 1.0)); | ||
viewZ = viewPos.z; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is not allowed to import from a folder, import every element from their respective files.