Merge pull request #115 from croakfang/master
fix missing mesh in Cheval Grand swimsuit export
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class BillboardBuilder : MonoBehaviour
|
||||
{
|
||||
public static Mesh CreateSphereMesh(float radius, float uvRadius, Vector2 uvCenter, int longitude = 6, int latitude = 6)
|
||||
{
|
||||
Mesh mesh = new Mesh();
|
||||
Vector3[] vertices = new Vector3[(longitude + 1) * (latitude + 1)];
|
||||
Vector2[] uvs = new Vector2[vertices.Length];
|
||||
int[] triangles = new int[longitude * latitude * 6];
|
||||
|
||||
int vert = 0, tri = 0;
|
||||
for (int lat = 0; lat <= latitude; lat++)
|
||||
{
|
||||
float a1 = Mathf.PI * lat / latitude;
|
||||
float y = Mathf.Cos(a1);
|
||||
float sin1 = Mathf.Sin(a1);
|
||||
|
||||
for (int lon = 0; lon <= longitude; lon++)
|
||||
{
|
||||
float a2 = 2 * Mathf.PI * lon / longitude;
|
||||
float x = sin1 * Mathf.Cos(a2);
|
||||
float z = sin1 * Mathf.Sin(a2);
|
||||
|
||||
vertices[vert] = new Vector3(x, y, z) * radius;
|
||||
//uvs[vert] = new Vector2((float)lon / longitude, (float)lat / latitude);
|
||||
|
||||
Vector3 p = vertices[vert].normalized;
|
||||
uvs[vert] = new Vector2(p.x, p.z) * uvRadius + uvCenter;
|
||||
|
||||
//uvs[vert] = new Vector2(p.x, p.z) * 0.5f + new Vector2(0.5f, 0.5f);
|
||||
|
||||
if (lat < latitude && lon < longitude)
|
||||
{
|
||||
int current = vert;
|
||||
int next = vert + longitude + 1;
|
||||
|
||||
triangles[tri++] = current;
|
||||
triangles[tri++] = current + 1;
|
||||
triangles[tri++] = next;
|
||||
|
||||
triangles[tri++] = current + 1;
|
||||
triangles[tri++] = next + 1;
|
||||
triangles[tri++] = next;
|
||||
}
|
||||
|
||||
vert++;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.uv = uvs;
|
||||
mesh.triangles = triangles;
|
||||
mesh.RecalculateNormals();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
public static void BuildBillboard(UmaContainerCharacter container)
|
||||
{
|
||||
int groupSize = 4;
|
||||
|
||||
foreach (SkinnedMeshRenderer s in container.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
if (s.name.Equals("M_Hair_Billboard") || s.name.Equals("M_Body_Billboard"))
|
||||
{
|
||||
Mesh sourceMesh = s.sharedMesh;
|
||||
Vector3[] vertices = sourceMesh.vertices;
|
||||
Vector2[] uv1s = sourceMesh.uv;
|
||||
Vector2[] uv2s = sourceMesh.uv2;
|
||||
|
||||
BoneWeight[] boneWeights = sourceMesh.boneWeights;
|
||||
Matrix4x4[] bindposes = sourceMesh.bindposes;
|
||||
|
||||
if (uv2s.Length != vertices.Length)
|
||||
{
|
||||
Debug.LogError("Unmatch vertices number.");
|
||||
return;
|
||||
}
|
||||
|
||||
// List
|
||||
List<Vector3> finalVertices = new List<Vector3>();
|
||||
List<int> finalTriangles = new List<int>();
|
||||
List<Vector3> finalNormals = new List<Vector3>();
|
||||
List<Vector2> finalUVs = new List<Vector2>();
|
||||
List<BoneWeight> finalBoneWeights = new List<BoneWeight>();
|
||||
|
||||
int sphereCount = 0;
|
||||
|
||||
for (int i = 0; i < vertices.Length; i += groupSize)
|
||||
{
|
||||
Vector3 center = vertices[i];
|
||||
float radius = Mathf.Abs(uv2s[i].x);
|
||||
|
||||
|
||||
if (radius <= 0.0001f)
|
||||
continue;
|
||||
|
||||
//Calc
|
||||
float min_x = 1;
|
||||
float max_x = 0;
|
||||
float min_y = 1;
|
||||
float max_y = 0;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (uv1s[i + j].x > max_x) max_x = uv1s[i + j].x;
|
||||
if (uv1s[i + j].x < min_x) min_x = uv1s[i + j].x;
|
||||
if (uv1s[i + j].y > max_y) max_y = uv1s[i + j].y;
|
||||
if (uv1s[i + j].y < min_y) min_y = uv1s[i + j].y;
|
||||
}
|
||||
|
||||
float center_x = (min_x + max_x) / 2;
|
||||
float center_y = (min_y + max_y) / 2;
|
||||
Vector2 uv_center = new Vector2(center_x, center_y);
|
||||
float uv_radius = (max_x - min_x) / 2 * 0.25f;
|
||||
|
||||
|
||||
// Create
|
||||
Mesh sphereMesh;
|
||||
|
||||
if (radius < 0.003)
|
||||
{
|
||||
sphereMesh = CreateSphereMesh(radius, uv_radius, uv_center);
|
||||
}
|
||||
else
|
||||
{
|
||||
sphereMesh = CreateSphereMesh(radius, uv_radius, uv_center, 12, 9);
|
||||
}
|
||||
|
||||
|
||||
int vertexOffset = finalVertices.Count;
|
||||
|
||||
foreach (Vector3 v in sphereMesh.vertices)
|
||||
finalVertices.Add(v + center);
|
||||
|
||||
finalTriangles.AddRange(System.Array.ConvertAll(sphereMesh.triangles, t => t + vertexOffset));
|
||||
finalNormals.AddRange(sphereMesh.normals);
|
||||
finalUVs.AddRange(sphereMesh.uv);
|
||||
|
||||
BoneWeight bw = boneWeights[i];
|
||||
for (int j = 0; j < sphereMesh.vertexCount; j++)
|
||||
finalBoneWeights.Add(bw);
|
||||
|
||||
sphereCount++;
|
||||
}
|
||||
|
||||
// Merge
|
||||
Mesh finalMesh = new Mesh();
|
||||
finalMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
||||
finalMesh.SetVertices(finalVertices);
|
||||
finalMesh.SetTriangles(finalTriangles, 0);
|
||||
finalMesh.SetNormals(finalNormals);
|
||||
finalMesh.SetUVs(0, finalUVs);
|
||||
finalMesh.boneWeights = finalBoneWeights.ToArray();
|
||||
finalMesh.bindposes = bindposes;
|
||||
|
||||
// Create
|
||||
GameObject resultGO = new GameObject("BoundSpheres");
|
||||
resultGO.transform.SetParent(s.transform, false);
|
||||
SkinnedMeshRenderer newSMR = resultGO.AddComponent<SkinnedMeshRenderer>();
|
||||
newSMR.sharedMesh = finalMesh;
|
||||
newSMR.bones = s.bones;
|
||||
newSMR.rootBone = s.rootBone;
|
||||
newSMR.material = s.sharedMaterial;
|
||||
|
||||
Debug.Log($"Generated {sphereCount} small spheres and combined them into a single mesh.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveBillboard(UmaContainerCharacter container)
|
||||
{
|
||||
foreach (SkinnedMeshRenderer s in container.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
if (s.name.Equals("BoundSpheres"))
|
||||
{
|
||||
GameObject.Destroy(s.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8657757b99bdfed4cafd242f24fe25f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -10,6 +10,8 @@ using System.IO;
|
||||
using UnityEngine;
|
||||
using static LibMMD.Model.Morph;
|
||||
using static LibMMD.Model.SkinningOperator;
|
||||
|
||||
using static BillboardBuilder;
|
||||
//using UnityGLTF;
|
||||
|
||||
|
||||
@@ -26,6 +28,7 @@ public class ModelExporter
|
||||
container.EnableEyeTracking = false;
|
||||
container.FaceDrivenKeyTarget?.FacialResetAll();
|
||||
AddBlendShape(container);
|
||||
BuildBillboard(container);
|
||||
|
||||
var textures = TextureExporter.ExportAllTexture(Path.GetDirectoryName(path), container.gameObject);
|
||||
var model = ReadPMXModel(container.CharaEntry, container, textures);
|
||||
@@ -38,6 +41,7 @@ public class ModelExporter
|
||||
writer.Close();
|
||||
fileStream.Close();
|
||||
|
||||
RemoveBillboard(container);
|
||||
ClearBlendShape(container);
|
||||
UmaViewerUI.Instance.ShowMessage($"PMX Save at {path}", UIMessageType.Success);
|
||||
}
|
||||
@@ -326,12 +330,12 @@ public class ModelExporter
|
||||
Vertex vertex = new Vertex();
|
||||
vertex.Coordinate = renderer.transform.TransformPoint(vertices[i]);
|
||||
vertex.Normal = normals[i];
|
||||
vertex.UvCoordinate = uv[i];
|
||||
vertex.UvCoordinate = new Vector2(uv[i].x, 1 - uv[i].y);
|
||||
|
||||
vertex.ExtraUvCoordinate = new Vector4[3]
|
||||
{
|
||||
uv1.Length > 0 ? uv1[i] : Vector2.zero,
|
||||
uv2.Length > 0 ? uv2[i] : Vector2.zero,
|
||||
uv1.Length > 0 ? new Vector2(uv1[i].x, 1 - uv1[i].y) : Vector2.zero,
|
||||
uv2.Length > 0 ? new Vector2(uv2[i].x, 1 - uv2[i].y) : Vector2.zero,
|
||||
colors.Length > 0 ? colors[i] : Color.clear
|
||||
};
|
||||
|
||||
|
||||
@@ -109,9 +109,9 @@ namespace LibMMD.Util
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void WriteVector3(BinaryWriter writer, Vector3 vector)
|
||||
public static void WriteVector3(BinaryWriter writer, Vector3 vector, bool useSizeAmplifier = true)
|
||||
{
|
||||
WriteAmpVector3(writer, vector, WorldSizeAmplifier);
|
||||
WriteAmpVector3(writer, vector, useSizeAmplifier ? WorldSizeAmplifier : 1);
|
||||
}
|
||||
|
||||
public static void WriteAmpVector3(BinaryWriter writer, Vector3 vector, float amp)
|
||||
|
||||
@@ -78,10 +78,10 @@ namespace LibMMD.Writer
|
||||
MMDReaderWriteUtil.WriteAmpVector3(writer, joint.Rotation, Mathf.Rad2Deg);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.PositionLowLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.PositionHiLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.RotationLowLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.RotationHiLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.RotationLowLimit, false);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.RotationHiLimit, false);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.SpringTranslate);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.SpringRotate);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, joint.SpringRotate, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ namespace LibMMD.Writer
|
||||
|
||||
if (bone.RotAxisFixed)
|
||||
{
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.RotAxis);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.RotAxis, false);
|
||||
}
|
||||
|
||||
if (bone.AppendRotate || bone.AppendTranslate)
|
||||
@@ -297,8 +297,8 @@ namespace LibMMD.Writer
|
||||
|
||||
if (bone.UseLocalAxis)
|
||||
{
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.LocalAxisVal.AxisX);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.LocalAxisVal.AxisZ);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.LocalAxisVal.AxisX, false);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, bone.LocalAxisVal.AxisZ, false);
|
||||
}
|
||||
|
||||
if (bone.ReceiveTransform)
|
||||
@@ -328,8 +328,8 @@ namespace LibMMD.Writer
|
||||
writer.Write(link.HasLimit ? (byte)1 : (byte)0);
|
||||
if (link.HasLimit)
|
||||
{
|
||||
MMDReaderWriteUtil.WriteVector3(writer, link.LoLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, link.HiLimit);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, link.LoLimit, false);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, link.HiLimit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -529,7 +529,7 @@ namespace LibMMD.Writer
|
||||
private static void WriteVertexBasic(BinaryWriter writer, Vector3 coordinate, Vector3 normal, Vector2 uvCoordinate)
|
||||
{
|
||||
MMDReaderWriteUtil.WriteVector3(writer, coordinate);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, normal);
|
||||
MMDReaderWriteUtil.WriteVector3(writer, normal, false);
|
||||
MMDReaderWriteUtil.WriteVector2(writer, uvCoordinate);
|
||||
}
|
||||
|
||||
|
||||
@@ -1683,6 +1683,6 @@ public class UmaContainerCharacter : UmaContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
return Instantiate(entry.Get<GameObject>());
|
||||
return Instantiate(entry.Get<GameObject>(), parent.transform);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user