Improved light baking, updated splashpack structure and documentation

This commit is contained in:
2025-03-30 21:31:02 +02:00
parent 9e0d1557ee
commit da12ade580
9 changed files with 523 additions and 227 deletions

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Diagnostics;
@@ -27,6 +28,8 @@ namespace SplashEdit.RuntimeCode
public PSXVertex v0;
public PSXVertex v1;
public PSXVertex v2;
public PSXTexture2D Texture;
}
/// <summary>
@@ -37,6 +40,40 @@ namespace SplashEdit.RuntimeCode
{
public List<Tri> Triangles;
private static Vector3[] RecalculateSmoothNormals(Mesh mesh)
{
Vector3[] normals = new Vector3[mesh.vertexCount];
Dictionary<Vector3, List<int>> vertexMap = new Dictionary<Vector3, List<int>>();
for (int i = 0; i < mesh.vertexCount; i++)
{
Vector3 vertex = mesh.vertices[i];
if (!vertexMap.ContainsKey(vertex))
{
vertexMap[vertex] = new List<int>();
}
vertexMap[vertex].Add(i);
}
foreach (var kvp in vertexMap)
{
Vector3 smoothNormal = Vector3.zero;
foreach (int index in kvp.Value)
{
smoothNormal += mesh.normals[index];
}
smoothNormal.Normalize();
foreach (int index in kvp.Value)
{
normals[index] = smoothNormal;
}
}
return normals;
}
/// <summary>
/// Creates a PSXMesh from a Unity Mesh by converting its vertices, normals, UVs, and applying shading.
/// </summary>
@@ -45,57 +82,99 @@ namespace SplashEdit.RuntimeCode
/// <param name="textureHeight">Height of the texture (default is 256).</param>
/// <param name="transform">Optional transform to convert vertices to world space.</param>
/// <returns>A new PSXMesh containing the converted triangles.</returns>
public static PSXMesh CreateFromUnityMesh(Mesh mesh, float GTEScaling, Transform transform, bool isStatic, int textureWidth = 256, int textureHeight = 256)
public static PSXMesh CreateFromUnityRenderer(Renderer renderer, float GTEScaling, Transform transform, List<PSXTexture2D> textures)
{
PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() };
// Get mesh data arrays.
Vector3[] vertices = mesh.vertices;
Vector3[] normals = mesh.normals;
Vector2[] uv = mesh.uv;
int[] indices = mesh.triangles;
// Get materials and mesh.
Material[] materials = renderer.sharedMaterials;
Mesh mesh = renderer.GetComponent<MeshFilter>().sharedMesh;
// Determine the primary light's direction and color for shading.
Light mainLight = RenderSettings.sun;
Vector3 lightDir = mainLight ? mainLight.transform.forward : Vector3.down; // Fixed: Removed negation.
Color lightColor = mainLight ? mainLight.color * mainLight.intensity : Color.white;
// Iterate over each triangle (group of 3 indices).
for (int i = 0; i < indices.Length; i += 3)
// Iterate over each submesh.
for (int submeshIndex = 0; submeshIndex < materials.Length; submeshIndex++)
{
int vid0 = indices[i];
int vid1 = indices[i + 1];
int vid2 = indices[i + 2];
// Get the triangles for this submesh.
int[] submeshTriangles = mesh.GetTriangles(submeshIndex);
Vector3 v0, v1, v2;
// Get the material for this submesh.
Material material = materials[submeshIndex];
// Transform vertices to world space if a transform is provided.
// Get the corresponding texture for this material (assume mainTexture).
Texture2D texture = material.mainTexture as Texture2D;
PSXTexture2D psxTexture = null;
if (isStatic)
if (texture != null)
{
v0 = transform.TransformPoint(vertices[vid0]);
v1 = transform.TransformPoint(vertices[vid1]);
v2 = transform.TransformPoint(vertices[vid2]);
}
else
{
// Extract ONLY world scale
Vector3 worldScale = transform.lossyScale;
// Apply scale *before* transformation, ensuring rotation isnt affected
v0 = Vector3.Scale(vertices[vid0], worldScale);
v1 = Vector3.Scale(vertices[vid1], worldScale);
v2 = Vector3.Scale(vertices[vid2], worldScale);
// Find the corresponding PSX texture based on the Unity texture.
psxTexture = textures.FirstOrDefault(t => t.OriginalTexture == texture);
}
// Convert vertices to PSX format including fixed-point conversion and shading.
PSXVertex psxV0 = ConvertToPSXVertex(v0, GTEScaling, normals[vid0], uv[vid0], lightDir, lightColor, textureWidth, textureHeight);
PSXVertex psxV1 = ConvertToPSXVertex(v1, GTEScaling, normals[vid1], uv[vid1], lightDir, lightColor, textureWidth, textureHeight);
PSXVertex psxV2 = ConvertToPSXVertex(v2, GTEScaling, normals[vid2], uv[vid2], lightDir, lightColor, textureWidth, textureHeight);
if (psxTexture == null)
{
continue;
}
// Add the constructed triangle to the mesh.
psxMesh.Triangles.Add(new Tri { v0 = psxV0, v1 = psxV1, v2 = psxV2 });
// Get mesh data arrays.
Vector3[] vertices = mesh.vertices;
Vector3[] normals = mesh.normals;// Assuming this function recalculates normals
Vector3[] smoothNormals = RecalculateSmoothNormals(mesh);
Vector2[] uv = mesh.uv;
// Iterate through the triangles of the submesh.
for (int i = 0; i < submeshTriangles.Length; i += 3)
{
int vid0 = submeshTriangles[i];
int vid1 = submeshTriangles[i + 1];
int vid2 = submeshTriangles[i + 2];
Vector3 faceNormal = Vector3.Cross(vertices[vid1] - vertices[vid0], vertices[vid2] - vertices[vid0]).normalized;
if (Vector3.Dot(faceNormal, normals[vid0]) < 0)
{
(vid1, vid2) = (vid2, vid1);
}
// Scale the vertices based on world scale.
Vector3 v0 = Vector3.Scale(vertices[vid0], transform.lossyScale);
Vector3 v1 = Vector3.Scale(vertices[vid1], transform.lossyScale);
Vector3 v2 = Vector3.Scale(vertices[vid2], transform.lossyScale);
// Transform the vertices to world space.
Vector3 wv0 = transform.TransformPoint(vertices[vid0]);
Vector3 wv1 = transform.TransformPoint(vertices[vid1]);
Vector3 wv2 = transform.TransformPoint(vertices[vid2]);
// Transform the normals to world space.
Vector3 wn0 = transform.TransformDirection(smoothNormals[vid0]).normalized;
Vector3 wn1 = transform.TransformDirection(smoothNormals[vid1]).normalized;
Vector3 wn2 = transform.TransformDirection(smoothNormals[vid2]).normalized;
// Compute lighting for each vertex (this can be a custom function).
Color cv0 = PSXLightingBaker.ComputeLighting(wv0, wn0);
Color cv1 = PSXLightingBaker.ComputeLighting(wv1, wn1);
Color cv2 = PSXLightingBaker.ComputeLighting(wv2, wn2);
// Convert vertices to PSX format, including fixed-point conversion and shading.
PSXVertex psxV0 = ConvertToPSXVertex(v0, GTEScaling, normals[vid0], uv[vid0], psxTexture?.Width ?? 0, psxTexture?.Height ?? 0);
PSXVertex psxV1 = ConvertToPSXVertex(v1, GTEScaling, normals[vid1], uv[vid1], psxTexture?.Width ?? 0, psxTexture?.Height ?? 0);
PSXVertex psxV2 = ConvertToPSXVertex(v2, GTEScaling, normals[vid2], uv[vid2], psxTexture?.Width ?? 0, psxTexture?.Height ?? 0);
// Apply lighting to the colors.
psxV0.r = (byte)Mathf.Clamp(cv0.r * 255, 0, 255);
psxV0.g = (byte)Mathf.Clamp(cv0.g * 255, 0, 255);
psxV0.b = (byte)Mathf.Clamp(cv0.b * 255, 0, 255);
psxV1.r = (byte)Mathf.Clamp(cv1.r * 255, 0, 255);
psxV1.g = (byte)Mathf.Clamp(cv1.g * 255, 0, 255);
psxV1.b = (byte)Mathf.Clamp(cv1.b * 255, 0, 255);
psxV2.r = (byte)Mathf.Clamp(cv2.r * 255, 0, 255);
psxV2.g = (byte)Mathf.Clamp(cv2.g * 255, 0, 255);
psxV2.b = (byte)Mathf.Clamp(cv2.b * 255, 0, 255);
// Add the constructed triangle to the mesh.
psxMesh.Triangles.Add(new Tri { v0 = psxV0, v1 = psxV1, v2 = psxV2, Texture = psxTexture });
}
}
return psxMesh;
@@ -112,13 +191,9 @@ namespace SplashEdit.RuntimeCode
/// <param name="textureWidth">Width of the texture for UV scaling.</param>
/// <param name="textureHeight">Height of the texture for UV scaling.</param>
/// <returns>A PSXVertex with converted coordinates, normals, UVs, and color.</returns>
private static PSXVertex ConvertToPSXVertex(Vector3 vertex, float GTEScaling, Vector3 normal, Vector2 uv, Vector3 lightDir, Color lightColor, int textureWidth, int textureHeight)
private static PSXVertex ConvertToPSXVertex(Vector3 vertex, float GTEScaling, Vector3 normal, Vector2 uv, int textureWidth, int textureHeight)
{
// Calculate light intensity based on the angle between the normalized normal and light direction.
float lightIntensity = Mathf.Clamp01(Vector3.Dot(normal.normalized, lightDir));
// Compute the final shaded color by multiplying the light color by the intensity.
Color shadedColor = lightColor * lightIntensity;
PSXVertex psxVertex = new PSXVertex
{
@@ -137,9 +212,7 @@ namespace SplashEdit.RuntimeCode
v = (byte)Mathf.Clamp((1.0f - uv.y) * (textureHeight - 1), 0, 255),
// Convert the computed color to a byte range.
r = (byte)Mathf.Clamp(shadedColor.r * 255, 0, 255),
g = (byte)Mathf.Clamp(shadedColor.g * 255, 0, 255),
b = (byte)Mathf.Clamp(shadedColor.b * 255, 0, 255)
};
return psxVertex;