Skip to content

Commit

Permalink
Reapply "Finally supported bump maps for BMD models."
Browse files Browse the repository at this point in the history
This reverts commit c70e3fe.
  • Loading branch information
MeltyPlayer committed Dec 21, 2024
1 parent c70e3fe commit 3bf11af
Show file tree
Hide file tree
Showing 22 changed files with 274 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Numerics;

using Assimp.Unmanaged;

using fin.language.equations.fixedFunction;
using fin.math;
using fin.model;
using fin.util.enumerables;


namespace fin.ui.rendering.gl.material;
Expand Down Expand Up @@ -48,6 +51,12 @@ protected override void Setup(
this.SetUpTexture($"texture{i}", i, finTexture, glTexture);
}

var normalTexture = material.NormalTexture;
if (normalTexture != null) {
var glTexture = GlTexture.FromTexture(normalTexture);
this.SetUpTexture("normalTexture", MaterialConstants.MAX_TEXTURES, normalTexture, glTexture);
}

var colorRegisterToUniform
= new Dictionary<IColorRegister, IShaderUniform<Vector3>>();
var scalarRegisterToUniform
Expand Down
30 changes: 17 additions & 13 deletions FinModelUtility/Fin/Fin.Ui/src/rendering/gl/util/GlUtil_Texture.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
using System.Runtime.CompilerServices;

using fin.model;
using fin.shaders.glsl;

using OpenTK.Graphics.OpenGL;

namespace fin.ui.rendering.gl;

public partial class GlState {
public int ActiveTexture { get; set; }= -1;
public int ActiveTexture { get; set; } = -1;

public int[] CurrentTextureBindings { get; set; } =
[-1, -1, -1, -1, -1, -1, -1, -1];
public int[] CurrentTextureBindings { get; }
= Enumerable.Repeat(-1, MaterialConstants.MAX_TEXTURES + 1).ToArray();
}

public static partial class GlUtil {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void BindTexture(int textureIndex, int value) {
if (currentState_.CurrentTextureBindings[textureIndex] == value) {
return;
}

if (currentState_.ActiveTexture != textureIndex) {
GL.ActiveTexture(TextureUnit.Texture0 +
(currentState_.ActiveTexture = textureIndex));
}
if (currentState_.CurrentTextureBindings[textureIndex] == value) {
return;
}

GL.BindTexture(TextureTarget.Texture2D,
currentState_.CurrentTextureBindings[textureIndex] = value);
if (currentState_.ActiveTexture != textureIndex) {
GL.ActiveTexture(TextureUnit.Texture0 +
(currentState_.ActiveTexture = textureIndex));
}

GL.BindTexture(TextureTarget.Texture2D,
currentState_.CurrentTextureBindings[textureIndex]
= value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void UnbindTexture(int textureIndex)
=> BindTexture(textureIndex, -1);
Expand Down
96 changes: 96 additions & 0 deletions FinModelUtility/Fin/Fin/src/image/BumpMapUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using fin.image.formats;

using SixLabors.ImageSharp.PixelFormats;

namespace fin.image;

public static class BumpMapUtils {
/// <summary>
/// Shamelessly stolen from:
/// https://stackoverflow.com/questions/10652797/whats-the-logic-behind-creating-a-normal-map-from-a-texture
/// </summary>
public static unsafe Rgb24Image ConvertBumpMapImageToNormalImage(
IReadOnlyImage image) {
var normalImage =
new Rgb24Image(PixelFormat.RGB888, image.Width, image.Height);
using var normalImageLock = normalImage.UnsafeLock();
var normalImageScan0 = normalImageLock.pixelScan0;

image.Access(bumpGetHandler => {
for (var y = 0; y < image.Height; ++y) {
for (var x = 0; x < image.Width; ++x) {
bumpGetHandler(
x,
y,
out var centerIntensity,
out _,
out _,
out _);

byte leftIntensity;
if (x > 0) {
bumpGetHandler(
x - 1,
y,
out leftIntensity,
out _,
out _,
out _);
} else {
leftIntensity = centerIntensity;
}

byte rightIntensity;
if (x < image.Width - 1) {
bumpGetHandler(
x + 1,
y,
out rightIntensity,
out _,
out _,
out _);
} else {
rightIntensity = centerIntensity;
}

byte upIntensity;
if (y > 0) {
bumpGetHandler(
x,
y - 1,
out upIntensity,
out _,
out _,
out _);
} else {
upIntensity = centerIntensity;
}

byte downIntensity;
if (y < image.Height - 1) {
bumpGetHandler(
x,
y + 1,
out downIntensity,
out _,
out _,
out _);
} else {
downIntensity = centerIntensity;
}

var xIntensity
= ((leftIntensity / 255f - rightIntensity / 255f + 1) * .5f) *
255;
var yIntensity
= ((upIntensity / 255f - downIntensity / 255f + 1) * .5f) * 255;

normalImageScan0[y * image.Width + x]
= new Rgb24((byte) xIntensity, (byte) yIntensity, 255);
}
}
});

return normalImage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public void Print(
var registers = material.Registers;
var textures = material.TextureSources;

var normalTexture = material.NormalTexture;
var hasNormalTexture = normalTexture != null;

sb.AppendLine($"#version {GlslConstants.FRAGMENT_SHADER_VERSION}");
sb.AppendLine(GlslConstants.FLOAT_PRECISION);
sb.AppendLine();
Expand Down Expand Up @@ -92,6 +95,12 @@ public void Print(
}
}

if (hasNormalTexture) {
sb.AppendLine(
$"uniform {GlslUtil.GetTypeOfTexture(normalTexture, this.animations_)} normalTexture;");
hadUniform = true;
}

foreach (var colorRegister in registers.ColorRegisters) {
if (equations.DoOutputsDependOn(colorRegister)) {
hadUniform = true;
Expand Down Expand Up @@ -133,6 +142,14 @@ public void Print(
AppendLineBetweenUniformsAndIns();
sb.AppendLine("in vec3 vertexPosition;");
sb.AppendLine("in vec3 vertexNormal;");

if (hasNormalTexture &&
shaderRequirements.TangentType == TangentType.DEFINED) {
sb.AppendLine("""
in vec3 tangent;
in vec3 binormal;
""");
}
}

var usedColors = shaderRequirements.UsedColors;
Expand Down Expand Up @@ -177,12 +194,41 @@ public void Print(

// Calculate lighting
if (dependsOnLights) {
sb.AppendLine(
$"""
// Have to renormalize because the vertex normals can become distorted when interpolated.
vec3 fragNormal = normalize(vertexNormal);
if (!hasNormalTexture) {
sb.AppendLine(
"""
// Have to renormalize because the vertex normals can become distorted when interpolated.
vec3 fragNormal = normalize(vertexNormal);
""");
} else {
sb.AppendLine(
$"""
// Have to renormalize because the vertex normals can become distorted when interpolated.
vec3 fragNormal = normalize(vertexNormal);
vec3 textureNormal = {GlslUtil.ReadColorFromTexture("normalTexture", $"{GlslConstants.IN_UV_NAME}{normalTexture?.UvIndex ?? 0}", normalTexture, this.animations_)}.xyz * 2.0 - 1.0;
fragNormal = normalize(mat3(tangent, binormal, fragNormal) * textureNormal);
""");

if (shaderRequirements.TangentType is TangentType.CALCULATED) {
// Shamelessly stolen from:
// https://community.khronos.org/t/computing-the-tangent-space-in-the-fragment-shader/52861
var texCoordName
= $"{GlslConstants.IN_UV_NAME}{normalTexture.UvIndex}";
sb.AppendLine(
$"""
vec3 Q1 = dFdx(vertexPosition);
vec3 Q2 = dFdy(vertexPosition);
vec2 st1 = dFdx({texCoordName});
vec2 st2 = dFdy({texCoordName});
vec3 tangent = normalize(Q1*st2.t - Q2*st1.t);
vec3 binormal = normalize(-Q1*st2.s + Q2*st1.s);
""");
}
}

""");
// TODO: Optimize this if the shader depends on merged lighting as well as individual lights for some reason.
if (dependsOnAnIndividualLight) {
sb.AppendLine(
Expand All @@ -209,7 +255,7 @@ public void Print(
vec4 mergedLightDiffuseColor = vec4(0);
vec4 mergedLightSpecularColor = vec4(0);
getMergedLightColors(vertexPosition, fragNormal, {GlslConstants.UNIFORM_SHININESS_NAME}, mergedLightDiffuseColor, mergedLightSpecularColor);
""");
}
}
Expand Down Expand Up @@ -322,14 +368,20 @@ private string GetAlphaCompareText_(
string alphaAccessorText,
float reference)
=> alphaCompareType switch {
AlphaCompareType.Never => "false",
AlphaCompareType.Less => $"{alphaAccessorText} < {reference:0.0###########}",
AlphaCompareType.Equal => $"{alphaAccessorText} == {reference:0.0###########}",
AlphaCompareType.LEqual => $"{alphaAccessorText} <= {reference:0.0###########}",
AlphaCompareType.Greater => $"{alphaAccessorText} > {reference:0.0###########}",
AlphaCompareType.NEqual => $"{alphaAccessorText} != {reference:0.0###########}",
AlphaCompareType.GEqual => $"{alphaAccessorText} >= {reference:0.0###########}",
AlphaCompareType.Always => "true",
AlphaCompareType.Never => "false",
AlphaCompareType.Less =>
$"{alphaAccessorText} < {reference:0.0###########}",
AlphaCompareType.Equal =>
$"{alphaAccessorText} == {reference:0.0###########}",
AlphaCompareType.LEqual =>
$"{alphaAccessorText} <= {reference:0.0###########}",
AlphaCompareType.Greater =>
$"{alphaAccessorText} > {reference:0.0###########}",
AlphaCompareType.NEqual =>
$"{alphaAccessorText} != {reference:0.0###########}",
AlphaCompareType.GEqual =>
$"{alphaAccessorText} >= {reference:0.0###########}",
AlphaCompareType.Always => "true",
_ => throw new ArgumentOutOfRangeException(
nameof(alphaCompareType),
alphaCompareType,
Expand Down
12 changes: 9 additions & 3 deletions FinModelUtility/Fin/Fin/src/model/MaterialInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ IMaterial SetBlendingSeparate(
LogicOp logicOp);
}


[GenerateReadOnly]
public partial interface IMaterialWithNormalTexture : IMaterial {
IReadOnlyTexture? NormalTexture { get; set; }
}


[GenerateReadOnly]
public partial interface INullMaterial : IMaterial;

Expand All @@ -135,10 +142,9 @@ public partial interface IColorMaterial : IMaterial {
}

[GenerateReadOnly]
public partial interface IStandardMaterial : IMaterial {
public partial interface IStandardMaterial : IMaterialWithNormalTexture {
IReadOnlyTexture? DiffuseTexture { get; set; }
IReadOnlyTexture? AmbientOcclusionTexture { get; set; }
IReadOnlyTexture? NormalTexture { get; set; }
IReadOnlyTexture? EmissiveTexture { get; set; }
IReadOnlyTexture? SpecularTexture { get; set; }
}
Expand Down Expand Up @@ -310,7 +316,7 @@ public enum FixedFunctionSource {
}

[GenerateReadOnly]
public partial interface IFixedFunctionMaterial : IMaterial {
public partial interface IFixedFunctionMaterial : IMaterialWithNormalTexture {
IFixedFunctionEquations<FixedFunctionSource> Equations { get; }
IFixedFunctionRegisters Registers { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,17 @@ public IFixedFunctionMaterial SetAlphaCompare(
AlphaCompareType.Always;

public float AlphaReference1 { get; private set; }

private IReadOnlyTexture? normalTexture_;

public IReadOnlyTexture? NormalTexture {
get => this.normalTexture_;
set {
this.normalTexture_ = value;
if (value != null) {
this.textures_.Add(value);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,7 @@ var usesDiffuse
])
.ToArray());

KnownChannel
mainTextureChannel;
KnownChannel mainTextureChannel;
if (usesSpecular) {
// TODO: Get specular color
gltfMaterialBuilder
Expand Down Expand Up @@ -211,6 +210,14 @@ var texture
.UseTexture(texture, gltfImageByFinImage[texture.Image]);
}

var normalTexture = fixedFunctionMaterial.NormalTexture;
if (normalTexture != null) {
gltfMaterialBuilder
.UseChannel(KnownChannel.Normal)
.UseTexture(normalTexture,
gltfImageByFinImage[normalTexture.Image]);
}

break;
}
default: {
Expand Down
2 changes: 2 additions & 0 deletions FinModelUtility/Fin/Fin/src/shaders/glsl/GlslUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ public static string GetVertexSrc(IReadOnlyModel model,

var modelRequirements = ModelRequirements.FromModel(model);
var hasNormals = modelRequirements.HasNormals;

var hasTangents = modelRequirements.HasTangents;
var hasBinormals = hasNormals && hasTangents;

var numBones = modelRequirements.NumBones;

vertexSrc.AppendLine($$"""
Expand Down
Loading

0 comments on commit 3bf11af

Please sign in to comment.