private Material GetMaterial(GeoFace geoFace, Vtf vtf, int textureGroup) { if (geoFace.TextureName != null) { string textureName = Path.GetFileNameWithoutExtension(geoFace.TextureName); if (vtf != null && textureName[0] == 'V') { if (textureName.EndsWithFast("BO DY")) { textureName = vtf.Maps[12]; } else { string key = textureName.Substring(1).Replace(" ", "").Replace("LF", "LT") + ".TMT"; if (vtf.Tmts.TryGetValue(key, out Tmt tmt)) { textureName = tmt.TextureNames[textureGroup]; } } } return(GetTextureMaterial(textureName, geoFace.SurfaceFlags2 == 5 || geoFace.SurfaceFlags2 == 7)); } return(GetColorMaterial("color" + geoFace.Color, geoFace.Color)); }
public GameObject ImportGeo(string filename, Vtf vtf, GameObject prefab, int textureGroup) { GeoMeshCacheEntry meshCacheEntry = ImportMesh(filename, vtf, textureGroup); GameObject obj = Object.Instantiate(prefab); obj.SetActive(false); obj.gameObject.name = meshCacheEntry.GeoMesh.Name; MeshFilter meshFilter = obj.GetComponent <MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = meshCacheEntry.Mesh; obj.GetComponent <MeshRenderer>().materials = meshCacheEntry.Materials; } MeshCollider collider = obj.GetComponent <MeshCollider>(); if (collider != null) { collider.sharedMesh = meshCacheEntry.Mesh; } return(obj.gameObject); }
private Material GetMaterial(GeoFace geoFace, Vtf vtf) { if (geoFace.TextureName != null) { var textureName = geoFace.TextureName; if (vtf != null && geoFace.TextureName.StartsWith("V")) { if (geoFace.TextureName.EndsWith("BO DY")) { textureName = vtf.Maps[12]; } else { var key = geoFace.TextureName.Substring(1).Replace(" ", "").Replace("LF", "LT") + ".TMT"; if (vtf.Tmts.ContainsKey(key)) { //Debug.Log("Vehicle tmt reference: " + geoFace.TextureName + " decoded: " + key); var tmt = vtf.Tmts[key]; textureName = tmt.TextureNames[0]; } } } return(GetTextureMaterial(textureName, geoFace.SurfaceFlags2 == 5 || geoFace.SurfaceFlags2 == 7)); //Debug.Log(geoFace.TextureName + "color=" + geoFace.Color + " flag1=" + geoFace.SurfaceFlags1 + " flag2=" + geoFace.SurfaceFlags2, mat); } return(GetColorMaterial("color" + geoFace.Color, geoFace.Color)); }
private GameObject ImportCarParts(GameObject parent, Vtf vtf, SdfPart[] sdfParts, bool wheel = false) { var partDict = new Dictionary <string, GameObject> { { "WORLD", parent } }; GameObject firstObject = null; foreach (var sdfPart in sdfParts) { if (sdfPart.Name == "NULL") { continue; } GameObject prefab = NoColliderPrefab; if (!wheel && sdfPart.Name.Substring(0, sdfPart.Name.Length - 1).EndsWith("BDY")) { prefab = CarBodyPrefab; } var partObj = ImportGeo(sdfPart.Name + ".geo", vtf, prefab); var parentName = sdfPart.ParentName; if (!partDict.ContainsKey(parentName)) { Debug.Log("Cant find parent '" + sdfPart.ParentName + "' for '" + sdfPart.Name + "'"); parentName = "WORLD"; } partObj.transform.parent = partDict[parentName].transform; partObj.transform.right = sdfPart.Right; partObj.transform.up = sdfPart.Up; partObj.transform.forward = sdfPart.Forward; partObj.transform.localPosition = sdfPart.Position; partDict.Add(sdfPart.Name, partObj); firstObject = partObj; } return(firstObject); }
private void ImportCarParts(Dictionary <string, GameObject> partDict, GameObject parent, Vtf vtf, SdfPart[] sdfParts, GameObject prefab, bool justChassis, bool forgetParentPosition = false, int textureGroup = 0, int layerMask = 0) { List <SdfPart> deferredParts = new List <SdfPart>(); foreach (SdfPart sdfPart in sdfParts) { LoadCarPart(sdfPart, parent, partDict, deferredParts, vtf, prefab, justChassis, forgetParentPosition, textureGroup, layerMask); } int deferredPartCount = deferredParts.Count; for (int i = 0; i < deferredPartCount; ++i) { LoadCarPart(deferredParts[i], parent, partDict, null, vtf, prefab, justChassis, forgetParentPosition, textureGroup, layerMask); } }
private void LoadCarPart(SdfPart sdfPart, GameObject parent, Dictionary <string, GameObject> partDict, List <SdfPart> deferredParts, Vtf vtf, GameObject prefab, bool justChassis, bool forgetParentPosition, int textureGroup, int layerMask) { if (sdfPart == null || sdfPart.Name == "NULL") { return; } if (_bannedNames.Any(b => sdfPart.Name.EndsWithFast(b))) { return; } GameObject parentObj; if (sdfPart.ParentName == "WORLD") { parentObj = parent; } else if (!partDict.TryGetValue(sdfPart.ParentName, out parentObj)) { if (deferredParts != null) { deferredParts.Add(sdfPart); return; } Debug.Log("Cant find parent '" + sdfPart.ParentName + "' for '" + sdfPart.Name + "'"); parentObj = parent; } if (justChassis && !(sdfPart.Name.Contains("BDY") || sdfPart.Name.EndsWithFast("CHAS"))) { return; } string geoFilename = sdfPart.Name + ".geo"; if (!VirtualFilesystem.Instance.FileExists(geoFilename)) { Debug.LogWarning("File does not exist: " + geoFilename); return; } GameObject partObj = ImportGeo(geoFilename, vtf, prefab, textureGroup); Transform partTransform = partObj.transform; if (!forgetParentPosition) { partTransform.SetParent(parentObj.transform); } partTransform.right = sdfPart.Right; partTransform.up = sdfPart.Up; partTransform.forward = sdfPart.Forward; partTransform.localPosition = sdfPart.Position; partTransform.localRotation = Quaternion.identity; if (forgetParentPosition) { partTransform.parent = parentObj.transform; } partObj.SetActive(true); if (partDict.ContainsKey(sdfPart.Name)) { partDict[sdfPart.Name] = partObj; } else { partDict.Add(sdfPart.Name, partObj); } if (layerMask != 0) { partObj.layer = layerMask; } // Special case for mirrors. if (sdfPart.Name.Contains("MIRI") && TryGetMaskTexture(geoFilename, out Texture2D maskTexture)) { RenderTexture renderTexture = new RenderTexture(256, 128, 24); GameObject mirrorCameraObj = Object.Instantiate(partObj); Transform mirrorObjTransform = mirrorCameraObj.transform; mirrorObjTransform.SetParent(partObj.transform); mirrorObjTransform.localPosition = Vector3.zero; mirrorObjTransform.localRotation = Quaternion.identity; Material mirrorMaterial = Object.Instantiate(_carMirrorMaterialPrefab); MeshRenderer meshRenderer = partObj.transform.GetComponent <MeshRenderer>(); mirrorMaterial.mainTexture = meshRenderer.material.mainTexture; mirrorMaterial.SetTexture("_MaskTex", maskTexture); meshRenderer.material = mirrorMaterial; GameObject cameraPivotObj = new GameObject("Camera Pivot"); UnityEngine.Camera mirrorCamera = cameraPivotObj.AddComponent <UnityEngine.Camera>(); mirrorCamera.cullingMask = ~LayerMask.GetMask("FirstPerson"); mirrorCamera.targetTexture = renderTexture; Transform pivotTransform = cameraPivotObj.transform; pivotTransform.SetParent(mirrorObjTransform); pivotTransform.localPosition = Vector3.zero; pivotTransform.localRotation = Quaternion.Euler(0f, 180f, 0f); Material cameraMaterial = Object.Instantiate(_carMirrorMaterialPrefab); cameraMaterial.mainTexture = renderTexture; MeshRenderer mirrorRenderer = mirrorCameraObj.GetComponent <MeshRenderer>(); cameraMaterial.SetTexture("_MaskTex", maskTexture); mirrorRenderer.material = cameraMaterial; } }
private RaySusp[] CreateWheelPair(Dictionary <string, GameObject> partDict, string placement, int wheelIndex, GameObject car, Vdf vdf, Vtf vtf, Wdf wheelDef) { string wheel1Name = placement + "Right"; RaySusp wheel = Object.Instantiate(placement == "Front" ? _steerWheelPrefab : _driveWheelPrefab, car.transform); wheel.gameObject.name = wheel1Name; wheel.WheelRadius = wheelDef.Radius; // This is not correct - find out where the radius is really stored wheel.SpringLength = wheelDef.Radius; ImportCarParts(partDict, wheel.transform.Find("Mesh").gameObject, vtf, wheelDef.Parts, _noColliderPrefab, false); wheel.transform.localPosition = vdf.WheelLoc[wheelIndex].Position; RaySusp wheel2 = Object.Instantiate(wheel, car.transform); wheel2.name = placement + "Left"; wheel2.transform.localPosition = vdf.WheelLoc[wheelIndex + 1].Position; wheel2.transform.Find("Mesh").localScale = new Vector3(-1, 1, 1); return(new[] { wheel, wheel2 }); }
public GameObject ImportVcf(string filename, bool importFirstPerson, out Vdf vdf) { Vcf vcf = VcfParser.ParseVcf(filename); vdf = VdfParser.ParseVdf(vcf.VdfFilename); Vtf vtf = VtfParser.ParseVtf(vcf.VtfFilename); Car carObject = Object.Instantiate(_carPrefab); carObject.Configure(vdf, vcf); carObject.gameObject.name = vdf.Name + " (" + vcf.VariantName + ")"; foreach (VLoc vLoc in vdf.VLocs) { GameObject vlocGo = new GameObject("VLOC"); vlocGo.transform.parent = carObject.transform; vlocGo.transform.localRotation = Quaternion.LookRotation(vLoc.Forward, vLoc.Up); vlocGo.transform.localPosition = vLoc.Position; } GameObject chassis = new GameObject("Chassis"); chassis.transform.parent = carObject.transform; GameObject thirdPerson = new GameObject("ThirdPerson"); thirdPerson.transform.parent = chassis.transform; Transform[] weaponMountTransforms = new Transform[vdf.HLocs.Count]; for (int i = 0; i < vdf.HLocs.Count; ++i) { HLoc hloc = vdf.HLocs[i]; Transform mountPoint = new GameObject(hloc.Label).transform; mountPoint.parent = thirdPerson.transform; mountPoint.localRotation = Quaternion.LookRotation(hloc.Forward, hloc.Up); mountPoint.localPosition = hloc.Position; weaponMountTransforms[i] = mountPoint; } Dictionary <string, GameObject> partDict = new Dictionary <string, GameObject>(); for (int i = 0; i < vdf.PartsThirdPerson.Count; ++i) { GameObject healthObject = new GameObject("Health " + i); healthObject.transform.SetParent(thirdPerson.transform); ImportCarParts(partDict, healthObject, vtf, vdf.PartsThirdPerson[i], _noColliderPrefab, false, false, i); if (i != 0) { healthObject.SetActive(false); } } MeshFilter[] meshFilters = thirdPerson.GetComponentsInChildren <MeshFilter>(); Bounds bounds = new Bounds(); bounds.SetMinMax(Vector3.one * float.MaxValue, Vector3.one * float.MinValue); foreach (MeshFilter meshFilter in meshFilters) { Vector3 min = Vector3.Min(bounds.min, meshFilter.transform.position + meshFilter.sharedMesh.bounds.min) - thirdPerson.transform.position; Vector3 max = Vector3.Max(bounds.max, meshFilter.transform.position + meshFilter.sharedMesh.bounds.max) - thirdPerson.transform.position; bounds.SetMinMax(min, max); } GameObject chassisCollider = new GameObject("ChassisColliders"); chassisCollider.transform.parent = carObject.transform; ImportCarParts(partDict, chassisCollider, vtf, vdf.PartsThirdPerson[0], _carBodyPrefab, true); for (int i = 0; i < vcf.Weapons.Count; ++i) { VcfWeapon weapon = vcf.Weapons[i]; int mountPoint = weapon.MountPoint; HLoc hloc = vdf.HLocs[mountPoint]; weapon.RearFacing = hloc.FacingDirection == 2; SdfPart[] partsArray; switch (hloc.MeshType) { case HardpointMeshType.Top: partsArray = weapon.Gdf.TopParts; break; case HardpointMeshType.Side: partsArray = weapon.Gdf.SideParts; break; case HardpointMeshType.Inside: partsArray = weapon.Gdf.InsideParts; break; case HardpointMeshType.Turret: partsArray = weapon.Gdf.TurretParts; break; default: partsArray = null; break; } if (partsArray != null) { Transform weaponTransform = new GameObject(weapon.Gdf.Name).transform; weaponTransform.SetParent(weaponMountTransforms[i]); weaponTransform.localPosition = Vector3.zero; weaponTransform.localRotation = Quaternion.identity; ImportCarParts(partDict, weaponTransform.gameObject, vtf, partsArray, _noColliderPrefab, false); weapon.Transform = weaponTransform; // Disable depth test for 'inside' weapons, otherwise they are obscured. if (hloc.MeshType == HardpointMeshType.Inside) { MeshRenderer weaponRenderer = weaponTransform.GetComponentInChildren <MeshRenderer>(); if (weaponRenderer != null) { weaponRenderer.sharedMaterial.shader = Shader.Find("Custom/CutOutWithoutZ"); } } } else { weapon.Transform = chassis.transform; } } // Note: The following is probably how I76 does collision detection. Two large boxes that encapsulate the entire vehicle. // Right now this won't work with Open76's raycast suspension, so I'm leaving this off for now. Investigate in the future. //var innerBox = chassisCollider.AddComponent<BoxCollider>(); //innerBox.center = vdf.BoundsInner.center; //innerBox.size = vdf.BoundsInner.size; //var outerBox = chassisCollider.AddComponent<BoxCollider>(); //outerBox.center = vdf.BoundsOuter.center; //outerBox.size = vdf.BoundsOuter.size; RaySusp[] frontWheels = null; if (vcf.FrontWheelDef != null) { frontWheels = CreateWheelPair(partDict, "Front", 0, carObject.gameObject, vdf, vtf, vcf.FrontWheelDef); carObject.Movement.FrontWheels = frontWheels; } if (vcf.MidWheelDef != null) { CreateWheelPair(partDict, "Mid", 2, carObject.gameObject, vdf, vtf, vcf.MidWheelDef); } RaySusp[] rearWheels = null; if (vcf.BackWheelDef != null) { rearWheels = CreateWheelPair(partDict, "Back", 4, carObject.gameObject, vdf, vtf, vcf.BackWheelDef); carObject.Movement.RearWheels = rearWheels; } if (importFirstPerson) { GameObject firstPerson = new GameObject("FirstPerson"); firstPerson.transform.parent = chassis.transform; ImportCarParts(partDict, firstPerson, vtf, vdf.PartsFirstPerson, _noColliderPrefab, false, true, 0, LayerMask.NameToLayer("FirstPerson")); carObject.InitPanels(); firstPerson.SetActive(false); } carObject.Movement.Initialise(chassis.transform, frontWheels, rearWheels); return(carObject.gameObject); }
public GeoMeshCacheEntry ImportMesh(string filename, Vtf vtf, int textureGroup) { if (MeshCache.TryGetValue(filename, out GeoMeshCacheEntry cacheEntry)) { return(cacheEntry); } GeoMesh geoMesh = GeoParser.ReadGeoMesh(filename); Mesh mesh = new Mesh(); List <Vector3> vertices = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); Dictionary <Material, List <GeoFace> > facesGroupedByMaterial = new Dictionary <Material, List <GeoFace> >(); GeoFace[] faces = geoMesh.Faces; for (int i = 0; i < faces.Length; ++i) { Material material = GetMaterial(faces[i], vtf, textureGroup); if (facesGroupedByMaterial.TryGetValue(material, out List <GeoFace> faceGroup)) { faceGroup.Add(faces[i]); } else { facesGroupedByMaterial.Add(material, new List <GeoFace> { faces[i] }); } } mesh.subMeshCount = facesGroupedByMaterial.Count; Dictionary <Material, List <int> > submeshTriangles = new Dictionary <Material, List <int> >(); foreach (KeyValuePair <Material, List <GeoFace> > faceGroup in facesGroupedByMaterial) { submeshTriangles[faceGroup.Key] = new List <int>(); List <GeoFace> faceGroupValues = faceGroup.Value; foreach (GeoFace face in faceGroupValues) { int numTriangles = face.VertexRefs.Length - 3 + 1; int viStart = vertices.Count; foreach (GeoVertexRef vertexRef in face.VertexRefs) { vertices.Add(geoMesh.Vertices[vertexRef.VertexIndex]); normals.Add(geoMesh.Normals[vertexRef.VertexIndex] * -1); uvs.Add(vertexRef.Uv); } for (int t = 1; t <= numTriangles; t++) { submeshTriangles[faceGroup.Key].Add(viStart + t); submeshTriangles[faceGroup.Key].Add(viStart); submeshTriangles[faceGroup.Key].Add(viStart + t + 1); } } } mesh.SetVertices(vertices); mesh.SetUVs(0, uvs); mesh.SetNormals(normals); int subMeshIndex = 0; foreach (KeyValuePair <Material, List <int> > submeshTriangle in submeshTriangles) { mesh.SetTriangles(submeshTriangles[submeshTriangle.Key], subMeshIndex++); } mesh.RecalculateBounds(); cacheEntry = new GeoMeshCacheEntry { GeoMesh = geoMesh, Mesh = mesh, Materials = facesGroupedByMaterial.Select(x => x.Key).ToArray() }; MeshCache.Add(filename, cacheEntry); return(cacheEntry); }
private ArcadeWheel[] CreateWheelPair(string placement, int wheelIndex, GameObject car, Vdf vdf, Vtf vtf, SdfPart[] parts) { var wheel1Name = placement + "Right"; var wheel = Instantiate(placement == "Front" ? SteerWheelPrefab : DriveWheelPrefab, car.transform); wheel.gameObject.name = wheel1Name; ImportCarParts(wheel.transform.Find("Mesh").gameObject, vtf, parts, true); wheel.transform.localPosition = vdf.WheelLoc[wheelIndex].Position; var wheel2 = Instantiate(wheel, car.transform); wheel2.name = placement + "Left"; wheel2.transform.localPosition = vdf.WheelLoc[wheelIndex + 1].Position; wheel2.transform.Find("Mesh").localScale = new Vector3(-1, 1, 1); return(new[] { wheel, wheel2 }); }
public GameObject ImportGeo(string filename, Vtf vtf, GameObject prefab) { var geoMesh = GeoParser.ReadGeoMesh(filename); var mesh = new Mesh(); var vertices = new List <Vector3>(); var uvs = new List <Vector2>(); var normals = new List <Vector3>(); var facesGroupedByMaterial = geoMesh.Faces.GroupBy(face => GetMaterial(face, vtf)).ToArray(); mesh.subMeshCount = facesGroupedByMaterial.Length; var submeshTriangles = new Dictionary <Material, List <int> >(); foreach (var faceGroup in facesGroupedByMaterial) { submeshTriangles[faceGroup.Key] = new List <int>(); foreach (var face in faceGroup) { var numTriangles = face.VertexRefs.Length - 3 + 1; var viStart = vertices.Count; foreach (var vertexRef in face.VertexRefs) { vertices.Add(geoMesh.Vertices[vertexRef.VertexIndex]); normals.Add(geoMesh.Normals[vertexRef.VertexIndex] * -1); uvs.Add(vertexRef.Uv); } for (var t = 1; t <= numTriangles; t++) { submeshTriangles[faceGroup.Key].Add(viStart + t); submeshTriangles[faceGroup.Key].Add(viStart); submeshTriangles[faceGroup.Key].Add(viStart + t + 1); } } } mesh.vertices = vertices.ToArray(); mesh.uv = uvs.ToArray(); mesh.normals = normals.ToArray(); var i = 0; foreach (var submeshTriangle in submeshTriangles) { mesh.SetTriangles(submeshTriangles[submeshTriangle.Key].ToArray(), i); i++; } var obj = Instantiate(prefab); obj.gameObject.name = geoMesh.Name; obj.GetComponent <MeshFilter>().sharedMesh = mesh; obj.GetComponent <MeshRenderer>().materials = facesGroupedByMaterial.Select(x => x.Key).ToArray(); var collider = obj.GetComponent <MeshCollider>(); if (collider != null) { collider.sharedMesh = mesh; } return(obj.gameObject); }