Skip to content

Instantly share code, notes, and snippets.

@chiepomme
Created March 10, 2017 05:17
Show Gist options
  • Save chiepomme/1ad552d0556e5fff78f1300ca5ea3306 to your computer and use it in GitHub Desktop.
Save chiepomme/1ad552d0556e5fff78f1300ca5ea3306 to your computer and use it in GitHub Desktop.
TransferUV
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