Improved light baking, updated splashpack structure and documentation
This commit is contained in:
@@ -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 isn’t 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;
|
||||
|
||||
Reference in New Issue
Block a user