Skip to content
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

IES shader #15952

Merged
merged 18 commits into from
Dec 5, 2024
33 changes: 33 additions & 0 deletions packages/dev/core/src/Lights/spotLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,30 @@ export class SpotLight extends ShadowLight {
private _lightAngleScale: number;
private _lightAngleOffset: number;

private _iesProfileTexture: Nullable<BaseTexture> = null;

/**
* Gets or sets the IES profile texture used to create the spotlight
* #UIAXAU#1
*/
public get iesProfileTexture(): Nullable<BaseTexture> {
return this._iesProfileTexture;
}

public set iesProfileTexture(value: Nullable<BaseTexture>) {
if (this._iesProfileTexture === value) {
return;
}

this._iesProfileTexture = value;

if (this._iesProfileTexture && SpotLight._IsTexture(this._iesProfileTexture)) {
this._iesProfileTexture.onLoadObservable.addOnce(() => {
this._markMeshesAsLightDirty();
});
}
}

/**
* Gets the cone angle of the spot light in Radians.
*/
Expand Down Expand Up @@ -385,6 +409,10 @@ export class SpotLight extends ShadowLight {
effect.setMatrix("textureProjectionMatrix" + lightIndex, this._projectionTextureMatrix);
effect.setTexture("projectionLightTexture" + lightIndex, this.projectionTexture);
}

if (this._iesProfileTexture && this._iesProfileTexture.isReady()) {
effect.setTexture("iesLightTexture" + lightIndex, this._iesProfileTexture);
}
return this;
}

Expand Down Expand Up @@ -439,6 +467,10 @@ export class SpotLight extends ShadowLight {
if (this._projectionTexture) {
this._projectionTexture.dispose();
}
if (this._iesProfileTexture) {
this._iesProfileTexture.dispose();
this._iesProfileTexture = null;
}
}

/**
Expand Down Expand Up @@ -473,6 +505,7 @@ export class SpotLight extends ShadowLight {
public prepareLightSpecificDefines(defines: any, lightIndex: number): void {
defines["SPOTLIGHT" + lightIndex] = true;
defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = this.projectionTexture && this.projectionTexture.isReady() ? true : false;
defines["IESLIGHTTEXTURE" + lightIndex] = this._iesProfileTexture && this._iesProfileTexture.isReady() ? true : false;
}
}

Expand Down
10 changes: 9 additions & 1 deletion packages/dev/core/src/Materials/Node/Blocks/Dual/lightBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,15 @@ export class LightBlock extends NodeMaterialBlock {
break;
}
const onlyUpdateBuffersList = state.uniforms.indexOf("vLightData" + lightIndex) >= 0;
PrepareUniformsAndSamplersForLight(lightIndex, state.uniforms, state.samplers, defines["PROJECTEDLIGHTTEXTURE" + lightIndex], uniformBuffers, onlyUpdateBuffersList);
PrepareUniformsAndSamplersForLight(
lightIndex,
state.uniforms,
state.samplers,
defines["PROJECTEDLIGHTTEXTURE" + lightIndex],
uniformBuffers,
onlyUpdateBuffersList,
defines["IESLIGHTTEXTURE" + lightIndex]
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,15 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
break;
}
const onlyUpdateBuffersList = state.uniforms.indexOf("vLightData" + lightIndex) >= 0;
PrepareUniformsAndSamplersForLight(lightIndex, state.uniforms, state.samplers, defines["PROJECTEDLIGHTTEXTURE" + lightIndex], uniformBuffers, onlyUpdateBuffersList);
PrepareUniformsAndSamplersForLight(
lightIndex,
state.uniforms,
state.samplers,
defines["PROJECTEDLIGHTTEXTURE" + lightIndex],
uniformBuffers,
onlyUpdateBuffersList,
defines["IESLIGHTTEXTURE" + lightIndex]
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class _IESTextureLoader implements IInternalTextureLoader {

const textureData = LoadIESData(uint8array);

callback(textureData.width, textureData.height, texture.generateMipMaps, false, () => {
callback(textureData.width, textureData.height, false, false, () => {
const engine = texture.getEngine();
texture.type = Constants.TEXTURETYPE_FLOAT;
texture.format = Constants.TEXTUREFORMAT_R;
Expand Down
17 changes: 15 additions & 2 deletions packages/dev/core/src/Materials/materialHelper.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -932,14 +932,16 @@ export function PrepareDefinesForCamera(scene: Scene, defines: any): boolean {
* @param projectedLightTexture defines if projected texture must be used
* @param uniformBuffersList defines an optional list of uniform buffers
* @param updateOnlyBuffersList True to only update the uniformBuffersList array
* @param iesLightTexture defines if IES texture must be used
*/
export function PrepareUniformsAndSamplersForLight(
lightIndex: number,
uniformsList: string[],
samplersList: string[],
projectedLightTexture?: any,
uniformBuffersList: Nullable<string[]> = null,
updateOnlyBuffersList = false
updateOnlyBuffersList = false,
iesLightTexture = false
) {
if (uniformBuffersList) {
uniformBuffersList.push("Light" + lightIndex);
Expand Down Expand Up @@ -977,6 +979,9 @@ export function PrepareUniformsAndSamplersForLight(
samplersList.push("projectionLightTexture" + lightIndex);
uniformsList.push("textureProjectionMatrix" + lightIndex);
}
if (iesLightTexture) {
samplersList.push("iesLightTexture" + lightIndex);
}
}

/**
Expand Down Expand Up @@ -1008,7 +1013,15 @@ export function PrepareUniformsAndSamplersList(uniformsListOrOptions: string[] |
if (!defines["LIGHT" + lightIndex]) {
break;
}
PrepareUniformsAndSamplersForLight(lightIndex, uniformsList, samplersList, defines["PROJECTEDLIGHTTEXTURE" + lightIndex], uniformBuffersList);
PrepareUniformsAndSamplersForLight(
lightIndex,
uniformsList,
samplersList,
defines["PROJECTEDLIGHTTEXTURE" + lightIndex],
uniformBuffersList,
false,
defines["IESLIGHTTEXTURE" + lightIndex]
);
}

if (defines["NUM_MORPH_INFLUENCERS"]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@
#endif
#else
#ifdef SPOTLIGHT{X}
info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness);
#ifdef IESLIGHTTEXTURE{X}
info = computeIESSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness, iesLightTexture{X});
#else
info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness);
#endif
#elif defined(HEMILIGHT{X})
info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, light{X}.vLightGround, glossiness);
#elif defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
#elif defined(HEMILIGHT{X})
uniform vec3 vLightGround{X};
#endif
#ifdef IESLIGHTTEXTURE{X}
uniform sampler2D iesLightTexture{X};
#endif
#ifdef PROJECTEDLIGHTTEXTURE{X}
uniform mat4 textureProjectionMatrix{X};
uniform sampler2D projectionLightTexture{X};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
vec4 shadowsInfo;
vec2 depthValues;
} light{X};
#ifdef IESLIGHTTEXTURE{X}
uniform sampler2D iesLightTexture{X};
#endif
#ifdef PROJECTEDLIGHTTEXTURE{X}
uniform mat4 textureProjectionMatrix{X};
uniform sampler2D projectionLightTexture{X};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,36 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
return result;
}

lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
lightingInfo result;
float getAttenuation(float cosAngle, float exponent) {
return max(0., pow(cosAngle, exponent));
}

float getIESAttenuation(float cosAngle, sampler2D iesLightSampler) {
float angle = acos(cosAngle) / PI;
return texture2D(iesLightSampler, vec2(angle, 0.), 0.).r;
}

lightingInfo basicSpotLighting(vec3 viewDirectionW, vec3 lightVectorW, vec3 vNormal, float attenuation, vec3 diffuseColor, vec3 specularColor, float glossiness) {
lightingInfo result;

// Diffuse
float ndl = max(0., dot(vNormal, lightVectorW));
#ifdef NDOTL
result.ndl = ndl;
#endif
result.diffuse = ndl * diffuseColor * attenuation;
#ifdef SPECULARTERM
// Specular
vec3 angleW = normalize(viewDirectionW + lightVectorW);
float specComp = max(0., dot(vNormal, angleW));
specComp = pow(specComp, max(1., glossiness));

result.specular = specComp * specularColor * attenuation;
#endif
return result;
}

lightingInfo computeIESSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness, sampler2D iesLightSampler) {
vec3 direction = lightData.xyz - vPositionW;
vec3 lightVectorW = normalize(direction);
float attenuation = max(0., 1.0 - length(direction) / range);
Expand All @@ -55,27 +82,38 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
float cosAngle = max(0., dot(lightDirection.xyz, -lightVectorW));

if (cosAngle >= lightDirection.w)
{
cosAngle = max(0., pow(cosAngle, lightData.w));
attenuation *= cosAngle;
{
attenuation *= getIESAttenuation(cosAngle, iesLightSampler);
return basicSpotLighting(viewDirectionW, lightVectorW, vNormal, attenuation, diffuseColor, specularColor, glossiness);
}

// Diffuse
float ndl = max(0., dot(vNormal, lightVectorW));
lightingInfo result;
result.diffuse = vec3(0.);
#ifdef SPECULARTERM
result.specular = vec3(0.);
#endif
#ifdef NDOTL
result.ndl = ndl;
result.ndl = 0.;
#endif
result.diffuse = ndl * diffuseColor * attenuation;
#ifdef SPECULARTERM
// Specular
vec3 angleW = normalize(viewDirectionW + lightVectorW);
float specComp = max(0., dot(vNormal, angleW));
specComp = pow(specComp, max(1., glossiness));

result.specular = specComp * specularColor * attenuation;
#endif
return result;
return result;
}

lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
vec3 direction = lightData.xyz - vPositionW;
vec3 lightVectorW = normalize(direction);
float attenuation = max(0., 1.0 - length(direction) / range);

// diffuse
float cosAngle = max(0., dot(lightDirection.xyz, -lightVectorW));

if (cosAngle >= lightDirection.w)
{
attenuation *= getAttenuation(cosAngle, lightData.w);
return basicSpotLighting(viewDirectionW, lightVectorW, vNormal, attenuation, diffuseColor, specularColor, glossiness);
}

lightingInfo result;
result.diffuse = vec3(0.);
#ifdef SPECULARTERM
result.specular = vec3(0.);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@
#endif
#else
#ifdef SPOTLIGHT{X}
info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness);
#ifdef IESLIGHTTEXTURE{X}
info = computeIESSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness, iesLightTexture{X});
#else
info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, diffuse{X}.a, glossiness);
#endif
#elif defined(HEMILIGHT{X})
info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, diffuse{X}.rgb, light{X}.vLightSpecular.rgb, light{X}.vLightGround, glossiness);
#elif defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

var<uniform> light{X} : Light{X};

#ifdef IESLIGHTTEXTURE{X}
var iesLightTexture{X}: texture_2d<f32>;
#endif

#ifdef PROJECTEDLIGHTTEXTURE{X}
uniform textureProjectionMatrix{X}: mat4x4f;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,36 @@ fn computeLighting(viewDirectionW: vec3f, vNormal: vec3f, lightData: vec4f, diff
return result;
}

fn computeSpotLighting(viewDirectionW: vec3f, vNormal: vec3f , lightData: vec4f, lightDirection: vec4f, diffuseColor: vec3f, specularColor: vec3f, range: f32, glossiness: f32) -> lightingInfo {
fn getAttenuation(cosAngle: f32, exponent: f32) -> f32 {
return max(0., pow(cosAngle, exponent));
}

fn getIESAttenuation(cosAngle: f32, iesLighttexture: texture_2d<f32>) -> f32 {
var angle = acos(cosAngle) / PI;
return textureLoad(iesLighttexture, vec2u(u32(angle * 180), 0), 0).r;
}

fn computeBasicSpotLighting(viewDirectionW: vec3f, lightVectorW: vec3f, vNormal: vec3f, attenuation: f32, diffuseColor: vec3f, specularColor: vec3f, glossiness: f32) -> lightingInfo {
var result: lightingInfo;

// Diffuse
var ndl: f32 = max(0., dot(vNormal, lightVectorW));
#ifdef NDOTL
result.ndl = ndl;
#endif
result.diffuse = ndl * diffuseColor * attenuation;
#ifdef SPECULARTERM
// Specular
var angleW: vec3f = normalize(viewDirectionW + lightVectorW);
var specComp: f32 = max(0., dot(vNormal, angleW));
specComp = pow(specComp, max(1., glossiness));

result.specular = specComp * specularColor * attenuation;
#endif
return result;
}

fn computeIESSpotLighting(viewDirectionW: vec3f, vNormal: vec3f , lightData: vec4f, lightDirection: vec4f, diffuseColor: vec3f, specularColor: vec3f, range: f32, glossiness: f32, iesLightTexture: texture_2d<f32>) -> lightingInfo {
var direction: vec3f = lightData.xyz - fragmentInputs.vPositionW;
var lightVectorW: vec3f = normalize(direction);
var attenuation: f32 = max(0., 1.0 - length(direction) / range);
Expand All @@ -56,26 +83,39 @@ fn computeSpotLighting(viewDirectionW: vec3f, vNormal: vec3f , lightData: vec4f,

if (cosAngle >= lightDirection.w)
{
cosAngle = max(0., pow(cosAngle, lightData.w));
attenuation *= cosAngle;
attenuation *= getIESAttenuation(cosAngle, iesLightTexture);
return computeBasicSpotLighting(viewDirectionW, lightVectorW, vNormal, attenuation, diffuseColor, specularColor, glossiness);
}

var result: lightingInfo;

// Diffuse
var ndl: f32 = max(0., dot(vNormal, lightVectorW));
result.diffuse = vec3f(0.);
#ifdef SPECULARTERM
result.specular = vec3f(0.);
#endif
#ifdef NDOTL
result.ndl = ndl;
result.ndl = 0.;
#endif
result.diffuse = ndl * diffuseColor * attenuation;
#ifdef SPECULARTERM
// Specular
var angleW: vec3f = normalize(viewDirectionW + lightVectorW);
var specComp: f32 = max(0., dot(vNormal, angleW));
specComp = pow(specComp, max(1., glossiness));

result.specular = specComp * specularColor * attenuation;
#endif
return result;
return result;
}

fn computeSpotLighting(viewDirectionW: vec3f, vNormal: vec3f , lightData: vec4f, lightDirection: vec4f, diffuseColor: vec3f, specularColor: vec3f, range: f32, glossiness: f32) -> lightingInfo {
var direction: vec3f = lightData.xyz - fragmentInputs.vPositionW;
var lightVectorW: vec3f = normalize(direction);
var attenuation: f32 = max(0., 1.0 - length(direction) / range);

// diffuse
var cosAngle: f32 = max(0., dot(lightDirection.xyz, -lightVectorW));

if (cosAngle >= lightDirection.w)
{
attenuation *= getAttenuation(cosAngle, lightData.w);
return computeBasicSpotLighting(viewDirectionW, lightVectorW, vNormal, attenuation, diffuseColor, specularColor, glossiness);
}

var result: lightingInfo;

result.diffuse = vec3f(0.);
#ifdef SPECULARTERM
result.specular = vec3f(0.);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading