GetRightVector() public static method

public static GetRightVector ( Quaternion q ) : Vector3
q Quaternion
return Vector3
示例#1
0
    //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;
                    }
                }
            }
        }
    }
示例#2
0
    //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);
    }
示例#3
0
    //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);
                }
            }
        }
    }
示例#4
0
    //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);
                }
            }
        }
    }
示例#5
0
    //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);
    }