Skip to content

Commit

Permalink
Static models show using Mlang in the ModelViewer
Browse files Browse the repository at this point in the history
  • Loading branch information
Helco committed Jan 9, 2024
1 parent 7926566 commit e6f6af1
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 25 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<VeldridHash>gb972ef1133</VeldridHash>
<DefaultEcsHash>0e92bb5</DefaultEcsHash>
<ImguiHash>beeb8dd</ImguiHash>
<MlangHash>f24fd56</MlangHash>
<MlangHash>38d78da</MlangHash>
<VeldridVersion>4.9.0-beta2-$(VeldridHash)</VeldridVersion>
<VeldridImguiVersion>5.87.0-$(VeldridHash)</VeldridImguiVersion>
<VeldridRenderdocVersion>1.0.1-$(VeldridHash)</VeldridRenderdocVersion>
Expand Down
2 changes: 1 addition & 1 deletion extern/Mlang
6 changes: 3 additions & 3 deletions zzre.core/rendering/MlangMaterial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ protected override void DisposeManaged()

protected void AddBinding(string name, BaseBinding binding)
{
if (!bindings.TryGetValue(name, out var oldBinding))
throw new ArgumentException($"Binding {binding} does not exist for shader {shaderName}");
oldBinding?.Dispose();
// TODO: Reenable exception after figuring out proper potential bindings set
if (bindings.TryGetValue(name, out var oldBinding))
oldBinding?.Dispose();
bindings[name] = binding;
}

Expand Down
6 changes: 5 additions & 1 deletion zzre/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ private static void Main(string[] args)

var pipelineCollection = new PipelineCollection(graphicsDevice);
pipelineCollection.AddShaderResourceAssemblyOf<Program>();
var shaderVariantCollection = new ShaderVariantCollection(graphicsDevice,
typeof(Program).Assembly.GetManifestResourceStream("shaders.mlss")
?? throw new InvalidDataException("Shader set is not compiled into zzre"));
var windowContainer = new WindowContainer(graphicsDevice);
var resourcePool = new CombinedResourcePool(new IResourcePool[]
{
Expand All @@ -79,6 +82,7 @@ private static void Main(string[] args)
.AddTag(graphicsDevice.ResourceFactory)
.AddTag<IResourcePool>(resourcePool)
.AddTag(pipelineCollection)
.AddTag(shaderVariantCollection)
.AddTag<IAssetLoader<Texture>>(new TextureAssetLoader(diContainer))
.AddTag(new OpenDocumentSet(diContainer))
.AddTag(IconFont.CreateForkAwesome(graphicsDevice));
Expand All @@ -90,7 +94,7 @@ private static void Main(string[] args)
windowContainer.MenuBar.AddButton("Tools/Scene Viewer", () => new SceneEditor(diContainer));

#if DEBUG
new ZanzarahWindow(diContainer);
//new ZanzarahWindow(diContainer);
#endif

window.Resized += () =>
Expand Down
12 changes: 6 additions & 6 deletions zzre/materials/ModelStandardMaterial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public struct ModelStandardMaterialUniforms
};
}

public class ModelMaterial : MlangMaterial
public class ModelMaterial : MlangMaterial, IStandardTransformMaterial
{
public enum BlendMode : uint
{
Expand All @@ -62,11 +62,11 @@ public enum BlendMode : uint

public ModelMaterial(ITagContainer diContainer) : base(diContainer, "model")
{
AddBinding("world", World = new(this));
AddBinding("projection", Projection = new(this));
AddBinding("view", View = new(this));
AddBinding("inTexShift", TexShift = new(this));
AddBinding("block_24_0", Colors = new(this));
AddBinding("block_20_0", World = new(this));
AddBinding("block_38_0", Projection = new(this));
AddBinding("block_39_0", View = new(this));
AddBinding("block_21_0", TexShift = new(this));
AddBinding("block_22_0", Colors = new(this));
AddBinding("mainTexture", Texture = new(this));
AddBinding("mainSampler", Sampler = new(this));
AddBinding("pose", Pose = new(this));
Expand Down
156 changes: 156 additions & 0 deletions zzre/rendering/ClumpBuffersDeinterleaved.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Veldrid;
using zzio;
using zzio.rwbs;
using zzio.vfs;
using zzre.materials;

namespace zzre;

public class ClumpBuffersDeinterleaved : BaseDisposable
{
public readonly struct SubMesh
{
public readonly int IndexOffset, IndexCount;
public readonly RWMaterial Material;

public SubMesh(int io, int ic, RWMaterial m) => (IndexOffset, IndexCount, Material) = (io, ic, m);
}

private readonly DeviceBuffer posBuffer;
private readonly DeviceBuffer normalBuffer;
private readonly DeviceBuffer uvBuffer;
private readonly DeviceBuffer colorBuffer;
private readonly DeviceBuffer? boneWeightBuffer;
private readonly DeviceBuffer? boneIndexBuffer;
private readonly DeviceBuffer indexBuffer;
private readonly SubMesh[] subMeshes;

public int VertexCount => (int)(posBuffer.SizeInBytes / (sizeof(float) * 3));
public int TriangleCount => (int)(indexBuffer.SizeInBytes / (sizeof(ushort) * 3));
public RWSkinPLG? Skin { get; }
public IReadOnlyList<SubMesh> SubMeshes => subMeshes;
public Vector3 BSphereCenter { get; }
public float BSphereRadius { get; }
public Box Bounds { get; }
public bool IsSolid { get; }
public RWGeometry RWGeometry { get; }
public string Name { get; set; }

public ClumpBuffersDeinterleaved(ITagContainer diContainer, FilePath path)
: this(diContainer, diContainer.GetTag<IResourcePool>().FindFile(path) ??
throw new FileNotFoundException($"Could not find model at {path.ToPOSIXString()}"))
{ }
public ClumpBuffersDeinterleaved(ITagContainer diContainer, IResource resource)
: this(diContainer, resource.OpenAsRWBS<RWClump>(), resource.Name.Replace(".DFF", "", System.StringComparison.InvariantCultureIgnoreCase)) { }


private unsafe DeviceBuffer BufferFromArray<T>(GraphicsDevice device, string attrName, T[]? array, int length = -1, T defValue = default) where T : unmanaged
{
if (array?.Length == 0)
array = null;
if (array == null && length < 0)
throw new System.ArgumentException();
if (array != null)
length = array.Length;
var buffer = device.ResourceFactory.CreateBuffer(new((uint)(sizeof(T) * length), BufferUsage.VertexBuffer));
buffer.Name = $"Clump {Name} {attrName}";
device.UpdateBuffer(buffer, 0, array ?? Enumerable.Repeat(defValue, length).ToArray());
return buffer;
}

public ClumpBuffersDeinterleaved(ITagContainer diContainer, RWClump clump, string name = "")
{
Name = name;
var device = diContainer.GetTag<GraphicsDevice>();
var atomic = clump.FindChildById(SectionId.Atomic, recursive: false) as RWAtomic;
var geometry = clump.FindChildById(SectionId.Geometry, true) as RWGeometry;
var materialList = geometry?.FindChildById(SectionId.MaterialList, false) as RWMaterialList;
var materials = materialList?.children.Where(s => s is RWMaterial).Cast<RWMaterial>().ToArray();
var morphTarget = geometry?.morphTargets[0]; // TODO: morph support for the one model that uses it?
if (geometry == null || morphTarget == null || materials == null || atomic == null)
throw new InvalidDataException("Could not find valid section structure in clump");
RWGeometry = geometry;
BSphereCenter = morphTarget.bsphereCenter;
BSphereRadius = morphTarget.bsphereRadius;
IsSolid = atomic.flags.HasFlag(AtomicFlags.CollisionTest);

var vertexCount = morphTarget.vertices.Length;
posBuffer = BufferFromArray(device, "Pos", morphTarget.vertices);
normalBuffer = BufferFromArray<Vector3>(device, "Normal", null, vertexCount);
uvBuffer = BufferFromArray(device, "UV", geometry.texCoords.Length > 0 ? geometry.texCoords[0] : null, vertexCount);
colorBuffer = BufferFromArray(device, "Color", geometry.colors, vertexCount, new IColor(255));

var vertices = new ModelStandardVertex[morphTarget.vertices.Length];
var bounds = new Box(morphTarget.vertices.First(), Vector3.Zero);
for (int i = 0; i < vertices.Length; i++)
bounds = bounds.Union(vertices[i].pos);
Bounds = bounds;

// TODO: might have to correlate to the materialIndices member of materialList
var trianglesByMatIdx = geometry.triangles.GroupBy(t => t.m).Where(g => g.Any());
var indices = trianglesByMatIdx.SelectMany(
g => g.SelectMany(t => new[] { t.v1, t.v2, t.v3 })
).ToArray();
subMeshes = new SubMesh[trianglesByMatIdx.Count()];
int nextIndexPtr = 0;
foreach (var (group, idx) in trianglesByMatIdx.Indexed())
{
subMeshes[idx] = new SubMesh(nextIndexPtr, group.Count() * 3, materials[group.Key]);
nextIndexPtr += subMeshes[idx].IndexCount;
}
indexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription((uint)indices.Length * 2, BufferUsage.IndexBuffer));
indexBuffer.Name = $"Clump {name} Indices";
device.UpdateBuffer(indexBuffer, 0, indices);

Skin = clump.FindChildById(SectionId.SkinPLG, true) as RWSkinPLG;
if (Skin != null)
{
if (vertices.Length != Skin.vertexWeights.GetLength(0))
throw new InvalidDataException("Vertex count in skin is not equal to geometry");
/*var skinVertices = new SkinVertex[vertices.Length];
for (int i = 0; i < skinVertices.Length; i++)
{
skinVertices[i].bone0 = Skin.vertexIndices[i, 0];
skinVertices[i].bone1 = Skin.vertexIndices[i, 1];
skinVertices[i].bone2 = Skin.vertexIndices[i, 2];
skinVertices[i].bone3 = Skin.vertexIndices[i, 3];
skinVertices[i].weights.X = Skin.vertexWeights[i, 0];
skinVertices[i].weights.Y = Skin.vertexWeights[i, 1];
skinVertices[i].weights.Z = Skin.vertexWeights[i, 2];
skinVertices[i].weights.W = Skin.vertexWeights[i, 3];
}
skinBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription((uint)skinVertices.Length * SkinVertex.Stride, BufferUsage.VertexBuffer));
skinBuffer.Name = $"Clump {name} Skin";
device.UpdateBuffer(skinBuffer, 0, skinVertices);*/
}
}

protected override void DisposeManaged()
{
base.DisposeManaged();
posBuffer.Dispose();
normalBuffer.Dispose();
uvBuffer.Dispose();
colorBuffer.Dispose();
boneWeightBuffer?.Dispose();
boneIndexBuffer?.Dispose();
indexBuffer.Dispose();
}

public void SetBuffers(CommandList commandList)
{
commandList.SetVertexBuffer(0, posBuffer);
commandList.SetVertexBuffer(1, normalBuffer);
commandList.SetVertexBuffer(2, uvBuffer);
commandList.SetVertexBuffer(3, colorBuffer);
commandList.SetIndexBuffer(indexBuffer, IndexFormat.UInt16);
}

public void SetSkinBuffer(CommandList commandList)
{
}
}
1 change: 0 additions & 1 deletion zzre/shaders/model.mlang
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ option HasTexShift;
option HasEnvMap;
option Blend = IsOpaque, IsAlphaBlend, IsAdditiveBlend, IsAdditiveAlphaBlend;


attributes
{
float3 inPos;
Expand Down
26 changes: 14 additions & 12 deletions zzre/tools/ModelViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ public class ModelViewer : ListDisposable, IDocumentEditor
private readonly ModelMaterialEdit modelMaterialEdit;
private readonly LocationBuffer locationBuffer;

private ClumpBuffers? geometryBuffers;
private ClumpBuffersDeinterleaved? geometryBuffers;
private GeometryTreeCollider? collider;
private ModelStandardMaterial[] materials = Array.Empty<ModelStandardMaterial>();
private ModelMaterial[] materials = Array.Empty<ModelMaterial>();
private DebugSkeletonRenderer? skeletonRenderer;
private int highlightedSplitI = -1;

Expand Down Expand Up @@ -127,30 +127,32 @@ private void LoadModelNow(IResource resource)
new FilePath("resources/textures/worlds"),
};

geometryBuffers = new ClumpBuffers(diContainer, resource);
geometryBuffers = new ClumpBuffersDeinterleaved(diContainer, resource);
AddDisposable(geometryBuffers);

materials = new ModelStandardMaterial[geometryBuffers.SubMeshes.Count];
materials = new ModelMaterial[geometryBuffers.SubMeshes.Count];
foreach (var (rwMaterial, index) in geometryBuffers.SubMeshes.Select(s => s.Material).Indexed())
{
var material = materials[index] = new ModelStandardMaterial(diContainer);
(material.MainTexture.Texture, material.Sampler.Sampler) = TryLoadTexture(texturePaths, rwMaterial);
var material = materials[index] = new ModelMaterial(diContainer);
(material.Texture.Texture, material.Sampler.Sampler) = TryLoadTexture(texturePaths, rwMaterial);
material.LinkTransformsTo(camera);
material.World.Ref = Matrix4x4.Identity;
material.Uniforms.Ref = ModelStandardMaterialUniforms.Default;
material.Uniforms.Ref.vertexColorFactor = 0.0f; // they seem to be set to some gray for models?
material.Uniforms.Ref.tint = rwMaterial.color.ToFColor();
material.Colors.Ref = ModelStandardMaterialUniforms.Default with
{
vertexColorFactor = 0f, // they seem to be set to some gray for models?
tint = rwMaterial.color.ToFColor()
};
AddDisposable(material);
}
modelMaterialEdit.Materials = materials;
//modelMaterialEdit.Materials = materials;

skeletonRenderer = null;
if (geometryBuffers.Skin != null)
/*if (geometryBuffers.Skin != null)
{
var skeleton = new Skeleton(geometryBuffers.Skin, resource.Name.Replace(".DFF", "", StringComparison.CurrentCultureIgnoreCase));
skeletonRenderer = new DebugSkeletonRenderer(diContainer.ExtendedWith(camera, locationBuffer), geometryBuffers, skeleton);
AddDisposable(skeletonRenderer);
}
}*/

collider = geometryBuffers.RWGeometry.FindChildById(zzio.rwbs.SectionId.CollisionPLG, true) == null
? null
Expand Down

0 comments on commit e6f6af1

Please sign in to comment.