Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by evan_unity · Dec 14, 2020 at 12:17 PM · 2dlightingtilemap

How can I make my lighting travel to other chunks?

I have a custom lighting system using tilemaps, and the lighting is handled in the chunk because I found that that's the easiest and has the best performance. My lighting currently looks like this: alt text

The lighting looks good, but there is one issue: light in chunks don't affect neighboring chunks. What is the best way to achieve this?

My Chunk script (where the lighting happens): using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps;

 public class Chunk : MonoBehaviour
 {
     [Header("Surface World Gen Values")]
     public int seed;
 
     public float surfaceFrequency;
     public float surfaceAmplitude;
     public int surfaceOctives;
     public float surfacePersistence;
     public float surfaceLacunarity;
 
     [Header("Cave World Gen Values")]
     [SerializeField] List<NoiseLayer> caveNoiseLayers;
 
     [Header("World Stats")]
     public int chunkSize = 4;
 
     public int baseGroundHeight = 50;
     public int minGroundHeight = 30;
     public int maxGroundHeight = 80;
 
     public int offsetX;
     public int offsetY;
 
     [Header("World")]
     public TileType[,] chunkMap;
 
     [Header("World Display")]
     [SerializeField] Tilemap chunkTilemap;
     [SerializeField] Tilemap lightingTilemap;
 
     [Header("Items")]
     [SerializeField] ItemObject itemObjectPrefab;
 
     [SerializeField] float[,] lighting;
     [SerializeField] Tile lightTile;
 
     DB_Tiles dbTiles;
     DB_Items dbItems;
 
     World world;
 
     PlayerController player;
 
     void Awake()
     {
         dbTiles = FindObjectOfType<DB_Tiles>();
         dbItems = FindObjectOfType<DB_Items>();
         world = FindObjectOfType<World>();
 
         player = FindObjectOfType<PlayerController>();
     }
 
     void Update()
     {
         if (Vector3.Distance(transform.position, player.transform.position) > player.chunkDistanceX * (chunkSize / 2) + (chunkSize / 2))
         {
             world.RemoveChunk(this);
             Destroy(gameObject);
         }
 
         CalculateLighting();
     }
 
     public void InitializeChunk(int _seed, float _surfFreq, float _surfAmpl, int _surfOct, float _surfPers, float _surgLac, List<NoiseLayer> _caveNoiseLayers, int _chunkSize, int _baseGroundHeight,
         int _minGroundHeight, int _maxGroundHeight, int _offsetX, int _offsetY)
     {
         seed = _seed;
         surfaceFrequency = _surfFreq;
         surfaceAmplitude = _surfAmpl;
         surfaceOctives = _surfOct;
         surfacePersistence = _surfPers;
         surfaceLacunarity = _surgLac;
 
         caveNoiseLayers = _caveNoiseLayers;
 
         chunkSize = _chunkSize;
 
         baseGroundHeight = _baseGroundHeight;
         minGroundHeight = _minGroundHeight;
         maxGroundHeight = _maxGroundHeight;
 
         offsetX = _offsetX;
         offsetY = _offsetY;
 
         CreateVirtualWorld();
     }
 
     void CreateVirtualWorld()
     {
         chunkMap = new TileType[chunkSize, chunkSize];
 
         for (int x = 0; x < chunkSize; x++)
         {
             for (int y = 0; y < chunkSize; y++)
             {
                 Vector3Int chunkPos = world.WorldToTilePos(transform.position);
                 Vector2 currentPos = new Vector2(x + chunkPos.x - offsetX, y + chunkPos.y - offsetY);
 
                 float perlinY = Mathf.FloorToInt(Noise.Noise1D(currentPos.x + seed, surfaceFrequency, surfaceAmplitude, surfaceOctives, surfacePersistence, surfaceLacunarity) + baseGroundHeight);
 
                 // Basic Terrain
                 if (perlinY > currentPos.y + 10)
                     chunkMap[x, y] = dbTiles.GetTileByName("Stone");
                 else if (perlinY > currentPos.y)
                     chunkMap[x, y] = dbTiles.GetTileByName("Dirt");
                 else if (perlinY == currentPos.y)
                     chunkMap[x, y] = dbTiles.GetTileByName("Grass");
                 else
                     chunkMap[x, y] = dbTiles.GetTileByName("Air");
 
                 // Caves
                 for (int i = caveNoiseLayers.Count - 1; i >= 0; i--)
                 {
                     if (caveNoiseLayers[i].enabled)
                     {
                         float freq = caveNoiseLayers[i].frequency;
                         float ampl = caveNoiseLayers[i].amplitude;
                         int oct = caveNoiseLayers[i].octives;
                         float pers = caveNoiseLayers[i].persistence;
                         float lac = caveNoiseLayers[i].lacunarity;
                         float layerX = currentPos.x + seed + caveNoiseLayers[i].offsetX;
                         float layerY = currentPos.y + seed + caveNoiseLayers[i].offsetY;
                         float thres = caveNoiseLayers[i].threshold;
 
                         if (perlinY > currentPos.y + caveNoiseLayers[i].minDistBelowSurface && perlinY < currentPos.y + caveNoiseLayers[i].maxDistBelowSurface)
                         {
                             if (Noise.Noise2D(layerX, layerY, freq, ampl, oct, pers, lac) < thres)
                             {
                                 chunkMap[x, y] = dbTiles.GetTileByName(caveNoiseLayers[i].tileName);
                             }
                         }
                     }
                 }
             }
         }
 
         CreatePhysicalWorld();
     }
 
     void CreatePhysicalWorld()
     {
         for (int x = 0; x < chunkSize; x++)
         {
             for (int y = 0; y < chunkSize; y++)
             {
                 //Vector3Int chunkPos = world.WorldToTileUnit(transform.position + new Vector3(-chunkSize, -chunkSize));
                 chunkTilemap.transform.position = transform.position;
 
                 Vector3Int tilePos = new Vector3Int(Mathf.FloorToInt(x), Mathf.FloorToInt(y), 0);
                 chunkTilemap.SetTile(tilePos, chunkMap[x, y].tile);
             }
         }
 
         CalculateLighting();
 
         FindObjectOfType<PlayerController>().InitializePlayer();
     }
 
     void CalculateLighting()
     {
         lighting = new float[chunkSize, chunkSize];
 
         // Get lights in chunk
         for (int x = 0; x < chunkSize; x++)
         {
             for (int y = 0; y < chunkSize; y++)
             {
                 if (chunkMap[x, y].emissive)
                 {
                     if (lighting[x, y] < chunkMap[x, y].lightStrength)
                         lighting[x, y] = chunkMap[x, y].lightStrength;
 
                     List<int> lightX = new List<int>();
                     List<int> lightY = new List<int>();
                     lightX.Add(x);
                     lightY.Add(y);
 
                     while (lightX.Count > 0)
                     {
                         float thisLighting = lighting[lightX[0], lightY[0]] * 0.5f;
                         if (lightX[0] + 1 < chunkSize && lighting[lightX[0] + 1, lightY[0]] < thisLighting)
                         {
                             lighting[lightX[0] + 1, lightY[0]] = thisLighting;
                             if (lighting[lightX[0] + 1, lightY[0]] > 0.05f)
                             {
                                 lightX.Add(lightX[0] + 1);
                                 lightY.Add(lightY[0]);
                             }
                         }
                         if (lightX[0] - 1 >= 0 && lighting[lightX[0] - 1, lightY[0]] < thisLighting)
                         {
                             lighting[lightX[0] - 1, lightY[0]] = thisLighting;
                             if (lighting[lightX[0] - 1, lightY[0]] > 0.05f)
                             {
                                 lightX.Add(lightX[0] - 1);
                                 lightY.Add(lightY[0]);
                             }
                         }
 
                         if (lightY[0] + 1 < chunkSize && lighting[lightX[0], lightY[0] + 1] < thisLighting)
                         {
                             lighting[lightX[0], lightY[0] + 1] = thisLighting;
                             if (lighting[lightX[0], lightY[0] + 1] > 0.05f)
                             {
                                 lightX.Add(lightX[0]);
                                 lightY.Add(lightY[0] + 1);
                             }
                         }
                         if (lightY[0] - 1 >= 0 && lighting[lightX[0], lightY[0] - 1] < thisLighting)
                         {
                             lighting[lightX[0], lightY[0] - 1] = thisLighting;
                             if (lighting[lightX[0], lightY[0] - 1] > 0.05f)
                             {
                                 lightX.Add(lightX[0]);
                                 lightY.Add(lightY[0] - 1);
                             }
                         }
 
                         lightX.RemoveAt(0);
                         lightY.RemoveAt(0);
                     }
                 }
             }
         }
 
         VisualizeLighting();
     }
 
     void VisualizeLighting()
     {
         // Visualize the lighting
         for (int x = 0; x < chunkSize; x++)
         {
             for (int y = 0; y < chunkSize; y++)
             {
                 Vector3Int tilePos = new Vector3Int(x, y, 0);
                 lightingTilemap.SetTile(tilePos, lightTile);
 
                 lightingTilemap.SetTileFlags(tilePos, TileFlags.None);
 
                 lightingTilemap.SetColor(tilePos, new Color(0, 0, 0, 1f - Mathf.Min(lighting[x, y], 1)));
             }
         }
     }
 
     public void TryDestroyTile(Vector2 destroyPos)
     {
         Vector3Int tilePos = chunkTilemap.WorldToCell(destroyPos);
         if (chunkMap[tilePos.x, tilePos.y].name != "Air")
         {
             TileType tileDestroyed = chunkMap[tilePos.x, tilePos.y];
             ItemObject newItem = Instantiate(itemObjectPrefab);
 
             newItem.transform.position = chunkTilemap.CellToWorld(new Vector3Int(tilePos.x, tilePos.y, tilePos.z)) + new Vector3(0.25f, 0.25f);
             if (tileDestroyed.name != "Grass")
                 newItem.StartItem(dbItems.GetItemByName(tileDestroyed.name));
             else
                 newItem.StartItem(dbItems.GetItemByName("Dirt"));
             chunkMap[tilePos.x, tilePos.y] = dbTiles.GetTileByName("Air");
             chunkTilemap.SetTile(tilePos, null);
         }
     }
 
     public void PlaceTile(Vector2 placePos, string tileName)
     {
         Vector3Int tilePos = chunkTilemap.WorldToCell(placePos);
         chunkMap[tilePos.x, tilePos.y] = dbTiles.GetTileByName(tileName);
         chunkTilemap.SetTile(tilePos, dbTiles.GetTileByName(tileName).tile);
     }
 
     public bool IsTouchingPlayer(Vector2 checkPos)
     {
         Vector3Int tilePos = chunkTilemap.WorldToCell(checkPos);
         Collider2D touching = Physics2D.OverlapBox(new Vector2((float)tilePos.x / 2f + 0.25f, (float)tilePos.y / 2f + 0.25f), new Vector2(0.49f, 0.49f), 0, LayerMask.GetMask("Player"));
         return touching;
     }
 
     public bool TileExistsAtPoint(Vector2 checkPos)
     {
         Vector3Int tilePos = chunkTilemap.WorldToCell(checkPos);
         return chunkTilemap.GetTile(tilePos) != null;
     }
 
     public bool HasTileAround(Vector2 checkPos)
     {
         Vector3Int tilePos = chunkTilemap.WorldToCell(checkPos);
 
         if (chunkTilemap.GetTile(new Vector3Int(tilePos.x + 1, tilePos.y, tilePos.z)) != null)
         {
             return true;
         }
         else if (chunkTilemap.GetTile(new Vector3Int(tilePos.x - 1, tilePos.y, tilePos.z)) != null)
         {
             return true;
         }
         else if (chunkTilemap.GetTile(new Vector3Int(tilePos.x, tilePos.y + 1, tilePos.z)) != null)
         {
             return true;
         }
         else if (chunkTilemap.GetTile(new Vector3Int(tilePos.x, tilePos.y - 1, tilePos.z)) != null)
         {
             return true;
         }
 
         return false;
     }
 }
 

My world script (where the chunks are made and stored: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps;

 public class World : MonoBehaviour
 {
     [Header("Surface World Gen Values")]
     public bool randomizeSeed;
     public int seed;
 
     public float surfaceFrequency;
     public float surfaceAmplitude;
     public int surfaceOctives;
     public float surfacePersistence;
     public float surfaceLacunarity;
 
     [Header("Cave World Gen Values")]
     [SerializeField] List<NoiseLayer> caveNoiseLayers;
 
     [Header("World Stats")]
     public int chunkSize = 4;
     public int worldSizeX = 100;
     public int worldSizeY = 100;
 
     public int baseGroundHeight = 50;
     public int minGroundHeight = 30;
     public int maxGroundHeight = 80;
 
     public bool centerX;
     public int offsetX;
     public bool autoY;
     public int offsetY;
 
     [Header("World")]
     public TileType[,] worldMap;
     [SerializeField] Chunk chunkPrefab;
 
     [Header("World Display")]
     [SerializeField] Tilemap worldTilemap;
 
     [Header("Items")]
     [SerializeField] ItemObject itemObjectPrefab;
 
     [Header("Chunks")]
     List<Chunk> chunks = new List<Chunk>();
     [SerializeField] List<Vector3Int> chunksToGenerate = new List<Vector3Int>();
 
     DB_Tiles dbTiles;
     DB_Items dbItems;
 
     public void InitializeWorld()
     {
         dbTiles = FindObjectOfType<DB_Tiles>();
         dbItems = FindObjectOfType<DB_Items>();
 
         if (centerX)
             offsetX = -(worldSizeX * chunkSize) / 2;
 
         if (autoY)
             offsetY = -worldSizeY * chunkSize;
     }
 
     public void SetGenerateChunk(Vector3Int chunkPos)
     {
         if (GetChunkAtPos(new Vector2(chunkPos.x, chunkPos.y)) == null && !chunksToGenerate.Contains(chunkPos))
             chunksToGenerate.Add(chunkPos);
     }
 
     public void GenerateChunk(Vector3Int chunkPos)
     {
         if (GetChunkAtPos(new Vector2(chunkPos.x, chunkPos.y)) == null)
         {
             Chunk newChunk = Instantiate(chunkPrefab, chunkPos, Quaternion.identity, transform);
             newChunk.InitializeChunk(seed, surfaceFrequency, surfaceAmplitude, surfaceOctives, surfacePersistence, surfaceLacunarity, caveNoiseLayers,
                 chunkSize, baseGroundHeight, minGroundHeight, maxGroundHeight, offsetX, offsetY);
             chunks.Add(newChunk);
         }
     }
 
     public Vector2 TileToWorldPos(Vector3Int tilePos)
     {
         Vector2 worldPos = worldTilemap.CellToWorld(tilePos);
         worldPos += new Vector2(0.25f, 0.25f);
         return worldPos;
     }
 
     public Vector3Int WorldToTilePos(Vector2 worldPos)
     {
         Vector3Int tilePos = worldTilemap.WorldToCell(worldPos);
         return tilePos;
     }
 
     public Vector3Int WorldToTileUnit(Vector2 worldPos)
     {
         worldPos /= 2;
         Vector3Int tileUnitPos = new Vector3Int(Mathf.RoundToInt(worldPos.x), Mathf.RoundToInt(worldPos.y), 0);
         return tileUnitPos;
     }
 
     public Chunk GetChunkAtPos(Vector2 pos)
     {
         pos /= chunkSize / 2;
         Vector3 convertedPos = new Vector3(Mathf.Floor(pos.x), Mathf.Floor(pos.y));
         convertedPos *= chunkSize / 2;
         for (int i = 0; i < chunks.Count; i++)
         {
             if (chunks[i].transform.position == convertedPos)
             {
                 return chunks[i];
             }
         }
 
         return null;
     }
 
     public Vector2 GetPosAsChunk(Vector2 pos)
     {
         pos /= chunkSize / 2;
         Vector3 convertedPos = new Vector3(Mathf.Floor(pos.x), Mathf.Floor(pos.y));
         convertedPos *= 5;
         return convertedPos;
     }
 
     void Update()
     {
         if (chunksToGenerate.Count > 0)
         {
             GenerateChunk(chunksToGenerate[0]);
             chunksToGenerate.RemoveAt(0);
         }
     }
 
     public void RemoveChunk(Chunk chunkToRemove)
     {
         chunks.Remove(chunkToRemove);
     }
 }
 
lighting.png (9.1 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

347 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

2D Light question 1 Answer

2D Point Light not working correctly on Tilemaps 1 Answer

Default Tilemap Material not affected by light 1 Answer

Why is 200x100 Tile Taking 3 100x100 Grid Spaces? 0 Answers

Ambient Light not working with some objects 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges