diff --git a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/BGlMaterialShader.cs b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/BGlMaterialShader.cs index d739ef34c..d72d2ca37 100644 --- a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/BGlMaterialShader.cs +++ b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/BGlMaterialShader.cs @@ -10,27 +10,13 @@ using OpenTK.Graphics.OpenGL; namespace fin.ui.rendering.gl.material { - public class CachedTextureUniformData { - public required int TextureIndex { get; init; } - public required ITexture? FinTexture { get; init; } - public required GlTexture GlTexture { get; init; } - - public required IReadOnlyFinMatrix3x2? Transform2d { get; init; } - public required IReadOnlyFinMatrix4x4? Transform3d { get; init; } - - public required bool HasFancyData { get; init; } - public required int SamplerLocation { get; init; } - public required int ClampMinLocation { get; init; } - public required int ClampMaxLocation { get; init; } - public required int Transform2dLocation { get; init; } - public required int Transform3dLocation { get; init; } - } - public abstract class BGlMaterialShader : IGlMaterialShader where TMaterial : IReadOnlyMaterial { private LinkedList cachedTextureUniformDatas_ = new(); + private LinkedList cachedLightUniformDatas_ = new(); + private readonly IModel model_; private readonly ILighting? lighting_; private readonly IBoneTransformManager? boneTransformManager_; @@ -46,10 +32,6 @@ public abstract class BGlMaterialShader : IGlMaterialShader private readonly int useLightingLocation_; private readonly int ambientLightColorLocation_; - private readonly int[] lightEnabledLocations_; - private readonly int[] lightPositionLocations_; - private readonly int[] lightNormalLocations_; - private readonly int[] lightColorLocations_; protected BGlMaterialShader( IModel model, @@ -84,25 +66,15 @@ protected BGlMaterialShader( this.ambientLightColorLocation_ = this.impl_.GetUniformLocation("ambientLightColor"); - this.lightEnabledLocations_ = new int[MaterialConstants.MAX_LIGHTS]; - this.lightPositionLocations_ = new int[MaterialConstants.MAX_LIGHTS]; - this.lightNormalLocations_ = new int[MaterialConstants.MAX_LIGHTS]; - this.lightColorLocations_ = new int[MaterialConstants.MAX_LIGHTS]; - for (var i = 0; i < MaterialConstants.MAX_LIGHTS; ++i) { - this.lightEnabledLocations_[i] = - this.impl_.GetUniformLocation( - $"{MaterialConstants.LIGHTS_NAME}[{i}].enabled"); - this.lightPositionLocations_[i] = - this.impl_.GetUniformLocation( - $"{MaterialConstants.LIGHTS_NAME}[{i}].position"); - this.lightNormalLocations_[i] = - this.impl_.GetUniformLocation( - $"{MaterialConstants.LIGHTS_NAME}[{i}].normal"); - this.lightColorLocations_[i] = - this.impl_.GetUniformLocation( - $"{MaterialConstants.LIGHTS_NAME}[{i}].color"); - } + if (lighting != null) { + var lights = lighting.Lights; + for (var i = 0; i < lights.Count; ++i) { + var light = lights[i]; + this.cachedLightUniformDatas_.AddLast( + new CachedLightUniformData(i, light, this.impl_)); + } + } this.Setup(material, this.impl_); } @@ -118,7 +90,8 @@ private void ReleaseUnmanagedResources_() { this.impl_.Dispose(); if (this.DisposeTextures) { - foreach (var cachedTextureUniformData in cachedTextureUniformDatas_) { + foreach (var cachedTextureUniformData in + this.cachedTextureUniformDatas_) { GlMaterialConstants.DisposeIfNotCommon( cachedTextureUniformData.GlTexture); } @@ -171,22 +144,24 @@ public void Use() { GL.Uniform1(this.shininessLocation_, this.Material.Shininess); - GL.Uniform1(this.useLightingLocation_, - this.UseLighting && this.lighting_ != null ? 1f : 0f); - - if (this.lighting_ != null) { - this.SetUpLightUniforms_(this.lighting_, MaterialConstants.MAX_LIGHTS); - } + this.PassInLightUniforms_(this.lighting_); foreach (var cachedTextureUniformData in this.cachedTextureUniformDatas_) { - this.BindTextureAndSetUpUniforms_(cachedTextureUniformData); + cachedTextureUniformData.BindTextureAndPassInUniforms(); } this.PassUniformsAndBindTextures(this.impl_); } - private void SetUpLightUniforms_(ILighting lighting, int max) { + private void PassInLightUniforms_(ILighting? lighting) { + var useLighting = this.UseLighting && this.lighting_ != null; + GL.Uniform1(this.useLightingLocation_, useLighting ? 1f : 0f); + + if (!useLighting) { + return; + } + var ambientLightStrength = lighting.AmbientLightStrength; var ambientLightColor = lighting.AmbientLightColor; GL.Uniform4(this.ambientLightColorLocation_, @@ -195,36 +170,8 @@ private void SetUpLightUniforms_(ILighting lighting, int max) { ambientLightColor.Bf * ambientLightStrength, ambientLightColor.Af * ambientLightStrength); - var lights = lighting.Lights; - for (var i = 0; i < max; ++i) { - var isEnabled = i < lights.Count && lights[i].Enabled; - - if (!isEnabled) { - continue; - } - - var light = lights[i]; - GL.Uniform1(this.lightEnabledLocations_[i], 1); - - var position = light.Position; - GL.Uniform3(this.lightPositionLocations_[i], - position.X, - position.Y, - position.Z); - - var normal = light.Normal; - GL.Uniform3(this.lightNormalLocations_[i], - normal.X, - normal.Y, - normal.Z); - - var strength = light.Strength; - var color = light.Color; - GL.Uniform4(this.lightColorLocations_[i], - color.Rf * strength, - color.Gf * strength, - color.Bf * strength, - color.Af * strength); + foreach (var cachedLightUniformData in this.cachedLightUniformDatas_) { + cachedLightUniformData.PassInUniforms(); } } @@ -232,165 +179,12 @@ protected void SetUpTexture( string textureName, int textureIndex, ITexture? finTexture, - GlTexture glTexture) { - int samplerLocation; - int clampMinLocation = -1; - int clampMaxLocation = -1; - int transform2dLocation = -1; - int transform3dLocation = -1; - - var hasFancyData = GlslUtil.RequiresFancyTextureData(finTexture); - if (!hasFancyData) { - samplerLocation = this.impl_.GetUniformLocation($"{textureName}"); - } else { - samplerLocation = - this.impl_.GetUniformLocation($"{textureName}.sampler"); - clampMinLocation = - this.impl_.GetUniformLocation($"{textureName}.clampMin"); - clampMaxLocation = - this.impl_.GetUniformLocation($"{textureName}.clampMax"); - transform2dLocation = - this.impl_.GetUniformLocation($"{textureName}.transform2d"); - transform3dLocation = - this.impl_.GetUniformLocation($"{textureName}.transform3d"); - } - - var isTransform3d = finTexture?.IsTransform3d ?? false; - - var cachedTextureUniformData = new CachedTextureUniformData { - TextureIndex = textureIndex, - FinTexture = finTexture, - GlTexture = glTexture, - Transform2d = isTransform3d - ? null - : CalculateTextureTransform2d_(finTexture), - Transform3d = isTransform3d - ? CalculateTextureTransform3d_(finTexture) - : null, - HasFancyData = hasFancyData, - SamplerLocation = samplerLocation, - ClampMinLocation = clampMinLocation, - ClampMaxLocation = clampMaxLocation, - Transform2dLocation = transform2dLocation, - Transform3dLocation = transform3dLocation, - }; - - this.cachedTextureUniformDatas_.AddLast(cachedTextureUniformData); - } - - private static IReadOnlyFinMatrix3x2 CalculateTextureTransform2d_( - ITexture? texture) { - if (texture == null) { - return FinMatrix3x2.IDENTITY; - } - - var textureOffset = texture.Offset; - var textureScale = texture.Scale; - var textureRotationRadians = texture.RotationRadians; - - if (textureOffset == null && - textureScale == null && - textureRotationRadians == null) { - return FinMatrix3x2.IDENTITY; - } - - Vector2? offset = null; - if (textureOffset != null) { - offset = new Vector2(textureOffset.X, textureOffset.Y); - } - - Vector2? scale = null; - if (textureScale != null) { - scale = new Vector2(textureScale.X, textureScale.Y); - } - - return FinMatrix3x2Util.FromTrss(offset, - textureRotationRadians?.Z, - scale, - null); - } - - private static IReadOnlyFinMatrix4x4 CalculateTextureTransform3d_( - ITexture? texture) { - if (texture == null) { - return FinMatrix4x4.IDENTITY; - } - - var textureOffset = texture.Offset; - var textureScale = texture.Scale; - var textureRotationRadians = texture.RotationRadians; - - if (textureOffset == null && - textureScale == null && - textureRotationRadians == null) { - return FinMatrix4x4.IDENTITY; - } - - Position? offset = null; - if (textureOffset != null) { - offset = - new Position(textureOffset.X, textureOffset.Y, textureOffset.Z); - } - - Quaternion? rotation = null; - if (textureRotationRadians != null) { - rotation = QuaternionUtil.CreateZyx(textureRotationRadians.X, - textureRotationRadians.Y, - textureRotationRadians.Z); - } - - Scale? scale = null; - if (textureScale != null) { - scale = new(textureScale.X, textureScale.Y, textureScale.Z); - } - - return FinMatrix4x4Util.FromTrs(offset, rotation, scale); - } - - private unsafe void BindTextureAndSetUpUniforms_( - CachedTextureUniformData uniformData) { - uniformData.GlTexture.Bind(uniformData.TextureIndex); - GL.Uniform1(uniformData.SamplerLocation, uniformData.TextureIndex); - - if (uniformData.HasFancyData) { - OpenTK.Vector2 clampMin = new(-10000); - OpenTK.Vector2 clampMax = new(10000); - - if (uniformData.FinTexture?.WrapModeU == WrapMode.MIRROR_CLAMP) { - clampMin.X = -1; - clampMax.X = 2; - } - - if (uniformData.FinTexture?.WrapModeV == WrapMode.MIRROR_CLAMP) { - clampMin.Y = -1; - clampMax.Y = 2; - } - - var clampS = uniformData.FinTexture?.ClampS; - var clampT = uniformData.FinTexture?.ClampT; - - if (clampS != null) { - clampMin.X = clampS.X; - clampMax.X = clampS.Y; - } - - if (clampT != null) { - clampMin.Y = clampT.X; - clampMax.Y = clampT.Y; - } - - GL.Uniform2(uniformData.ClampMinLocation, clampMin); - GL.Uniform2(uniformData.ClampMaxLocation, clampMax); - - if (!(uniformData.FinTexture?.IsTransform3d ?? false)) { - var mat2d = uniformData.Transform2d!.Impl; - var ptr = (float*) &mat2d; - GL.UniformMatrix2x3(uniformData.Transform2dLocation, 1, true, ptr); - } else { - var mat3d = uniformData.Transform3d!.Impl; - GlTransform.UniformMatrix4(uniformData.Transform3dLocation, mat3d); - } - } - } + GlTexture glTexture) + => this.cachedTextureUniformDatas_.AddLast( + new CachedTextureUniformData(textureName, + textureIndex, + finTexture, + glTexture, + this.impl_)); } } \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedLightUniformData.cs b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedLightUniformData.cs new file mode 100644 index 000000000..83dee92c8 --- /dev/null +++ b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedLightUniformData.cs @@ -0,0 +1,111 @@ +using fin.model; + +using OpenTK.Graphics.OpenGL; + +namespace fin.ui.rendering.gl.material { + public class CachedLightUniformData { + public IReadOnlyLight Light { get; } + + public int EnabledLocation { get; } + + public int SourceTypeLocation { get; } + public int PositionLocation { get; } + public int NormalLocation { get; } + + public int ColorLocation { get; } + + public int DiffuseFunctionLocation { get; } + public int AttenuationFunctionLocation { get; } + public int CosineAttenuationLocation { get; } + public int DistanceAttenuationLocation { get; } + + public CachedLightUniformData( + int lightIndex, + IReadOnlyLight light, + GlShaderProgram shaderProgram) { + this.Light = light; + + var lightAccessor = $"{MaterialConstants.LIGHTS_NAME}[{lightIndex}]"; + + this.EnabledLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.enabled"); + + this.SourceTypeLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.sourceType"); + this.PositionLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.position"); + this.NormalLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.normal"); + + this.ColorLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.color"); + + this.DiffuseFunctionLocation = + shaderProgram.GetUniformLocation($"{lightAccessor}.diffuseFunction"); + this.AttenuationFunctionLocation = + shaderProgram.GetUniformLocation( + $"{lightAccessor}.attenuationFunction"); + this.CosineAttenuationLocation = + shaderProgram.GetUniformLocation( + $"{lightAccessor}.cosineAttenuation"); + this.DistanceAttenuationLocation = + shaderProgram.GetUniformLocation( + $"{lightAccessor}.distanceAttenuation"); + } + + public void PassInUniforms() { + var light = this.Light; + if (!light.Enabled) { + return; + } + + GL.Uniform1(this.EnabledLocation, 1); + + GL.Uniform1(this.SourceTypeLocation, (int) light.SourceType); + + var position = light.Position; + if (position != null) { + GL.Uniform3(this.PositionLocation, + position.X, + position.Y, + position.Z); + } + + var normal = light.Normal; + if (normal != null) { + GL.Uniform3(this.NormalLocation, + normal.X, + normal.Y, + normal.Z); + } + + var strength = light.Strength; + var color = light.Color; + GL.Uniform4(this.ColorLocation, + color.Rf * strength, + color.Gf * strength, + color.Bf * strength, + color.Af * strength); + + GL.Uniform1(this.DiffuseFunctionLocation, (int) light.DiffuseFunction); + GL.Uniform1(this.AttenuationFunctionLocation, + (int) light.AttenuationFunction); + + var cosineAttenuation = light.CosineAttenuation; + if (cosineAttenuation != null) { + GL.Uniform3(this.CosineAttenuationLocation, + cosineAttenuation.X, + cosineAttenuation.Y, + cosineAttenuation.Z); + } + + var distanceAttenuation = light.DistanceAttenuation; + if (distanceAttenuation != null) { + GL.Uniform3(this.DistanceAttenuationLocation, + distanceAttenuation.X, + distanceAttenuation.Y, + distanceAttenuation.Z); + } + } + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedTextureUniformData.cs b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedTextureUniformData.cs new file mode 100644 index 000000000..44782fff9 --- /dev/null +++ b/FinModelUtility/Fin/Fin.Ui/src/rendering/gl/material/CachedTextureUniformData.cs @@ -0,0 +1,176 @@ +using System.Numerics; + +using fin.math.matrix.four; +using fin.math.matrix.three; +using fin.math.rotations; +using fin.model; +using fin.shaders.glsl; + +using OpenTK.Graphics.OpenGL; + +namespace fin.ui.rendering.gl.material { + public class CachedTextureUniformData { + public int TextureIndex { get; } + public ITexture? FinTexture { get; } + public GlTexture GlTexture { get; } + + public IReadOnlyFinMatrix3x2? Transform2d { get; } + public IReadOnlyFinMatrix4x4? Transform3d { get; } + + public bool HasFancyData { get; } + public int SamplerLocation { get; } + public int ClampMinLocation { get; } + public int ClampMaxLocation { get; } + public int Transform2dLocation { get; } + public int Transform3dLocation { get; } + + public CachedTextureUniformData( + string textureName, + int textureIndex, + ITexture? finTexture, + GlTexture glTexture, + GlShaderProgram shaderProgram) { + this.TextureIndex = textureIndex; + this.FinTexture = finTexture; + this.GlTexture = glTexture; + + this.HasFancyData = GlslUtil.RequiresFancyTextureData(finTexture); + if (!this.HasFancyData) { + this.SamplerLocation = + shaderProgram.GetUniformLocation($"{textureName}"); + } else { + this.SamplerLocation = + shaderProgram.GetUniformLocation($"{textureName}.sampler"); + this.ClampMinLocation = + shaderProgram.GetUniformLocation($"{textureName}.clampMin"); + this.ClampMaxLocation = + shaderProgram.GetUniformLocation($"{textureName}.clampMax"); + this.Transform2dLocation = + shaderProgram.GetUniformLocation($"{textureName}.transform2d"); + this.Transform3dLocation = + shaderProgram.GetUniformLocation($"{textureName}.transform3d"); + } + + var isTransform3d = finTexture?.IsTransform3d ?? false; + if (isTransform3d) { + this.Transform3d = CalculateTextureTransform3d_(finTexture); + } else { + this.Transform2d = CalculateTextureTransform2d_(finTexture); + } + } + + public unsafe void BindTextureAndPassInUniforms() { + this.GlTexture.Bind(this.TextureIndex); + GL.Uniform1(this.SamplerLocation, this.TextureIndex); + + if (this.HasFancyData) { + OpenTK.Vector2 clampMin = new(-10000); + OpenTK.Vector2 clampMax = new(10000); + + if (this.FinTexture?.WrapModeU == WrapMode.MIRROR_CLAMP) { + clampMin.X = -1; + clampMax.X = 2; + } + + if (this.FinTexture?.WrapModeV == WrapMode.MIRROR_CLAMP) { + clampMin.Y = -1; + clampMax.Y = 2; + } + + var clampS = this.FinTexture?.ClampS; + var clampT = this.FinTexture?.ClampT; + + if (clampS != null) { + clampMin.X = clampS.X; + clampMax.X = clampS.Y; + } + + if (clampT != null) { + clampMin.Y = clampT.X; + clampMax.Y = clampT.Y; + } + + GL.Uniform2(this.ClampMinLocation, clampMin); + GL.Uniform2(this.ClampMaxLocation, clampMax); + + if (!(this.FinTexture?.IsTransform3d ?? false)) { + var mat2d = this.Transform2d!.Impl; + var ptr = (float*) &mat2d; + GL.UniformMatrix2x3(this.Transform2dLocation, 1, true, ptr); + } else { + var mat3d = this.Transform3d!.Impl; + GlTransform.UniformMatrix4(this.Transform3dLocation, mat3d); + } + } + } + + private static IReadOnlyFinMatrix3x2 CalculateTextureTransform2d_( + ITexture? texture) { + if (texture == null) { + return FinMatrix3x2.IDENTITY; + } + + var textureOffset = texture.Offset; + var textureScale = texture.Scale; + var textureRotationRadians = texture.RotationRadians; + + if (textureOffset == null && + textureScale == null && + textureRotationRadians == null) { + return FinMatrix3x2.IDENTITY; + } + + Vector2? offset = null; + if (textureOffset != null) { + offset = new Vector2(textureOffset.X, textureOffset.Y); + } + + Vector2? scale = null; + if (textureScale != null) { + scale = new Vector2(textureScale.X, textureScale.Y); + } + + return FinMatrix3x2Util.FromTrss(offset, + textureRotationRadians?.Z, + scale, + null); + } + + private static IReadOnlyFinMatrix4x4 CalculateTextureTransform3d_( + ITexture? texture) { + if (texture == null) { + return FinMatrix4x4.IDENTITY; + } + + var textureOffset = texture.Offset; + var textureScale = texture.Scale; + var textureRotationRadians = texture.RotationRadians; + + if (textureOffset == null && + textureScale == null && + textureRotationRadians == null) { + return FinMatrix4x4.IDENTITY; + } + + Position? offset = null; + if (textureOffset != null) { + offset = + new Position(textureOffset.X, textureOffset.Y, textureOffset.Z); + } + + Quaternion? rotation = null; + if (textureRotationRadians != null) { + rotation = QuaternionUtil.CreateZyx(textureRotationRadians.X, + textureRotationRadians.Y, + textureRotationRadians.Z); + } + + Scale? scale = null; + if (textureScale != null) { + scale = new(textureScale.X, textureScale.Y, textureScale.Z); + } + + return FinMatrix4x4Util.FromTrs(offset, rotation, scale); + } + } +} \ No newline at end of file diff --git a/FinModelUtility/Fin/Fin/src/model/LightingInterfaces.cs b/FinModelUtility/Fin/Fin/src/model/LightingInterfaces.cs index 5c389ba4b..c5b4f29e2 100644 --- a/FinModelUtility/Fin/Fin/src/model/LightingInterfaces.cs +++ b/FinModelUtility/Fin/Fin/src/model/LightingInterfaces.cs @@ -11,6 +11,13 @@ public interface IReadOnlyLighting { float AmbientLightStrength { get; } } + public enum LightSourceType { + UNDEFINED, + POSITION, + RAY, + LINE, + } + public enum AttenuationFunction { NONE, SPECULAR, @@ -27,14 +34,16 @@ public interface IReadOnlyLight { string Name { get; } bool Enabled { get; } - IReadOnlyVector3 Position { get; } - IReadOnlyVector3 Normal { get; } + LightSourceType SourceType { get; } + + IReadOnlyVector3? Position { get; } + IReadOnlyVector3? Normal { get; } float Strength { get; } IColor Color { get; } - IReadOnlyVector3 CosineAttenuation { get; } - IReadOnlyVector3 DistanceAttenuation { get; } + IReadOnlyVector3? CosineAttenuation { get; } + IReadOnlyVector3? DistanceAttenuation { get; } AttenuationFunction AttenuationFunction { get; } DiffuseFunction DiffuseFunction { get; } diff --git a/FinModelUtility/Fin/Fin/src/model/impl/LightingImpl.cs b/FinModelUtility/Fin/Fin/src/model/impl/LightingImpl.cs index 2cb9b5abe..97cfb7f59 100644 --- a/FinModelUtility/Fin/Fin/src/model/impl/LightingImpl.cs +++ b/FinModelUtility/Fin/Fin/src/model/impl/LightingImpl.cs @@ -2,7 +2,6 @@ using System.Drawing; using fin.color; -using fin.schema.vector; namespace fin.model.impl { public partial class ModelImpl { @@ -35,17 +34,33 @@ public ILight SetName(string name) { public bool Enabled { get; set; } = true; - public IReadOnlyVector3 Position { get; private set; } = new Vector3f(); + public LightSourceType SourceType { get; private set; } + + private void UpdateSourceType_() { + if (this.Position != null && this.Normal != null) { + this.SourceType = LightSourceType.RAY; + } else if (this.Position != null) { + this.SourceType = LightSourceType.POSITION; + } else if (this.Normal != null) { + this.SourceType = LightSourceType.LINE; + } else { + this.SourceType = LightSourceType.UNDEFINED; + } + } + + public IReadOnlyVector3? Position { get; private set; } public ILight SetPosition(IReadOnlyVector3 position) { this.Position = position; + this.UpdateSourceType_(); return this; } - public IReadOnlyVector3 Normal { get; private set; } = new Vector3f(); + public IReadOnlyVector3? Normal { get; private set; } public ILight SetNormal(IReadOnlyVector3 normal) { this.Normal = normal; + this.UpdateSourceType_(); return this; } @@ -60,23 +75,23 @@ public ILight SetColor(IColor color) { } - public IReadOnlyVector3 CosineAttenuation { get; private set; } + public IReadOnlyVector3? CosineAttenuation { get; private set; } public ILight SetCosineAttenuation(IReadOnlyVector3 cosineAttenuation) { this.CosineAttenuation = cosineAttenuation; return this; } - public IReadOnlyVector3 DistanceAttenuation { get; private set; } + public IReadOnlyVector3? DistanceAttenuation { get; private set; } - public ILight - SetDistanceAttenuation(IReadOnlyVector3 distanceAttenuation) { + public ILight SetDistanceAttenuation( + IReadOnlyVector3 distanceAttenuation) { this.DistanceAttenuation = distanceAttenuation; return this; } public AttenuationFunction AttenuationFunction { get; private set; } = - AttenuationFunction.SPECULAR; + AttenuationFunction.NONE; public ILight SetAttenuationFunction( AttenuationFunction attenuationFunction) { diff --git a/FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs b/FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs index 2611bd963..a02ae175c 100644 --- a/FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs +++ b/FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs @@ -116,10 +116,13 @@ public static string GetLightHeader(bool withAmbientLight) { struct Light { bool enabled; + + int sourceType; vec3 position; vec3 normal; + vec4 color; - float shininess; + int diffuseFunction; int attenuationFunction; vec3 cosineAttenuation; @@ -138,11 +141,50 @@ public static string GetIndividualLightColorsFunction() { // https://github.com/LordNed/JStudio/blob/93c5c4479ffb1babefe829cfc9794694a1cb93e6/JStudio/J3D/ShaderGen/VertexShaderGen.cs#L336C9-L336C9 return $$""" - void getLightNormalAndAttenuation(Light light, vec3 position, vec3 normal, out vec3 lightNormal, out float attenuation) { - lightNormal = light.normal; - attenuation = 1; - return; + vec3 surfaceToLight = light.position - position; + + lightNormal = (light.sourceType == {{(int) LightSourceType.LINE}}) + ? light.normal : normalize(surfaceToLight); + + if (light.attenuationFunction == {{(int) AttenuationFunction.NONE}}) { + attenuation = 1; + return; + } + + + // Attenuation is calculated as a fraction, (cosine attenuation) / (distance attenuation). + + // Numerator (Cosine attenuation) + vec3 cosAttn = light.cosineAttenuation; + + vec3 attnDotLhs = (light.attenuationFunction == {{(int) AttenuationFunction.SPECULAR}}) + ? normal : lightNormal; + float attn = dot(attnDotLhs, light.normal); + vec3 attnPowers = vec3(1, attn, attn*attn); + + float attenuationNumerator = max(0, dot(cosAttn, attnPowers)); + + // Denominator (Distance attenuation) + float attenuationDenominator = 1; + if (light.sourceType != {{(int) LightSourceType.LINE}}) { + vec3 distAttn = light.distanceAttenuation; + + if (light.attenuationFunction == {{(int) AttenuationFunction.SPECULAR}}) { + float attn = max(0, dot(normal, light.normal)); + if (light.diffuseFunction != {{(int) DiffuseFunction.NONE}}) { + distAttn = normalize(distAttn); + } + + attenuationDenominator = dot(distAttn, attnPowers); + } else { + float dist2 = dot(surfaceToLight, surfaceToLight); + float dist = sqrt(dist2); + attenuationDenominator = dot(distAttn, vec3(1, dist, dist2)); + } + } + + attenuation = attenuationNumerator / attenuationDenominator; } void getIndividualLightColors(Light light, vec3 position, vec3 normal, float shininess, out vec4 diffuseColor, out vec4 specularColor) { @@ -156,8 +198,10 @@ void getIndividualLightColors(Light light, vec3 position, vec3 normal, float shi getLightNormalAndAttenuation(light, position, normal, lightNormal, attenuation); float lightAmount = 1; - float diffuseLightAmount = max(-dot(normal, lightNormal), 0); - lightAmount = min(diffuseLightAmount, 1); + if (light.diffuseFunction == {{(int) DiffuseFunction.SIGNED}} || light.diffuseFunction == {{(int) DiffuseFunction.CLAMP}}) { + float diffuseLightAmount = max(-dot(normal, lightNormal), 0); + lightAmount = min(diffuseLightAmount, 1); + } diffuseColor = light.color * lightAmount * attenuation;