//Setup all the papi lights. private void SetupPapiLights(ref List <SpriteLights.LightData> lightData, RunwayData runwayData, bool randomBrightness) { for (int side = 0; side < 2; side++) { if (runwayData.papiType[side] != PapiType.NONE) { //Calculate the offset direction. Vector3 lengthOffsetDir = Math3d.GetForwardVector(runwayData.rotation[side]); Vector3 sideOffsetDir = Math3d.GetRightVector(runwayData.rotation[side]); Vector3 lengthEdgeOffsetVec = Math3d.SetVectorLength(lengthOffsetDir, 337f); if ((runwayData.papiType[side] == PapiType.PAPIRIGHT) || (runwayData.papiType[side] == PapiType.PAPIBOTH)) { Vector3 startOffsetVec = lengthEdgeOffsetVec + Math3d.SetVectorLength(sideOffsetDir, (runwayData.width * 0.5f) + 15f); Vector3 startPosition = runwayData.thresholdPosition[side] + startOffsetVec; Vector3 currentPosition = startPosition; Vector3 sideOffsetVec = Math3d.SetVectorLength(sideOffsetDir, 9f); for (int i = 0; i < 4; i++) { SpriteLights.LightData data = new SpriteLights.LightData(); float angle = GetPapiAngle(i); data.position = currentPosition; data.rotation = runwayData.rotation[side] * Quaternion.Euler(Vector3.right * angle); lightData.Add(data); currentPosition += sideOffsetVec; } } if ((runwayData.papiType[side] == PapiType.PAPILEFT) || (runwayData.papiType[side] == PapiType.PAPIBOTH)) { sideOffsetDir *= -1; Vector3 startOffsetVec = lengthEdgeOffsetVec + Math3d.SetVectorLength(sideOffsetDir, (runwayData.width * 0.5f) + 15f); Vector3 startPosition = runwayData.thresholdPosition[side] + startOffsetVec; Vector3 currentPosition = startPosition; Vector3 sideOffsetVec = Math3d.SetVectorLength(sideOffsetDir, 9f); for (int i = 0; i < 4; i++) { SpriteLights.LightData data = new SpriteLights.LightData(); float angle = GetPapiAngle(i); data.position = currentPosition; data.rotation = runwayData.rotation[side] * Quaternion.Euler(Vector3.right * angle); lightData.Add(data); currentPosition += sideOffsetVec; } } } } }
//Create a light mesh object. Cram as much lights as you can into the LightData array. If there are too many lights for one GameObject, it will //automatically be split into multiple objects. public static GameObject[] CreateLights(string name, LightData[] lightData, Material material) { int transformAmount = lightData.Length; int lightsInThisBatch; //The triangle limit is 21844 (65534 vertices) per mesh, so split the objects up if needed. int meshAmount = (int)Mathf.Ceil(transformAmount / (float)maxTriangleAmount); GameObject[] lightObjects = new GameObject[meshAmount]; //Get the remainder. int remainder = (int)(transformAmount % (float)maxTriangleAmount); //Loop through the mesh batches. for (int l = 0; l < meshAmount; l++) { //Get the amount of lights in this mesh batch. if (meshAmount == 1) { lightsInThisBatch = transformAmount; } else { //Last mesh batch. if (l == (meshAmount - 1)) { if (remainder == 0) { lightsInThisBatch = maxTriangleAmount; } else { lightsInThisBatch = remainder; } } else { lightsInThisBatch = maxTriangleAmount; } } int vertexCount = lightsInThisBatch * 3; Vector4[] corners = new Vector4[vertexCount]; Vector2[] uvs = new Vector2[vertexCount]; Vector4[] triangleCorners = new Vector4[3]; Vector2[] triangleUvs = new Vector2[3]; bool directional = false; bool omnidirectional = false; bool strobe = false; bool papi = false; Vector3 normal = Vector3.one; Vector3 right = Vector3.one; Vector3 up = Vector3.one; //Create temporary arrays. Vector3[] centers = new Vector3[vertexCount]; Vector3[] normals = new Vector3[vertexCount]; int[] triangles = new int[vertexCount]; int[] indices = new int[vertexCount]; //What is stored in here, depends on the shader. Vector2[] uv3Channel = new Vector2[vertexCount]; Vector2[] uv2Channel = new Vector2[vertexCount]; Vector2[] uv4Channel = new Vector2[vertexCount]; Color[] colorChannel = new Color[vertexCount]; if (material.shader.name.Contains("Directional")) { directional = true; } if (material.shader.name.Contains("Omnidirectional")) { omnidirectional = true; } if (material.shader.name.Contains("Strobe")) { strobe = true; } if (material.shader.name.Contains("PAPI")) { papi = true; } //Loop through all the lights and set them up. for (int i = 0; i < lightsInThisBatch; i++) { int e = i * 3; int e1 = e + 1; int e2 = e + 2; int index = (l * maxTriangleAmount) + i; //Generate a triangle which fits over a quad. GenerateTriangle(out triangleCorners, out triangleUvs, lightData[index].size, Quaternion.identity); centers[e] = lightData[index].position; centers[e1] = lightData[index].position; centers[e2] = lightData[index].position; //Get the rotation vectors. normal = -Math3d.GetForwardVector(lightData[index].rotation); right = Math3d.GetRightVector(lightData[index].rotation); up = Math3d.GetUpVector(lightData[index].rotation); //Store the scale offset in the w component of the triangle corner. triangleCorners[0] = new Vector4(triangleCorners[0].x, triangleCorners[0].y, triangleCorners[0].z, lightData[index].size); triangleCorners[1] = new Vector4(triangleCorners[1].x, triangleCorners[1].y, triangleCorners[1].z, lightData[index].size); triangleCorners[2] = new Vector4(triangleCorners[2].x, triangleCorners[2].y, triangleCorners[2].z, lightData[index].size); corners[e] = triangleCorners[0]; corners[e1] = triangleCorners[1]; corners[e2] = triangleCorners[2]; uvs[e] = triangleUvs[0]; uvs[e1] = triangleUvs[1]; uvs[e2] = triangleUvs[2]; normals[e] = normal; normals[e1] = normal; normals[e2] = normal; if (papi) { uv2Channel[e] = right; uv2Channel[e1] = right; uv2Channel[e2] = right; uv3Channel[e] = up; uv3Channel[e1] = up; uv3Channel[e2] = up; //Compose the z vector. Vector2 zVector = new Vector2(right.z, up.z); uv4Channel[e] = zVector; uv4Channel[e1] = zVector; uv4Channel[e2] = zVector; } if (directional) { //Create the back color. Vector2 RG = new Vector2(lightData[index].backColor.r, lightData[index].backColor.g); Vector2 BA = new Vector2(lightData[index].backColor.b, lightData[index].backColor.a); uv2Channel[e] = RG; uv2Channel[e1] = RG; uv2Channel[e2] = RG; uv3Channel[e] = BA; uv3Channel[e1] = BA; uv3Channel[e2] = BA; } if (omnidirectional) { //Create the back color. Vector2 RG = new Vector2(lightData[index].backColor.r, lightData[index].backColor.g); uv2Channel[e] = RG; uv2Channel[e1] = RG; uv2Channel[e2] = RG; uv3Channel[e] = up; uv3Channel[e1] = up; uv3Channel[e2] = up; //Compose the z vector. The x component is used for the blue component of the back color. Vector2 zVector = new Vector2(lightData[index].backColor.b, up.z); uv4Channel[e] = zVector; uv4Channel[e1] = zVector; uv4Channel[e2] = zVector; } if (strobe) { //Store the light and group id in the color channel. Color id = new Color(lightData[index].strobeID, lightData[index].strobeGroupID, 0, 0); colorChannel[e] = id; colorChannel[e1] = id; colorChannel[e2] = id; } if (directional || omnidirectional) { //Create the front color. Note that the light brightness value is stored in the alpha channel. Color frontColor = new Color(lightData[index].frontColor.r, lightData[index].frontColor.g, lightData[index].frontColor.b, lightData[index].brightness); colorChannel[e] = frontColor; colorChannel[e1] = frontColor; colorChannel[e2] = frontColor; } triangles[e] = e; triangles[e1] = e1; triangles[e2] = e2; indices[e] = e; indices[e1] = e1; indices[e2] = e2; } //Create a new gameObject. GameObject lightObject = new GameObject(name + " " + l); lightObjects[l] = lightObject; //Add the required components to the game object. MeshFilter meshFilter = lightObject.AddComponent <MeshFilter>(); MeshRenderer meshRenderer = lightObject.AddComponent <MeshRenderer>(); //Create a new mesh. meshFilter.sharedMesh = new Mesh(); //Apply the mesh properties meshFilter.sharedMesh.vertices = centers; meshFilter.sharedMesh.tangents = corners; //The mesh corner is stored in the tangent channel. The scale is stored in the w component. meshFilter.sharedMesh.normals = normals; meshFilter.sharedMesh.uv = uvs; meshFilter.sharedMesh.triangles = triangles; meshFilter.sharedMesh.colors = colorChannel; //Front color for directional lights. Alpha is the brightness reduction. //ID for strobe lights. meshFilter.sharedMesh.uv2 = uv2Channel; //RG(BA) back color for directional lights. //Rotation vector for omnidirectional lights and PAPIs. meshFilter.sharedMesh.uv3 = uv3Channel; //(RG)BA back color for directional lights. Alpha is for invisibility. //Rotation vector for omnidirectional lights and PAPIS. meshFilter.sharedMesh.uv4 = uv4Channel; //The UV channels only hold two floats, so use a third UV channel to store the Z components of the vectors. //Set the indices. meshFilter.sharedMesh.SetIndices(indices, MeshTopology.Triangles, 0); //Set the gameObject properties; meshRenderer.sharedMaterial = material; meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; meshRenderer.receiveShadows = false; meshRenderer.useLightProbes = false; meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; } return(lightObjects); }
//Setup all the threshold lights. private void SetupThresholdLights(ref List <SpriteLights.LightData> lightData, RunwayData runwayData, bool randomBrightness, float brightness, float size) { for (int side = 0; side < 2; side++) { //Calculate the amount of lights. int lightAmountInRow = (int)Mathf.Ceil(runwayData.width / thresholdLightsSpacing); //Calculate the width of the threshold light row. float rowWidth = (lightAmountInRow - 1) * thresholdLightsSpacing; //Set start position. Vector3 sideOffsetDir = Math3d.GetRightVector(runwayData.rotation[side]); Vector3 startOffsetAVec = Math3d.SetVectorLength(sideOffsetDir, rowWidth * 0.5f); Vector3 startPosition = runwayData.thresholdPosition[side] + startOffsetAVec; Vector3 thresholdACorner = startPosition; Vector3 currentPosition = startPosition; Vector3 sideOffsetVec = Math3d.SetVectorLength(-sideOffsetDir, thresholdLightsSpacing); SpriteLights.LightData data; //Create lights. for (int i = 0; i < lightAmountInRow; i++) { data = new SpriteLights.LightData(); data.position = currentPosition; data.rotation = runwayData.rotation[side]; data.frontColor = greenLight; data.brightness = SetBrightness(randomBrightness, brightness); data.backColor = redLight; data.size = size; lightData.Add(data); currentPosition += sideOffsetVec; } //Create wing bars. if (runwayData.thresholdWingbar[side] != ThresholdWingbar.NONE) { int lightAmount = 0; if (runwayData.thresholdWingbar[side] == ThresholdWingbar.LARGE) { lightAmount = 9; } if (runwayData.thresholdWingbar[side] == ThresholdWingbar.SMALL) { lightAmount = 4; } Vector3 barSideOffsetVec = Math3d.SetVectorLength(sideOffsetDir, 1.5f); //Set start position. currentPosition = thresholdACorner; //Create wing bars. for (int i = 0; i < lightAmount * 2; i++) { data = new SpriteLights.LightData(); //Set the new start position. if (i == lightAmount) { currentPosition = runwayData.thresholdPosition[side] - startOffsetAVec; barSideOffsetVec *= -1; } currentPosition += barSideOffsetVec; data.position = currentPosition; data.rotation = runwayData.rotation[side]; data.frontColor = greenLight; data.brightness = SetBrightness(randomBrightness, brightness); data.size = size; lightData.Add(data); } } } }
//Setup all the strobe lights. private void SetupStrobeLights(ref List <SpriteLights.LightData> lightData, ApproachLightData allApproachLightData, RunwayData runwayData, float strobeTimeStep) { float groupID = Random.Range(0.0f, 0.99f); for (int side = 0; side < 2; side++) { if (runwayData.lightingType[side] != LightingType.NONE) { SvgData[] svgData = allApproachLightData.GetApproachLightData(runwayData.lightingType[side]); if ((runwayData.strobeType[side] == StrobeType.ODALS) || (runwayData.strobeType[side] == StrobeType.BOTH)) { for (int i = 0; i < svgData.Length; i++) { SpriteLights.LightData data = new SpriteLights.LightData(); Vector3 position = (runwayData.rotation[side] * svgData[i].position) + runwayData.thresholdPosition[side]; if (svgData[i].materialString == strobeCString) { data.position = position; //Set the direction and upward rotation of the light. data.rotation = runwayData.rotation[side] * Quaternion.Euler(Vector3.right * runwayData.lightAngle); data.strobeID = svgData[i].id * strobeTimeStep; data.strobeGroupID = groupID; lightData.Add(data); } } } if ((runwayData.strobeType[side] == StrobeType.REIL) || (runwayData.strobeType[side] == StrobeType.BOTH)) { float distanceOffset = 0; Vector3 sideOffsetDir = Math3d.GetRightVector(runwayData.rotation[side]); //If threshold wing bars are used, the REIL distance must be bigger, otherwise they overlap. if (runwayData.thresholdWingbar[side] == ThresholdWingbar.LARGE) { distanceOffset = 15.5f; } if ((runwayData.thresholdWingbar[side] == ThresholdWingbar.SMALL) || (runwayData.thresholdWingbar[side] == ThresholdWingbar.NONE)) { distanceOffset = 12f; } //Right strobe. Vector3 startOffsetAVec = Math3d.SetVectorLength(sideOffsetDir, (runwayData.width * 0.5f) + distanceOffset); Vector3 position = runwayData.thresholdPosition[side] + startOffsetAVec; SpriteLights.LightData data = new SpriteLights.LightData(); data.position = position; //Set the direction and upward rotation of the light. data.rotation = runwayData.rotation[side] * Quaternion.Euler(Vector3.right * runwayData.lightAngle); //The strobe ID is 0, so it will flash at the same time as all other strobes with ID 0. //The group ID is the same as the walking strobe, so it is synchronized with that. data.strobeID = 0; data.strobeGroupID = groupID; lightData.Add(data); //Left strobe. position = runwayData.thresholdPosition[side] - startOffsetAVec; data = new SpriteLights.LightData(); data.position = position; //Set the direction and upward rotation of the light. data.rotation = runwayData.rotation[side] * Quaternion.Euler(Vector3.right * runwayData.lightAngle); data.strobeGroupID = groupID; lightData.Add(data); } } } }
//Setup all the edge lights. private void SetupEdgeLights(ref List <SpriteLights.LightData> lightData, RunwayData runwayData, bool randomBrightness, float brightness, float size) { float sideFactor = 0; //Calculate the amount of lights. int lightAmountInRow = (int)Mathf.Floor(runwayData.length / runwayData.edgeLightsSpacing); //Calculate the offset direction. Vector3 lengthOffsetDir = Math3d.GetForwardVector(runwayData.rotation[0]); Vector3 sideOffsetDir = Math3d.GetRightVector(runwayData.rotation[0]); //Calculate the start position. float rowLength = (lightAmountInRow - 1) * runwayData.edgeLightsSpacing; float edgeForwardOffset = (runwayData.length - rowLength) * 0.5f; Vector3 lengthEdgeOffsetVec = Math3d.SetVectorLength(lengthOffsetDir, edgeForwardOffset); Vector3 startOffsetVec = lengthEdgeOffsetVec + Math3d.SetVectorLength(sideOffsetDir, runwayData.width * 0.5f); Vector3 startPosition = runwayData.thresholdPosition[0] + startOffsetVec; Vector3 currentPosition = startPosition; Vector3 lengthOffsetVec = Math3d.SetVectorLength(lengthOffsetDir, runwayData.edgeLightsSpacing); //Calculate the point where the lights should change color. float amberA = 600f + runwayData.edgeLightsSpacing; float amberB = (runwayData.length - (600f + runwayData.edgeLightsSpacing)); int doubleLightAmountInRow = lightAmountInRow * 2; for (int i = 0; i < doubleLightAmountInRow; i++) { bool passedAmberA = false; bool passedAmberB = false; SpriteLights.LightData data = new SpriteLights.LightData(); //Shift the current position for the other side. if (i == lightAmountInRow) { startOffsetVec = lengthEdgeOffsetVec + Math3d.SetVectorLength(-sideOffsetDir, runwayData.width * 0.5f); currentPosition = runwayData.thresholdPosition[0] + startOffsetVec; //Reset flags. passedAmberA = false; passedAmberB = false; sideFactor = lightAmountInRow; } data.position = currentPosition; data.rotation = runwayData.rotation[0]; //Calculate the distance to the threshold. float currentDistance = ((i - sideFactor) * runwayData.edgeLightsSpacing) + edgeForwardOffset; //The last 600 meter of the runway has red centerline lights. if (currentDistance <= amberA) { data.frontColor = whiteLight; data.brightness = SetBrightness(randomBrightness, brightness); data.backColor = amberLight; passedAmberA = true; } //The last 300 meter of the runway has red centerline lights. if (currentDistance >= amberB) { passedAmberB = true; data.frontColor = amberLight; data.brightness = SetBrightness(randomBrightness, brightness); data.backColor = whiteLight; } //Middle of the runway if (!passedAmberA && !passedAmberB) { data.frontColor = whiteLight; data.brightness = SetBrightness(randomBrightness, brightness); data.backColor = whiteLight; } data.size = size; lightData.Add(data); currentPosition += lengthOffsetVec; } }
//Create a light mesh object. Cram as much lights as you can into the LightData array. If there are too many lights for one GameObject, it will //automatically be split into multiple objects. //When creating city lights, use the function overload which takes a position array instead of a lightData array. private static GameObject[] CreateLightsAll(string name, LightData[] lightData, Vector3[] positions, float simpleShaderLightSize, Material material, UnityEngine.Rendering.IndexFormat meshIndexFormat) { int transformAmount = 0; if (lightData != null) { transformAmount = lightData.Length; } else { transformAmount = positions.Length; } int lightsInThisBatch; int maxTriangles; if (meshIndexFormat == UnityEngine.Rendering.IndexFormat.UInt32) { maxTriangles = maxTriangls32; } else { maxTriangles = maxTriangls16; } //The triangle limit is 21844 (16 bit) or 1431655765 (32 bit) per mesh, so split the objects up if needed. int meshAmount = (int)Mathf.Ceil(transformAmount / (float)maxTriangles); GameObject[] lightObjects = new GameObject[meshAmount]; //Get the remainder. int remainder = (int)(transformAmount % (float)maxTriangles); //Loop through the mesh batches. for (int l = 0; l < meshAmount; l++) { //Get the amount of lights in this mesh batch. if (meshAmount == 1) { lightsInThisBatch = transformAmount; } else { //Last mesh batch. if (l == (meshAmount - 1)) { if (remainder == 0) { lightsInThisBatch = maxTriangles; } else { lightsInThisBatch = remainder; } } else { lightsInThisBatch = maxTriangles; } } bool directional = false; bool omnidirectional = false; bool strobe = false; bool papi = false; bool simple = false; int vertexCount = lightsInThisBatch * 3; Vector4[] corners = new Vector4[vertexCount]; Vector2[] uvs = new Vector2[vertexCount]; Vector4[] triangleCorners = new Vector4[3]; Vector2[] triangleUvs = new Vector2[3]; Vector3[] normals = null; Vector3 normal = Vector3.one; Vector3 right = Vector3.one; Vector3 up = Vector3.one; //Create temporary arrays. Vector3[] centers = new Vector3[vertexCount]; int[] triangles = new int[vertexCount]; int[] indices = new int[vertexCount]; Vector2[] uv2Channel = null; Vector2[] uv3Channel = null; Vector2[] uv4Channel = null; Color[] colorChannel = null; Vector4 corner0 = Vector4.zero; Vector4 corner1 = Vector4.zero; Vector4 corner2 = Vector4.zero; //Generate a triangle which fits over a quad. //Taken out of the function for performance. //GenerateTriangle(out triangleCorners, out triangleUvs); //Set the points, counter clockwise as an upright triangle, with the left //corner as point 0, right corner point 1, and top is point 2. //X and Y are computed like this: //x = (1f / Mathf.Tan(60f * Mathf.Deg2Rad)) + 0.5f; //y = // (0.5f / Mathf.Tan(30f * Mathf.Deg2Rad)) + 0.5f; triangleCorners[0] = new Vector4(-1.07735f, -0.5f, 0.0f, 1.0f); triangleCorners[1] = new Vector4(1.07735f, -0.5f, 0.0f, 1.0f); triangleCorners[2] = new Vector4(0.0f, 1.366025f, 0.0f, 1.0f); //Computed like this: //float u = Math3d.NormalizeComplex(localPoints[i].x, -0.5f, 0.5f); //float v = Math3d.NormalizeComplex(localPoints[i].y, -0.5f, 0.5f); triangleUvs[0].x = -0.57735f; triangleUvs[0].y = 0f; triangleUvs[1].x = 1.57735f; triangleUvs[1].y = 0f; triangleUvs[2].x = 0.5f; triangleUvs[2].y = 1.866025f; if (lightData != null) { normals = new Vector3[vertexCount]; //What is stored in here, depends on the shader. uv2Channel = new Vector2[vertexCount]; uv3Channel = new Vector2[vertexCount]; uv4Channel = new Vector2[vertexCount]; colorChannel = new Color[vertexCount]; if (material.shader.name.Contains("Directional")) { directional = true; } if (material.shader.name.Contains("Omnidirectional")) { omnidirectional = true; } if (material.shader.name.Contains("Strobe")) { strobe = true; } if (material.shader.name.Contains("PAPI")) { papi = true; } } else { simple = true; corner0 = new Vector4(triangleCorners[0].x, triangleCorners[0].y, triangleCorners[0].z, simpleShaderLightSize); corner1 = new Vector4(triangleCorners[1].x, triangleCorners[1].y, triangleCorners[1].z, simpleShaderLightSize); corner2 = new Vector4(triangleCorners[2].x, triangleCorners[2].y, triangleCorners[2].z, simpleShaderLightSize); } //Loop through all the lights and set them up. for (int i = 0; i < lightsInThisBatch; i++) { float size = 0; int e = i * 3; int e1 = e + 1; int e2 = e + 2; int index = (l * maxTriangles) + i; if (lightData != null) { size = lightData[index].size; centers[e] = lightData[index].position; centers[e1] = lightData[index].position; centers[e2] = lightData[index].position; corners[e] = new Vector4(triangleCorners[0].x, triangleCorners[0].y, triangleCorners[0].z, size); corners[e1] = new Vector4(triangleCorners[1].x, triangleCorners[1].y, triangleCorners[1].z, size); corners[e2] = new Vector4(triangleCorners[2].x, triangleCorners[2].y, triangleCorners[2].z, size); } else { size = simpleShaderLightSize; centers[e] = positions[index]; centers[e1] = positions[index]; centers[e2] = positions[index]; corners[e] = corner0; corners[e1] = corner1; corners[e2] = corner2; } uvs[e] = triangleUvs[0]; uvs[e1] = triangleUvs[1]; uvs[e2] = triangleUvs[2]; if (lightData != null) { if (papi || omnidirectional) { up = Math3d.GetUpVector(lightData[index].rotation); } if (!simple) { normal = -Math3d.GetForwardVector(lightData[index].rotation); normals[e] = normal; normals[e1] = normal; normals[e2] = normal; } if (papi) { right = Math3d.GetRightVector(lightData[index].rotation); uv2Channel[e] = right; uv2Channel[e1] = right; uv2Channel[e2] = right; uv3Channel[e] = up; uv3Channel[e1] = up; uv3Channel[e2] = up; //Compose the z vector. Vector2 zVector = new Vector2(right.z, up.z); uv4Channel[e] = zVector; uv4Channel[e1] = zVector; uv4Channel[e2] = zVector; } if (directional) { //Create the back color. Vector2 RG = new Vector2(lightData[index].backColor.r, lightData[index].backColor.g); Vector2 BA = new Vector2(lightData[index].backColor.b, lightData[index].backColor.a); uv2Channel[e] = RG; uv2Channel[e1] = RG; uv2Channel[e2] = RG; uv3Channel[e] = BA; uv3Channel[e1] = BA; uv3Channel[e2] = BA; } if (omnidirectional) { //Create the back color. Vector2 RG = new Vector2(lightData[index].backColor.r, lightData[index].backColor.g); uv2Channel[e] = RG; uv2Channel[e1] = RG; uv2Channel[e2] = RG; uv3Channel[e] = up; uv3Channel[e1] = up; uv3Channel[e2] = up; //Compose the z vector. The x component is used for the blue component of the back color. Vector2 zVector = new Vector2(lightData[index].backColor.b, up.z); uv4Channel[e] = zVector; uv4Channel[e1] = zVector; uv4Channel[e2] = zVector; } if (strobe) { //Store the light and group id in the color channel. Color id = new Color(lightData[index].strobeID, lightData[index].strobeGroupID, 0, 0); colorChannel[e] = id; colorChannel[e1] = id; colorChannel[e2] = id; } if (directional || omnidirectional) { //Create the front color. Note that the light brightness value is stored in the alpha channel. Color frontColor = new Color(lightData[index].frontColor.r, lightData[index].frontColor.g, lightData[index].frontColor.b, lightData[index].brightness); colorChannel[e] = frontColor; colorChannel[e1] = frontColor; colorChannel[e2] = frontColor; } } triangles[e] = e; triangles[e1] = e1; triangles[e2] = e2; indices[e] = e; indices[e1] = e1; indices[e2] = e2; } //Create a new gameObject. GameObject lightObject = new GameObject(name + " " + l); lightObjects[l] = lightObject; //Add the required components to the game object. MeshFilter meshFilter = lightObject.AddComponent <MeshFilter>(); MeshRenderer meshRenderer = lightObject.AddComponent <MeshRenderer>(); //Create a new mesh. meshFilter.sharedMesh = new Mesh(); //Apply the mesh properties. meshFilter.sharedMesh.indexFormat = meshIndexFormat; meshFilter.sharedMesh.vertices = centers; meshFilter.sharedMesh.tangents = corners; //The mesh corner is stored in the tangent channel. The scale is stored in the w component. meshFilter.sharedMesh.uv = uvs; meshFilter.sharedMesh.triangles = triangles; if (!simple) { meshFilter.sharedMesh.normals = normals; meshFilter.sharedMesh.colors = colorChannel; //Front color for directional lights. Alpha is the brightness reduction. //ID for strobe lights. meshFilter.sharedMesh.uv2 = uv2Channel; //RG(BA) back color for directional lights. //Rotation vector for omnidirectional lights and PAPIs. meshFilter.sharedMesh.uv3 = uv3Channel; //(RG)BA back color for directional lights. Alpha is for invisibility. //Rotation vector for omnidirectional lights and PAPIS. meshFilter.sharedMesh.uv4 = uv4Channel; //The UV channels only hold two floats, so use a third UV channel to store the Z components of the vectors. } //Set the indices. meshFilter.sharedMesh.SetIndices(indices, MeshTopology.Triangles, 0); //Set the gameObject properties; meshRenderer.sharedMaterial = material; meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; meshRenderer.receiveShadows = false; meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; } return(lightObjects); }