diff --git a/FModel/Resources/default.frag b/FModel/Resources/default.frag index d839e904..7b611df2 100644 --- a/FModel/Resources/default.frag +++ b/FModel/Resources/default.frag @@ -1,118 +1,136 @@ #version 330 core +#define MAX_UV_COUNT 8 in vec3 fPos; in vec3 fNormal; +in vec3 fTangent; in vec2 fTexCoords; in float fTexLayer; in vec4 fColor; -struct Material { - sampler2D diffuseMap[8]; - sampler2D normalMap[8]; - sampler2D specularMap[8]; - sampler2D emissionMap[8]; - - bool useSpecularMap; - - bool hasDiffuseColor; - vec4 diffuseColor; - - vec4 emissionColor[8]; - - float metallic_value; - float roughness_value; +struct Texture +{ + sampler2D Sampler; + vec4 Color; }; -struct Light { - vec3 position; - vec3 ambient; - vec3 diffuse; - vec3 specular; +struct Boost +{ + vec3 Color; + float Exponent; }; -uniform Material material; -uniform Light light; -uniform vec3 viewPos; -uniform bool display_vertex_colors; -uniform int numTexCoords; +struct Mask +{ + sampler2D Sampler; + Boost SkinBoost; + + float AmbientOcclusion; + float Cavity; +}; + +struct Parameters +{ + Texture Diffuse[MAX_UV_COUNT]; + Texture Normals[MAX_UV_COUNT]; + Texture SpecularMasks[MAX_UV_COUNT]; + Texture Emissive[MAX_UV_COUNT]; + + Mask M; + bool HasM; + + float Roughness; + float SpecularMult; + float EmissiveMult; + + float UVScale; +}; + +uniform Parameters uParameters; +uniform int uNumTexCoords; +uniform vec3 uViewPos; +uniform bool bVertexColors; +uniform bool bVertexNormals; +uniform bool bVertexTangent; +uniform bool bVertexTexCoords; out vec4 FragColor; int LayerToIndex() { - return min(int(fTexLayer), numTexCoords - 1); + return min(int(fTexLayer), uNumTexCoords - 1); } -vec4 SamplerSelector(sampler2D array[8]) +vec4 SamplerToVector(sampler2D s) { - return texture(array[LayerToIndex()], fTexCoords); + return texture(s, fTexCoords * uParameters.UVScale); } -vec4 VectorSelector(vec4 array[8]) +vec3 ComputeNormals(int layer) { - return array[LayerToIndex()]; -} + vec3 normal = SamplerToVector(uParameters.Normals[layer].Sampler).rgb * 2.0 - 1.0; -vec3 getNormalFromMap() -{ - vec3 tangentNormal = SamplerSelector(material.normalMap).xyz * 2.0 - 1.0; - - vec3 q1 = dFdx(fPos); - vec3 q2 = dFdy(fPos); - vec2 st1 = dFdx(fTexCoords); - vec2 st2 = dFdy(fTexCoords); - - vec3 n = normalize(fNormal); - vec3 t = normalize(q1*st2.t - q2*st1.t); + vec3 t = normalize(fTangent); + vec3 n = normalize(fNormal); vec3 b = -normalize(cross(n, t)); mat3 tbn = mat3(t, b, n); - return normalize(tbn * tangentNormal); + return normalize(tbn * normal); } void main() { - if (display_vertex_colors) + if (bVertexColors) { FragColor = fColor; } + else if (bVertexNormals) + { + FragColor = vec4(fNormal, 1); + } + else if (bVertexTangent) + { + FragColor = vec4(fTangent, 1); + } + else if (bVertexTexCoords) + { + FragColor = vec4(fTexCoords, 0, 1); + } else { - vec3 n_normal_map = getNormalFromMap(); - vec3 n_light_direction = normalize(light.position - fPos); - float diff = max(dot(n_normal_map, n_light_direction), 0.0f); + int layer = LayerToIndex(); + vec4 diffuse = SamplerToVector(uParameters.Diffuse[layer].Sampler); + vec3 result = uParameters.Diffuse[layer].Color.rgb * diffuse.rgb; - if (material.hasDiffuseColor) + vec3 normals = ComputeNormals(layer); + vec3 light_direction = normalize(uViewPos - fPos); + result += max(dot(normals, light_direction), 0.0f) * result; + + if (uParameters.HasM) { - vec4 result = vec4(light.ambient, 1.0) * material.diffuseColor; - result += vec4(light.diffuse, 1.0) * diff * material.diffuseColor; - FragColor = result; - } - else - { - vec4 diffuse_map = SamplerSelector(material.diffuseMap); - vec3 diffuse_no_alpha = vec3(diffuse_map); - vec3 result = light.ambient * diffuse_no_alpha; + vec3 m = SamplerToVector(uParameters.M.Sampler).rgb; + float subsurface = clamp(m.b * .04f, 0.0f, 1.0f); - // diffuse - result += light.diffuse * diff * diffuse_no_alpha; - - // specular - if (material.useSpecularMap) + if (subsurface > 0.0f && uParameters.M.SkinBoost.Exponent > 0.0f) { - vec3 n_view_direction = normalize(viewPos - fPos); - vec3 reflect_direction = reflect(-n_light_direction, n_normal_map); - float metallic = pow(max(dot(n_view_direction, reflect_direction), 0.0f), material.metallic_value); - vec3 specular_map = vec3(SamplerSelector(material.specularMap)); - result += specular_map.r * light.specular * (metallic * specular_map.g); - result += material.roughness_value * specular_map.b; + vec3 color = pow(uParameters.M.SkinBoost.Exponent, 2) * uParameters.M.SkinBoost.Color; + result *= clamp(color * m.b, 0.0f, 1.0f); } - // emission - vec3 emission_map = vec3(SamplerSelector(material.emissionMap)); - result += VectorSelector(material.emissionColor).rgb * emission_map; - - FragColor = vec4(result, 1.0); + result *= m.r * uParameters.M.AmbientOcclusion; + result += m.g * uParameters.M.Cavity; } + + vec3 reflect_direction = reflect(-light_direction, normals); + vec3 specular_masks = SamplerToVector(uParameters.SpecularMasks[layer].Sampler).rgb; + float specular = uParameters.SpecularMult * max(0.0f, specular_masks.r); + float metallic = max(0.0f, dot(light_direction, reflect_direction) * specular_masks.g); + float roughness = max(0.0f, uParameters.Roughness * specular_masks.b); + result += metallic * roughness * specular; + + vec4 emissive = SamplerToVector(uParameters.Emissive[layer].Sampler); + result += uParameters.Emissive[layer].Color.rgb * emissive.rgb * uParameters.EmissiveMult; + + FragColor = vec4(result, 1.0f); } } diff --git a/FModel/Resources/default.vert b/FModel/Resources/default.vert index f8288001..e56cf130 100644 --- a/FModel/Resources/default.vert +++ b/FModel/Resources/default.vert @@ -2,13 +2,14 @@ layout (location = 1) in vec3 vPos; layout (location = 2) in vec3 vNormal; -layout (location = 3) in vec2 vTexCoords; -layout (location = 4) in float vTexLayer; -layout (location = 5) in vec4 vColor; -layout (location = 6) in ivec4 vBoneIds; -layout (location = 7) in vec4 vWeights; -layout (location = 8) in mat4 vInstanceMatrix; -layout (location = 12) in vec3 vMorphTarget; +layout (location = 3) in vec3 vTangent; +layout (location = 4) in vec2 vTexCoords; +layout (location = 5) in float vTexLayer; +layout (location = 6) in vec4 vColor; +layout (location = 7) in ivec4 vBoneIds; +layout (location = 8) in vec4 vWeights; +layout (location = 9) in mat4 vInstanceMatrix; +layout (location = 13) in vec3 vMorphTarget; uniform mat4 uView; uniform mat4 uProjection; @@ -16,6 +17,7 @@ uniform float uMorphTime; out vec3 fPos; out vec3 fNormal; +out vec3 fTangent; out vec2 fTexCoords; out float fTexLayer; out vec4 fColor; @@ -27,6 +29,7 @@ void main() fPos = vec3(vInstanceMatrix * vec4(pos, 1.0)); fNormal = mat3(transpose(inverse(vInstanceMatrix))) * vNormal; + fTangent = mat3(transpose(inverse(vInstanceMatrix))) * vTangent; fTexCoords = vTexCoords; fTexLayer = vTexLayer; fColor = vColor; diff --git a/FModel/Resources/outline.vert b/FModel/Resources/outline.vert index fe031346..bec2f1d5 100644 --- a/FModel/Resources/outline.vert +++ b/FModel/Resources/outline.vert @@ -2,20 +2,20 @@ layout (location = 1) in vec3 vPos; layout (location = 2) in vec3 vNormal; -layout (location = 8) in mat4 vInstanceMatrix; -layout (location = 12) in vec3 vMorphTarget; +layout (location = 9) in mat4 vInstanceMatrix; +layout (location = 13) in vec3 vMorphTarget; uniform mat4 uView; +uniform vec3 uViewPos; uniform mat4 uProjection; uniform float uMorphTime; -uniform vec3 viewPos; void main() { vec3 pos = vec3(vInstanceMatrix * vec4(mix(vPos, vMorphTarget, uMorphTime), 1.0)); vec3 nor = mat3(transpose(inverse(vInstanceMatrix))) * vNormal; - float scaleFactor = distance(pos, viewPos) * 0.0025; + float scaleFactor = distance(pos, uViewPos) * 0.0025; vec3 scaleVertex = pos + nor * scaleFactor; gl_Position = uProjection * uView * vec4(scaleVertex, 1.0); } diff --git a/FModel/Resources/picking.vert b/FModel/Resources/picking.vert index 53ee7fff..ba37651b 100644 --- a/FModel/Resources/picking.vert +++ b/FModel/Resources/picking.vert @@ -1,8 +1,8 @@ #version 330 core layout (location = 1) in vec3 vPos; -layout (location = 8) in mat4 vInstanceMatrix; -layout (location = 12) in vec3 vMorphTarget; +layout (location = 9) in mat4 vInstanceMatrix; +layout (location = 13) in vec3 vMorphTarget; uniform mat4 uView; uniform mat4 uProjection; diff --git a/FModel/Views/Snooper/Cache.cs b/FModel/Views/Snooper/Cache.cs index ce35a67f..b9479c8d 100644 --- a/FModel/Views/Snooper/Cache.cs +++ b/FModel/Views/Snooper/Cache.cs @@ -56,24 +56,6 @@ public class Cache : IDisposable } } - public void Render(Shader shader) - { - foreach (var model in Models.Values) - { - if (!model.Show) continue; - model.Render(shader); - } - } - - public void Outline(Shader shader) - { - foreach (var model in Models.Values) - { - if (!model.IsSelected || !model.Show) continue; - model.Outline(shader); - } - } - public void DisposeModels() { foreach (var model in Models.Values) diff --git a/FModel/Views/Snooper/Material.cs b/FModel/Views/Snooper/Material.cs index 4582e60a..85d767fe 100644 --- a/FModel/Views/Snooper/Material.cs +++ b/FModel/Views/Snooper/Material.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using CUE4Parse.UE4.Assets.Exports.Material; using CUE4Parse.UE4.Assets.Exports.Texture; +using CUE4Parse.UE4.Objects.Core.Math; using OpenTK.Graphics.OpenGL4; -using OpenTK.Mathematics; namespace FModel.Views.Snooper; @@ -22,12 +23,17 @@ public class Material : IDisposable public Texture[] SpecularMasks; public Texture[] Emissive; - public Vector4 DiffuseColor; - public Vector4[] EmissionColor; - public bool HasSpecularMap; - public bool HasDiffuseColor; + public Vector4[] DiffuseColor; + public Vector4[] EmissiveColor; - private Vector3 _ambientLight; + public Mask M; + public bool HasM; + + public float Roughness; + public float SpecularMult = 1f; + public float EmissiveMult = 1f; + + public float UVScale = 1f; public Material() { @@ -39,13 +45,7 @@ public class Material : IDisposable Normals = Array.Empty(); SpecularMasks = Array.Empty(); Emissive = Array.Empty(); - - DiffuseColor = Vector4.Zero; - EmissionColor = Array.Empty(); - HasSpecularMap = false; - HasDiffuseColor = false; - - _ambientLight = Vector3.One; + EmissiveColor = Array.Empty(); } public Material(UMaterialInterface unrealMaterial) : this() @@ -65,7 +65,7 @@ public class Material : IDisposable if (Parameters.IsNull) { - DiffuseColor = new Vector4(1, 0, 0, 1); + Diffuse = new[] { new Texture(new FLinearColor(1f, 0f, 0f, 1f)) }; } else { @@ -74,29 +74,53 @@ public class Material : IDisposable Fill(cache, numTexCoords, ref SpecularMasks, true, CMaterialParams2.SpecularMasks, CMaterialParams2.FallbackSpecularMasks); Fill(cache, numTexCoords, ref Emissive, true, CMaterialParams2.Emissive, CMaterialParams2.FallbackEmissive); - // if (Parameters.Colors.TryGetValue("ColorMult", out var color) && color is { A: > 0}) - // { - // DiffuseColor = new Vector4(color.R, color.G, color.B, color.A); - // } + if (Parameters.TryGetTexture2d(out var o, "M") && cache.TryGetCachedTexture(o, out var t)) + { + M = new Mask { Texture = t, AmbientOcclusion = 0.7f }; + HasM = true; + if (Parameters.TryGetLinearColor(out var l, "Skin Boost Color And Exponent")) + M.SkinBoost = new Boost { Color = new Vector3(l.R, l.G, l.B), Exponent = l.A }; + } - EmissionColor = new Vector4[numTexCoords]; - for (int i = 0; i < EmissionColor.Length; i++) + if (Parameters.TryGetScalar(out var roughnessMin, "RoughnessMin", "SpecRoughnessMin") && + Parameters.TryGetScalar(out var roughnessMax, "RoughnessMax", "SpecRoughnessMax")) + Roughness = (roughnessMin + roughnessMax) / 2f; + if (Parameters.TryGetScalar(out var roughness, "Rough", "Roughness")) + Roughness = roughness; + + if (Parameters.TryGetScalar(out var specularMult, "SpecularMult")) + SpecularMult = specularMult; + if (Parameters.TryGetScalar(out var emissiveMult, "emissive mult", "Emissive_Mult")) + EmissiveMult = emissiveMult; + + if (Parameters.TryGetScalar(out var uvScale, "UV Scale")) + UVScale = uvScale; + + DiffuseColor = new Vector4[numTexCoords]; + for (int i = 0; i < DiffuseColor.Length; i++) + { + if (Diffuse[i] == null) continue; + + if (Parameters.TryGetLinearColor(out var color, "ColorMult", "Color_mul", "Color") && color is { A: > 0 }) + { + DiffuseColor[i] = new Vector4(color.R, color.G, color.B, color.A); + } + else DiffuseColor[i] = new Vector4(0.5f); + } + + EmissiveColor = new Vector4[numTexCoords]; + for (int i = 0; i < EmissiveColor.Length; i++) { if (Emissive[i] == null) continue; - if (Parameters.TryGetLinearColor(out var color, $"Emissive{(i > 0 ? i + 1 : "")}") && color is { A: > 0 }) + string[] names = i == 0 ? new[] { "Emissive", "EmissiveColor", "Emissive Color" } : new[] { $"Emissive{i + 1}" }; + if (Parameters.TryGetLinearColor(out var color, names) && color is { A: > 0 }) { - EmissionColor[i] = new Vector4(color.R, color.G, color.B, color.A); + EmissiveColor[i] = new Vector4(color.R, color.G, color.B, color.A); } - else EmissionColor[i] = Vector4.One; + else EmissiveColor[i] = Vector4.One; } - - // diffuse light is based on normal map, so increase ambient if no normal map - _ambientLight = new Vector3(Normals[0] == null ? 1.0f : 0.2f); - HasSpecularMap = SpecularMasks[0] != null; } - - HasDiffuseColor = DiffuseColor != Vector4.Zero; } /// @@ -118,11 +142,6 @@ public class Material : IDisposable array[i] = array[i - 1]; } } - else if (Parameters.Colors.TryGetValue("Color", out var linearColor)) // POC - { - for (int i = 0; i < array.Length; i++) - array[i] = new Texture(linearColor); - } else if (Parameters.Textures.TryGetValue(fallback, out var u) && u is UTexture2D o && cache.TryGetCachedTexture(o, out var t)) { for (int i = 0; i < array.Length; i++) @@ -138,41 +157,45 @@ public class Material : IDisposable public void Render(Shader shader) { var unit = 0; - for (var i = 0; i < Diffuse.Length; i++) { - shader.SetUniform($"material.diffuseMap[{i}]", unit); + shader.SetUniform($"uParameters.Diffuse[{i}].Sampler", unit); + shader.SetUniform($"uParameters.Diffuse[{i}].Color", DiffuseColor[i]); Diffuse[i]?.Bind(TextureUnit.Texture0 + unit++); } for (var i = 0; i < Normals.Length; i++) { - shader.SetUniform($"material.normalMap[{i}]", unit); + shader.SetUniform($"uParameters.Normals[{i}].Sampler", unit); Normals[i]?.Bind(TextureUnit.Texture0 + unit++); } for (var i = 0; i < SpecularMasks.Length; i++) { - shader.SetUniform($"material.specularMap[{i}]", unit); + shader.SetUniform($"uParameters.SpecularMasks[{i}].Sampler", unit); SpecularMasks[i]?.Bind(TextureUnit.Texture0 + unit++); } for (var i = 0; i < Emissive.Length; i++) { - shader.SetUniform($"material.emissionMap[{i}]", unit); - shader.SetUniform($"material.emissionColor[{i}]", EmissionColor[i]); + shader.SetUniform($"uParameters.Emissive[{i}].Sampler", unit); + shader.SetUniform($"uParameters.Emissive[{i}].Color", EmissiveColor[i]); Emissive[i]?.Bind(TextureUnit.Texture0 + unit++); } - shader.SetUniform("material.useSpecularMap", HasSpecularMap); + M.Texture?.Bind(TextureUnit.Texture31); + shader.SetUniform("uParameters.M.Sampler", 31); + shader.SetUniform("uParameters.M.SkinBoost.Color", M.SkinBoost.Color); + shader.SetUniform("uParameters.M.SkinBoost.Exponent", M.SkinBoost.Exponent); + shader.SetUniform("uParameters.M.AmbientOcclusion", M.AmbientOcclusion); + shader.SetUniform("uParameters.M.Cavity", M.Cavity); + shader.SetUniform("uParameters.HasM", HasM); - shader.SetUniform("material.hasDiffuseColor", HasDiffuseColor); - shader.SetUniform("material.diffuseColor", DiffuseColor); + shader.SetUniform("uParameters.Roughness", Roughness); + shader.SetUniform("uParameters.SpecularMult", SpecularMult); + shader.SetUniform("uParameters.EmissiveMult", EmissiveMult); - shader.SetUniform("material.metallic_value", 1f); - shader.SetUniform("material.roughness_value", 0f); - - shader.SetUniform("light.ambient", _ambientLight); + shader.SetUniform("uParameters.UVScale", UVScale); } public void Dispose() @@ -193,6 +216,22 @@ public class Material : IDisposable { Emissive[i]?.Dispose(); } + M.Texture?.Dispose(); GL.DeleteProgram(_handle); } } + +public struct Mask +{ + public Texture Texture; + public Boost SkinBoost; + + public float AmbientOcclusion; + public float Cavity; +} + +public struct Boost +{ + public Vector3 Color; + public float Exponent; +} diff --git a/FModel/Views/Snooper/Model.cs b/FModel/Views/Snooper/Model.cs index 2a13dbde..d9a99cf3 100644 --- a/FModel/Views/Snooper/Model.cs +++ b/FModel/Views/Snooper/Model.cs @@ -21,7 +21,7 @@ public class Model : IDisposable private BufferObject _matrixVbo; private VertexArrayObject _vao; - private readonly int _vertexSize = 10; // VertexIndex + Position + Normal + UV + TextureLayer + private readonly int _vertexSize = 13; // VertexIndex + Position + Normal + Tangent + UV + TextureLayer private readonly uint[] _facesIndex = { 1, 0, 2 }; private const int _faceSize = 3; // just so we don't have to do .Length @@ -46,7 +46,10 @@ public class Model : IDisposable public bool Wireframe; public bool IsSetup; public bool IsSelected; - public bool DisplayVertexColors; + public bool bVertexColors; + public bool bVertexNormals; + public bool bVertexTangent; + public bool bVertexTexCoords; public bool DisplayBones; public int SelectedInstance; public float MorphTime; @@ -127,6 +130,9 @@ public class Model : IDisposable Vertices[baseIndex + count++] = vert.Normal.X; Vertices[baseIndex + count++] = vert.Normal.Z; Vertices[baseIndex + count++] = vert.Normal.Y; + Vertices[baseIndex + count++] = vert.Tangent.X; + Vertices[baseIndex + count++] = vert.Tangent.Z; + Vertices[baseIndex + count++] = vert.Tangent.Y; Vertices[baseIndex + count++] = vert.UV.U; Vertices[baseIndex + count++] = vert.UV.V; Vertices[baseIndex + count++] = lod.ExtraUV.IsValueCreated ? lod.ExtraUV.Value[0][indice].U : .5f; @@ -188,7 +194,7 @@ public class Model : IDisposable for (var i = 0; i < instanceMatrix.Length; i++) instanceMatrix[i] = Transforms[i].Matrix; _matrixVbo = new BufferObject(instanceMatrix, BufferTarget.ArrayBuffer); - _vao.BindInstancing(); // VertexAttributePointer 7, 8, 9, 10 + _vao.BindInstancing(); // VertexAttributePointer } public void Setup(Cache cache) @@ -202,11 +208,12 @@ public class Model : IDisposable _vao.VertexAttributePointer(0, 1, VertexAttribPointerType.Int, _vertexSize, 0); // vertex index _vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 1); // position _vao.VertexAttributePointer(2, 3, VertexAttribPointerType.Float, _vertexSize, 4); // normal - _vao.VertexAttributePointer(3, 2, VertexAttribPointerType.Float, _vertexSize, 7); // uv - _vao.VertexAttributePointer(4, 1, VertexAttribPointerType.Float, _vertexSize, 9); // texture index - _vao.VertexAttributePointer(5, 4, VertexAttribPointerType.Float, _vertexSize, 10); // color - _vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Int, _vertexSize, 14); // boneids - _vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Float, _vertexSize, 18); // boneweights + _vao.VertexAttributePointer(3, 3, VertexAttribPointerType.Float, _vertexSize, 7); // tangent + _vao.VertexAttributePointer(4, 2, VertexAttribPointerType.Float, _vertexSize, 10); // uv + _vao.VertexAttributePointer(5, 1, VertexAttribPointerType.Float, _vertexSize, 12); // texture index + _vao.VertexAttributePointer(6, 4, VertexAttribPointerType.Float, _vertexSize, 13); // color + _vao.VertexAttributePointer(7, 4, VertexAttribPointerType.Int, _vertexSize, 17); // boneids + _vao.VertexAttributePointer(8, 4, VertexAttribPointerType.Float, _vertexSize, 21); // boneweights SetupInstances(); // instanced models transform @@ -226,7 +233,7 @@ public class Model : IDisposable _morphVbo = new BufferObject(Morphs[morph].Vertices, BufferTarget.ArrayBuffer); } _vao.Bind(); - _vao.VertexAttributePointer(12, 3, VertexAttribPointerType.Float, 3, 0); // morph position + _vao.VertexAttributePointer(13, 3, VertexAttribPointerType.Float, 3, 0); // morph position _vao.Unbind(); } @@ -249,8 +256,11 @@ public class Model : IDisposable _vao.Bind(); shader.SetUniform("uMorphTime", MorphTime); - shader.SetUniform("display_vertex_colors", DisplayVertexColors); - shader.SetUniform("numTexCoords", NumTexCoords); + shader.SetUniform("uNumTexCoords", NumTexCoords); + shader.SetUniform("bVertexColors", bVertexColors); + shader.SetUniform("bVertexNormals", bVertexNormals); + shader.SetUniform("bVertexTangent", bVertexTangent); + shader.SetUniform("bVertexTexCoords", bVertexTexCoords); GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill); for (int section = 0; section < Sections.Length; section++) @@ -280,12 +290,11 @@ public class Model : IDisposable public void Outline(Shader shader) { - GL.StencilMask(0x00); + GL.Enable(EnableCap.StencilTest); GL.Disable(EnableCap.DepthTest); GL.StencilFunc(StencilFunction.Notequal, 1, 0xFF); _vao.Bind(); - shader.Use(); shader.SetUniform("uMorphTime", MorphTime); GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill); @@ -298,7 +307,7 @@ public class Model : IDisposable GL.StencilFunc(StencilFunction.Always, 0, 0xFF); GL.Enable(EnableCap.DepthTest); - GL.StencilMask(0xFF); + GL.Disable(EnableCap.StencilTest); } public void Dispose() diff --git a/FModel/Views/Snooper/PickingTexture.cs b/FModel/Views/Snooper/PickingTexture.cs index 5c2b1d3d..1033a49d 100644 --- a/FModel/Views/Snooper/PickingTexture.cs +++ b/FModel/Views/Snooper/PickingTexture.cs @@ -58,10 +58,7 @@ public class PickingTexture : IDisposable Bind(); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - _shader.Use(); - _shader.SetUniform("uView", viewMatrix); - _shader.SetUniform("uProjection", projMatrix); - + _shader.Render(viewMatrix, projMatrix); foreach ((FGuid guid, Model model) in models) { _shader.SetUniform("uA", guid.A); diff --git a/FModel/Views/Snooper/Renderer.cs b/FModel/Views/Snooper/Renderer.cs index 0357eb27..59e8a880 100644 --- a/FModel/Views/Snooper/Renderer.cs +++ b/FModel/Views/Snooper/Renderer.cs @@ -11,7 +11,6 @@ using CUE4Parse.UE4.Assets.Exports.Texture; using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.Engine; using CUE4Parse.UE4.Objects.UObject; -using OpenTK.Graphics.OpenGL4; using Vector3 = OpenTK.Mathematics.Vector3; namespace FModel.Views.Snooper; @@ -20,8 +19,6 @@ public class Renderer : IDisposable { private Shader _shader; private Shader _outline; - private Vector3 _diffuseLight; - private Vector3 _specularLight; public PickingTexture Picking { get; } public Cache Cache { get; } @@ -60,8 +57,6 @@ public class Renderer : IDisposable { _shader = new Shader(); _outline = new Shader("outline"); - _diffuseLight = new Vector3(0.75f); - _specularLight = new Vector3(0.5f); Picking.Setup(); Cache.Setup(); @@ -72,24 +67,22 @@ public class Renderer : IDisposable var viewMatrix = cam.GetViewMatrix(); var projMatrix = cam.GetProjectionMatrix(); - _outline.Use(); - _outline.SetUniform("uView", viewMatrix); - _outline.SetUniform("uProjection", projMatrix); - _outline.SetUniform("viewPos", cam.Position); + // render pass + _shader.Render(viewMatrix, cam.Position, projMatrix); + foreach (var model in Cache.Models.Values) + { + if (!model.Show) continue; + model.Render(_shader); + } - _shader.Use(); - _shader.SetUniform("uView", viewMatrix); - _shader.SetUniform("uProjection", projMatrix); - _shader.SetUniform("viewPos", cam.Position); - - _shader.SetUniform("light.position", cam.Position); - _shader.SetUniform("light.diffuse", _diffuseLight); - _shader.SetUniform("light.specular", _specularLight); - - Cache.Render(_shader); - GL.Enable(EnableCap.StencilTest); - Cache.Outline(_outline); + // outline pass + if (Cache.Models.TryGetValue(Settings.SelectedModel, out var selected) && selected.Show) + { + _outline.Render(viewMatrix, cam.Position, projMatrix); + selected.Outline(_outline); + } + // picking pass (dedicated FBO, binding to 0 afterward) Picking.Render(viewMatrix, projMatrix, Cache.Models); } diff --git a/FModel/Views/Snooper/Shader.cs b/FModel/Views/Snooper/Shader.cs index 2dd722b3..e78c16ee 100644 --- a/FModel/Views/Snooper/Shader.cs +++ b/FModel/Views/Snooper/Shader.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Reflection; @@ -35,11 +35,40 @@ public class Shader : IDisposable GL.DeleteShader(f); } + private int LoadShader(ShaderType type, string file) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + using var stream = executingAssembly.GetManifestResourceStream($"{executingAssembly.GetName().Name}.Resources.{file}"); + using var reader = new StreamReader(stream); + var handle = GL.CreateShader(type); + GL.ShaderSource(handle, reader.ReadToEnd()); + GL.CompileShader(handle); + string infoLog = GL.GetShaderInfoLog(handle); + if (!string.IsNullOrWhiteSpace(infoLog)) + { + throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); + } + + return handle; + } + public void Use() { GL.UseProgram(_handle); } + public void Render(Matrix4 viewMatrix, Vector3 viewPos, Matrix4 projMatrix) + { + Render(viewMatrix, projMatrix); + SetUniform("uViewPos", viewPos); + } + public void Render(Matrix4 viewMatrix, Matrix4 projMatrix) + { + Use(); + SetUniform("uView", viewMatrix); + SetUniform("uProjection", projMatrix); + } + public void SetUniform(string name, int value) { int location = GL.GetUniformLocation(_handle, name); @@ -83,24 +112,28 @@ public class Shader : IDisposable GL.Uniform1(location, value); } - public void SetUniform(string name, Vector3 value) + public void SetUniform(string name, Vector3 value) => SetUniform3(name, value.X, value.Y, value.Z); + public void SetUniform(string name, System.Numerics.Vector3 value) => SetUniform3(name, value.X, value.Y, value.Z); + public void SetUniform3(string name, float x, float y, float z) { int location = GL.GetUniformLocation(_handle, name); if (location == -1) { throw new Exception($"{name} uniform not found on shader."); } - GL.Uniform3(location, value.X, value.Y, value.Z); + GL.Uniform3(location, x, y, z); } - public void SetUniform(string name, Vector4 value) + public void SetUniform(string name, Vector4 value) => SetUniform4(name, value.X, value.Y, value.Z, value.W); + public void SetUniform(string name, System.Numerics.Vector4 value) => SetUniform4(name, value.X, value.Y, value.Z, value.W); + public void SetUniform4(string name, float x, float y, float z, float w) { int location = GL.GetUniformLocation(_handle, name); if (location == -1) { throw new Exception($"{name} uniform not found on shader."); } - GL.Uniform4(location, value.X, value.Y, value.Z, value.W); + GL.Uniform4(location, x, y, z, w); } public int GetUniformLocation(string uniform) @@ -135,21 +168,4 @@ public class Shader : IDisposable { GL.DeleteProgram(_handle); } - - private int LoadShader(ShaderType type, string file) - { - var executingAssembly = Assembly.GetExecutingAssembly(); - using var stream = executingAssembly.GetManifestResourceStream($"{executingAssembly.GetName().Name}.Resources.{file}"); - using var reader = new StreamReader(stream); - var handle = GL.CreateShader(type); - GL.ShaderSource(handle, reader.ReadToEnd()); - GL.CompileShader(handle); - string infoLog = GL.GetShaderInfoLog(handle); - if (!string.IsNullOrWhiteSpace(infoLog)) - { - throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}"); - } - - return handle; - } } diff --git a/FModel/Views/Snooper/SnimGui.cs b/FModel/Views/Snooper/SnimGui.cs index 5cc0aeb2..0f1ca15b 100644 --- a/FModel/Views/Snooper/SnimGui.cs +++ b/FModel/Views/Snooper/SnimGui.cs @@ -1,4 +1,6 @@ using System; +using CUE4Parse.UE4.Assets.Exports.Material; +using CUE4Parse.UE4.Objects.Core.Math; using CUE4Parse.UE4.Objects.Core.Misc; using FModel.Framework; using ImGuiNET; @@ -36,17 +38,51 @@ public class SnimGui DrawNavbar(); ImGui.Begin("Camera"); - ImGui.DragFloat("Speed", ref s.Camera.Speed, 0.01f); + ImGui.DragFloat("Speed", ref s.Camera.Speed, 0.01f, 0.05f); ImGui.DragFloat("Far Plane", ref s.Camera.Far, 0.1f, 5f, s.Camera.Far * 2f, "%.2f m", ImGuiSliderFlags.AlwaysClamp); ImGui.End(); ImGui.Begin("World"); ImGui.End(); ImGui.Begin("Timeline"); ImGui.End(); - ImGui.Begin("Materials"); - ImGui.End(); - ImGui.Begin("Textures"); - ImGui.End(); + if (ImGui.Begin("Materials")) + { + PushStyleCompact(); + var guid = s.Renderer.Settings.SelectedModel; + if (s.Renderer.Cache.Models.TryGetValue(guid, out var model) && + s.Renderer.Settings.TryGetSection(model, out var section)) + { + var material = model.Materials[section.MaterialIndex]; + foreach ((string key, float value) in material.Parameters.Scalars) + { + ImGui.Text($"{key}: {value}"); + } + ImGui.Spacing(); ImGui.Separator(); ImGui.Spacing(); + foreach ((string key, FLinearColor value) in material.Parameters.Colors) + { + ImGui.Text(key); ImGui.SameLine(); + ImGui.ColorButton(key, new Vector4(value.R, value.G, value.B, value.A)); + } + } + else NoMeshSelected(); + PopStyleCompact(); + } + if (ImGui.Begin("Textures")) + { + PushStyleCompact(); + var guid = s.Renderer.Settings.SelectedModel; + if (s.Renderer.Cache.Models.TryGetValue(guid, out var model) && + s.Renderer.Settings.TryGetSection(model, out var section)) + { + var material = model.Materials[section.MaterialIndex]; + foreach ((string key, UUnrealMaterial value) in material.Parameters.Textures) + { + ImGui.Text($"{key}: {value.Name}"); + } + } + else NoMeshSelected(); + PopStyleCompact(); + } DrawUvChannels(s); DrawTransform(s); @@ -170,7 +206,7 @@ public class SnimGui ImGui.Text($"Entity: ({model.Type}) {model.Name}"); ImGui.Text($"Guid: {guid.ToString(EGuidFormats.UniqueObjectGuid)}"); - ImGui.Columns(4, "Actions", false); + ImGui.Columns(3, "Actions", false); if (ImGui.Button("Go To")) { var instancePos = model.Transforms[model.SelectedInstance].Position; @@ -178,7 +214,11 @@ public class SnimGui } ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show); ImGui.NextColumn(); ImGui.BeginDisabled(!model.Show); ImGui.Checkbox("Wire", ref model.Wireframe); ImGui.EndDisabled(); - ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.DisplayVertexColors); ImGui.EndDisabled(); + ImGui.Columns(4); + ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.bVertexColors); ImGui.EndDisabled(); + ImGui.NextColumn(); ImGui.Checkbox("Normals", ref model.bVertexNormals); + ImGui.NextColumn(); ImGui.Checkbox("Tangent", ref model.bVertexTangent); + ImGui.NextColumn(); ImGui.Checkbox("Coords", ref model.bVertexTexCoords); ImGui.Columns(1); ImGui.Separator(); @@ -301,6 +341,22 @@ public class SnimGui ImGui.EndTabItem(); } } + + if (ImGui.Begin("test") && s.Renderer.Settings.TryGetSection(model, out var sec)) + { + var material = model.Materials[sec.MaterialIndex]; + ImGui.DragFloat("Roughness", ref material.Roughness, .01f, 0f, 1f); + ImGui.DragFloat("Specular Multiplier", ref material.SpecularMult, .01f, 0f); + ImGui.DragFloat("Emissive Multiplier", ref material.EmissiveMult, .01f, 0f); + ImGui.DragFloat("UV Scale", ref material.UVScale, .01f, 0f); + if (material.HasM) + { + ImGui.ColorEdit3("Skin Boost Color", ref material.M.SkinBoost.Color); + ImGui.DragFloat("Skin Boost Exponent", ref material.M.SkinBoost.Exponent, .01f, 0f); + ImGui.DragFloat("AmbientOcclusion", ref material.M.AmbientOcclusion, .01f, 0f, 1f); + ImGui.DragFloat("Cavity", ref material.M.Cavity, .01f, 0f, 1f); + } + } } else NoMeshSelected(); PopStyleCompact(); @@ -402,10 +458,11 @@ public class SnimGui { if (material.Diffuse.Length > 0) { - var size = new Vector2(ImGui.GetContentRegionAvail().X / 4.75f); + var size = new Vector2(ImGui.GetContentRegionAvail().X / 5.75f); DrawSquareTexture(material.Diffuse[material.SelectedChannel], size); ImGui.SameLine(); DrawSquareTexture(material.Normals[material.SelectedChannel], size); ImGui.SameLine(); DrawSquareTexture(material.SpecularMasks[material.SelectedChannel], size); ImGui.SameLine(); + DrawSquareTexture(material.M.Texture, size); ImGui.SameLine(); DrawSquareTexture(material.Emissive[material.SelectedChannel], size); ImGui.SameLine(); } else TextColored(_errorColor, "no texture in material section"); @@ -453,6 +510,7 @@ public class SnimGui { var guid = s.Renderer.Picking.ReadPixel(ImGui.GetMousePos(), ImGui.GetCursorScreenPos(), size); s.Renderer.Settings.SelectModel(guid); + ImGui.SetWindowFocus("Outliner"); } } diff --git a/FModel/Views/Snooper/VertexArrayObject.cs b/FModel/Views/Snooper/VertexArrayObject.cs index 4c178f7f..f2bc3b53 100644 --- a/FModel/Views/Snooper/VertexArrayObject.cs +++ b/FModel/Views/Snooper/VertexArrayObject.cs @@ -41,19 +41,19 @@ public class VertexArrayObject : IDisposable where TVer Bind(); var size = sizeof(Vector4); - GL.EnableVertexAttribArray(8); - GL.VertexAttribPointer(8, 4, VertexAttribPointerType.Float, false, 4 * size, 0); GL.EnableVertexAttribArray(9); - GL.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * size, 1 * size); + GL.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * size, 0); GL.EnableVertexAttribArray(10); - GL.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * size, 2 * size); + GL.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * size, 1 * size); GL.EnableVertexAttribArray(11); - GL.VertexAttribPointer(11, 4, VertexAttribPointerType.Float, false, 4 * size, 3 * size); + GL.VertexAttribPointer(11, 4, VertexAttribPointerType.Float, false, 4 * size, 2 * size); + GL.EnableVertexAttribArray(12); + GL.VertexAttribPointer(12, 4, VertexAttribPointerType.Float, false, 4 * size, 3 * size); - GL.VertexAttribDivisor(8, 1); GL.VertexAttribDivisor(9, 1); GL.VertexAttribDivisor(10, 1); GL.VertexAttribDivisor(11, 1); + GL.VertexAttribDivisor(12, 1); Unbind(); }