public void testBSPTree() { Mesh mesh = (meshFilter.mesh.vertexCount > 0) ? meshFilter.mesh : meshFilter.sharedMesh; PrintMesh(mesh); var materials = new List <Material>(); meshRenderer.GetSharedMaterials(materials); var start = System.DateTime.Now; tree = CSG.BSPTreeCreator.Construct(mesh, materials, maxTrianglesInLeaves, nbCandidates, precision); Debug.Log("BSPTree created in: " + (System.DateTime.Now - start).TotalMilliseconds + " ms"); Debug.Log(tree.PrintString()); Mesh computedMesh = tree.ComputeMesh(); PrintMesh(computedMesh); GameObject go = new GameObject(); go.AddComponent <MeshFilter>().sharedMesh = computedMesh; go.AddComponent <MeshRenderer>().sharedMaterials = tree.Materials.ToArray(); go.transform.localPosition = transform.localPosition; go.transform.localRotation = transform.localRotation; go.transform.localScale = transform.localScale; go.transform.Translate(1.5f, 0, 0); }
void Update() { if (sy != slidery.value) { index = 0; sy = slidery.value; } else if (sx != sliderx.value) { index = 1; sx = sliderx.value; } else if (sz != sliderz.value) { index = 2; sz = sliderz.value; } valuey = valuey - 0.01f; foreach (Transform child in gameObject.transform) { MeshRenderer meshRenderer = child.GetComponent <MeshRenderer>(); if (meshRenderer != null) { meshRenderer.enabled = true; // location.lat =0; List <Material> materials = new List <Material>(); meshRenderer.GetSharedMaterials(materials); foreach (Material material in materials) { if (index == -1) { if (valuey <= 0) { valuey = 0; } _topYVector(valuey, material); } else if (index == 0) { _topYVector(slidery.value, material); } else if (index == 1) { _topXVector(sliderx.value, material); } else if (index == 2) { _topZVector(sliderz.value, material); } } } } }
private void Draw(Matrix4x4 rotationMatrix, int pixelsPerUnit) { var parent = transform.parent; var drawPosition = parent.TransformPoint(rotationMatrix // Compensate actor (parent game object) rotation. .MultiplyPoint3x4(parent.InverseTransformPoint(transform.position))); var drawTransform = Matrix4x4.TRS(drawPosition * pixelsPerUnit, parent.localRotation, parent.lossyScale * pixelsPerUnit); meshRenderer.GetPropertyBlock(propertyBlock); meshRenderer.GetSharedMaterials(materials); for (int i = 0; i < materials.Count; i++) { commandBuffer.DrawMesh(meshFilter.sharedMesh, drawTransform, materials[i], i + meshRenderer.subMeshStartIndex, -1, propertyBlock); } }
public void AddGameObject(GameObject go, int layer, bool isBatchable) { if (!childs.ContainsKey(go)) { childs.Add(go, 0); go.transform.parent = objectContainer; if (isBatchable) { ChildRendering cr = new ChildRendering(); cr.gameObject = go; foreach (Transform t in go.transform) { if (batchableNames.Contains(t.name)) { MeshFilter mf = t.gameObject.GetComponent <MeshFilter>(); MeshRenderer mr = t.gameObject.GetComponent <MeshRenderer>(); if (mf != null && mf.sharedMesh != null && mr != null) { cr.meshFilters.Add(mf); cr.meshRenderers.Add(mr); List <Material> m = new List <Material>(); mr.GetSharedMaterials(m); cr.meshMaterials.UnionWith(m); batchUpdate.UnionWith(m); } } } if (cr.meshFilters.Count != 0) { childRendering.Add(go, cr); } if (batchUpdate.Count != 0) { SetBatchVisible(false); } } } else { Debug.LogError(go.name + " already inserted in " + gameObject.name); } }
private void SetMaterialsIfModified(MeshRenderer meshRenderer, Material[] renderMaterials) { meshRenderer.GetSharedMaterials(sSharedMaterials); if (sSharedMaterials != null && sSharedMaterials.Count == renderMaterials.Length) { for (int i = 0; i < renderMaterials.Length; i++) { if (renderMaterials[i] != sSharedMaterials[i]) { goto SetMaterials; } } sSharedMaterials.Clear(); // prevent dangling references return; } sSharedMaterials.Clear(); // prevent dangling references SetMaterials: meshRenderer.sharedMaterials = renderMaterials; }
// Start is called before the first frame update void Start() { Shader shader = (Shader.Find("Unlit/CilpShader")); if (shader != null) { } slidery = GameObject.Find("SliderY").GetComponent <Slider>(); sliderx = GameObject.Find("SliderX").GetComponent <Slider>(); sliderz = GameObject.Find("SliderZ").GetComponent <Slider>(); foreach (Transform child in gameObject.transform) { if (child.name.Equals("logo") || child.name.Equals("tree_04")) { continue; } MeshRenderer meshRenderer = child.GetComponent <MeshRenderer>(); // Location location = child.gameObject.AddComponent<Location>(); if (meshRenderer != null) { meshRenderer.enabled = false; float y = meshRenderer.bounds.size.y / 2 + child.transform.position.y; float _y = child.transform.position.y - meshRenderer.bounds.size.y / 2; if (!child.name.Equals("LH_43") && !child.name.Equals("B_01") && !child.name.Equals("B_02") && !child.name.Equals("B_03")) { float x = meshRenderer.bounds.size.x / 2 + child.transform.position.x; float _x = child.transform.position.x - meshRenderer.bounds.size.x / 2; float z = meshRenderer.bounds.size.z / 2 + child.transform.position.z; float _z = child.transform.position.z - meshRenderer.bounds.size.z / 2; if (minX > _x) { minX = _x; } if (x > maxX) { maxX = x; } if (minZ > _z) { minZ = _z; } if (z > maxZ) { maxZ = z; } } if (y > maxY) { maxY = y; } if (minY > _y) { minY = _y; } List <Material> materials = new List <Material>(); meshRenderer.GetSharedMaterials(materials); foreach (Material material in materials) { material.shader = shader; material.SetFloat("_clip", 1); } } } //if (transform.position.y < 0) //{ // Debug.Log(minY + "---" + maxY + "=@==" + transform.position.y); // minY = minY - transform.position.y; // maxY = maxY - transform.position.y; // transform.position = new Vector3(transform.position.x, 0, transform.position.z); // Debug.Log(minY + "---" + maxY + "=@==" + transform.position.y); //} // Debug.Log(minX + "===" + maxX); //Debug.Log(minZ + "---" + maxZ + "=@==" + transform.position.z); // maxX = maxX + 1 * sacale; maxZ = maxZ - 1 * sacale; }
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { // set up initial counts and values for everything MaxFarmers = maxFarmers; MaxDrones = maxDrones; droneCount = 0; farmerCount = 0; BoardWidth = boardWidth; PerformTaskSystem.InitializeTillSystem(maxFarmers); // set up mesh rendering from prefab MeshRenderer meshRenderer = TilePrefab.GetComponent <MeshRenderer>(); var meshFilter = TilePrefab.GetComponent <MeshFilter>(); var materials = new List <Material>(MATERIAL_NUMBER); var mesh = meshFilter.sharedMesh; meshRenderer.GetSharedMaterials(materials); // set up entity and manager entityManager = dstManager; boardEntity = conversionSystem.GetPrimaryEntity(TilePrefab); // a board archetype boardArchetype = entityManager.CreateArchetype( typeof(Translation), typeof(GridBoard)); // Generate rock prefab entity rockEntity = conversionSystem.GetPrimaryEntity(RockPrefab); entityManager.AddComponentData(rockEntity, new RockTag { }); // Generate drone prefab entity droneEntity = conversionSystem.GetPrimaryEntity(DronePrefab); entityManager.AddComponentData(droneEntity, new MovementComponent { }); entityManager.AddComponentData(droneEntity, new EntityInfo { specificEntity = droneEntity, type = -1 }); entityManager.AddComponent(droneEntity, typeof(DroneTag)); // generate 3 plants to use for everything else plantEntity = new Entity[DIFF_PLANT_COUNT]; Unity.Mathematics.Random rand = new Unity.Mathematics.Random(42); int nextRandom = rand.NextInt(); MeshRenderer meshPlantRenderer = PlantMeshPrefab.GetComponent <MeshRenderer>(); var meshPlantFilter = PlantMeshPrefab.GetComponent <MeshFilter>(); var materials2 = new List <Material>(MATERIAL_NUMBER); meshPlantRenderer.GetSharedMaterials(materials2); for (int i = 0; i < DIFF_PLANT_COUNT; i++) { plantMesh = GeneratePlantMesh(nextRandom); var meshPlantTmp = Instantiate(plantMesh); meshPlantFilter.sharedMesh = meshPlantTmp; plantEntity[i] = conversionSystem.GetPrimaryEntity(PlantMeshPrefab); Convert(plantEntity[i], dstManager, conversionSystem, meshPlantRenderer, meshPlantTmp, materials2); entityManager.AddComponent(plantEntity[i], typeof(PlantTag)); entityManager.SetComponentData(plantEntity[i], new Translation { Value = new float3(-1, -5, -1) }); entityManager.AddComponentData(plantEntity[i], new NonUniformScale { Value = new float3(1.0f, 2.0f, 1.0f) }); entityManager.AddComponentData(plantEntity[i], new PlantComponent { timeGrown = 0, state = (int)PlantState.None, reserveIndex = -1 }); nextRandom = rand.NextInt(); } // create atlas and texture info CalculatePredeterminedTextures(); // if textures changed we'd have to re-create them with the following: //CreateAtlasData(); //CreateTextures(); // the texture indices in the world // clearing memory gives everything the first image in the uv's, // which is conveniently non-tilled ground blockIndices = new NativeArray <int>(BoardWidth * BoardWidth, Allocator.Persistent, NativeArrayOptions.ClearMemory); // initialize hash table that stores all the tile state info GridData gdata = GridData.GetInstance(); gdata.Initialize(BoardWidth); // generate the terrain mesh and add it to the world Mesh mesh2; int maxX = BoardWidth / MAX_MESH_WIDTH; int maxZ = BoardWidth / MAX_MESH_WIDTH; // only one mesh allMeshes = new Mesh[(maxX + 1) * (maxZ + 1)]; allUVs = new NativeArray <float2> [(maxX + 1) * (maxZ + 1)]; allVerts = new NativeArray <float3> [(maxX + 1) * (maxZ + 1)]; allTris = new NativeArray <int> [(maxX + 1) * (maxZ + 1)]; // for small enough meshes it's just a single mesh in the world int height = 0; if (maxX == 0 && maxZ == 0) { int cornerX = 0; int cornerZ = 0; allUVs[0] = new NativeArray <float2>(BoardWidth * BoardWidth * 4, Allocator.Persistent); mesh2 = GenerateTerrainMesh(BoardWidth, BoardWidth, 0, 0, height, allUVs[0]); mesh = Instantiate(mesh2); allMeshes[0] = mesh; meshFilter.sharedMesh = mesh; var segmentEntity = conversionSystem.CreateAdditionalEntity(gameObject); var pos = new float3(cornerX, 0, cornerZ); var localToWorld = new LocalToWorld { Value = float4x4.Translate(pos) }; var aabb = new AABB { Center = pos, Extents = new float3(BoardWidth, 0.5f, BoardWidth) }; var worldRenderBounds = new WorldRenderBounds { Value = aabb }; dstManager.AddComponentData(segmentEntity, localToWorld); dstManager.AddComponentData(segmentEntity, worldRenderBounds); dstManager.AddComponent(segmentEntity, ComponentType.ChunkComponent <ChunkWorldRenderBounds>()); //dstManager.AddComponent(segmentEntity, typeof(Frozen)); Convert(segmentEntity, dstManager, conversionSystem, meshRenderer, mesh, materials); } else { // FIX: this could be parallelized as all meshes are // independent from each other // for larger meshes it's broken up into // 64k vertex pieces for (int index = 0; index < (maxX + 1) * (maxZ + 1); index++) { //Parallel.For(0, (maxX + 1) * (maxZ + 1), (index) => //{ int x = (int)(index / (maxX + 1)); int z = index - (maxX + 1) * x; //UnityEngine.Debug.Log("x: " + x + " " + z); int cornerX = x * MAX_MESH_WIDTH; int cornerZ = z * MAX_MESH_WIDTH; int width = 0; int depth = 0; int startX = 0; int startZ = 0; float3 pos = new float3(cornerX, 0, cornerZ); if (x < maxX && z < maxZ) { startX = cornerX; startZ = cornerZ; width = MAX_MESH_WIDTH; depth = MAX_MESH_WIDTH; } else if (x < maxX) { startX = cornerX; startZ = cornerZ; width = MAX_MESH_WIDTH; depth = BoardWidth - cornerZ; } else if (z < maxZ) { startX = cornerX; startZ = cornerZ; width = BoardWidth - cornerX; depth = MAX_MESH_WIDTH; } else { startX = cornerX; startZ = cornerZ; width = BoardWidth - cornerX; depth = BoardWidth - cornerZ; } //UnityEngine.Debug.Log("index " + index + " " + width + " " + depth + // " " + cornerX + " " + cornerZ); allUVs[index] = new NativeArray <float2>(width * depth * 4, Allocator.Persistent); allVerts[index] = new NativeArray <float3>(width * depth * 4, Allocator.Persistent); allTris[index] = new NativeArray <int>(width * depth * 6, Allocator.Persistent); NativeArray <float2> uvs = allUVs[index]; NativeArray <float3> vert = allVerts[index]; NativeArray <int> tri = allTris[index]; int triangleIndex = 0; int vertexIndex = 0; int vertexMultiplier = 4; // create quads to fit uv's to so we can use more than one uv int uvIndex = 0; for (x = 0; x < width; x++) { for (z = 0; z < depth; z++) { int y = height; int textureIndex = 0; int index2D = (z + startZ) + width * (x + startX); textureIndex = blockIndices[index2D]; // add vertices for the quad first // front vert[vertexIndex] = new float3(x + 0.5f, 0.5f, z + -0.5f); vert[vertexIndex + 1] = new float3(x + 0.5f, 0.5f, z + 0.5f); vert[vertexIndex + 2] = new float3(x + -0.5f, 0.5f, z + 0.5f); vert[vertexIndex + 3] = new float3(x + -0.5f, 0.5f, z + -0.5f); // set the UV's uvs[uvIndex] = new float2(textures[textureIndex].pixelStartX, textures[textureIndex].pixelStartY); uvs[uvIndex + 1] = new float2(textures[textureIndex].pixelStartX, textures[textureIndex].pixelEndY); uvs[uvIndex + 2] = new float2(textures[textureIndex].pixelEndX, textures[textureIndex].pixelEndY); uvs[uvIndex + 3] = new float2(textures[textureIndex].pixelEndX, textures[textureIndex].pixelStartY); uvIndex += 4; // front or top face tri[triangleIndex] = vertexIndex; tri[triangleIndex + 1] = vertexIndex + 2; tri[triangleIndex + 2] = vertexIndex + 1; tri[triangleIndex + 3] = vertexIndex; tri[triangleIndex + 4] = vertexIndex + 3; tri[triangleIndex + 5] = vertexIndex + 2; triangleIndex += 6; // increment the vertices vertexIndex += vertexMultiplier; } } AABB aabb; aabb = new AABB { Center = pos, Extents = new float3(width, 0.5f, depth) }; mesh2 = new Mesh(); mesh2.SetVertices(allVerts[index]); mesh2.SetUVs(0, allUVs[index]); mesh2.SetTriangles(allTris[index].ToArray(), 0); mesh2.RecalculateNormals(); mesh2.RecalculateBounds(); mesh = Instantiate(mesh2); meshFilter.sharedMesh = mesh; //Debug.Log("creating mesh for : " + x + " " + z + " " + (z + (maxX + 1) * x)); allMeshes[index] = mesh; var segmentEntity = conversionSystem.CreateAdditionalEntity(gameObject); var localToWorld = new LocalToWorld { Value = float4x4.Translate(pos) }; var worldRenderBounds = new WorldRenderBounds { Value = aabb }; dstManager.AddComponentData(segmentEntity, localToWorld); dstManager.AddComponentData(segmentEntity, worldRenderBounds); dstManager.AddComponent(segmentEntity, ComponentType.ChunkComponent <ChunkWorldRenderBounds>()); //dstManager.AddComponent(segmentEntity, typeof(Frozen)); Convert(segmentEntity, dstManager, conversionSystem, meshRenderer, mesh, materials); } //); } // generate rocks and such on the grid GenerateGrid(); // generate the farmers // Create farmer entity prefab from the game object hierarchy once farmerEntity = conversionSystem.GetPrimaryEntity(FarmerPrefab); entityManager.AddComponent <FarmerTag>(farmerEntity); // FIX: this could be parallelized // NOTE: NOT WORTH DOING UNTIL ALL THE add/set component is // part of burst as that's all this is // Also note: usually not that many farmers to justify // parallelization. for (int i = 0; i < farmerNumber; i++) { farmerCount++; var instance = entityManager.Instantiate(farmerEntity); if (i == 0) { firstFarmer = instance; } int startX = Math.Abs(rand.NextInt()) % gdata.width; int startZ = Math.Abs(rand.NextInt()) % gdata.width; // Place the instantiated entity in a grid with some noise var position = new float3(startX, 2, startZ); entityManager.SetComponentData(instance, new Translation() { Value = position }); var data = new MovementComponent { startPos = new float2(startX, startZ), speed = 2, targetPos = new float2(startX, startZ), }; var entityData = new EntityInfo { specificEntity = instance, type = -1 }; entityManager.AddComponentData(instance, data); entityManager.AddComponentData(instance, entityData); // give his first command based on the 1's in the hash entityManager.AddComponent <NeedsTaskTag>(instance); } if (blockIndices.IsCreated) { blockIndices.Dispose(); } }
/// <summary> /// Gets all the meshes and outputs to a string (even grabbing the child of each gameObject) /// </summary> /// <returns>The mesh to string.</returns> /// <param name="gameObj">GameObject Parent.</param> /// <param name="materials">Every Material in the parent that can be accessed.</param> /// <param name="objects">The StringBuidler to create objects for the FBX file.</param> /// <param name="connections">The StringBuidler to create connections for the FBX file.</param> /// <param name="parentObject">Parent object, if left null this is the top parent.</param> /// <param name="parentModelId">Parent model id, 0 if top parent.</param> public static long GetMeshToString(GameObject gameObj, Material[] materials, ref StringBuilder objects, ref StringBuilder connections, GameObject parentObject = null, long parentModelId = 0) { StringBuilder tempObjectSb = new StringBuilder(); StringBuilder tempConnectionsSb = new StringBuilder(); long geometryId = FBXExporter.GetRandomFBXId(); long modelId = FBXExporter.GetRandomFBXId(); // Sees if there is a mesh to export and add to the system MeshFilter filter = gameObj.ThreadSafe_GetComponent <MeshFilter>(); SkinnedMeshRenderer skinnedMesh = gameObj.ThreadSafe_GetComponent <SkinnedMeshRenderer>(); // The mesh to export is this level's mesh that is going to be exported Mesh meshToExport = ThreadSafeUtils.CreateMesh(); if (filter != null) { meshToExport = filter.GetSharedMesh(); } else if (skinnedMesh != null) // If this object has a skinned mesh on it, bake that mesh into whatever pose it is at and add it as a new mesh to export { meshToExport = new Mesh(); skinnedMesh.ThreadSafe_BakeMesh(meshToExport); } if (meshToExport == null) { Debug.LogError("Couldn't find a mesh to export"); } string meshName = gameObj.GetName(); // A NULL parent means that the gameObject is at the top string isMesh = "Null"; if (meshToExport != null) { meshName = meshToExport.GetName(); isMesh = "Mesh"; } if (filter != null) { if (filter.GetSharedMesh() == null) { // The MeshFilter has no mesh assigned, so treat it like an FBX Null node. filter = null; } else { meshName = filter.GetSharedMesh().GetName(); isMesh = "Mesh"; } } // If we've got a skinned mesh without a name, give it a random name if (meshName == "" && skinnedMesh != null) { meshName = "Skinned Mesh " + Random.Range(0, 1000000); } if (parentModelId == 0) { tempConnectionsSb.AppendLine("\t;Model::" + meshName + ", Model::RootNode"); } else { tempConnectionsSb.AppendLine("\t;Model::" + meshName + ", Model::USING PARENT"); } tempConnectionsSb.AppendLine("\tC: \"OO\"," + modelId + "," + parentModelId); tempConnectionsSb.AppendLine(); tempObjectSb.AppendLine("\tModel: " + modelId + ", \"Model::" + gameObj.GetName() + "\", \"" + isMesh + "\" {"); tempObjectSb.AppendLine("\t\tVersion: 232"); tempObjectSb.AppendLine("\t\tProperties70: {"); tempObjectSb.AppendLine("\t\t\tP: \"RotationOrder\", \"enum\", \"\", \"\",4"); tempObjectSb.AppendLine("\t\t\tP: \"RotationActive\", \"bool\", \"\", \"\",1"); tempObjectSb.AppendLine("\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); tempObjectSb.AppendLine("\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); tempObjectSb.AppendLine("\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); // ===== Local Translation Offset ========= Vector3 position = gameObj.GetTransform().GetLocalPosition(); tempObjectSb.Append("\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A+\","); // Append the X Y Z coords to the system tempObjectSb.AppendFormat("{0},{1},{2}", FE.FBXFormat(position.GetX() * -1), FE.FBXFormat(position.GetY()), FE.FBXFormat(position.GetZ())); tempObjectSb.AppendLine(); // Rotates the object correctly from Unity space Vector3 localRotation = gameObj.GetTransform().GetLocalEulerAngles(); tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A+\",{0},{1},{2}", FE.FBXFormat(localRotation.GetX()), FE.FBXFormat(localRotation.GetY() * -1), FE.FBXFormat(-1 * localRotation.GetZ())); tempObjectSb.AppendLine(); // Adds the local scale of this object Vector3 localScale = gameObj.GetTransform().GetLocalScale(); tempObjectSb.AppendFormat("\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", FE.FBXFormat(localScale.GetX()), FE.FBXFormat(localScale.GetY()), FE.FBXFormat(localScale.GetZ())); tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\tP: \"currentUVSet\", \"KString\", \"\", \"U\", \"map1\""); tempObjectSb.AppendLine("\t\t}"); tempObjectSb.AppendLine("\t\tShading: T"); tempObjectSb.AppendLine("\t\tCulling: \"CullingOff\""); tempObjectSb.AppendLine("\t}"); // Adds in geometry if it exists, if it it does not exist, this is a empty gameObject file and skips over this if (meshToExport != null) { Mesh mesh = meshToExport; // ================================= // General Geometry Info // ================================= // Generate the geometry information for the mesh created tempObjectSb.AppendLine("\tGeometry: " + geometryId + ", \"Geometry::\", \"Mesh\" {"); // ===== WRITE THE VERTICIES ===== Vector3[] verticies = mesh.GetVertices(); int vertCount = mesh.GetVertexCount() * 3; // <= because the list of points is just a list of comma seperated values, we need to multiply by three tempObjectSb.AppendLine("\t\tVertices: *" + vertCount + " {"); tempObjectSb.Append("\t\t\ta: "); for (int i = 0; i < verticies.Length; i++) { if (i > 0) { tempObjectSb.Append(","); } // Points in the verticies. We also reverse the x value because Unity has a reverse X coordinate tempObjectSb.AppendFormat("{0},{1},{2}", FE.FBXFormat(verticies[i].GetX() * -1), FE.FBXFormat(verticies[i].GetY()), FE.FBXFormat(verticies[i].GetZ())); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t} "); // ======= WRITE THE TRIANGLES ======== int triangleCount = mesh.GetTriangles().Length; int[] triangles = mesh.GetTriangles(); tempObjectSb.AppendLine("\t\tPolygonVertexIndex: *" + triangleCount + " {"); // Write triangle indexes tempObjectSb.Append("\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // To get the correct normals, must rewind the triangles since we flipped the x direction tempObjectSb.AppendFormat("{0},{1},{2}", triangles[i], triangles[i + 2], (triangles[i + 1] * -1) - 1); // <= Tells the poly is ended } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t} "); tempObjectSb.AppendLine("\t\tGeometryVersion: 124"); tempObjectSb.AppendLine("\t\tLayerElementNormal: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"Direct\""); // ===== WRITE THE NORMALS ========== Vector3[] normals = mesh.ThreadSafe_GetNormals(); tempObjectSb.AppendLine("\t\t\tNormals: *" + (triangleCount * 3) + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // To get the correct normals, must rewind the normal triangles like the triangles above since x was flipped Vector3 newNormal = normals[triangles[i]]; tempObjectSb.AppendFormat("{0},{1},{2},", FE.FBXFormat(newNormal.GetX() * -1), // Switch normal as is tradition FE.FBXFormat(newNormal.GetY()), FE.FBXFormat(newNormal.GetZ())); newNormal = normals[triangles[i + 2]]; tempObjectSb.AppendFormat("{0},{1},{2},", FE.FBXFormat(newNormal.GetX() * -1), // Switch normal as is tradition FE.FBXFormat(newNormal.GetY()), FE.FBXFormat(newNormal.GetZ())); newNormal = normals[triangles[i + 1]]; tempObjectSb.AppendFormat("{0},{1},{2}", FE.FBXFormat(newNormal.GetX() * -1), // Switch normal as is tradition FE.FBXFormat(newNormal.GetY()), FE.FBXFormat(newNormal.GetZ())); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); // ===== WRITE THE COLORS ===== bool containsColors = mesh.ThreadSafe_GetColors().Length == verticies.Length; if (containsColors) { Color[] colors = mesh.ThreadSafe_GetColors(); Dictionary <Color, int> colorTable = new Dictionary <Color, int>(); // reducing amount of data by only keeping unique colors. int idx = 0; // build index table of all the different colors present in the mesh for (int i = 0; i < colors.Length; i++) { if (!colorTable.ContainsKey(colors[i])) { colorTable[colors[i]] = idx; idx++; } } tempObjectSb.AppendLine("\t\tLayerElementColor: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"Col\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); tempObjectSb.AppendLine("\t\t\tColors: *" + colorTable.Count * 4 + " {"); tempObjectSb.Append("\t\t\t\ta: "); bool first = true; foreach (KeyValuePair <Color, int> color in colorTable) { if (!first) { tempObjectSb.Append(","); } tempObjectSb.AppendFormat("{0},{1},{2},{3}", FE.FBXFormat(color.Key.GetR()), FE.FBXFormat(color.Key.GetG()), FE.FBXFormat(color.Key.GetB()), FE.FBXFormat(color.Key.GetA())); first = false; } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t\t}"); // Color index tempObjectSb.AppendLine("\t\t\tColorIndex: *" + triangles.Length + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangles.Length; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // Triangles need to be fliped for the x flip int index1 = triangles[i]; int index2 = triangles[i + 2]; int index3 = triangles[i + 1]; // Find the color index related to that vertice index index1 = colorTable[colors[index1]]; index2 = colorTable[colors[index2]]; index3 = colorTable[colors[index3]]; tempObjectSb.AppendFormat("{0},{1},{2}", index1, index2, index3); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); } else { Debug.LogWarning("Mesh contains " + mesh.GetVertices().Length + " vertices for " + mesh.ThreadSafe_GetColors().Length + " colors. Skip color export"); } // ================ UV CREATION ========================= // -- UV 1 Creation int uvLength = mesh.GetUV().Length; Vector2[] uvs = mesh.GetUV(); tempObjectSb.AppendLine("\t\tLayerElementUV: 0 {"); // the Zero here is for the first UV map tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"map1\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygonVertex\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); tempObjectSb.AppendLine("\t\t\tUV: *" + uvLength * 2 + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < uvLength; i++) { if (i > 0) { tempObjectSb.Append(","); } tempObjectSb.AppendFormat("{0},{1}", FE.FBXFormat(uvs[i].GetX()), FE.FBXFormat(uvs[i].GetY())); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t\t}"); // UV tile index coords tempObjectSb.AppendLine("\t\t\tUVIndex: *" + triangleCount + " {"); tempObjectSb.Append("\t\t\t\ta: "); for (int i = 0; i < triangleCount; i += 3) { if (i > 0) { tempObjectSb.Append(","); } // Triangles need to be fliped for the x flip int index1 = triangles[i]; int index2 = triangles[i + 2]; int index3 = triangles[i + 1]; tempObjectSb.AppendFormat("{0},{1},{2}", index1, index2, index3); } tempObjectSb.AppendLine(); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); // -- UV 2 Creation // TODO: Add UV2 Creation here // -- Smoothing // TODO: Smoothing doesn't seem to do anything when importing. This maybe should be added. -KBH // ============ MATERIALS ============= tempObjectSb.AppendLine("\t\tLayerElementMaterial: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 101"); tempObjectSb.AppendLine("\t\t\tName: \"\""); tempObjectSb.AppendLine("\t\t\tMappingInformationType: \"ByPolygon\""); tempObjectSb.AppendLine("\t\t\tReferenceInformationType: \"IndexToDirect\""); int totalFaceCount = 0; // So by polygon means that we need 1/3rd of how many indicies we wrote. int numberOfSubmeshes = mesh.GetSubmeshCount(); StringBuilder submeshesSb = new StringBuilder(); // For just one submesh, we set them all to zero if (numberOfSubmeshes == 1) { int numFaces = triangles.Length / 3; for (int i = 0; i < numFaces; i++) { submeshesSb.Append("0,"); totalFaceCount++; } } else { List <int[]> allSubmeshes = new List <int[]>(); // Load all submeshes into a space for (int i = 0; i < numberOfSubmeshes; i++) { allSubmeshes.Add(mesh.ThreadSafe_GetIndices(i)); } // TODO: Optimize this search pattern for (int i = 0; i < triangles.Length; i += 3) { for (int subMeshIndex = 0; subMeshIndex < allSubmeshes.Count; subMeshIndex++) { bool breaker = false; for (int n = 0; n < allSubmeshes[subMeshIndex].Length; n += 3) { if (triangles[i] == allSubmeshes[subMeshIndex][n] && triangles[i + 1] == allSubmeshes[subMeshIndex][n + 1] && triangles[i + 2] == allSubmeshes[subMeshIndex][n + 2]) { submeshesSb.Append(subMeshIndex.ToString()); submeshesSb.Append(","); totalFaceCount++; break; } if (breaker) { break; } } } } } tempObjectSb.AppendLine("\t\t\tMaterials: *" + totalFaceCount + " {"); tempObjectSb.Append("\t\t\t\ta: "); tempObjectSb.AppendLine(submeshesSb.ToString()); tempObjectSb.AppendLine("\t\t\t} "); tempObjectSb.AppendLine("\t\t}"); // ============= INFORMS WHAT TYPE OF LATER ELEMENTS ARE IN THIS GEOMETRY ================= tempObjectSb.AppendLine("\t\tLayer: 0 {"); tempObjectSb.AppendLine("\t\t\tVersion: 100"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementNormal\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementMaterial\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementTexture\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); if (containsColors) { tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementColor\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); } tempObjectSb.AppendLine("\t\t\tLayerElement: {"); tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementUV\""); tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 0"); tempObjectSb.AppendLine("\t\t\t}"); // TODO: Here we would add UV layer 1 for ambient occlusion UV file // tempObjectSb.AppendLine("\t\t\tLayerElement: {"); // tempObjectSb.AppendLine("\t\t\t\tType: \"LayerElementUV\""); // tempObjectSb.AppendLine("\t\t\t\tTypedIndex: 1"); // tempObjectSb.AppendLine("\t\t\t}"); tempObjectSb.AppendLine("\t\t}"); tempObjectSb.AppendLine("\t}"); // Add the connection for the model to the geometry so it is attached the right mesh tempConnectionsSb.AppendLine("\t;Geometry::, Model::" + mesh.GetName()); tempConnectionsSb.AppendLine("\tC: \"OO\"," + geometryId + "," + modelId); tempConnectionsSb.AppendLine(); // Add the connection of all the materials in order of submesh MeshRenderer meshRenderer = gameObj.ThreadSafe_GetComponent <MeshRenderer>(); if (meshRenderer != null) { Material[] allMaterialsInThisMesh = meshRenderer.GetSharedMaterials(); for (int i = 0; i < allMaterialsInThisMesh.Length; i++) { Material mat = allMaterialsInThisMesh[i]; int referenceId = Mathf.Abs(mat.ThreadSafe_GetInstanceID()); if (mat == null) { Debug.LogError("ERROR: the game object " + gameObj.GetName() + " has an empty material on it. This will export problematic files. Please fix and reexport"); continue; } tempConnectionsSb.AppendLine("\t;Material::" + mat.GetName() + ", Model::" + mesh.GetName()); tempConnectionsSb.AppendLine("\tC: \"OO\"," + referenceId + "," + modelId); tempConnectionsSb.AppendLine(); } } } // Recursively add all the other objects to the string that has been built. for (int i = 0; i < gameObj.GetTransform().ThreadSafe_GetChildCount(); i++) { GameObject childObject = gameObj.GetTransform().ThreadSafe_GetChild(i).GetGameObject(); FBXUnityMeshGetter.GetMeshToString(childObject, materials, ref tempObjectSb, ref tempConnectionsSb, gameObj, modelId); } objects.Append(tempObjectSb.ToString()); connections.Append(tempConnectionsSb.ToString()); return(modelId); }