static void AddCollider(GameObject gameObject, bool hasPhysics) { // If no mesh is defined skip this GameObject var meshFilter = gameObject.GetComponent <MeshFilter>(); var sharedMesh = meshFilter ? meshFilter.sharedMesh : null; if (!sharedMesh) { return; } var colliderTarget = gameObject; var lodGroup = gameObject.GetComponentInParent <LODGroup>(); if (lodGroup) { colliderTarget = lodGroup.gameObject; } // If target already has colliders do not modify if (colliderTarget.GetComponentsInChildren <Collider>().Length > 0) { return; } // Add a mesh collider to this object var meshCollider = EP.AddComponent <MeshCollider>(colliderTarget); meshCollider.sharedMesh = sharedMesh; meshCollider.convex = hasPhysics; }
public static LightProbeGroup CreateLightProbes(GameObject gameObject) { // Light probe positions are evaluated relative to LightProbeGroup // https://docs.unity3d.com/ScriptReference/LightProbeGroup-probePositions.html var group = gameObject.GetComponent <LightProbeGroup>(); if (!group) { group = EP.AddComponent <LightProbeGroup>(gameObject); } // IDEA: Find child LightProbeGroups and exclude probes in those volumes // This would enable adjusting the probe density in different areas. // TODO: Enable configuration to use other placement strategies group.probePositions = LightProbeGrid(gameObject, probeSpaces); return(group); }
/// <summary> /// Make a copy of light source as area light, with equivalent illumination /// </summary> /// <remarks> /// Intensity is scaled relative to the area of the light /// </remarks> public static GameObject MakeAreaCopy(Light light, Vector2 areaSize) { var gameObject = EP.Instantiate(); GameObjectUtility.SetStaticEditorFlags(gameObject, (StaticEditorFlags) ~0); EP.SetParent(gameObject.transform, light.transform.parent); gameObject.transform.localPosition = light.transform.localPosition; gameObject.transform.localRotation = light.transform.localRotation; var areaLight = EP.AddComponent <Light>(gameObject); areaLight.lightmapBakeType = LightmapBakeType.Baked; areaLight.type = LightType.Rectangle; areaLight.areaSize = areaSize; areaLight.intensity = light.intensity / (areaSize.x * areaSize.y); areaLight.color = light.color; areaLight.range = light.range; return(gameObject); }
/// <summary> /// Configure the light probe proxy volume for lower levels of detail in group /// </summary> public static void ConfigureLODGroup(LODGroup lodGroup) { // TODO: Check if group is static - if not, also configure the lowest level of detail. // Only lower levels of detail will use probes // IMPORTANT: Proxy volumes always update, so only generate them if they will be used. var lods = lodGroup.GetLODs(); if (lods.Length < 2) { return; } // FIXME: Local bounds are needed var worldBounds = RendererWorldBounds(lodGroup.gameObject); // TEMP: Assume that only axis swaps pertain var localBounds = new Bounds(); localBounds.center = lodGroup.transform.InverseTransformPoint(worldBounds.center); localBounds.size = lodGroup.transform.InverseTransformDirection(worldBounds.size); localBounds.size = new Vector3(Mathf.Abs(localBounds.size.x), Mathf.Abs(localBounds.size.y), Mathf.Abs(localBounds.size.z)); // If object bounds > probe spacing in any dimension use a proxy volume var useProxy = false; for (var i = 0; i < 3; ++i) { useProxy |= localBounds.size[i] > probeSpaces[i]; } var proxy = lodGroup.gameObject.GetComponent <LightProbeProxyVolume>(); if (useProxy) { if (!proxy) { proxy = EP.AddComponent <LightProbeProxyVolume>(lodGroup.gameObject); } // Configure proxy bounds proxy.boundingBoxMode = LightProbeProxyVolume.BoundingBoxMode.Custom; proxy.originCustom = localBounds.center; proxy.sizeCustom = localBounds.size; // Configure spacing proxy.probePositionMode = LightProbeProxyVolume.ProbePositionMode.CellCorner; proxy.resolutionMode = LightProbeProxyVolume.ResolutionMode.Custom; proxy.gridResolutionX = ProxyResolution(localBounds.size.x / probeSpaces.x); proxy.gridResolutionY = ProxyResolution(localBounds.size.y / probeSpaces.y); proxy.gridResolutionZ = ProxyResolution(localBounds.size.z / probeSpaces.z); // Remaining settings proxy.qualityMode = LightProbeProxyVolume.QualityMode.Normal; proxy.refreshMode = LightProbeProxyVolume.RefreshMode.Automatic; } else { if (proxy) { EP.Destroy(proxy); } proxy = null; } // Configure all lower levels of detail to use probes for (var l = 1; l < lods.Length; ++l) { foreach (var renderer in lods[l].renderers) { renderer.lightProbeUsage = useProxy ? UnityEngine.Rendering.LightProbeUsage.UseProxyVolume : UnityEngine.Rendering.LightProbeUsage.BlendProbes; renderer.lightProbeProxyVolumeOverride = lodGroup.gameObject; var meshRender = renderer as MeshRenderer; if (!meshRender) { continue; } meshRender.receiveGI = ReceiveGI.LightProbes; } } }
static void MergeGroup(string pathName, List <GameObject> group) { // Gather LODGroup and Renderers LODGroup lodGroup = null; var renderers = new List <RendererSort>(); foreach (var gameObject in group) { var renderer = gameObject.GetComponent <Renderer>(); if (renderer) { renderers.Add(new RendererSort(renderer)); } var isGroup = gameObject.GetComponent <LODGroup>(); if (isGroup) { var lods = isGroup.GetLODs(); foreach (var lod in lods) { foreach (var lodRenderer in lod.renderers) { // Renderers must begin as siblings of LODGroup EP.SetParent(lodRenderer.transform, isGroup.transform.parent); renderers.Add(new RendererSort(lodRenderer)); } } if (!!lodGroup || !!renderer) { // LODGroup manager cannot be duplicated, and cannot have renderer component Debug.LogWarning($"Removing LODGroup found on {gameObject.Path()}"); EP.Destroy(isGroup); continue; } lodGroup = isGroup; } } if (!lodGroup) { lodGroup = EP.AddComponent <LODGroup>(EP.Instantiate()); } // renderers[0] has the lowest vertex count renderers.Sort((l, m) => l.vertexCount - m.vertexCount); // Remove missing meshes and duplicate levels of detail var vertexCount = 0; var removeRenderers = new List <RendererSort>(); foreach (var renderer in renderers) { if (vertexCount == renderer.vertexCount) { removeRenderers.Add(renderer); continue; } vertexCount = renderer.vertexCount; } foreach (var renderer in removeRenderers) { renderers.Remove(renderer); EP.Destroy(renderer.renderer.gameObject); // NOTE: Duplicate mesh asset could be removed } if (renderers.Count == 0) { EP.Destroy(lodGroup.gameObject); return; } // renderers[0] has the highest vertrex count renderers.Reverse(); // Configure manager in hierarchy lodGroup.gameObject.name = pathName.Substring(pathName.LastIndexOf('/') + 1); EP.SetParent(lodGroup.transform, renderers[0].renderer.transform.parent); lodGroup.transform.localPosition = renderers[0].renderer.transform.localPosition; lodGroup.transform.localRotation = renderers[0].renderer.transform.localRotation; lodGroup.transform.localScale = renderers[0].renderer.transform.localScale; for (var r = 0; r < renderers.Count; ++r) { var renderer = renderers[r].renderer; // TODO: Used PathNameExtension for this! var lodIndex = renderer.gameObject.name.LastIndexOf(lodSuffix); if (lodIndex >= 0) { renderer.gameObject.name = renderer.gameObject.name.Substring(0, lodIndex); } renderer.gameObject.name += lodSuffix + r.ToString(); EP.SetParent(renderer.transform, lodGroup.transform); } // Configure the group var lodList = new LOD[renderers.Count]; for (var r = 0; r < renderers.Count; ++r) { lodList[r].renderers = new[] { renderers[r].renderer } } ; ConfigureLODGroup(lodGroup, lodList); // Configure the renderers and materials foreach (var lod in lodGroup.GetLODs()) { foreach (var renderer in lod.renderers) { SetLightmapScale(renderer); foreach (var material in renderer.sharedMaterials) { UseFadingShader(material); } } } }