-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathSceneMeshFactory.cs
158 lines (143 loc) · 6.19 KB
/
SceneMeshFactory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using OpenTK;
using OpenTK.Graphics.OpenGL4;
using System;
namespace Bonsai.Shaders.Rendering
{
static class SceneMeshFactory
{
const int ElementSizeVector3D = 3;
const int ElementSizeColor4D = 4;
class VertexBounds
{
Vector3 minimum = Vector3.One * float.MaxValue;
Vector3 maximum = Vector3.One * float.MinValue;
public Vector3 Center
{
get { return (maximum + minimum) / 2; }
}
public Vector3 Extents
{
get { return (maximum - minimum) / 2; }
}
public void Add(float x, float y, float z)
{
var vertex = new Vector3(x, y, z);
Vector3.ComponentMin(ref minimum, ref vertex, out minimum);
Vector3.ComponentMax(ref maximum, ref vertex, out maximum);
}
}
static int PushAttribArray(int index, int elementSize, int stride, int offset)
{
GL.EnableVertexAttribArray(index);
GL.VertexAttribPointer(
index, elementSize,
VertexAttribPointerType.Float,
false, stride, offset);
return offset + elementSize * BlittableValueType<float>.Stride;
}
static float[] GetVertices(Assimp.Mesh resource, out int stride, out VertexBounds bounds)
{
stride = 0;
bounds = new VertexBounds();
if (resource.HasVertices) stride += ElementSizeVector3D;
for (int i = 0; i < resource.TextureCoordinateChannelCount; i++)
{
stride += resource.UVComponentCount[i];
}
stride += resource.VertexColorChannelCount * ElementSizeColor4D;
if (resource.HasNormals) stride += ElementSizeVector3D;
var vertices = new float[resource.VertexCount * stride];
for (int i = 0, v = 0; i < resource.VertexCount; i++)
{
if (resource.HasVertices)
{
var vertex = resource.Vertices[i];
vertices[v++] = vertex.X;
vertices[v++] = vertex.Y;
vertices[v++] = vertex.Z;
bounds.Add(vertex.X, vertex.Y, vertex.Z);
}
for (int k = 0; k < resource.TextureCoordinateChannelCount; k++)
{
var texCoord = resource.TextureCoordinateChannels[k][i];
vertices[v++] = texCoord.X;
vertices[v++] = texCoord.Y;
if (resource.UVComponentCount[k] > 2)
{
vertices[v++] = texCoord.Z;
}
}
for (int c = 0; c < resource.VertexColorChannelCount; c++)
{
var color = resource.VertexColorChannels[c][i];
vertices[v++] = color.R;
vertices[v++] = color.G;
vertices[v++] = color.B;
vertices[v++] = color.A;
}
if (resource.HasNormals)
{
var normal = resource.Normals[i];
vertices[v++] = normal.X;
vertices[v++] = normal.Y;
vertices[v++] = normal.Z;
}
}
stride *= BlittableValueType<float>.Stride;
return vertices;
}
public static SceneMesh CreateMesh(Assimp.Mesh resource)
{
var mesh = new SceneMesh();
mesh.MaterialIndex = resource.MaterialIndex;
var vertices = GetVertices(resource, out int stride, out VertexBounds bounds);
mesh.Bounds = new Bounds(bounds.Center, bounds.Extents);
mesh.VertexCount = resource.VertexCount;
mesh.DrawMode = PrimitiveType.Triangles;
GL.BindVertexArray(mesh.VertexArray);
GL.BindBuffer(BufferTarget.ArrayBuffer, mesh.VertexBuffer);
GL.BufferData(BufferTarget.ArrayBuffer,
new IntPtr(vertices.Length * BlittableValueType<float>.Stride),
vertices, BufferUsageHint.StaticDraw);
if (resource.HasFaces)
{
mesh.EnsureElementArray();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, mesh.ElementArray);
if (resource.VertexCount <= short.MaxValue)
{
var indices = resource.GetShortIndices();
mesh.VertexCount = indices.Length;
mesh.ElementArrayType = DrawElementsType.UnsignedShort;
GL.BufferData(BufferTarget.ElementArrayBuffer,
new IntPtr(indices.Length * BlittableValueType<short>.Stride),
indices, BufferUsageHint.StaticDraw);
}
else
{
var indices = resource.GetIndices();
mesh.VertexCount = indices.Length;
mesh.ElementArrayType = DrawElementsType.UnsignedInt;
GL.BufferData(BufferTarget.ElementArrayBuffer,
new IntPtr(indices.Length * BlittableValueType<int>.Stride),
indices, BufferUsageHint.StaticDraw);
}
}
var attrib = 0;
var offset = 0;
if (resource.HasVertices) offset = PushAttribArray(attrib++, ElementSizeVector3D, stride, offset);
for (int k = 0; k < resource.TextureCoordinateChannelCount; k++)
{
offset = PushAttribArray(attrib++, resource.UVComponentCount[k], stride, offset);
}
for (int c = 0; c < resource.VertexColorChannelCount; c++)
{
offset = PushAttribArray(attrib++, ElementSizeColor4D, stride, offset);
}
if (resource.HasNormals) PushAttribArray(attrib++, ElementSizeVector3D, stride, offset);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindVertexArray(0);
return mesh;
}
}
}