bool Mesh::_get(const StringName& p_name,Variant &r_ret) const { String sname=p_name; if (p_name=="morph_target/names") { DVector<String> sk; for(int i=0;i<morph_targets.size();i++) sk.push_back(morph_targets[i]); r_ret=sk; return true; } else if (p_name=="morph_target/mode") { r_ret = get_morph_target_mode(); return true; } else if (sname.begins_with("surface_")) { int sl=sname.find("/"); if (sl==-1) return false; int idx=sname.substr(8,sl-8).to_int()-1; String what = sname.get_slice("/",1); if (what=="material") r_ret=surface_get_material(idx); else if (what=="name") r_ret=surface_get_name(idx); return true; } else if (sname=="custom_aabb/custom_aabb") { r_ret=custom_aabb; return true; } else if (!sname.begins_with("surfaces")) return false; int idx=sname.get_slice("/",1).to_int(); ERR_FAIL_INDEX_V(idx,surfaces.size(),false); Dictionary d; d["primitive"]=surface_get_primitive_type(idx); d["arrays"]=surface_get_arrays(idx); d["morph_arrays"]=surface_get_morph_arrays(idx); d["alphasort"]=surface_is_alpha_sorting_enabled(idx); Ref<Material> m = surface_get_material(idx); if (m.is_valid()) d["material"]=m; String n = surface_get_name(idx); if (n!="") d["name"]=n; r_ret=d; return true; }
Ref<Shape> Mesh::create_convex_shape() const { PoolVector<Vector3> vertices; for (int i = 0; i < get_surface_count(); i++) { Array a = surface_get_arrays(i); PoolVector<Vector3> v = a[ARRAY_VERTEX]; vertices.append_array(v); } Ref<ConvexPolygonShape> shape = memnew(ConvexPolygonShape); shape->set_points(vertices); return shape; }
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) return triangle_mesh; int facecount = 0; for (int i = 0; i < get_surface_count(); i++) { if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) continue; if (surface_get_format(i) & ARRAY_FORMAT_INDEX) { facecount += surface_get_array_index_len(i); } else { facecount += surface_get_array_len(i); } } if (facecount == 0 || (facecount % 3) != 0) return triangle_mesh; PoolVector<Vector3> faces; faces.resize(facecount); PoolVector<Vector3>::Write facesw = faces.write(); int widx = 0; for (int i = 0; i < get_surface_count(); i++) { if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) continue; Array a = surface_get_arrays(i); int vc = surface_get_array_len(i); PoolVector<Vector3> vertices = a[ARRAY_VERTEX]; PoolVector<Vector3>::Read vr = vertices.read(); if (surface_get_format(i) & ARRAY_FORMAT_INDEX) { int ic = surface_get_array_index_len(i); PoolVector<int> indices = a[ARRAY_INDEX]; PoolVector<int>::Read ir = indices.read(); for (int i = 0; i < ic; i++) { int index = ir[i]; facesw[widx++] = vr[index]; } } else { for (int i = 0; i < vc; i++) facesw[widx++] = vr[i]; } } facesw = PoolVector<Vector3>::Write(); triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh)); triangle_mesh->create(faces); return triangle_mesh; }
Ref<Mesh> Mesh::create_outline(float p_margin) const { Array arrays; int index_accum = 0; for (int i = 0; i < get_surface_count(); i++) { if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) continue; Array a = surface_get_arrays(i); if (i == 0) { arrays = a; PoolVector<Vector3> v = a[ARRAY_VERTEX]; index_accum += v.size(); } else { int vcount = 0; for (int j = 0; j < arrays.size(); j++) { if (arrays[j].get_type() == Variant::NIL || a[j].get_type() == Variant::NIL) { //mismatch, do not use arrays[j] = Variant(); continue; } switch (j) { case ARRAY_VERTEX: case ARRAY_NORMAL: { PoolVector<Vector3> dst = arrays[j]; PoolVector<Vector3> src = a[j]; if (j == ARRAY_VERTEX) vcount = src.size(); if (dst.size() == 0 || src.size() == 0) { arrays[j] = Variant(); continue; } dst.append_array(src); arrays[j] = dst; } break; case ARRAY_TANGENT: case ARRAY_BONES: case ARRAY_WEIGHTS: { PoolVector<real_t> dst = arrays[j]; PoolVector<real_t> src = a[j]; if (dst.size() == 0 || src.size() == 0) { arrays[j] = Variant(); continue; } dst.append_array(src); arrays[j] = dst; } break; case ARRAY_COLOR: { PoolVector<Color> dst = arrays[j]; PoolVector<Color> src = a[j]; if (dst.size() == 0 || src.size() == 0) { arrays[j] = Variant(); continue; } dst.append_array(src); arrays[j] = dst; } break; case ARRAY_TEX_UV: case ARRAY_TEX_UV2: { PoolVector<Vector2> dst = arrays[j]; PoolVector<Vector2> src = a[j]; if (dst.size() == 0 || src.size() == 0) { arrays[j] = Variant(); continue; } dst.append_array(src); arrays[j] = dst; } break; case ARRAY_INDEX: { PoolVector<int> dst = arrays[j]; PoolVector<int> src = a[j]; if (dst.size() == 0 || src.size() == 0) { arrays[j] = Variant(); continue; } { int ss = src.size(); PoolVector<int>::Write w = src.write(); for (int k = 0; k < ss; k++) { w[k] += index_accum; } } dst.append_array(src); arrays[j] = dst; index_accum += vcount; } break; } } } } ERR_FAIL_COND_V(arrays.size() != ARRAY_MAX, Ref<ArrayMesh>()); { PoolVector<int>::Write ir; PoolVector<int> indices = arrays[ARRAY_INDEX]; bool has_indices = false; PoolVector<Vector3> vertices = arrays[ARRAY_VERTEX]; int vc = vertices.size(); ERR_FAIL_COND_V(!vc, Ref<ArrayMesh>()); PoolVector<Vector3>::Write r = vertices.write(); if (indices.size()) { vc = indices.size(); ir = indices.write(); has_indices = true; } Map<Vector3, Vector3> normal_accum; //fill normals with triangle normals for (int i = 0; i < vc; i += 3) { Vector3 t[3]; if (has_indices) { t[0] = r[ir[i + 0]]; t[1] = r[ir[i + 1]]; t[2] = r[ir[i + 2]]; } else { t[0] = r[i + 0]; t[1] = r[i + 1]; t[2] = r[i + 2]; } Vector3 n = Plane(t[0], t[1], t[2]).normal; for (int j = 0; j < 3; j++) { Map<Vector3, Vector3>::Element *E = normal_accum.find(t[j]); if (!E) { normal_accum[t[j]] = n; } else { float d = n.dot(E->get()); if (d < 1.0) E->get() += n * (1.0 - d); //E->get()+=n; } } } //normalize for (Map<Vector3, Vector3>::Element *E = normal_accum.front(); E; E = E->next()) { E->get().normalize(); } //displace normals int vc2 = vertices.size(); for (int i = 0; i < vc2; i++) { Vector3 t = r[i]; Map<Vector3, Vector3>::Element *E = normal_accum.find(t); ERR_CONTINUE(!E); t += E->get() * p_margin; r[i] = t; } r = PoolVector<Vector3>::Write(); arrays[ARRAY_VERTEX] = vertices; if (!has_indices) { PoolVector<int> new_indices; new_indices.resize(vertices.size()); PoolVector<int>::Write iw = new_indices.write(); for (int j = 0; j < vc2; j += 3) { iw[j] = j; iw[j + 1] = j + 2; iw[j + 2] = j + 1; } iw = PoolVector<int>::Write(); arrays[ARRAY_INDEX] = new_indices; } else { for (int j = 0; j < vc; j += 3) { SWAP(ir[j + 1], ir[j + 2]); } ir = PoolVector<int>::Write(); arrays[ARRAY_INDEX] = indices; } } Ref<ArrayMesh> newmesh = memnew(ArrayMesh); newmesh->add_surface_from_arrays(PRIMITIVE_TRIANGLES, arrays); return newmesh; }
Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_EXPLAIN("Can't unwrap mesh with blend shapes"); ERR_FAIL_COND_V(blend_shapes.size() != 0, ERR_UNAVAILABLE); Vector<float> vertices; Vector<float> normals; Vector<int> indices; Vector<int> face_materials; Vector<float> uv; Vector<Pair<int, int> > uv_index; Vector<ArrayMeshLightmapSurface> surfaces; for (int i = 0; i < get_surface_count(); i++) { ArrayMeshLightmapSurface s; s.primitive = surface_get_primitive_type(i); if (s.primitive != Mesh::PRIMITIVE_TRIANGLES) { ERR_EXPLAIN("Only triangles are supported for lightmap unwrap"); ERR_FAIL_V(ERR_UNAVAILABLE); } s.format = surface_get_format(i); if (!(s.format & ARRAY_FORMAT_NORMAL)) { ERR_EXPLAIN("Normals are required for lightmap unwrap"); ERR_FAIL_V(ERR_UNAVAILABLE); } Array arrays = surface_get_arrays(i); s.material = surface_get_material(i); s.vertices = SurfaceTool::create_vertex_array_from_triangle_arrays(arrays); PoolVector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX]; int vc = rvertices.size(); PoolVector<Vector3>::Read r = rvertices.read(); PoolVector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL]; PoolVector<Vector3>::Read rn = rnormals.read(); int vertex_ofs = vertices.size() / 3; vertices.resize((vertex_ofs + vc) * 3); normals.resize((vertex_ofs + vc) * 3); uv_index.resize(vertex_ofs + vc); for (int j = 0; j < vc; j++) { Vector3 v = p_base_transform.xform(r[j]); Vector3 n = p_base_transform.basis.xform(rn[j]).normalized(); vertices[(j + vertex_ofs) * 3 + 0] = v.x; vertices[(j + vertex_ofs) * 3 + 1] = v.y; vertices[(j + vertex_ofs) * 3 + 2] = v.z; normals[(j + vertex_ofs) * 3 + 0] = n.x; normals[(j + vertex_ofs) * 3 + 1] = n.y; normals[(j + vertex_ofs) * 3 + 2] = n.z; uv_index[j + vertex_ofs] = Pair<int, int>(i, j); } PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; int ic = rindices.size(); if (ic == 0) { for (int j = 0; j < vc / 3; j++) { if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) continue; indices.push_back(vertex_ofs + j * 3 + 0); indices.push_back(vertex_ofs + j * 3 + 1); indices.push_back(vertex_ofs + j * 3 + 2); face_materials.push_back(i); } } else { PoolVector<int>::Read ri = rindices.read(); for (int j = 0; j < ic / 3; j++) { if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) continue; indices.push_back(vertex_ofs + ri[j * 3 + 0]); indices.push_back(vertex_ofs + ri[j * 3 + 1]); indices.push_back(vertex_ofs + ri[j * 3 + 2]); face_materials.push_back(i); } } surfaces.push_back(s); } //unwrap float *gen_uvs; int *gen_vertices; int *gen_indices; int gen_vertex_count; int gen_index_count; int size_x; int size_y; bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), face_materials.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y); if (!ok) { return ERR_CANT_CREATE; } //remove surfaces while (get_surface_count()) { surface_remove(0); } //create surfacetools for each surface.. Vector<Ref<SurfaceTool> > surfaces_tools; for (int i = 0; i < surfaces.size(); i++) { Ref<SurfaceTool> st; st.instance(); st->begin(Mesh::PRIMITIVE_TRIANGLES); st->set_material(surfaces[i].material); surfaces_tools.push_back(st); //stay there } print_line("gen indices: " + itos(gen_index_count)); //go through all indices for (int i = 0; i < gen_index_count; i += 3) { ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_index.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_index.size(), ERR_BUG); ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_index.size(), ERR_BUG); ERR_FAIL_COND_V(uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 1]]].first || uv_index[gen_vertices[gen_indices[i + 0]]].first != uv_index[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG); int surface = uv_index[gen_vertices[gen_indices[i + 0]]].first; for (int j = 0; j < 3; j++) { SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second]; if (surfaces[surface].format & ARRAY_FORMAT_COLOR) { surfaces_tools[surface]->add_color(v.color); } if (surfaces[surface].format & ARRAY_FORMAT_TEX_UV) { surfaces_tools[surface]->add_uv(v.uv); } if (surfaces[surface].format & ARRAY_FORMAT_NORMAL) { surfaces_tools[surface]->add_normal(v.normal); } if (surfaces[surface].format & ARRAY_FORMAT_TANGENT) { Plane t; t.normal = v.tangent; t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1; surfaces_tools[surface]->add_tangent(t); } if (surfaces[surface].format & ARRAY_FORMAT_BONES) { surfaces_tools[surface]->add_bones(v.bones); } if (surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) { surfaces_tools[surface]->add_weights(v.weights); } Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]); surfaces_tools[surface]->add_uv2(uv2); surfaces_tools[surface]->add_vertex(v.vertex); } } //free stuff ::free(gen_vertices); ::free(gen_indices); ::free(gen_uvs); //generate surfaces for (int i = 0; i < surfaces_tools.size(); i++) { surfaces_tools[i]->index(); surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), surfaces[i].format); } set_lightmap_size_hint(Size2(size_x, size_y)); return OK; }
Array PrimitiveMesh::get_mesh_arrays() const { return surface_get_arrays(0); }