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.
137 lines
5.3 KiB
137 lines
5.3 KiB
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
public partial class RenderModule
|
|
{
|
|
private readonly UniQuake uq;
|
|
|
|
public RenderModule(UniQuake uniQuake)
|
|
{
|
|
uq = uniQuake;
|
|
BuildCallbacks();
|
|
}
|
|
|
|
private float xPos = -8f;
|
|
|
|
private int UploadAliasModel(string name, QVec3 boundsMin, QVec3 boundsMax, QAliasHeader header,
|
|
QTriVertex[][] poseVertices, QTriangle[] triangles, QSTVert[] stVertices)
|
|
{
|
|
Debug.Log($"Alias model '{name}' with {header.numVerts} vertices, {header.numTriangles} triangles, {header.numFrames} frame(s)");
|
|
|
|
ConvertVertices(header, poseVertices[0], out var vertices, out var normals);
|
|
ConvertTriangles(triangles, out var indices);
|
|
ConvertUVs(stVertices, header.skinWidth, header.skinHeight, out var uvs);
|
|
|
|
var mesh = new Mesh { name = name };
|
|
mesh.SetVertices(vertices);
|
|
mesh.SetNormals(normals);
|
|
mesh.SetIndices(indices, MeshTopology.Triangles, 0, false);
|
|
mesh.SetUVs(0, uvs);
|
|
|
|
CreateBlendShapes(mesh, vertices, normals, header, poseVertices);
|
|
|
|
mesh.Optimize(); // This ensures that triangles will be properly fused and organized in the best possible way
|
|
mesh.RecalculateBounds();
|
|
mesh.UploadMeshData(true);
|
|
|
|
var go = new GameObject(System.IO.Path.GetFileNameWithoutExtension(name));
|
|
go.transform.SetPositionAndRotation(new Vector3(xPos, 0, 0), Quaternion.Euler(-90, 90, 0));
|
|
|
|
if (header.numFrames > 1)
|
|
{
|
|
var mr = go.AddComponent<SkinnedMeshRenderer>();
|
|
mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
|
|
mr.sharedMesh = mesh;
|
|
mr.shadowCastingMode = ShadowCastingMode.Off;
|
|
mr.receiveShadows = false;
|
|
mr.lightProbeUsage = LightProbeUsage.Off;
|
|
mr.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
|
go.AddComponent<AliasModelAnimator>();
|
|
}
|
|
else
|
|
{
|
|
var mf = go.AddComponent<MeshFilter>();
|
|
mf.sharedMesh = mesh;
|
|
var mr = go.AddComponent<MeshRenderer>();
|
|
mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
|
|
mr.shadowCastingMode = ShadowCastingMode.Off;
|
|
mr.receiveShadows = false;
|
|
mr.lightProbeUsage = LightProbeUsage.Off;
|
|
mr.reflectionProbeUsage = ReflectionProbeUsage.Off;
|
|
}
|
|
|
|
xPos += 0.5f;
|
|
return 1;
|
|
}
|
|
|
|
private static void ConvertVertices(QAliasHeader header, QTriVertex[] triVerts, out Vector3[] vertices, out Vector3[] normals)
|
|
{
|
|
int numVerts = triVerts.Length;
|
|
vertices = new Vector3[numVerts];
|
|
normals = new Vector3[numVerts];
|
|
|
|
Vector3 scale = header.scale.ToVector3();
|
|
Vector3 origin = header.scaleOrigin.ToVector3();
|
|
|
|
for (int i = 0; i < numVerts; ++i)
|
|
{
|
|
vertices[i] = Vector3.Scale(triVerts[i].ToVector3(), scale);
|
|
normals[i] = QLightNormals.Get(triVerts[i].lightNormalIndex);
|
|
}
|
|
}
|
|
|
|
private static void ConvertTriangles(QTriangle[] triangles, out ushort[] indices)
|
|
{
|
|
int numTris = triangles.Length;
|
|
indices = new ushort[numTris * 3];
|
|
|
|
for (int i = 0; i < numTris; ++i)
|
|
{
|
|
indices[i * 3 + 0] = (ushort)triangles[i].vertIndex[2];
|
|
indices[i * 3 + 1] = (ushort)triangles[i].vertIndex[1];
|
|
indices[i * 3 + 2] = (ushort)triangles[i].vertIndex[0];
|
|
}
|
|
}
|
|
|
|
private static void ConvertUVs(QSTVert[] stVerts, int skinWidth, int skinHeight, out Vector2[] uvs)
|
|
{
|
|
int numVerts = stVerts.Length;
|
|
uvs = new Vector2[numVerts];
|
|
|
|
// TODO FIXME: this only works correctly for the front side of a model.
|
|
// To also correctly UV the back side, we need to duplicate vertices on the back/front seam,
|
|
// and add half the skin width to UVs that are on back side vertices.
|
|
Vector2 scale = new Vector2(1.0f / skinWidth, 1.0f / skinHeight);
|
|
|
|
for (int i = 0; i < numVerts; ++i)
|
|
{
|
|
uvs[i] = Vector2.Scale(new Vector2(stVerts[i].s, skinHeight - stVerts[i].t), scale);
|
|
}
|
|
}
|
|
|
|
private static void CreateBlendShapes(
|
|
Mesh mesh, Vector3[] baseVertices, Vector3[] baseNormals,
|
|
QAliasHeader header, QTriVertex[][] poseVertices)
|
|
{
|
|
var deltaVertices = new Vector3[header.numVerts];
|
|
var deltaNormals = new Vector3[header.numVerts];
|
|
|
|
Vector3 scale = header.scale.ToVector3();
|
|
Vector3 origin = header.scaleOrigin.ToVector3();
|
|
|
|
// Frame 0 is the base pose, so we start with frame 1
|
|
for (int frameIdx = 1; frameIdx < header.numFrames; ++frameIdx)
|
|
{
|
|
var poseVerts = poseVertices[frameIdx];
|
|
|
|
for (int vertIdx = 0; vertIdx < header.numVerts; ++vertIdx)
|
|
{
|
|
Vector3 vert = Vector3.Scale(poseVerts[vertIdx].ToVector3(), scale);
|
|
deltaVertices[vertIdx] = vert - baseVertices[vertIdx];
|
|
deltaNormals[vertIdx] = QLightNormals.Get(poseVerts[vertIdx].lightNormalIndex) - baseNormals[vertIdx];
|
|
}
|
|
|
|
mesh.AddBlendShapeFrame(mesh.name, (float)frameIdx / (header.numFrames-1), deltaVertices, deltaNormals, null);
|
|
}
|
|
}
|
|
}
|