Last active
May 29, 2019 16:10
-
-
Save promontis/ca686732cfec04b4d9e38542dafd9468 to your computer and use it in GitHub Desktop.
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.Collections.Generic; | |
using System.Linq; | |
using System.Numerics; | |
using SharpGLTF.Geometry; | |
using SharpGLTF.Geometry.VertexTypes; | |
using SharpGLTF.Materials; | |
using VERTEX = SharpGLTF.Geometry.VertexBuilder< | |
SharpGLTF.Geometry.VertexTypes.VertexPositionNormal, | |
SharpGLTF.Geometry.VertexTypes.VertexTexture1, | |
SharpGLTF.Geometry.VertexTypes.VertexEmpty>; | |
namespace Stylister.Modeling3D.Core.Geometry | |
{ | |
public class PolygonMeshBuilder | |
{ | |
private readonly List<Vector2> _points = new List<Vector2>(); | |
private readonly List<Vector2> _outlinePoints = new List<Vector2>(); | |
private readonly List<List<Vector2>> _holes = new List<List<Vector2>>(); | |
private readonly List<double> _epoints = new List<double>(); | |
private readonly List<int> _eholes = new List<int>(); | |
public PolygonMeshBuilder(List<Vector2> counters) | |
{ | |
var points = counters; | |
AddToEPoints(points); | |
_points.AddRange(points); | |
_outlinePoints.AddRange(points); | |
} | |
private void AddToEPoints(List<Vector2> points) | |
{ | |
_epoints.AddRange(points.SelectMany(point => new List<double> { point.X, point.Y })); | |
} | |
private PolygonMeshBuilder AddHole(List<Vector2> hole) | |
{ | |
_points.AddRange(hole); | |
_holes.Add(hole); | |
_eholes.Add(_epoints.Count / 2); | |
AddToEPoints(hole); | |
return this; | |
} | |
private VertexData BuildVertexData(float depth) | |
{ | |
var result = new VertexData(); | |
var normals = new List<Vector3>(); | |
var positions = new List<Vector3>(); | |
var uvs = new List<Vector2>(); | |
var bounds = _points.ComputeBounds(); | |
foreach (var point in _points) | |
{ | |
normals.Add(new Vector3(0, 1.0f, 0)); | |
positions.Add(new Vector3(point.X, 0, point.Y)); | |
uvs.Add(new Vector2((point.X - bounds.Min.X) / bounds.Width, (point.Y - bounds.Min.Y) / bounds.Height)); | |
} | |
var res = Earcut.Tessellate(_epoints, _eholes); | |
var indices = new List<int>(res); | |
if (depth > 0) | |
{ | |
var positionsCount = positions.Count / 3; | |
// Add the elements at the depth | |
foreach (var point in _points) | |
{ | |
normals.Add(new Vector3(0, -1.0f, 0)); | |
positions.Add(new Vector3(point.X, -depth, point.Y)); | |
uvs.Add(new Vector2(1 - (point.X - bounds.Min.X) / bounds.Width, 1 - (point.Y - bounds.Min.Y) / bounds.Height)); | |
} | |
var totalCount = indices.Count; | |
for (var i = 0; i < totalCount; i += 3) | |
{ | |
var i0 = indices[i + 0]; | |
var i1 = indices[i + 1]; | |
var i2 = indices[i + 2]; | |
indices.Add(i2 + positionsCount); | |
indices.Add(i1 + positionsCount); | |
indices.Add(i0 + positionsCount); | |
} | |
// Add the sides | |
AddSide(positions, normals, uvs, indices, bounds, _outlinePoints, depth, false); | |
foreach (var hole in _holes) | |
{ | |
AddSide(positions, normals, uvs, indices, bounds, hole, depth, true); | |
} | |
} | |
result.Indices = indices; | |
result.Positions = positions; | |
result.Normals = normals; | |
result.Uvs = uvs; | |
return result; | |
} | |
private void AddSide(List<Vector3> positions, List<Vector3> normals, List<Vector2> uvs, List<int> indices, Bounds bounds, List<Vector2> points, float depth, bool flip) | |
{ | |
var startIndex = positions.Count / 3; | |
var uLength = 0.0f; | |
for (var i = 0; i < points.Count; i++) | |
{ | |
var p = points[i]; | |
var p1 = i + 1 > points.Count - 1 ? points[0] : points[i + 1]; | |
positions.Add(new Vector3(p.X, 0, p.Y)); | |
positions.Add(new Vector3(p.X, -depth, p.Y)); | |
positions.Add(new Vector3(p1.X, 0, p1.Y)); | |
positions.Add(new Vector3(p1.X, -depth, p1.Y)); | |
var v1 = new Vector3(p.X, 0, p.Y); | |
var v2 = new Vector3(p1.X, 0, p1.Y); | |
var v3 = v2 - v1; | |
var v4 = new Vector3(0, 1, 0); | |
var vn = Vector3.Cross(v3, v4); | |
vn = Vector3.Normalize(vn); | |
uvs.Add(new Vector2(uLength / bounds.Width, 0)); | |
uvs.Add(new Vector2(uLength / bounds.Width, 1)); | |
uLength += v3.Length(); | |
uvs.Add(new Vector2(uLength / bounds.Width, 0)); | |
uvs.Add(new Vector2(uLength / bounds.Width, 1)); | |
if (!flip) | |
{ | |
normals.Add(new Vector3(-vn.X, -vn.Y, -vn.Z)); | |
normals.Add(new Vector3(-vn.X, -vn.Y, -vn.Z)); | |
normals.Add(new Vector3(-vn.X, -vn.Y, -vn.Z)); | |
normals.Add(new Vector3(-vn.X, -vn.Y, -vn.Z)); | |
indices.Add(startIndex); | |
indices.Add(startIndex + 1); | |
indices.Add(startIndex + 2); | |
indices.Add(startIndex + 1); | |
indices.Add(startIndex + 3); | |
indices.Add(startIndex + 2); | |
} | |
else | |
{ | |
normals.Add(new Vector3(vn.X, vn.Y, vn.Z)); | |
normals.Add(new Vector3(vn.X, vn.Y, vn.Z)); | |
normals.Add(new Vector3(vn.X, vn.Y, vn.Z)); | |
normals.Add(new Vector3(vn.X, vn.Y, vn.Z)); | |
indices.Add(startIndex); | |
indices.Add(startIndex + 2); | |
indices.Add(startIndex + 1); | |
indices.Add(startIndex + 1); | |
indices.Add(startIndex + 2); | |
indices.Add(startIndex + 3); | |
} | |
startIndex += 4; | |
} | |
} | |
public MeshBuilder<VertexPositionNormal, VertexTexture1, VertexEmpty> Build(float depth = 0) | |
{ | |
VERTEX CreateVertexFromIndex(VertexData vertexData1, int index) | |
{ | |
return new VERTEX( | |
new VertexPositionNormal(vertexData1.Positions[index],vertexData1.Normals[index]), | |
new VertexTexture1(vertexData1.Uvs[index]), | |
new VertexEmpty()); | |
} | |
var result = VERTEX.CreateCompatibleMesh(); | |
var vertexData = BuildVertexData(depth); | |
var material = new MaterialBuilder("material"); | |
var primitive = result.UsePrimitive(material); | |
for (var i = 2; i < vertexData.Indices.Count; i += 3) | |
{ | |
var idx0 = vertexData.Indices[i - 2]; | |
var idx1 = vertexData.Indices[i - 1]; | |
var idx2 = vertexData.Indices[i - 0]; | |
var a = CreateVertexFromIndex(vertexData, idx0); | |
var b = CreateVertexFromIndex(vertexData, idx1); | |
var c = CreateVertexFromIndex(vertexData, idx2); | |
primitive.AddTriangle(a, b, c); | |
} | |
return result; | |
} | |
} | |
public class VertexData | |
{ | |
public List<int> Indices { get; set; } | |
public List<Vector3> Positions { get; set; } | |
public List<Vector3> Normals { get; set; } | |
public List<Vector2> Uvs { get; set; } | |
} | |
} |
@vpenades
Cool! I've just updated the code :) Far cleaner indeed!
The indices are correct like this, right?
yes, it seems it's correct now... dunno if it's working for you, thought.
I would improve the VertexData code a bit further:
public class VertexData
{
public List<int> Indices { get; set; }
public List<Vector3> Positions { get; set; }
public List<Vector3> Normals { get; set; }
public List<Vector2> Uvs { get; set; }
VERTEX GetVertex(int index)
{
index = Indices[ index ];
return new VERTEX(
new VertexPositionNormal( Positions[index], Normals[index] ),
new VertexTexture1( Uvs[index] ),
new VertexEmpty( ) );
}
}
{
for (var i = 2; i < vertexData.Indices.Count; i += 3)
{
var a = vertexData.GetVertex(i-2);
var b = vertexData.GetVertex(i-1);
var c = vertexData.GetVertex(i-0);
primitive.AddTriangle(a, b, c);
}
}
you could even move the whole "Build" method inside VertexData class...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I believe you need to multiply the indices you get from this: public List Indices { get; set; } by 3, 3, and 2
because your Positions, Normals and Uvs are stored as plain floats.
I would suggest you to replace Vertex data with this:
and things will be easier to index.