Lighting seams between dynamically created quads
I realize that there are many different questions about similar issues, but I've been unable to find a resolution to this one. I'm randomly filling a 2d grid, then drawing a tile at each point and adding a light on top of that tile. This is leading to a strange visual effect you can see in this screenshot:
The texture is seamless, and the lighting seems to be odd at the margins as well. The normal for each vertex is simply pointed upward, which I believe is correct.
Code below:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Code.Generators{
public class RoomGenerator : MonoBehaviour
{
public float resolution;
public float height;
public float width;
[Range(1,4)]
public int iterationSize;
[Range(0,1)]
public float fillRatio;
private int vertHeight;
private int vertWidth;
private bool[,] dualSpace;
private int[,] meshSpaceMapping;
private DualPoint[] activePoints;
private const int defaultValue = -1;
private GameObject floorHolder;
private GameObject lightHolder;
private GameObject wallHolder;
void Start(){
DrawFloor(Random.Range(0, 100));
}
public void DrawFloor(int seed){
if (floorHolder == null){
floorHolder = new GameObject("FloorHolder");
floorHolder.transform.parent = gameObject.transform;
}
vertWidth = Mathf.CeilToInt(width/resolution);
vertHeight = Mathf.CeilToInt(height/resolution);
meshSpaceMapping = new int[vertWidth,vertHeight];
for (int i=0;i<vertWidth * vertHeight;i++)
{
meshSpaceMapping[i % vertWidth, i / vertWidth] = defaultValue;
}
GenerateFillDual(seed);
GenerateMeshFromFillData();
}
private void LightFloor(DualPoint floorTile){
if (lightHolder == null){
lightHolder = new GameObject("LightHolder");
lightHolder.transform.parent = gameObject.transform;
}
Vector3 thisPosition = new Vector3((floorTile.x + 0.5f) * resolution, 100, (floorTile.z + 0.5f) * resolution);
GameObject newLight = new GameObject(string.Format("LightFor{0}", floorTile.GetName()));
newLight.transform.parent = lightHolder.transform;
Light thisLight = newLight.AddComponent<Light>();
thisLight.type = LightType.Point;
thisLight.range = 150;
thisLight.intensity = 8;
thisLight.transform.position = thisPosition;
}
private void GenerateMeshFromFillData()
{
for (int i = 0; i < activePoints.Length; i++){
GenerateFloorTile(activePoints[i]);
}
}
private void GenerateFloorTile(DualPoint dualPoint, bool light=true){
GameObject floorTile = new GameObject();
floorTile.transform.parent = floorHolder.transform;
floorTile.name = dualPoint.GetName();
MeshRenderer meshRenderer = floorTile.AddComponent<MeshRenderer>();
meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
Texture2D floorTexture = new Texture2D(128, 128);
if (dualPoint.type == DualPoint.PointType.Wood){
floorTexture = Resources.Load<Texture2D>("Textures/SeamlessWood");
} else if (dualPoint.type == DualPoint.PointType.Marble){
floorTexture = Resources.Load<Texture2D>("Textures/SeamlessMarble");
}
meshRenderer.sharedMaterial.SetTexture("_MainTex", floorTexture);
MeshFilter meshFilter = floorTile.AddComponent<MeshFilter>();
Mesh mesh = new Mesh();
mesh.vertices = new Vector3[]{
new Vector3(dualPoint.x * resolution, 0, dualPoint.z * resolution),
new Vector3((dualPoint.x + 1) * resolution, 0, dualPoint.z * resolution),
new Vector3(dualPoint.x * resolution, 0, (dualPoint.z + 1) * resolution),
new Vector3((dualPoint.x +1) * resolution, 0, (dualPoint.z+1) * resolution)
};
mesh.triangles = new int[]{1, 0, 3, 0, 2, 3};
mesh.uv = new Vector2[]{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.normals = new Vector3[]{Vector3.up, Vector3.up, Vector3.up, Vector3.up};
meshFilter.mesh = mesh;
MeshCollider meshCollider = floorTile.AddComponent<MeshCollider>();
if (light){
LightFloor(dualPoint);
}
}
private void GenerateFillDual(int seed){
Random.InitState(seed);
dualSpace = new bool[vertWidth-1, vertHeight-1];
// Prohibit spawning on an edge
DualPoint firstPoint = new DualPoint{x=Random.Range(1, vertWidth-2), z=Random.Range(1, vertHeight-2), type=DualPoint.PointType.Wood};
int desiredSize = (int) (((vertWidth-1) * (vertHeight-1)) * fillRatio);
Debug.Log(desiredSize);
if (activePoints == null){
activePoints = new DualPoint[desiredSize];
}
activePoints[0] = firstPoint;
List<DualPoint> candidateList = new List<DualPoint>();
int activeCounter = 0;
activatePoint(firstPoint, candidateList);
activeCounter++;
while (activeCounter < desiredSize){
int newPoints = Mathf.Min(iterationSize, desiredSize - activeCounter);
List<DualPoint> selectedCandidates = candidateList.OrderBy(x => Random.Range(0f, 1f)).Take(newPoints).Distinct().ToList();
foreach (DualPoint dp in selectedCandidates){
activePoints[activeCounter] = dp;
activatePoint(dp, candidateList);
activeCounter++;
}
}
}
private void activatePoint(DualPoint newPoint, List<DualPoint> candidateList){
dualSpace[newPoint.x, newPoint.z] = true;
candidateList.RemoveAll(item => item.Equals(newPoint));
DualPoint[] newPoints = {
new DualPoint{x=newPoint.x - 1, z=newPoint.z, type=DualPoint.PointType.Wood},
new DualPoint{x=newPoint.x + 1, z=newPoint.z, type=DualPoint.PointType.Wood},
new DualPoint{x=newPoint.x, z=newPoint.z - 1, type=DualPoint.PointType.Wood},
new DualPoint{x=newPoint.x, z=newPoint.z + 1, type=DualPoint.PointType.Wood},
};
for (int i = 0; i < newPoints.Length; i++){
if (IsValid(newPoints[i]) && !dualSpace[newPoints[i].x, newPoints[i].z]){
candidateList.Add(newPoints[i]);
}
}
}
private bool IsValid(DualPoint testPoint){
if (testPoint.x < 0 || testPoint.z < 0){
return false;
}
if (testPoint.x > (dualSpace.GetLength(0)-1) || testPoint.z > (dualSpace.GetLength(1)-1)){
return false;
}
return true;
}
}
public struct DualPoint{
public int x;
public int z;
public enum PointType {Wood, Marble};
public PointType type;
public bool Equals(DualPoint obj) => x == obj.x && z == obj.z;
public string GetName() => string.Format("{0} Tile {1}{2}", type.ToString(), x, z);
}
}
Your answer
Follow this Question
Related Questions
How can I identify the location of mesh triangles at run time? (Procedural Generation) 1 Answer
Marching Cubes - Triangles not creating 1 Answer
Procedural Mesh Generation with Mathf.PerlinNoise Creates Flat, Irregular Terrain 0 Answers
Terrain from perlin noise grid pattern in shadows 1 Answer
How can I reference a specific set of triangles or quads in a procedurally generated mesh? 0 Answers