private void Awake() { UnityEngine.Bounds mapBoundsWorldSpace = this.Map.GetComponent <UnityEngine.MeshRenderer>().bounds; WorldBounds = new WorldBounds { //The world scale must be an integer value, or you will encounter floating point errors with the grid system XZGridSize = gridSize, //LEFT BOTTOM CORNER XZGridWorldSpaceMin = new int2 ( //Only works with symmetrical shapes and assumes its centered at 0/0/0 (int)math.floor(-mapBoundsWorldSpace.extents.x), (int)math.floor(-mapBoundsWorldSpace.extents.z) ), //TOP RIGHT CORNER XZGridWorldSpaceMax = new int2 ( //Only works with symmetrical shapes //Only works with symmetrical shapes and assumes its centered at 0/0/0 (int)math.floor(mapBoundsWorldSpace.extents.x), (int)math.floor(mapBoundsWorldSpace.extents.z) ), WorldSpaceCellSize = gridCellSize }; }
// get world bound coordinates WorldBounds getWorldBounds() { GameObject[] outerwalls = GameObject.FindGameObjectsWithTag("outerWall"); WorldBounds wb = new WorldBounds(); List <GameObject> horizontalWalls = new List <GameObject>(); List <GameObject> verticalWalls = new List <GameObject>(); foreach (GameObject outerWall in outerwalls) { if (outerWall.transform.rotation.y == 0) { horizontalWalls.Add(outerWall); } else { verticalWalls.Add(outerWall); } } float zmax = Single.MinValue, zmin = Single.MaxValue; foreach (GameObject horwall in horizontalWalls) { if (horwall.transform.position.z > zmax) { zmax = horwall.transform.position.z; } if (horwall.transform.position.z < zmin) { zmin = horwall.transform.position.z; } } float xmax = Single.MinValue, xmin = Single.MaxValue; foreach (GameObject verWall in verticalWalls) { if (verWall.transform.position.x > xmax) { xmax = verWall.transform.position.x; } if (verWall.transform.position.x < xmin) { xmin = verWall.transform.position.x; } } wb.topleft = new Vector3(xmin, verticalWalls[0].transform.position.y, zmax); wb.topright = new Vector3(xmax, verticalWalls[0].transform.position.y, zmax); wb.bottomleft = new Vector3(xmin, verticalWalls[0].transform.position.y, zmin); wb.bottomright = new Vector3(xmax, verticalWalls[0].transform.position.y, zmin); return(wb); }
public static int2 WorldSpaceToCell(this WorldBounds worldBounds, float3 worldSpace) { return(new int2 ( WorldSpaceToCell(worldSpace.x, worldBounds.XZGridWorldSpaceMin.x, 0, worldBounds.XZGridSize.x, worldBounds), WorldSpaceToCell(worldSpace.z, worldBounds.XZGridWorldSpaceMin.y, 0, worldBounds.XZGridSize.y, worldBounds) )); }
public static float3 CellToWorldSpace(this WorldBounds worldBounds, int2 cell, float overrideY = 0f) { //Pathfinding grid is on x, z components (2d) but cell is x and y return(new float3 ( CellToWorldSpace(cell.x, worldBounds.XZGridWorldSpaceMin.x, worldBounds), overrideY, CellToWorldSpace(cell.y, worldBounds.XZGridWorldSpaceMin.y, worldBounds) )); }
//Calculate the whole pathfinding grid in a fixed interval to save performance. protected override void OnUpdate() { this.currentTime += Time.DeltaTime; if (this.currentTime >= UpdateInterval) { Entity worldBoundsEntity = this.GetEntityQuery(this.EntityManager.GetWorldBoundsIdentifier()).GetSingletonEntity(); WorldBounds worldBounds = this.EntityManager.GetComponentData <WorldBounds>(worldBoundsEntity); CollisionWorld collisionWorldForJob = this.physicsWorld.PhysicsWorld.CollisionWorld; //SystemBase Dependency for the Physics system -> This system must wait for the phyiscs world to complete in order to create a new parallel jobs this.Dependency = JobHandle.CombineDependencies(Dependency, this.physicsWorld.FinalJobHandle); //Can not take the collider, because the raycast does not allow to query a object gridbased -> it detects hit only once, even if multiple boxcasts are present //So we take the world render bounds and the AABB of the world render bounds NativeArray <WorldRenderBounds> worldRenderBoundsOfObstacles = this.GetEntityQuery(this.EntityManager.GetRenderableTypes() .Concat(new ComponentType[] { this.EntityManager.GetObstacleIdentifier() }).ToArray()) .ToComponentDataArray <WorldRenderBounds>(Allocator.TempJob); this.Dependency = JobHandle.CombineDependencies(this.Dependency, this.Entities .ForEach((Entity entity, ref PathNode pathNode) => { //Get AABB from cubic shape of each path node float3 bottomLeft = worldBounds.CellToWorldSpace(new int2(pathNode.X, pathNode.Y)); float3 topRight = worldBounds.CellToWorldSpace(new int2(pathNode.X + 1, pathNode.Y + 1)); float3 center = (bottomLeft + topRight) / 2; AABB pathNodeAABB = new AABB { Center = center, Extents = worldBounds.WorldSpaceCellSize }; //Check if there is any worldRenderBoundsObstacle that intersects the AABB of pathNode for (int i = 0; i < worldRenderBoundsOfObstacles.Length; ++i) { //Unfortunately have to cast to bounds to get the intersects method, the ecs struct only has a contains which is not the same if (worldRenderBoundsOfObstacles[i].Value.ToBounds().Intersects(pathNodeAABB.ToBounds())) { pathNode.IsTraversable = false; break; } } }) .WithDeallocateOnJobCompletion(worldRenderBoundsOfObstacles) .ScheduleParallel(this.Dependency)); this.Dependency.Complete(); this.currentTime = 0f; } }
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { WorldBounds worldBounds = WorldBoundsStaticAccessor.WorldBounds; UnityEngine.Mesh altarMesh = altarGameObject.GetComponent <UnityEngine.MeshFilter>().mesh; UnityEngine.Material altarMaterial = altarGameObject.GetComponent <UnityEngine.MeshRenderer>().material; UnityEngine.Transform altarTransform = altarGameObject.GetComponent <UnityEngine.Transform>(); using (NativeArray <Entity> altar = dstManager.CreateEntity(dstManager.CreateAltarArchetype(), 1, Allocator.Temp)) { dstManager.SetComponentData(altar[0], new Translation { Value = new float3 ( UnityEngine.Random.Range(worldBounds.XZGridWorldSpaceMin.x, worldBounds.XZGridWorldSpaceMax.x), 0f, UnityEngine.Random.Range(worldBounds.XZGridWorldSpaceMin.y, worldBounds.XZGridWorldSpaceMax.y) ) }); dstManager.SetComponentData(altar[0], new NonUniformScale { Value = altarMesh.bounds.size }); dstManager.SetComponentData(altar[0], new Rotation { Value = altarTransform.rotation }); dstManager.SetComponentData(altar[0], new PhysicsCollider { Value = BoxCollider.Create ( CollisionGeomeotrySingleton.Instance.CreateOrGetBoxGeometry(this.colliderScale), CollisionFilterSingleton.Instance.CollidesWithPlayerFilter ) }); dstManager.SetSharedComponentData <RenderMesh>(altar[0], new RenderMesh { mesh = altarMesh, material = altarMaterial }); } DestroyImmediate(this.altarGameObject); }
/// <summary> /// Constructor /// </summary> /// <param name="xBlocks">Number of x blocks to represent the world</param> /// <param name="yBlocks">Number of y blocks to represent the world</param> /// <param name="bounds">World boundries</param> public WorldGrid(int xBlocks, int yBlocks, WorldBounds bounds) { _numXBlocks = xBlocks; _numYBlocks = yBlocks; _xBlockWidth = (float)bounds.XBound / (float)xBlocks; _yBlockHeight = (float)bounds.YBound / (float)yBlocks; _buckets = new GridBucket[_numXBlocks, _numYBlocks]; // Initiliase the buckets for (int x = 0; x < _numXBlocks; x++) { for (int y = 0; y < _numYBlocks; y++) { GridBucket bucket = new GridBucket(); _buckets[x, y] = bucket; } } }
//generate walls void generatewalls() { GameObject[] walls = GameObject.FindGameObjectsWithTag("wall"); GameObject[] outerwalls = GameObject.FindGameObjectsWithTag("outerWall"); GameObject[] totalWalls = new GameObject[walls.Length + outerwalls.Length]; walls.CopyTo(totalWalls, 0); outerwalls.CopyTo(totalWalls, walls.Length); WorldBounds wb = getWorldBounds(); //placing two walls bool success = false; float xcord = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); float zcord = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); float xcord1 = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); float zcord1 = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); success = false; //try placing wall with random coordinates until valid wall placed while (!success) { success = placeWall(xcord, zcord, xcord1, zcord); } success = false; xcord = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); zcord = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); xcord1 = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); zcord1 = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); //try placing wall with random coordinates until valid wall placed while (!success) { success = placeWall(xcord, zcord, xcord, zcord1); } }
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { UnityEngine.MeshRenderer meshRenderer = this.Map.GetComponent <UnityEngine.MeshRenderer>(); dstManager.AddComponentData(entity, new PhysicsCollider { Value = BoxCollider.Create ( CollisionGeomeotrySingleton.Instance.CreateOrGetBoxGeometry(meshRenderer.bounds.size), CollisionFilterSingleton.Instance.BelongsToNonTraversableFilter ) }); Entity worldBoundsEntity = dstManager.CreateEntity(dstManager.CreateWorldBoundsArchetype()); WorldBounds worldBounds = WorldBoundsStaticAccessor.WorldBounds; dstManager.SetComponentData(worldBoundsEntity, worldBounds); using (NativeArray <Entity> pathNodes = dstManager.CreateEntity(dstManager.CreatePathnodeArchetype(), worldBounds.XZGridSize.x * worldBounds.XZGridSize.y, Allocator.Temp)) { for (int x = 0; x < worldBounds.XZGridSize.x; ++x) { for (int y = 0; y < worldBounds.XZGridSize.y; ++y) { int index = AStarUtility.CalculateIndex(x, y, worldBounds.XZGridSize.x); dstManager.SetComponentData(pathNodes[index], new PathNode { X = x, Y = y, Index = index, GCost = int.MaxValue, HCost = int.MaxValue, IsTraversable = true, //Phyisics check in MonsterPathfindingGridSystem.cs but not in FindPath Method of AStar.cs saves performance! PreviousNodeIndex = -1 }); } } } }
public bool[,] CreateImportanceMap(Vector3 lightDirection, int photonCount, WorldBounds bounds, out int importanceMapIntersectCount) { bool[,] hiresMap; importanceMapIntersectCount = 0; float width = bounds.X.Difference; float height = bounds.Y.Difference; float countRoot = (float)Math.Sqrt(photonCount); int countX = (int)Math.Ceiling((countRoot * height) / width); int countY = (int)Math.Ceiling((countRoot * width) / height); float distanceX = width / (float)countX; float distanceY = height / (float)countY; hiresMap = new bool[countX, countY]; //lightDirection *= -1; // back to original; float xPos, yPos; yPos = bounds.Y.Lower; for (int y = 0; y < countY; y++) { xPos = bounds.X.Lower; for (int x = 0; x < countX; x++) { RadiosityIntersection intersect = m_bsp[0].RadiosityIntersect(new Vector3(xPos, yPos, bounds.Z.Upper), lightDirection); // DeMorgan's Theorem FTW! hiresMap[x, y] = !(intersect.NoIntersection || intersect.WrongSide); if (hiresMap[x, y]) { importanceMapIntersectCount++; } xPos += distanceX; IncrementProgress(); } yPos += distanceY; } //importanceMap = hiresMap; return(hiresMap); }
//generate pillars void generatePillars() { WorldBounds wb = getWorldBounds(); for (int i = 0; i < noOfPillars; i++) { float xcord = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); float zcord = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); float ycord = wb.bottomleft.y; float PillarWidth = UnityEngine.Random.Range(0.5f, PillarMaxWidth); //randomly generating pillar coordinates and placing pillar. The loop continues until successfully pillar placed while (!placePillars(xcord, zcord, PillarWidth)) { xcord = wb.topleft.x + (wb.topright.x - wb.topleft.x) * UnityEngine.Random.Range(0.1f, 1.0f); zcord = wb.bottomleft.z + (wb.topleft.z - wb.bottomleft.z) * UnityEngine.Random.Range(0.1f, 1.0f); ycord = wb.bottomleft.y; PillarWidth = UnityEngine.Random.Range(0.5f, PillarMaxWidth); } } }
/// <summary> /// Begins calculating a light mapping solution. /// </summary> /// <exception cref="System.ApplicationException"> /// Thrown when no BSP is in the current scene graph. /// </exception> public void Begin() { // MdxRender.RenderDebug = false; SetOperation("Loading scenario..."); _scenario = Prometheus.Instance.ProjectManager.ScenarioTag as ScenarioBase; if (_scenario == null) { throw new RadiosityException("The current project has no scenario tag or the scenario tag is invalid."); } if (_scenario.BspList.Count <= 0) { throw new RadiosityException("The current project's scenario tag does not contain a bsp tag or the bsp tag is invalid."); } SetOperation("Retrieving lighting information..."); m_bsp = _scenario.BspList; WorldBounds bounds = m_bsp[0].WorldBounds; foreach (IBsp bsp in m_bsp) { bounds &= bsp.WorldBounds; } // We need to find the six planes of world bounds. m_worldBounds = bounds.CalculatePlanes(); // Try and obtain any lighting information. if (Prometheus.Instance.ProjectManager.ScenarioTag != null) { this.m_lights = _scenario.WorldLighting; this.m_models = _scenario.StaticModels; if (m_models == null) { m_models = new List <IModel>(); } } else { ICamera camera = MdxRender.Camera; List <RadiosityLight> lights = new List <RadiosityLight>(); this.m_lights = new List <ILight>(); m_lights.Add(new RadiosityLight(camera.Position, new RealColor(1f, 1f, 1.0f), 20f)); } // Get each lightmap from the currently loaded BSP. for (int i = 0; i < m_bsp.Count; i++) { // Add the DirectX texture to the high dynamic range texture collection. foreach (BaseTexture _texture in m_bsp[i].Lightmaps) { TextureMap _lightmap = new TextureMap(_texture); m_textures.AddTexture(_lightmap); } } // TODO: Figure out the number of photons each light gets. For now, set them all to use the same amount. float totalPower = 0f; float maxPower = 0f; foreach (ILight light in m_lights) { totalPower += light.Power; maxPower = Math.Max(light.Power, maxPower); } int directionalPhotons = 0; foreach (ILight light in m_lights) { int photonCount = (int)((float)m_maxPhotons * light.Power / totalPower);//(int)Math.Round((light.Power / totalPower) * (float)m_maxPhotons); light.PhotonCount = photonCount; light.Color.Multiply(light.Power); if (light is DirectionalLight) { directionalPhotons += photonCount; } } bool[,] importance; int count; ChangeStage(RadiosityStage.CreatingImportanceMap, directionalPhotons); SetOperation("Optimizing Pass..."); for (int l = 0; l < m_lights.Count; l++) { if (m_lights[l] is DirectionalLight) { DirectionalLight light = m_lights[l] as DirectionalLight; if (light.PhotonCount > 0) { importance = CreateImportanceMap(light.Direction, light.PhotonCount, bounds, out count); } else { importance = null; count = 0; } RadiosityHelper.ImportanceMap = importance; RadiosityHelper.ImportanceMapOnPixels = count; } } //currentOperation = "Saving any unsaved data..."; //this.SaveAll(); photonMap = new PhotonMap(m_maxBounces * m_maxPhotons); SetOperation("Perform radiosity..."); // Process collisions. this.ProcessCollisions(); ChangeStage(RadiosityStage.Done, 100); Interfaces.Output.Write(Interfaces.OutputTypes.Information, m_photonsLost + " photon(s) lost during radiosity."); if (OnComplete != null) { OnComplete(); } }
private void CreateLightmaps() { // Stage 2: Render onto lightmaps // * Step 1: Initialize // * Step 2: Iterate through textures // * Iterate through materials // * Compute a pixel rectangle for the current material // * Iterate through the pixels in the material // * Convert the UV pixel coordinates to a 3D point // * Gather n photons that are on that surface int screenWidth = MdxRender.Device.Viewport.Width; int screenHeight = MdxRender.Device.Viewport.Height; float dist2 = RadiosityHelper.GatherDistance * RadiosityHelper.GatherDistance; if (m_bsp == null) { _scenario = Prometheus.Instance.ProjectManager.ScenarioTag as ScenarioBase; if (_scenario == null) { throw new RadiosityException("The current project has no scenario tag or the scenario tag is invalid."); } if (_scenario.BspList.Count <= 0) { throw new RadiosityException("The current project's scenario tag does not contain a bsp tag or the bsp tag is invalid."); } SetOperation("Retrieving lighting information..."); m_bsp = _scenario.BspList; WorldBounds bounds = m_bsp[0].WorldBounds; foreach (IBsp bsp in m_bsp) { bounds &= bsp.WorldBounds; } // We need to find the six planes of world bounds. m_worldBounds = bounds.CalculatePlanes(); for (int i = 0; i < m_bsp.Count; i++) { // Add the DirectX texture to the high dynamic range texture collection. foreach (BaseTexture _texture in m_bsp[i].Lightmaps) { TextureMap _lightmap = new TextureMap(_texture); m_textures.AddTexture(_lightmap); } } } Vector3 badPoint = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); string path = (Prometheus.Instance.ProjectManager.ProjectFolder as DiskFileLibrary).RootPath + "LightMaps\\"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } //float dist2 = RadiosityHelper.GatherDistance * RadiosityHelper.GatherDistance; if ((photonMap != null) && (photonMap.store.Length > 0)) { int totalPixels = 0; foreach (TextureMap texMap in m_textures) { totalPixels += (int)Math.Ceiling(texMap.Width * texMap.Height * RadiosityHelper.LightmapScale * RadiosityHelper.LightmapScale); } ChangeStage(RadiosityStage.TextureGeneration, totalPixels); int texIndex = 0; float hemisphereSizeDivisor = 1f / ((float)Math.PI * dist2); float maxIntensity = float.MinValue; foreach (TextureMap texMap in m_textures) { CreateLightmap(dist2, badPoint, path, texIndex, hemisphereSizeDivisor, texMap, ref maxIntensity); texIndex++; } } UpdateViewportLightmaps(); }
void Awake() { Instance = this; }
private static int WorldSpaceToCell(float worldSpaceCoordinate, int offset, int min, int max, WorldBounds worldBounds) { //Have to clamp the value, otherwise flooring will make certain values fall below 0 or above grid size because the mesh is too big etc. return((int)(math.clamp(math.floor((worldSpaceCoordinate - offset) / worldBounds.WorldSpaceCellSize), min, max))); }
private static float CellToWorldSpace(int coordinate, int offset, WorldBounds worldBounds) { return(worldBounds.WorldSpaceCellSize * coordinate + offset); }