/** * Creates and adds the navmesh to this scene. */ private void setNavmesh(GameObjectBlueprint bp) { // We need to set the node transforms before calculating the navmesh shape GameModel gameModel = new GameModel(bp.model, bp.name, bp.position, bp.rotation, bp.scale); Array<NodePart> nodes = gameModel.modelInstance.model.getNode("navmesh").parts; // Sort the model meshParts array according to material name nodes.sort(new NavMeshNodeSorter()); // The model transform must be applied to the meshparts for shape generation to work correctly. gameModel.modelInstance.calculateTransforms(); Matrix4 transform = new Matrix4(); for (Node node : gameModel.modelInstance.nodes) { transform.set(node.globalTransform).inv(); for (NodePart nodePart : node.parts) { nodePart.meshPart.mesh.transform(transform); } } navMesh = new NavMesh(gameModel.modelInstance.model); btCollisionShape shape = navMesh.getShape(); navmeshBody = new InvisibleBody("navmesh", shape, 0, gameModel.modelInstance.transform, GameEngine.NAVMESH_FLAG, GameEngine.NAVMESH_FLAG, false, false); worldBounds.set(gameModel.boundingBox); gameModel.dispose(); }
@Deprecated public static Model createFromMesh (final Mesh mesh, int indexOffset, int vertexCount, int primitiveType, final Material material) { Model result = new Model(); MeshPart meshPart = new MeshPart(); meshPart.id = "part1"; meshPart.indexOffset = indexOffset; meshPart.numVertices = vertexCount; meshPart.primitiveType = primitiveType; meshPart.mesh = mesh; NodePart partMaterial = new NodePart(); partMaterial.material = material; partMaterial.meshPart = meshPart; Node node = new Node(); node.id = "node1"; node.parts.add(partMaterial); result.meshes.add(mesh); result.materials.add(material); result.nodes.add(node); result.meshParts.add(meshPart); result.manageDisposable(mesh); return result; }
private Node copyNode (Node node) { Node copy = new Node(); copy.id = node.id; copy.inheritTransform = node.inheritTransform; copy.translation.set(node.translation); copy.rotation.set(node.rotation); copy.scale.set(node.scale); copy.localTransform.set(node.localTransform); copy.globalTransform.set(node.globalTransform); for (NodePart nodePart : node.parts) { copy.parts.add(copyNodePart(nodePart)); } for (Node child : node.getChildren()) { copy.addChild(copyNode(child)); } return copy; }
private NodePart copyNodePart (NodePart nodePart) { NodePart copy = new NodePart(); copy.meshPart = new MeshPart(); copy.meshPart.id = nodePart.meshPart.id; copy.meshPart.indexOffset = nodePart.meshPart.indexOffset; copy.meshPart.numVertices = nodePart.meshPart.numVertices; copy.meshPart.primitiveType = nodePart.meshPart.primitiveType; copy.meshPart.mesh = nodePart.meshPart.mesh; if (nodePart.invBoneBindTransforms != null) nodePartBones.put(copy, nodePart.invBoneBindTransforms); final int index = materials.indexOf(nodePart.material, false); if (index < 0) materials.add(copy.material = nodePart.material.copy()); else copy.material = materials.get(index); return copy; }
@Deprecated public static Model createFromMesh(final Mesh mesh, int indexOffset, int vertexCount, int primitiveType, final Material material) { Model result = new Model(); MeshPart meshPart = new MeshPart(); meshPart.id = "part1"; meshPart.offset = indexOffset; meshPart.size = vertexCount; meshPart.primitiveType = primitiveType; meshPart.mesh = mesh; NodePart partMaterial = new NodePart(); partMaterial.material = material; partMaterial.meshPart = meshPart; Node node = new Node(); node.id = "node1"; node.parts.add(partMaterial); result.meshes.add(mesh); result.materials.add(material); result.nodes.add(node); result.meshParts.add(meshPart); result.manageDisposable(mesh); return result; }
private Node copyNode(Node parent, Node node) { Node copy = new Node(); copy.id = node.id; //copy.boneId = node.boneId; copy.parent = parent; copy.translation.set(node.translation); copy.rotation.set(node.rotation); copy.scale.set(node.scale); copy.localTransform.set(node.localTransform); copy.globalTransform.set(node.globalTransform); for(NodePart nodePart: node.parts) { copy.parts.add(copyNodePart(nodePart)); } for(Node child: node.children) { copy.children.add(copyNode(copy, child)); } return copy; }
private NodePart copyNodePart (NodePart nodePart) { NodePart copy = new NodePart(); copy.meshPart = new MeshPart(); copy.meshPart.id = nodePart.meshPart.id; copy.meshPart.indexOffset = nodePart.meshPart.indexOffset; copy.meshPart.numVertices = nodePart.meshPart.numVertices; copy.meshPart.primitiveType = nodePart.meshPart.primitiveType; copy.meshPart.mesh = nodePart.meshPart.mesh; if (nodePart.invBoneBindTransforms != null) nodePartBones.put(copy, nodePart.invBoneBindTransforms); // final int index = materials.indexOf(nodePart.material, false); // if (index < 0) // materials.add(copy.material = nodePart.material.copy()); // else // copy.material = materials.get(index); // copy.material = nodePart.material; return copy; }
protected void collectModelNodeVertexPositions(Node node, Array<Vector3> destVertices, Vector3 scaleFactor, Vector3 positionOffset) { final Matrix4 transform = node.globalTransform; for (int i = 0; i < node.parts.size; ++i) { NodePart nodePart = node.parts.get(i); MeshPart meshPart = nodePart.meshPart; ShortBuffer indices = meshPart.mesh.getIndicesBuffer(); FloatBuffer vertices = meshPart.mesh.getVerticesBuffer(); final int strideInFloats = meshPart.mesh.getVertexSize() / (Float.SIZE / 8); for (int j = 0; j < meshPart.numVertices; ++j) { int index = indices.get(meshPart.indexOffset + j); int offset = index * strideInFloats; tmpPosition.set(vertices.get(offset), vertices.get(offset + 1), vertices.get(offset + 2)) .add(positionOffset) .scl(scaleFactor) .mul(transform); destVertices.add(new Vector3(tmpPosition)); } } for (int i = 0; i < node.children.size; ++i) collectModelNodeVertexPositions(node.children.get(i), destVertices, scaleFactor, positionOffset); }
private NodePart getPart(int index) { ModelInstance inst = gameWorld.renderer().getRenderable(selected()); int i = 0; for (Node node : inst.nodes) { for (NodePart part : node.parts) { if(i == index) return part; i++; } } return null; }
private void setVColorBlendAttributes() { Array<String> modelsIdsInScene = assets.getPlaceholderIdsByType(BlenderModel.class); Array<BlenderModel> instancesWithId = new Array<BlenderModel>(); for (String id : modelsIdsInScene) { instancesWithId.clear(); assets.getPlaceholders(id, BlenderModel.class, instancesWithId); for (BlenderModel blenderModel : instancesWithId) { // Maybe check if // renderable.meshPart.mesh.getVertexAttribute(VertexAttributes.Usage.ColorUnpacked) != null if (blenderModel.custom_properties.containsKey("v_color_material_blend")) { Model model = assets.getAsset(id, Model.class); String redMaterialName = blenderModel.custom_properties.get("v_color_material_red"); String greenMaterialName = blenderModel.custom_properties.get("v_color_material_green"); String blueMaterialName = blenderModel.custom_properties.get("v_color_material_blue"); TextureAttribute redTexAttr = (TextureAttribute) model.getMaterial(redMaterialName).get(TextureAttribute.Diffuse); TextureAttribute greenTexAttr = (TextureAttribute) model.getMaterial(greenMaterialName).get(TextureAttribute.Diffuse); TextureAttribute blueTexAttr = (TextureAttribute) model.getMaterial(blueMaterialName).get(TextureAttribute.Diffuse); VertexColorTextureBlend redAttribute = new VertexColorTextureBlend(VertexColorTextureBlend.Red, redTexAttr.textureDescription.texture); VertexColorTextureBlend greenAttribute = new VertexColorTextureBlend(VertexColorTextureBlend.Green, greenTexAttr.textureDescription.texture); VertexColorTextureBlend blueAttribute = new VertexColorTextureBlend(VertexColorTextureBlend.Blue, blueTexAttr.textureDescription.texture); for (Node node : model.nodes) { for (NodePart nodePart : node.parts) { nodePart.material.set(redAttribute, greenAttribute, blueAttribute); } } break; } } } }
/** * Translate each vertex along its normal by specified amount. * * @param model * @param amount */ public static void fatten(Model model, float amount) { Vector3 pos = new Vector3(); Vector3 nor = new Vector3(); for (Node node : model.nodes) { for (NodePart n : node.parts) { Mesh mesh = n.meshPart.mesh; FloatBuffer buf = mesh.getVerticesBuffer(); int lastFloat = mesh.getNumVertices() * mesh.getVertexSize() / 4; int vertexFloats = (mesh.getVertexSize() / 4); VertexAttribute posAttr = mesh.getVertexAttributes().findByUsage(VertexAttributes.Usage.Position); VertexAttribute norAttr = mesh.getVertexAttributes().findByUsage(VertexAttributes.Usage.Normal); if (posAttr == null || norAttr == null) { throw new IllegalArgumentException("Position/normal vertex attribute not found"); } int pOff = posAttr.offset / 4; int nOff = norAttr.offset / 4; for (int i = 0; i < lastFloat; i += vertexFloats) { pos.x = buf.get(pOff + i); pos.y = buf.get(pOff + i + 1); pos.z = buf.get(pOff + i + 2); nor.x = buf.get(nOff + i); nor.y = buf.get(nOff + i + 1); nor.z = buf.get(nOff + i + 2); nor.nor().scl(amount); buf.put(pOff + i, pos.x + nor.x); buf.put(pOff + i + 1, pos.y + nor.y); buf.put(pOff + i + 2, pos.z + nor.z); } } } }
/** * Returns true if all parts of the assigned node can be used to create collision shapes * @param node The node to check. * @return True if the node is valid. */ private boolean areAllPartsValid(Node node) { if (node == null) { return false; } for (NodePart nodePart : node.parts) { boolean usesTriangles = (nodePart.meshPart.primitiveType == GL20.GL_TRIANGLES); if ((nodePart.meshPart.size <= 0) || !usesTriangles) { return false; } } return true; }
private static void rebuildReferences (final Model model, final Node node) { for (final NodePart mpm : node.parts) { if (!model.materials.contains(mpm.material, true)) model.materials.add(mpm.material); if (!model.meshParts.contains(mpm.meshPart, true)) { model.meshParts.add(mpm.meshPart); if (!model.meshes.contains(mpm.meshPart.mesh, true)) model.meshes.add(mpm.meshPart.mesh); model.manageDisposable(mpm.meshPart.mesh); } } for (final Node child : node.getChildren()) rebuildReferences(model, child); }
private void loadNodes (Iterable<ModelNode> modelNodes) { nodePartBones.clear(); for (ModelNode node : modelNodes) { nodes.add(loadNode(node)); } for (ObjectMap.Entry<NodePart, ArrayMap<String, Matrix4>> e : nodePartBones.entries()) { if (e.key.invBoneBindTransforms == null) e.key.invBoneBindTransforms = new ArrayMap<Node, Matrix4>(Node.class, Matrix4.class); e.key.invBoneBindTransforms.clear(); for (ObjectMap.Entry<String, Matrix4> b : e.value.entries()) e.key.invBoneBindTransforms.put(getNode(b.key), new Matrix4(b.value).inv()); } }
private void setBones () { for (ObjectMap.Entry<NodePart, ArrayMap<Node, Matrix4>> e : nodePartBones.entries()) { if (e.key.invBoneBindTransforms == null) e.key.invBoneBindTransforms = new ArrayMap<Node, Matrix4>(true, e.value.size, Node.class, Matrix4.class); e.key.invBoneBindTransforms.clear(); for (final ObjectMap.Entry<Node, Matrix4> b : e.value.entries()) e.key.invBoneBindTransforms.put(getNode(b.key.id), b.value); // Share the inv bind matrix with the model e.key.bones = new Matrix4[e.value.size]; for (int i = 0; i < e.key.bones.length; i++) e.key.bones[i] = new Matrix4(); } }
public Renderable getRenderable (final Renderable out, final Node node, final NodePart nodePart) { nodePart.setRenderable(out); if (nodePart.bones == null && transform != null) out.worldTransform.set(transform).mul(node.globalTransform); else if (transform != null) out.worldTransform.set(transform); else out.worldTransform.idt(); out.userData = userData; return out; }
protected void getRenderables (Node node, Array<Renderable> renderables, Pool<Renderable> pool) { if (node.parts.size > 0) { for (NodePart nodePart : node.parts) { if (nodePart.enabled) renderables.add(getRenderable(pool.obtain(), node, nodePart)); } } for (Node child : node.getChildren()) { getRenderables(child, renderables, pool); } }
private static void rebuildReferences(final Model model, final Node node) { for (final NodePart mpm : node.parts) { if (!model.materials.contains(mpm.material, true)) model.materials.add(mpm.material); if (!model.meshParts.contains(mpm.meshPart, true)) { model.meshParts.add(mpm.meshPart); if (!model.meshes.contains(mpm.meshPart.mesh, true)) model.meshes.add(mpm.meshPart.mesh); model.manageDisposable(mpm.meshPart.mesh); } } Iterable<Node> nodeIter = node.getChildren(); for (final Node child : nodeIter) rebuildReferences(model, child); }
private void loadNodes (Iterable<ModelNode> modelNodes) { nodePartBones.clear(); for (ModelNode node : modelNodes) { nodes.add(loadNode(null, node)); } for (ObjectMap.Entry<NodePart, ArrayMap<String, Matrix4>> e : nodePartBones.entries()) { if (e.key.invBoneBindTransforms == null) e.key.invBoneBindTransforms = new ArrayMap<Node, Matrix4>(Node.class, Matrix4.class); e.key.invBoneBindTransforms.clear(); for (ObjectMap.Entry<String, Matrix4> b : e.value.entries()) e.key.invBoneBindTransforms.put(getNode(b.key), new Matrix4(b.value).inv()); } }
private Node loadNode (Node parent, ModelNode modelNode) { Node node = new Node(); node.id = modelNode.id; node.parent = parent; if (modelNode.translation != null) node.translation.set(modelNode.translation); if (modelNode.rotation != null) node.rotation.set(modelNode.rotation); if (modelNode.scale != null) node.scale.set(modelNode.scale); // FIXME create temporary maps for faster lookup? if (modelNode.parts != null) { for (ModelNodePart modelNodePart : modelNode.parts) { MeshPart meshPart = null; if (modelNodePart.meshPartId != null) { for (MeshPart part : meshParts) { if (modelNodePart.meshPartId.equals(part.id)) { meshPart = part; break; } } } if (meshPart == null) throw new GdxRuntimeException("Invalid node: " + node.id); NodePart nodePart = new NodePart(); nodePart.meshPart = meshPart; // nodePart.material = meshMaterial; node.parts.add(nodePart); if (modelNodePart.bones != null) nodePartBones.put(nodePart, modelNodePart.bones); } } if (modelNode.children != null) { for (ModelNode child : modelNode.children) { node.children.add(loadNode(node, child)); } } return node; }
private void setBones() { for (ObjectMap.Entry<NodePart,ArrayMap<Node, Matrix4>> e : nodePartBones.entries()) { if (e.key.invBoneBindTransforms == null) e.key.invBoneBindTransforms = new ArrayMap<Node, Matrix4>(true, e.value.size, Node.class, Matrix4.class); e.key.invBoneBindTransforms.clear(); for (final ObjectMap.Entry<Node, Matrix4> b : e.value.entries()) e.key.invBoneBindTransforms.put(getNode(b.key.id), b.value); // Share the inv bind matrix with the model e.key.bones = new Matrix4[e.value.size]; for (int i = 0; i < e.key.bones.length; i++) e.key.bones[i] = new Matrix4(); } }
public Renderable getRenderable(final Renderable out, final Node node, final NodePart nodePart) { nodePart.setRenderable(out); if (nodePart.bones == null && transform != null) out.worldTransform.set(transform).mul(node.globalTransform); else if (transform != null) out.worldTransform.set(transform); else out.worldTransform.idt(); out.userData = userData; return out; }
protected void getRenderables(Node node, Array<Renderable> renderables, Pool<Renderable> pool) { if(node.parts.size > 0) { for(NodePart nodePart: node.parts) { renderables.add(getRenderable(pool.obtain(), node, nodePart)); } } for(Node child: node.children) { getRenderables(child, renderables, pool); } }
private Model loadRenderModel(String name) { if (models.containsKey(name)) return models.get(name); // FIXME we load the models synchronously cause we are lazy int error = 0; PointerBuffer modelPointer = PointerBuffer.allocateDirect(1); while (true) { error = VRRenderModels.VRRenderModels_LoadRenderModel_Async(name, modelPointer); if (error != VR.EVRRenderModelError_VRRenderModelError_Loading) break; } if (error != VR.EVRRenderModelError_VRRenderModelError_None) return null; RenderModel renderModel = new RenderModel(modelPointer.getByteBuffer(RenderModel.SIZEOF)); error = 0; PointerBuffer texturePointer = PointerBuffer.allocateDirect(1); while (true) { error = VRRenderModels.VRRenderModels_LoadTexture_Async(renderModel.diffuseTextureId(), texturePointer); if (error != VR.EVRRenderModelError_VRRenderModelError_Loading) break; } if (error != VR.EVRRenderModelError_VRRenderModelError_None) { VRRenderModels.VRRenderModels_FreeRenderModel(renderModel); return null; } RenderModelTextureMap renderModelTexture = new RenderModelTextureMap(texturePointer.getByteBuffer(RenderModelTextureMap.SIZEOF)); // convert to a Model Mesh mesh = new Mesh(true, renderModel.unVertexCount(), renderModel.unTriangleCount() * 3, VertexAttribute.Position(), VertexAttribute.Normal(), VertexAttribute.TexCoords(0)); MeshPart meshPart = new MeshPart(name, mesh, 0, renderModel.unTriangleCount() * 3, GL20.GL_TRIANGLES); RenderModelVertex.Buffer vertices = renderModel.rVertexData(); float[] packedVertices = new float[8 * renderModel.unVertexCount()]; int i = 0; while(vertices.remaining() > 0) { RenderModelVertex v = vertices.get(); packedVertices[i++] = v.vPosition().v(0); packedVertices[i++] = v.vPosition().v(1); packedVertices[i++] = v.vPosition().v(2); packedVertices[i++] = v.vNormal().v(0); packedVertices[i++] = v.vNormal().v(1); packedVertices[i++] = v.vNormal().v(2); packedVertices[i++] = v.rfTextureCoord().get(0); packedVertices[i++] = v.rfTextureCoord().get(1); } mesh.setVertices(packedVertices); short[] indices = new short[renderModel.unTriangleCount() * 3]; renderModel.IndexData().get(indices); mesh.setIndices(indices); Pixmap pixmap = new Pixmap(renderModelTexture.unWidth(), renderModelTexture.unHeight(), Format.RGBA8888); byte[] pixels = new byte[renderModelTexture.unWidth() * renderModelTexture.unHeight() * 4]; renderModelTexture.rubTextureMapData(pixels.length).get(pixels); pixmap.getPixels().put(pixels); pixmap.getPixels().position(0); Texture texture = new Texture(new PixmapTextureData(pixmap, pixmap.getFormat(), true, true)); Material material = new Material(new TextureAttribute(TextureAttribute.Diffuse, texture)); Model model = new Model(); model.meshes.add(mesh); model.meshParts.add(meshPart); model.materials.add(material); Node node = new Node(); node.id = name; node.parts.add(new NodePart(meshPart, material)); model.nodes.add(node); model.manageDisposable(mesh); model.manageDisposable(texture); VRRenderModels.VRRenderModels_FreeRenderModel(renderModel); VRRenderModels.VRRenderModels_FreeTexture(renderModelTexture); models.put(name, model); return model; }
/** Add one or more {@link NodePart} instances to this btTriangleIndexVertexArray. * The specified meshes must be indexed and triangulated and must outlive this btTriangleIndexVertexArray. * The buffers for the vertices and indices are shared amongst both. */ public <T extends NodePart> btTriangleIndexVertexArray addNodeParts(final Iterable<T> nodeParts) { for (final NodePart nodePart : nodeParts) addMeshPart(nodePart.meshPart); return this; }
public void testHit(NodePart p, Ray ray) { testHit(p.meshPart.mesh, ray); }
private void updateModelInstances() { if(opaqueFaces != null) { if(opaqueModel != null) opaqueModel.dispose(); Mesh opaqueMesh = mesher.meshFaces(opaqueFaces, meshBuilder); modelBuilder.begin(); modelBuilder.part(String.format("c-%d,%d", startPosition.x, startPosition.z), opaqueMesh, GL20.GL_TRIANGLES, new Material(TextureAttribute.createDiffuse(NormalBlockRenderer.getBlockMap()))); opaqueModel = modelBuilder.end(); opaqueModelInstance = new ModelInstance(opaqueModel) { @Override public Renderable getRenderable(final Renderable out, final Node node, final NodePart nodePart) { super.getRenderable(out, node, nodePart); if(RadixClient.getInstance().isWireframe()) { out.primitiveType = GL20.GL_LINES; } else { out.primitiveType = GL20.GL_TRIANGLES; } return out; } }; opaqueFaces = null; } if(translucentFaces != null) { if(translucentModel != null) translucentModel.dispose(); Mesh translucentMesh = mesher.meshFaces(translucentFaces, meshBuilder); modelBuilder.begin(); modelBuilder.part(String.format("c-%d,%d-t", startPosition.x, startPosition.z), translucentMesh, GL20.GL_TRIANGLES, new Material(TextureAttribute.createDiffuse(NormalBlockRenderer.getBlockMap()), new BlendingAttribute(), FloatAttribute.createAlphaTest(0.25f))); translucentModel = modelBuilder.end(); translucentModelInstance = new ModelInstance(translucentModel) { @Override public Renderable getRenderable(final Renderable out, final Node node, final NodePart nodePart) { super.getRenderable(out, node, nodePart); if(RadixClient.getInstance().isWireframe()) { out.primitiveType = GL20.GL_LINES; } else { out.primitiveType = GL20.GL_TRIANGLES; } return out; } }; translucentFaces = null; } }
@Override public int compare(NodePart a, NodePart b) { return a.material.id.compareTo(b.material.id); }
/** Adds the specified MeshPart to the current Node. The Mesh will be managed by the model and disposed when the model is * disposed. The resources the Material might contain are not managed, use {@link #manage(Disposable)} to add those to the * model. */ public void part (final MeshPart meshpart, final Material material) { if (node == null) node(); node.parts.add(new NodePart(meshpart, material)); }
private Node loadNode (ModelNode modelNode) { Node node = new Node(); node.id = modelNode.id; if (modelNode.translation != null) node.translation.set(modelNode.translation); if (modelNode.rotation != null) node.rotation.set(modelNode.rotation); if (modelNode.scale != null) node.scale.set(modelNode.scale); // FIXME create temporary maps for faster lookup? if (modelNode.parts != null) { for (ModelNodePart modelNodePart : modelNode.parts) { MeshPart meshPart = null; Material meshMaterial = null; if (modelNodePart.meshPartId != null) { for (MeshPart part : meshParts) { if (modelNodePart.meshPartId.equals(part.id)) { meshPart = part; break; } } } if (modelNodePart.materialId != null) { for (Material material : materials) { if (modelNodePart.materialId.equals(material.id)) { meshMaterial = material; break; } } } if (meshPart == null || meshMaterial == null) throw new GdxRuntimeException("Invalid node: " + node.id); if (meshPart != null && meshMaterial != null) { NodePart nodePart = new NodePart(); nodePart.meshPart = meshPart; nodePart.material = meshMaterial; node.parts.add(nodePart); if (modelNodePart.bones != null) nodePartBones.put(nodePart, modelNodePart.bones); } } } if (modelNode.children != null) { for (ModelNode child : modelNode.children) { node.addChild(loadNode(child)); } } return node; }
protected void collectModelNodeVertices(Node node, Vertices destVertices, MaterialTileMapping textures, Color color, Vector3 scaleFactor, Vector3 positionOffset) { final Matrix4 transform = node.globalTransform; for (int i = 0; i < node.parts.size; ++i) { NodePart nodePart = node.parts.get(i); MaterialTileMapping.TileTexture texture = textures.get(nodePart.material.id); MeshPart meshPart = nodePart.meshPart; ShortBuffer indices = meshPart.mesh.getIndicesBuffer(); FloatBuffer vertices = meshPart.mesh.getVerticesBuffer(); final int strideInFloats = meshPart.mesh.getVertexSize() / (Float.SIZE / 8); if (destVertices.remainingSpace() < meshPart.numVertices) throw new RuntimeException("Not enough space to collect this MeshPart's vertices."); for (int j = 0; j < meshPart.numVertices; ++j) { int index = indices.get(meshPart.indexOffset + j); int offset = index * strideInFloats; tmpPosition.set(vertices.get(offset), vertices.get(offset + 1), vertices.get(offset + 2)) .add(positionOffset) .scl(scaleFactor) .mul(transform); destVertices.setPos(tmpPosition); offset += 3; if (meshPart.mesh.getVertexAttribute(VertexAttributes.Usage.Color) != null) { // TODO: blend mesh color and source model color somehow? destVertices.setCol(vertices.get(offset), vertices.get(offset + 1), vertices.get(offset + 2), vertices.get(offset + 3)); offset += 4; } else destVertices.setCol(color); // TODO: better to throw exception (or check beforehand) if this is missing? setting zero's doesn't feel like the best solution if (meshPart.mesh.getVertexAttribute(VertexAttributes.Usage.Normal) != null) { tmpNormal.set(vertices.get(offset), vertices.get(offset + 1), vertices.get(offset + 2)) .rot(transform); destVertices.setNor(tmpNormal); offset += 3; } else destVertices.setNor(Vector3.Zero); // TODO: better to throw exception (or check beforehand) if this is missing? setting zero's doesn't feel like the best solution if (meshPart.mesh.getVertexAttribute(VertexAttributes.Usage.TextureCoordinates) != null) { destVertices.setUV( TextureAtlas.scaleTexCoordU(vertices.get(offset), texture.materialMinU, texture.materialMaxU, texture.region), TextureAtlas.scaleTexCoordV(vertices.get(offset + 1), texture.materialMinV, texture.materialMaxV, texture.region) ); offset += 3; } else destVertices.setUV(Vector2.Zero); destVertices.moveNext(); } } for (int i = 0; i < node.children.size; ++i) collectModelNodeVertices(node.children.get(i), destVertices, textures, color, scaleFactor, positionOffset); }
/** * Adds the specified MeshPart to the current Node. The Mesh will be managed * by the model and disposed when the model is disposed. The resources the * Material might contain are not managed, use {@link #manage(Disposable)} * to add those to the model. */ public void part(final MeshPart meshpart, final Material material) { if (node == null) node(); node.parts.add(new NodePart(meshpart, material)); }