1 module armos.graphics.mesh; 2 import armos.types; 3 import armos.math; 4 import armos.graphics; 5 6 /++ 7 ポリゴンで構成された形状を表すclassです. 8 +/ 9 class Mesh { 10 public{ 11 alias int IndexType; 12 13 bool isVertsChanged = false; 14 bool isFaceDirty = false; 15 bool isIndicesChanged = false; 16 17 Vector4f[] vertices; 18 Vector3f[] normals; 19 Vector3f[] tangents; 20 Vector4f[] texCoords0; 21 Vector4f[] texCoords1; 22 alias texCoords0 texCoords; 23 armos.types.FloatColor[] colors; 24 IndexType[] indices; 25 26 /// テクスチャ座標の数を表します. 27 size_t numTexCoords()const{ 28 return texCoords.length; 29 } 30 31 /// 頂点座標の数を表します. 32 size_t numVertices()const{ 33 return vertices.length; 34 } 35 36 /// 法線ベクトルの数を表します. 37 size_t numNormals()const{ 38 return normals.length; 39 } 40 41 /// 頂点インデックスの数を表します. 42 size_t numIndices()const{ 43 return indices.length; 44 } 45 46 /// meshの描画モードを返します. 47 PrimitiveMode primitiveMode()const{ 48 return _primitiveMode; 49 } 50 51 /// meshの描画モードを指定します. 52 Mesh primitiveMode(in PrimitiveMode mode){ 53 _primitiveMode = mode; 54 return this; 55 } 56 57 /++ 58 テクスチャ座標を追加します. 59 +/ 60 Mesh addTexCoord(in Vector2f vec){ 61 addTexCoord(vec[0], vec[1]); 62 return this; 63 } 64 65 /++ 66 テクスチャ座標を追加します. 67 +/ 68 Mesh addTexCoord(in float u, in float v){ 69 texCoords ~= Vector4f(u, v, 0f, 1f); 70 return this; 71 } 72 73 /++ 74 頂点座標を追加します. 75 +/ 76 Mesh addVertex(in Vector3f vec){ 77 vertices ~= Vector4f(vec[0], vec[1], vec[2], 1); 78 isVertsChanged = true; 79 isFaceDirty = true; 80 return this; 81 }; 82 unittest{ 83 auto mesh = new Mesh; 84 mesh.addVertex(Vector3f(0, 1, 2)); 85 mesh.addVertex(Vector3f(3, 4, 5)); 86 mesh.addVertex(Vector3f(6, 7, 8)); 87 assert(mesh.vertices[1][1] == 4.0); 88 assert(mesh.isFaceDirty); 89 assert(mesh.isVertsChanged); 90 } 91 92 /++ 93 頂点座標を追加します. 94 +/ 95 Mesh addVertex(in float x, in float y, in float z){ 96 addVertex(Vector3f(x, y, z)); 97 return this; 98 } 99 100 /++ 101 法線ベクトルを追加します. 102 +/ 103 Mesh addNormal(in Vector3f vec){ 104 normals ~= vec; 105 return this; 106 } 107 108 /++ 109 法線ベクトルを追加します. 110 +/ 111 Mesh addNormal(in float x, in float y, in float z){ 112 addNormal(Vector3f(x, y, z)); 113 return this; 114 } 115 116 /++ 117 頂点インデックスを追加します. 118 +/ 119 Mesh addIndex(in IndexType index){ 120 indices ~= index; 121 isIndicesChanged = true; 122 isFaceDirty = true; 123 return this; 124 }; 125 unittest{ 126 auto mesh = new Mesh; 127 mesh.addIndex(1); 128 mesh.addIndex(2); 129 mesh.addIndex(3); 130 assert(mesh.indices[1] == 2); 131 assert(mesh.isIndicesChanged); 132 assert(mesh.isFaceDirty); 133 } 134 135 /++ 136 meshを描画します. 137 Params: 138 renderMode = 面,線,点のどれを描画するか指定します. 139 +/ 140 Mesh draw(in PolyRenderMode renderMode){ 141 currentRenderer.draw(this, renderMode, false, false, false); 142 return this; 143 }; 144 145 /++ 146 meshをワイヤフレームで描画します. 147 +/ 148 Mesh drawWireFrame(){ 149 draw(PolyRenderMode.WireFrame); 150 return this; 151 }; 152 153 /++ 154 meshの頂点を点で描画します. 155 +/ 156 Mesh drawVertices(){ 157 draw(PolyRenderMode.Points); 158 return this; 159 }; 160 161 /++ 162 meshの面を塗りつぶして描画します. 163 +/ 164 Mesh drawFill(){ 165 draw(PolyRenderMode.Fill); 166 return this; 167 }; 168 169 /// 170 Mesh calcNormal(){ 171 switch (_primitiveMode) { 172 case PrimitiveMode.Triangles: 173 Vector3f[] normalSums = new Vector3f[numVertices]; 174 foreach (ref sum; normalSums) { 175 sum = Vector3f.zero; 176 } 177 for (size_t i = 0; i < numIndices; i+=3){ 178 immutable v1 = vertices[indices[i]].xyz; 179 immutable v2 = vertices[indices[i+1]].xyz; 180 immutable v3 = vertices[indices[i+2]].xyz; 181 immutable n = (v2-v1).vectorProduct(v3-v1).normalized; 182 normalSums[indices[i]] += n; 183 normalSums[indices[i+1]] += n; 184 normalSums[indices[i+2]] += n; 185 } 186 187 import std.algorithm:map; 188 import std.array:array; 189 normals = normalSums.map!(n => n.normalized).array; 190 break; 191 default: 192 return this; 193 } 194 return this; 195 } 196 197 /// 198 Mesh opBinary(string op:"~")(Mesh rhs){ 199 assert(this.primitiveMode == rhs.primitiveMode, "missmatch primitive mode"); 200 import std.algorithm; 201 import std.conv; 202 import std.array:array; 203 auto result = new Mesh; 204 result.indices = this.indices ~ rhs.indices.map!(i => (i + this.vertices.length).to!int).array; 205 result.vertices = this.vertices ~ rhs.vertices; 206 result.normals = this.normals ~ rhs.normals; 207 result.tangents = this.tangents ~ rhs.tangents; 208 result.texCoords0 = this.texCoords0 ~ rhs.texCoords0; 209 result.texCoords1 = this.texCoords1 ~ rhs.texCoords1; 210 result.colors = this.colors ~ rhs.colors; 211 return result; 212 } 213 214 unittest{ 215 alias V = Vector4f; 216 auto m1 = new Mesh; 217 m1.vertices = [ 218 V(1, 0, 0, 1), 219 V(0, 2, 0, 1), 220 V(0, 0, 3, 1) 221 ]; 222 m1.indices = [0, 1, 2]; 223 224 auto m2 = new Mesh; 225 m2.vertices = [ 226 V(4, 0, 0, 1), 227 V(0, 5, 0, 1), 228 V(0, 0, 6, 1) 229 ]; 230 m2.indices = [0, 1, 2]; 231 232 auto m3 = m1 ~ m2; 233 assert(m3.vertices.length == 6); 234 assert(m3.vertices == m1.vertices ~ m2.vertices); 235 assert(m3.indices.length == m1.indices.length+m2.indices.length); 236 assert(m3.indices == [0, 1, 2, 3, 4, 5]); 237 } 238 239 /// 240 void opOpAssign(string op:"~")(Mesh rhs){ 241 assert(this.primitiveMode == rhs.primitiveMode, "missmatch primitive mode"); 242 import std.algorithm; 243 import std.conv; 244 import std.array:array; 245 this.indices ~= rhs.indices.map!(i => (i + this.vertices.length).to!int).array; 246 this.vertices ~= rhs.vertices; 247 this.normals ~= rhs.normals; 248 this.tangents ~= rhs.tangents; 249 this.texCoords0 ~= rhs.texCoords0; 250 this.texCoords1 ~= rhs.texCoords1; 251 this.colors ~= rhs.colors; 252 } 253 254 unittest{ 255 alias V = Vector4f; 256 auto m1 = new Mesh; 257 m1.vertices = [ 258 V(1, 0, 0, 1), 259 V(0, 2, 0, 1), 260 V(0, 0, 3, 1) 261 ]; 262 m1.indices = [0, 1, 2]; 263 264 auto m2 = new Mesh; 265 m2.vertices = [ 266 V(4, 0, 0, 1), 267 V(0, 5, 0, 1), 268 V(0, 0, 6, 1) 269 ]; 270 m2.indices = [0, 1, 2]; 271 272 m1 ~= m2; 273 assert(m1.vertices.length == 6); 274 assert(m1.vertices == [ 275 V(1, 0, 0, 1), 276 V(0, 2, 0, 1), 277 V(0, 0, 3, 1) 278 ] ~ [ 279 V(4, 0, 0, 1), 280 V(0, 5, 0, 1), 281 V(0, 0, 6, 1) 282 ]); 283 assert(m1.indices.length == 6); 284 assert(m1.indices == [0, 1, 2, 3, 4, 5]); 285 } 286 }//public 287 288 private{ 289 PrimitiveMode _primitiveMode = PrimitiveMode.Triangles; 290 }//private 291 }//class Mesh