refactored & improved shaders and materials

This commit is contained in:
4sval 2022-11-07 02:10:41 +01:00
parent b8d731c3ae
commit 86c3eba85f
12 changed files with 341 additions and 226 deletions

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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)

View File

@ -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<Texture>();
SpecularMasks = Array.Empty<Texture>();
Emissive = Array.Empty<Texture>();
DiffuseColor = Vector4.Zero;
EmissionColor = Array.Empty<Vector4>();
HasSpecularMap = false;
HasDiffuseColor = false;
_ambientLight = Vector3.One;
EmissiveColor = Array.Empty<Vector4>();
}
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;
}
/// <param name="cache"></param>
@ -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;
}

View File

@ -21,7 +21,7 @@ public class Model : IDisposable
private BufferObject<Matrix4x4> _matrixVbo;
private VertexArrayObject<float, uint> _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<Matrix4x4>(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<float>(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()

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -41,19 +41,19 @@ public class VertexArrayObject<TVertexType, TIndexType> : 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();
}