umap lights

This commit is contained in:
4sval 2022-11-24 02:44:01 +01:00
parent ce529c41ec
commit 8b072e39fc
18 changed files with 336 additions and 38 deletions

@ -1 +1 @@
Subproject commit 2e3274d96eb02b4b376f9f44942da81593130d28
Subproject commit 54a95bf82efd13cd9e4423f182296f0c0127ccaf

View File

@ -105,6 +105,8 @@
<None Remove="Resources\outline.vert" />
<None Remove="Resources\picking.frag" />
<None Remove="Resources\picking.vert" />
<None Remove="Resources\light.frag" />
<None Remove="Resources\light.vert" />
</ItemGroup>
<ItemGroup>
@ -126,6 +128,8 @@
<EmbeddedResource Include="Resources\outline.vert" />
<EmbeddedResource Include="Resources\picking.frag" />
<EmbeddedResource Include="Resources\picking.vert" />
<EmbeddedResource Include="Resources\light.frag" />
<EmbeddedResource Include="Resources\light.vert" />
</ItemGroup>
<ItemGroup>
@ -222,6 +226,8 @@
<Resource Include="Resources\px.png" />
<Resource Include="Resources\py.png" />
<Resource Include="Resources\pz.png" />
<Resource Include="Resources\pointlight.png" />
<Resource Include="Resources\spotlight.png" />
</ItemGroup>
<ItemGroup>

View File

@ -2,6 +2,7 @@
#define PI 3.1415926535897932384626433832795
#define MAX_UV_COUNT 8
#define MAX_LIGHT_COUNT 100
in vec3 fPos;
in vec3 fNormal;
@ -46,7 +47,19 @@ struct Parameters
float UVScale;
};
struct Light {
vec4 Color;
vec3 Position;
float Intensity;
float Constant;
float Linear;
float Quadratic;
};
uniform Parameters uParameters;
uniform Light uLights[MAX_LIGHT_COUNT];
uniform int uNumLights;
uniform int uNumTexCoords;
uniform vec3 uViewPos;
uniform vec3 uViewDir;
@ -175,6 +188,27 @@ void main()
if (!bVertexColors[1])
{
result += CalcPBRLight(layer, normals);
vec3 lights = vec3(uNumLights > 0 ? 0 : 1);
for (int i = 0; i < uNumLights; i++)
{
float distance = length(uLights[i].Position - fPos);
float attenuation = 1.0 / (1.0 + uLights[i].Linear * distance + uLights[i].Quadratic * (distance * distance));
vec3 intensity = uLights[i].Color.rgb * uLights[i].Intensity;
lights += result * intensity * attenuation;
// float attenuation = 0.0;
// float theta = dot(normalize(uLights[i].Position - fPos), normalize(-uLights[i].Direction));
// if(theta > uLights[i].ConeAngle)
// {
// float distanceToLight = length(uLights[i].Position - fPos);
// attenuation = 1.0 / (1.0 + uLights[i].Attenuation * pow(distanceToLight, 2));
// }
//
// vec3 intensity = uLights[i].Color.rgb * uLights[i].Intensity;
// lights += result * intensity * attenuation;
}
result *= lights; // use * to darken the scene, + to lighten it
}
result = result / (result + vec3(1.0f));

View File

@ -0,0 +1,16 @@
#version 330
uniform sampler2D uIcon;
uniform vec4 uColor;
in vec2 fTexCoords;
out vec4 FragColor;
void main()
{
vec4 color = uColor * texture(uIcon, fTexCoords);
if (color.a < 0.1) discard;
FragColor = uColor;
}

View File

@ -0,0 +1,15 @@
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 9) in mat4 vInstanceMatrix;
uniform mat4 uView;
uniform mat4 uProjection;
out vec2 fTexCoords;
void main()
{
gl_Position = uProjection * uView * vInstanceMatrix * vec4(inverse(mat3(uView)) * vPos, 1.0);
fTexCoords = -vPos.xy;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -372,7 +372,7 @@
IsChecked="{Binding SaveMaterials, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/>
</UniformGrid>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Preview Static Meshes From Worlds (.umap)" VerticalAlignment="Center" Margin="0 0 0 5" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Preview Static Meshes From Levels (.umap)" VerticalAlignment="Center" Margin="0 0 0 5" />
<CheckBox Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
IsChecked="{Binding PreviewWorlds, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"/>

View File

@ -13,6 +13,8 @@ public class Cache : IDisposable
{
public readonly Dictionary<FGuid, Model> Models;
public readonly Dictionary<FGuid, Texture> Textures;
public readonly List<Light> Lights;
public readonly Dictionary<string, Texture> Icons;
private ETexturePlatform _platform;
@ -22,12 +24,18 @@ public class Cache : IDisposable
{
Models = new Dictionary<FGuid, Model>();
Textures = new Dictionary<FGuid, Texture>();
Icons = new Dictionary<string, Texture>();
Lights = new List<Light>();
Icons = new Dictionary<string, Texture>
{
["material"] = new ("materialicon"),
["noimage"] = new ("T_Placeholder_Item_Image"),
["pointlight"] = new ("pointlight"),
["spotlight"] = new ("spotlight"),
};
_platform = UserSettings.Default.OverridedPlatform;
_game = Services.ApplicationService.ApplicationView.CUE4Parse.Game;
Icons["material"] = new Texture("materialicon");
Icons["noimage"] = new Texture("T_Placeholder_Item_Image");
}
public bool TryGetCachedModel(UStaticMesh o, out Model model)
@ -72,6 +80,11 @@ public class Cache : IDisposable
if (model.IsSetup) continue;
model.Setup(this);
}
foreach (var light in Lights)
{
light.Setup();
}
}
public void DisposeModels()
@ -94,10 +107,16 @@ public class Cache : IDisposable
}
}
public void Dispose()
public void Reset()
{
DisposeModels();
Models.Clear();
Lights.Clear();
}
public void Dispose()
{
Reset();
DisposeTextures();
Textures.Clear();

View File

@ -129,7 +129,7 @@ public class Camera
if (ImGui.BeginTable("camera_editor", 2))
{
SnimGui.Layout("Speed");ImGui.PushID(1);
ImGui.DragFloat("", ref Speed, _step, _zero, _infinite, "%.2f s/m", _clamp);
ImGui.DragFloat("", ref Speed, _step, _zero, _infinite, "%.2f m/s", _clamp);
ImGui.PopID();SnimGui.Layout("Far Plane");ImGui.PushID(2);
ImGui.DragFloat("", ref Far, 0.1f, 0.1f, Far * 2f, "%.2f m", _clamp);
ImGui.PopID();

View File

@ -0,0 +1,95 @@
using System;
using System.Numerics;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Objects.Core.Math;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public abstract class Light : IDisposable
{
private int _handle;
private BufferObject<uint> _ebo;
private BufferObject<float> _vbo;
private BufferObject<Matrix4x4> _matrixVbo;
private VertexArrayObject<float, uint> _vao;
public readonly uint[] Indices = { 0, 1, 2, 3, 4, 5 };
public readonly float[] Vertices = {
1f, 1f, 0f,
-1f, -1f, 0f,
-1f, 1f, 0f,
-1f, -1f, 0f,
1f, 1f, 0f,
1f, -1f, 0
};
public Texture Icon;
public readonly Transform Transform;
public readonly Vector4 Color;
public readonly float Intensity;
public readonly float Linear;
public readonly float Quadratic;
public Light(Texture icon, UObject light, FVector position)
{
var p = light.GetOrDefault("RelativeLocation", FVector.ZeroVector);
var r = light.GetOrDefault("RelativeRotation", FRotator.ZeroRotator);
Transform = Transform.Identity;
Transform.Scale = new FVector(0.25f);
Transform.Position = position + r.RotateVector(p.ToMapVector()) * Constants.SCALE_DOWN_RATIO;
Icon = icon;
Color = light.GetOrDefault("LightColor", new FColor(0xFF, 0xFF, 0xFF, 0xFF));
Intensity = light.GetOrDefault("Intensity", 1.0f);
var radius = light.GetOrDefault("AttenuationRadius", 0.0f) * Constants.SCALE_DOWN_RATIO;
Linear = 4.5f / radius;
Quadratic = 75.0f / MathF.Pow(radius, 2);
}
public void SetupInstances()
{
var instanceMatrix = new [] {Transform.Matrix};
_matrixVbo = new BufferObject<Matrix4x4>(instanceMatrix, BufferTarget.ArrayBuffer);
_vao.BindInstancing(); // VertexAttributePointer
}
public void Setup()
{
_handle = GL.CreateProgram();
_ebo = new BufferObject<uint>(Indices, BufferTarget.ElementArrayBuffer);
_vbo = new BufferObject<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_vbo, _ebo);
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 3, 0); // position
SetupInstances();
}
public abstract void Render(int i, Shader shader);
public void Render(Shader shader)
{
// GL.Disable(EnableCap.DepthTest);
_vao.Bind();
Icon?.Bind(TextureUnit.Texture0);
shader.SetUniform("uIcon", 0);
shader.SetUniform("uColor", Color);
GL.DrawArrays(PrimitiveType.Triangles, 0, Indices.Length);
// GL.Enable(EnableCap.DepthTest);
}
public void Dispose()
{
_ebo?.Dispose();
_vbo?.Dispose();
_vao?.Dispose();
GL.DeleteProgram(_handle);
}
}

View File

@ -83,7 +83,7 @@ public class Material : IDisposable
}
{ // colors
DiffuseColor = FillColors(numTexCoords, Diffuse, CMaterialParams2.DiffuseColors, new Vector4(0.5f));
DiffuseColor = FillColors(numTexCoords, Diffuse, CMaterialParams2.DiffuseColors, Vector4.One);
EmissiveColor = FillColors(numTexCoords, Emissive, CMaterialParams2.EmissiveColors, Vector4.One);
}
@ -208,10 +208,15 @@ public class Material : IDisposable
private const float _zero = 0.000001f; // doesn't actually work if _infinite is used as max value /shrug
private const float _infinite = 0.0f;
private const ImGuiSliderFlags _clamp = ImGuiSliderFlags.AlwaysClamp;
public void ImGuiParameters()
private void PushStyle()
{
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 3));
ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 1));
}
public void ImGuiParameters()
{
PushStyle();
if (ImGui.BeginTable("parameters", 2))
{
SnimGui.Layout("Emissive Multiplier");ImGui.PushID(1);
@ -253,7 +258,40 @@ public class Material : IDisposable
}
}
public IntPtr? GetSelectedTexture()
public void ImGuiTextures(Dictionary<string, Texture> icons, Model model)
{
PushStyle();
if (ImGui.BeginTable("material_textures", 2))
{
SnimGui.Layout("Channel");ImGui.PushID(1); ImGui.BeginDisabled(model.NumTexCoords < 2);
ImGui.DragInt("", ref SelectedChannel, _step, 0, model.NumTexCoords - 1, "UV %i", ImGuiSliderFlags.AlwaysClamp);
ImGui.EndDisabled();ImGui.PopID();SnimGui.Layout("Type");ImGui.PushID(2);
ImGui.Combo("texture_type", ref SelectedTexture, "Diffuse\0Normals\0Specular\0Ambient Occlusion\0Emissive\0");
ImGui.PopID();
switch (SelectedTexture)
{
case 0:
SnimGui.Layout("Color");ImGui.PushID(3);
ImGui.ColorEdit4("", ref DiffuseColor[SelectedChannel], ImGuiColorEditFlags.NoAlpha);
ImGui.PopID();
break;
case 4:
SnimGui.Layout("Color");ImGui.PushID(3);
ImGui.ColorEdit4("", ref EmissiveColor[SelectedChannel], ImGuiColorEditFlags.NoAlpha);
ImGui.PopID();
break;
}
ImGui.EndTable();
}
ImGui.PopStyleVar(2);
ImGui.Image(GetSelectedTexture() ?? icons["noimage"].GetPointer(), new Vector2(ImGui.GetContentRegionAvail().X), Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1.0f, 1.0f, 1.0f, 0.25f));
ImGui.Spacing();
}
private IntPtr? GetSelectedTexture()
{
return SelectedTexture switch
{

View File

@ -0,0 +1,21 @@
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Objects.Core.Math;
namespace FModel.Views.Snooper;
public class PointLight : Light
{
public PointLight(Texture icon, UObject point, FVector position) : base(icon, point, position)
{
}
public override void Render(int i, Shader shader)
{
shader.SetUniform($"uLights[{i}].Color", Color);
shader.SetUniform($"uLights[{i}].Position", Transform.Position);
shader.SetUniform($"uLights[{i}].Intensity", Intensity);
shader.SetUniform($"uLights[{i}].Linear", Linear);
shader.SetUniform($"uLights[{i}].Quadratic", Quadratic);
}
}

View File

@ -24,9 +24,11 @@ public class Renderer : IDisposable
private readonly Grid _grid;
private Shader _shader;
private Shader _outline;
private Shader _light;
public bool ShowSkybox;
public bool ShowGrid;
public bool ShowLights;
public int VertexColor;
public PickingTexture Picking { get; }
@ -49,6 +51,7 @@ public class Renderer : IDisposable
public Camera Load(CancellationToken cancellationToken, UObject export)
{
ShowLights = false;
return export switch
{
UStaticMesh st => LoadStaticMesh(st),
@ -86,6 +89,7 @@ public class Renderer : IDisposable
_shader = new Shader();
_outline = new Shader("outline");
_light = new Shader("light");
Picking.Setup();
Cache.Setup();
@ -101,17 +105,28 @@ public class Renderer : IDisposable
_shader.Render(viewMatrix, cam.Position, cam.Direction, projMatrix);
for (int i = 0; i < 6; i++)
{
_shader.SetUniform($"bVertexColors[{i}]", i == VertexColor);
}
// render pass
// render model pass
foreach (var model in Cache.Models.Values)
{
if (!model.Show) continue;
model.Render(_shader);
}
{ // light pass
var uNumLights = Cache.Lights.Count;
_shader.SetUniform("uNumLights", ShowLights ? uNumLights : 0);
if (ShowLights)
for (int i = 0; i < uNumLights; i++)
Cache.Lights[i].Render(i, _shader);
_light.Render(viewMatrix, projMatrix);
for (int i = 0; i < uNumLights; i++)
Cache.Lights[i].Render(_light);
}
// outline pass
if (Cache.Models.TryGetValue(Settings.SelectedModel, out var selected) && selected.Show)
{
@ -188,6 +203,7 @@ public class Renderer : IDisposable
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"{original.Name} ... {i}/{length}");
WorldCamera(actor, ref cam);
// WorldLight(actor);
WorldMesh(actor, transform);
AdditionalWorlds(actor, transform.Matrix, cancellationToken);
}
@ -209,6 +225,14 @@ public class Renderer : IDisposable
0.01f, far * 25f, Math.Max(5f, far / 10f));
}
private void WorldLight(UObject actor)
{
if (!actor.TryGetValue(out FPackageIndex lightComponent, "LightComponent") ||
lightComponent.Load() is not { } lightObject) return;
Cache.Lights.Add(new PointLight(Cache.Icons["pointlight"], lightObject, FVector.ZeroVector));
}
private void WorldMesh(UObject actor, Transform transform)
{
if (!actor.TryGetValue(out FPackageIndex staticMeshComponent, "StaticMeshComponent", "Mesh") ||
@ -274,6 +298,17 @@ public class Renderer : IDisposable
}
Cache.Models[guid] = model;
}
if (actor.TryGetValue(out FPackageIndex treasureLight, "TreasureLight", "PointLight") &&
treasureLight.TryLoad(out var tl) && tl.Template.TryLoad(out tl))
{
Cache.Lights.Add(new PointLight(Cache.Icons["pointlight"], tl, t.Position));
}
if (actor.TryGetValue(out FPackageIndex spotLight, "SpotLight") &&
spotLight.TryLoad(out var sl) && sl.Template.TryLoad(out sl))
{
Cache.Lights.Add(new SpotLight(Cache.Icons["spotlight"], sl, t.Position));
}
}
private void AdditionalWorlds(UObject actor, Matrix4x4 relation, CancellationToken cancellationToken)
@ -308,6 +343,7 @@ public class Renderer : IDisposable
_grid?.Dispose();
_shader?.Dispose();
_outline?.Dispose();
_light?.Dispose();
Picking?.Dispose();
Cache?.Dispose();
}

View File

@ -63,7 +63,9 @@ public class SnimGui
ImGui.Checkbox("", ref s.Renderer.ShowSkybox);
ImGui.PopID();Layout("Grid");ImGui.PushID(2);
ImGui.Checkbox("", ref s.Renderer.ShowGrid);
ImGui.PopID();Layout("Vertex Colors");ImGui.PushID(3);
ImGui.PopID();Layout("Lights");ImGui.PushID(3);
ImGui.Checkbox("", ref s.Renderer.ShowLights);
ImGui.PopID();Layout("Vertex Colors");ImGui.PushID(4);
ImGui.Combo("vertex_colors", ref s.Renderer.VertexColor,
"Default\0Diffuse Only\0Colors\0Normals\0Tangent\0Texture Coordinates\0");
ImGui.PopID();
@ -441,22 +443,7 @@ public class SnimGui
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.CollapsingHeader("Textures"))
{
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 3));
ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(0, 1));
if (ImGui.BeginTable("material_textures", 2))
{
Layout("Channel");ImGui.PushID(1); ImGui.BeginDisabled(model.NumTexCoords < 2);
ImGui.DragInt("", ref material.SelectedChannel, 1, 0, model.NumTexCoords - 1, "UV %i", ImGuiSliderFlags.AlwaysClamp);
ImGui.EndDisabled();ImGui.PopID();Layout("Type");ImGui.PushID(2);
ImGui.Combo("texture_type", ref material.SelectedTexture,
"Diffuse\0Normals\0Specular\0Ambient Occlusion\0Emissive\0");
ImGui.PopID();
ImGui.EndTable();
}
ImGui.PopStyleVar(2);
ImGui.Image(material.GetSelectedTexture() ?? icons["noimage"].GetPointer(), new Vector2(ImGui.GetContentRegionAvail().X), Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1.0f, 1.0f, 1.0f, 0.25f));
ImGui.Spacing();
material.ImGuiTextures(icons, model);
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);

View File

@ -49,8 +49,7 @@ public class Snooper : GameWindow
if (clear)
{
_previousSpeed = 0f;
Renderer.Cache.DisposeModels();
Renderer.Cache.Models.Clear();
Renderer.Cache.Reset();
Renderer.Settings.Reset();
Renderer.Save();
}

View File

@ -0,0 +1,32 @@
using System;
using System.Numerics;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Objects.Core.Math;
namespace FModel.Views.Snooper;
public class SpotLight : PointLight
{
public Vector3 Direction; // ???
public float Attenuation;
public float ConeAngle;
public SpotLight(Texture icon, UObject spot, FVector position) : base(icon, spot, position)
{
// var p = spot.GetOrDefault("RelativeLocation", FVector.ZeroVector);
// var r = spot.GetOrDefault("RelativeRotation", FRotator.ZeroRotator);
// Direction = position + r.UnrotateVector(p.ToMapVector()) * Constants.SCALE_DOWN_RATIO;
Attenuation = spot.GetOrDefault("AttenuationRadius", 0.0f) * Constants.SCALE_DOWN_RATIO;
ConeAngle = (spot.GetOrDefault("InnerConeAngle", 50f) + spot.GetOrDefault("OuterConeAngle", 60f)) / 2f;
ConeAngle = MathF.Cos(Helper.DegreesToRadians(ConeAngle));
}
public new void Render(int i, Shader shader)
{
base.Render(i, shader);
// shader.SetUniform($"uLights[{i}].Direction", Direction);
// shader.SetUniform($"uLights[{i}].Attenuation", Attenuation);
// shader.SetUniform($"uLights[{i}].ConeAngle", ConeAngle);
}
}

View File

@ -36,6 +36,11 @@ public class VertexArrayObject<TVertexType, TIndexType> : IDisposable where TVer
GL.BindVertexArray(_handle);
}
public void Unbind()
{
GL.BindVertexArray(0);
}
public unsafe void BindInstancing()
{
Bind();
@ -58,11 +63,6 @@ public class VertexArrayObject<TVertexType, TIndexType> : IDisposable where TVer
Unbind();
}
public void Unbind()
{
GL.BindVertexArray(0);
}
public void Dispose()
{
GL.DeleteVertexArray(_handle);