/// <summary> /// Generates a bullet hole decal. /// </summary> /// <param name="surface">The surface properties of the hit object.</param> /// <param name="hitInfo">The information about the projectile impact such as position and rotation.</param> public virtual void CreateBulletDecal(SurfaceIdentifier surface, RaycastHit hitInfo) { SurfaceType surfaceType = surface.GetSurfaceType(hitInfo.point, hitInfo.triangleIndex); if (surface && surfaceType) { if (surface.AllowDecals(hitInfo.triangleIndex) && m_MaxDecals > 0) { Material material = surfaceType.GetRandomDecalMaterial(); if (material) { GameObject decal = new GameObject("BulletMark_Decal"); decal.transform.position = hitInfo.point; decal.transform.rotation = Quaternion.FromToRotation(Vector3.back, hitInfo.normal); decal.transform.Rotate(new Vector3(0, 0, Random.Range(0, 360))); float scale = surfaceType.GetRandomDecalSize() / 5; decal.transform.localScale = new Vector3(scale, scale, scale); decal.transform.parent = hitInfo.transform; DecalPresets decalPresets = new DecalPresets() { maxAngle = 60, pushDistance = 0.009f + RegisterDecal(decal, scale), material = material }; Decal d = decal.AddComponent <Decal>(); d.Calculate(decalPresets, hitInfo.collider.gameObject); } } GameObject particle = surfaceType.GetRandomImpactParticle(); if (particle) { Instantiate(particle, hitInfo.point, Quaternion.FromToRotation(Vector3.up, hitInfo.normal)); } AudioClip clip = surfaceType.GetRandomImpactSound(); if (clip) { AudioManager.Instance.PlayClipAtPoint(clip, hitInfo.point, 1, 25, surfaceType.BulletImpactVolume); } } }
public void Calculate(DecalPresets presets, GameObject affectedObject) { if (!affectedObject) { Debug.LogWarning("No object will be affected. Decal will not be calculated."); return; } angleCosine = Mathf.Cos(presets.maxAngle * Mathf.Deg2Rad); m_InstancesList = new List <MeshInstance>(); CalculateObjectDecal(affectedObject); if (m_InstancesList.Count > 0) { MeshInstance[] instances = new MeshInstance[m_InstancesList.Count]; for (int i = 0; i < instances.Length; i++) { instances[i] = m_InstancesList[i]; } MeshRenderer meshRenderer = gameObject.GetComponent <MeshRenderer>(); if (!meshRenderer) { meshRenderer = gameObject.AddComponent <MeshRenderer>(); } meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; meshRenderer.material = presets.material; MeshFilter meshFilter = gameObject.GetComponent <MeshFilter>(); if (!meshFilter) { meshFilter = gameObject.AddComponent <MeshFilter>(); } else { DestroyImmediate(meshFilter.sharedMesh); } Mesh finalMesh = MeshCombineUtility.Combine(instances, true); if (presets.pushDistance > 0.0f) { List <List <int> > relations = new List <List <int> >(); Vector3[] vert = finalMesh.vertices; Vector3[] normals = finalMesh.normals; bool[] usedIndex = new bool[vert.Length]; for (int i = 0; i < usedIndex.Length; i++) { usedIndex[i] = false; } for (int i = 0; i < vert.Length; i++) { if (usedIndex[i]) { continue; } List <int> c = new List <int> { i }; usedIndex[i] = true; for (int j = i + 1; j < vert.Length; j++) { if (usedIndex[j]) { continue; } if (Vector3.Distance(vert[i], vert[j]) > 0.001f) { continue; } c.Add(j); usedIndex[j] = true; } relations.Add(c); } for (int i = 0, k = relations.Count; i < k; i++) { Vector3 nNormal = Vector3.zero; foreach (int j in relations[i]) { nNormal += normals[j]; } nNormal = (nNormal / relations[i].Count).normalized; foreach (int j in relations[i]) { vert[j] += nNormal * (presets.pushDistance); } } finalMesh.vertices = vert; } finalMesh.name = "DecalMesh"; meshFilter.mesh = finalMesh; for (int i = 0; i < m_InstancesList.Count; i++) { DestroyImmediate(m_InstancesList[i].mesh); } } m_InstancesList.Clear(); m_InstancesList = null; }