Created
March 10, 2017 05:17
-
-
Save chiepomme/1ad552d0556e5fff78f1300ca5ea3306 to your computer and use it in GitHub Desktop.
TransferUV
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.IO; | |
namespace ObjUVProjector | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var original = ParseObj(@"F:\idol\Assets\1.OBJ"); | |
var remeshed = ParseObj(@"F:\idol\Assets\2.OBJ"); | |
// remeshed の頂点のを同じグループの中で一番近い頂点座標を持つ頂点の UV 座標に書き換えてあげる | |
foreach (var groupedFaces in remeshed.faceGroups) | |
{ | |
var group = groupedFaces.Key; | |
var faces = groupedFaces.Value; | |
foreach (var face in faces) | |
{ | |
foreach (var vertex in face.vertices) | |
{ | |
var remeshedPosition = remeshed.positions[vertex.positionIndex - 1]; | |
var remeshedUV = remeshed.uvs[vertex.uvIndex - 1]; | |
var nearestThree = original.faceGroups[group] | |
.SelectMany(f => f.vertices) | |
.OrderBy(v => remeshedPosition.SqrDistanceTo(original.positions[v.positionIndex - 1])) | |
.Take(3) | |
.Select(v => new { vertex = v, distance = Math.Pow(remeshedPosition.SqrDistanceTo(original.positions[v.positionIndex - 1]), 0.5), uv = original.uvs[v.uvIndex - 1] }) | |
.ToArray(); | |
var totalDistance = nearestThree.Select(v => v.distance).Sum(); | |
var nearestThreeAverageUV = nearestThree.Aggregate(new UVPosition(0, 0), (acc, vert) => | |
{ | |
acc.u += vert.uv.u * (vert.distance / totalDistance); | |
acc.v += vert.uv.v * (vert.distance / totalDistance); | |
return acc; | |
}); | |
Console.WriteLine("" + remeshedUV + " -> " + nearestThreeAverageUV); | |
remeshedUV.u = nearestThreeAverageUV.u; | |
remeshedUV.v = nearestThreeAverageUV.v; | |
} | |
} | |
} | |
File.WriteAllText(@"F:\idol\Assets\3.OBJ", remeshed.ToString()); | |
} | |
class VertexPosition | |
{ | |
public double x; | |
public double y; | |
public double z; | |
public Group group; | |
public VertexPosition(double x, double y, double z) | |
{ | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
group = null; | |
} | |
public override string ToString() | |
{ | |
return string.Format("v {0} {1} {2}", x, y, z); | |
} | |
public double SqrDistanceTo(VertexPosition other) | |
{ | |
return ((other.x - x) * (other.x - x)) + ((other.y - y) * (other.y - y)); | |
} | |
} | |
class UVPosition | |
{ | |
public double u; | |
public double v; | |
public Group group; | |
public UVPosition(double u, double v) | |
{ | |
this.u = u; | |
this.v = v; | |
group = null; | |
} | |
public override string ToString() | |
{ | |
return string.Format("vt {0} {1}", u, v); | |
} | |
} | |
class Face | |
{ | |
public List<Vertex> vertices = new List<Vertex>(); | |
public Face() | |
{ | |
} | |
public override string ToString() | |
{ | |
return string.Format("f {0}", string.Join(" ", vertices.Select(v => v.ToString()).ToArray())); | |
} | |
} | |
class Vertex | |
{ | |
public int positionIndex; | |
public int uvIndex; | |
public Vertex(int positionIndex, int uvIndex) | |
{ | |
this.positionIndex = positionIndex; | |
this.uvIndex = uvIndex; | |
} | |
public override string ToString() | |
{ | |
return string.Format("{0}/{1}", positionIndex, uvIndex); | |
} | |
} | |
class Group : IEquatable<Group> | |
{ | |
public int index; | |
public string name; | |
public Group(int index, string name) | |
{ | |
this.index = index; | |
this.name = name; | |
} | |
public override string ToString() | |
{ | |
return string.Format("g {0}", name); | |
} | |
public override int GetHashCode() | |
{ | |
return index; | |
} | |
public bool Equals(Group other) | |
{ | |
return other.index == index; | |
} | |
} | |
class Model | |
{ | |
public readonly StringBuilder prefix = new StringBuilder(); | |
public readonly List<VertexPosition> positions = new List<VertexPosition>(); | |
public readonly List<UVPosition> uvs = new List<UVPosition>(); | |
public readonly Dictionary<Group, List<Face>> faceGroups = new Dictionary<Group, List<Face>>(); | |
public override string ToString() | |
{ | |
var sb = new StringBuilder(); | |
sb.AppendLine(prefix.ToString()); | |
foreach (var vertex in positions) | |
{ | |
sb.AppendLine(vertex.ToString()); | |
} | |
foreach (var uv in uvs) | |
{ | |
sb.AppendLine(uv.ToString()); | |
} | |
foreach (var groupedFaces in faceGroups) | |
{ | |
var group = groupedFaces.Key; | |
var faces = groupedFaces.Value; | |
sb.AppendLine(group.ToString()); | |
foreach (var face in faces) | |
{ | |
sb.AppendLine(face.ToString()); | |
} | |
} | |
return sb.ToString(); | |
} | |
} | |
static Model ParseObj(string path) | |
{ | |
bool readingPrefix = true; | |
var model = new Model(); | |
using (var reader = new StreamReader(path, Encoding.UTF8)) | |
{ | |
string line; | |
Group currentGroup = null; | |
var index = 0; | |
while ((line = reader.ReadLine()) != null) | |
{ | |
if (readingPrefix) | |
{ | |
if (line.StartsWith("v ")) | |
{ | |
readingPrefix = false; | |
} | |
else | |
{ | |
model.prefix.AppendLine(line); | |
continue; | |
} | |
} | |
if (line.StartsWith("v ")) | |
{ | |
var splitLine = line.Split(' '); | |
var x = double.Parse(splitLine[1]); | |
var y = double.Parse(splitLine[2]); | |
var z = double.Parse(splitLine[3]); | |
model.positions.Add(new VertexPosition(x, y, z)); | |
} | |
else if (line.StartsWith("vt ")) | |
{ | |
var splitLine = line.Split(' '); | |
var u = double.Parse(splitLine[1]); | |
var v = double.Parse(splitLine[2]); | |
model.uvs.Add(new UVPosition(u, v)); | |
} | |
if (line.StartsWith("g ")) | |
{ | |
var splitLine = line.Split(' '); | |
currentGroup = model.faceGroups.Keys.FirstOrDefault(g => g.name == splitLine[1]); | |
if (currentGroup == null) | |
{ | |
currentGroup = new Group(index, splitLine[1]); | |
index += 1; | |
} | |
if (!model.faceGroups.ContainsKey(currentGroup)) | |
{ | |
model.faceGroups[currentGroup] = new List<Face>(); | |
} | |
} | |
else if (line.StartsWith("f ")) | |
{ | |
var splitLine = line.Split(' '); | |
try | |
{ | |
var face = new Face(); | |
foreach (var faceEntry in splitLine.Skip(1)) | |
{ | |
var indices = faceEntry.Split('/'); | |
var vertex = new Vertex(int.Parse(indices[0]), int.Parse(indices[1])); | |
model.positions[vertex.positionIndex - 1].group = currentGroup; | |
model.uvs[vertex.uvIndex - 1].group = currentGroup; | |
face.vertices.Add(vertex); | |
} | |
model.faceGroups[currentGroup].Add(face); | |
} | |
catch (Exception) | |
{ | |
Console.WriteLine(line); | |
throw; | |
} | |
} | |
} | |
} | |
return model; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment