You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
5.2 KiB
156 lines
5.2 KiB
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
public class BrushModel
|
|
{
|
|
private readonly string name;
|
|
private readonly List<Mesh> meshes = new List<Mesh>();
|
|
|
|
// Reusable temporary data containers
|
|
private readonly List<Vector3> tempVertices = new List<Vector3>();
|
|
private readonly List<Vector2> tempTextureUVs = new List<Vector2>();
|
|
private readonly List<Vector2> tempLightmapUVs = new List<Vector2>();
|
|
private readonly List<ushort> tempIndices = new List<ushort>();
|
|
|
|
private readonly GameObject rootGameObject;
|
|
private readonly Material debugMaterial;
|
|
|
|
public BrushModel(string name)
|
|
{
|
|
this.name = name;
|
|
|
|
rootGameObject = new GameObject(name);
|
|
rootGameObject.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
|
|
|
|
debugMaterial = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
|
|
}
|
|
|
|
public void ImportMeshData(QModel model)
|
|
{
|
|
var subModels = model.SubModels;
|
|
var surfaces = model.Surfaces;
|
|
|
|
for (int modelIdx = 0; modelIdx < subModels.Length; ++modelIdx)
|
|
{
|
|
var modelGO = new GameObject($"SubModel_{modelIdx}");
|
|
modelGO.transform.SetParent(rootGameObject.transform);
|
|
|
|
var headNode = subModels[modelIdx].GetHeadNode(model);
|
|
|
|
var surfaceGroups = new Dictionary<(string, int), List<QSurface>>();
|
|
GroupSurfaces(headNode, surfaces, surfaceGroups);
|
|
|
|
foreach (var group in surfaceGroups)
|
|
{
|
|
var key = group.Key;
|
|
var groupGO = new GameObject($"T{key.Item1}_L{key.Item2}");
|
|
groupGO.transform.SetParent(modelGO.transform);
|
|
|
|
for (int i = 0; i < group.Value.Count; ++i)
|
|
{
|
|
CreateSurfaceMeshes(group.Value[i], $"{i}", groupGO);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void GroupSurfaces(QNode node, QSurface[] surfaces, Dictionary<(string, int), List<QSurface>> surfaceGroups)
|
|
{
|
|
if (node.contents < 0) // Leaf node
|
|
return;
|
|
|
|
for (int surfIdx = 0; surfIdx < node.numSurfaces; ++surfIdx)
|
|
{
|
|
var surface = surfaces[node.firstSurface + surfIdx];
|
|
|
|
string texName = surface.TextureInfo.Texture.name;
|
|
int lightNum = surface.lightmapTextureNum;
|
|
var key = (texName, lightNum);
|
|
|
|
if (!surfaceGroups.ContainsKey(key))
|
|
surfaceGroups[key] = new List<QSurface>();
|
|
|
|
surfaceGroups[key].Add(surface);
|
|
}
|
|
|
|
foreach (var childNode in node.Children)
|
|
{
|
|
GroupSurfaces(childNode, surfaces, surfaceGroups);
|
|
}
|
|
}
|
|
|
|
private void CreateNodeMeshes(QNode node, QSurface[] surfaces, GameObject parentGO)
|
|
{
|
|
if (node.contents < 0) // Leaf node
|
|
return;
|
|
|
|
var nodeGO = new GameObject("Node");
|
|
nodeGO.transform.SetParent(parentGO.transform);
|
|
|
|
for (int surfIdx = 0; surfIdx < node.numSurfaces; ++surfIdx)
|
|
{
|
|
var surface = surfaces[node.firstSurface + surfIdx];
|
|
CreateSurfaceMeshes(surface, $"{node.firstSurface + surfIdx}", nodeGO);
|
|
}
|
|
|
|
foreach (var childNode in node.Children)
|
|
{
|
|
CreateNodeMeshes(childNode, surfaces, nodeGO);
|
|
}
|
|
}
|
|
|
|
private void CreateSurfaceMeshes(QSurface surface, string key, GameObject nodeGO)
|
|
{
|
|
foreach (var polyVerts in surface.GetPolygons())
|
|
{
|
|
tempVertices.Clear();
|
|
tempTextureUVs.Clear();
|
|
tempLightmapUVs.Clear();
|
|
tempIndices.Clear();
|
|
|
|
for (int vertIdx = 0; vertIdx < polyVerts.Length; ++vertIdx)
|
|
{
|
|
tempVertices.Add(polyVerts[vertIdx].position.ToVector3().ToUnity());
|
|
tempTextureUVs.Add(polyVerts[vertIdx].textureUV.ToVector2());
|
|
tempLightmapUVs.Add(polyVerts[vertIdx].lightmapUV.ToVector2());
|
|
}
|
|
|
|
// Reconstruct triangle fan
|
|
for (ushort index = 2; index < polyVerts.Length; ++index)
|
|
{
|
|
tempIndices.Add(0);
|
|
tempIndices.Add((ushort) (index - 1));
|
|
tempIndices.Add(index);
|
|
}
|
|
|
|
Mesh mesh = new Mesh();
|
|
mesh.name = $"Surface_{key}";
|
|
mesh.SetVertices(tempVertices);
|
|
mesh.SetUVs(0, tempTextureUVs);
|
|
mesh.SetUVs(1, tempLightmapUVs);
|
|
mesh.SetIndices(tempIndices, MeshTopology.Triangles, 0);
|
|
mesh.RecalculateNormals();
|
|
mesh.UploadMeshData(true);
|
|
meshes.Add(mesh);
|
|
|
|
CreateMeshObject(mesh, nodeGO);
|
|
}
|
|
}
|
|
|
|
private void CreateMeshObject(Mesh mesh, GameObject parentGO)
|
|
{
|
|
var meshGO = new GameObject(mesh.name);
|
|
meshGO.transform.SetParent(parentGO.transform);
|
|
|
|
var mf = meshGO.AddComponent<MeshFilter>();
|
|
mf.sharedMesh = mesh;
|
|
|
|
var mr = meshGO.AddComponent<MeshRenderer>();
|
|
mr.sharedMaterial = debugMaterial;
|
|
mr.shadowCastingMode = ShadowCastingMode.Off;
|
|
mr.receiveShadows = false;
|
|
mr.lightProbeUsage = LightProbeUsage.Off;
|
|
mr.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
|
}
|
|
}
|