예제 #1
0
        static bool GatherInternal(Func <MyBillboard, bool> handleWindow)
        {
            m_batches.Clear();

            // counting sorted billboards
            m_sortedCount   = 0;
            m_unsortedCount = 0;
            m_windowCount   = 0;
            PreGatherList(MyRenderProxy.BillboardsRead);
            PreGatherList(m_billboardsOnce);

            if (BillboardCount == 0)
            {
                return(false);
            }

            ResizeStorage();

            int sortedIndex   = 0;
            int unsortedIndex = 0;

            GatherList(MyRenderProxy.BillboardsRead, ref sortedIndex, ref unsortedIndex);
            GatherList(m_billboardsOnce, ref sortedIndex, ref unsortedIndex);

            Array.Sort(m_sortedBuffer, 0, m_sortedCount);

            int                   i             = 0;
            bool                  resetBindings = false;
            int                   windowidx     = 0;
            var                   N             = BillboardCountSafe;
            int                   currentOffset = 0;
            ISrvBindable          prevTex       = null;
            ISrvBindable          batchTex      = null;
            MyTransparentMaterial prevMaterial  = null;

            while (true)
            {
                if (i == N)
                {
                    AddBatch(N, currentOffset, prevTex, prevMaterial);
                    break;
                }

                MyBillboard           billboard = m_sortedBuffer[i];
                MyTransparentMaterial material  = MyTransparentMaterials.GetMaterial(billboard.Material);
                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);
                    batchTex = atlasItem.Texture;
                }
                else
                {
                    MyFileTextureManager texManager = MyManagers.FileTextures;
                    switch (material.TextureType)
                    {
                    case MyTransparentMaterialTextureType.FileTexture:
                        batchTex = texManager.GetTexture(material.Texture, MyFileTextureEnum.GUI, true);
                        break;

                    case MyTransparentMaterialTextureType.RenderTarget:
                        batchTex      = MyRender11.DrawSpritesOffscreen(material.Name, material.TargetSize.X, material.TargetSize.Y);
                        resetBindings = true;
                        break;

                    default:
                        throw new Exception();
                    }
                }

                bool closeBatch = i > 0 && (batchTex != prevTex || i == m_sortedCount);
                if (closeBatch)
                {
                    AddBatch(i, currentOffset, prevTex, prevMaterial);
                    currentOffset = i;
                }

                var billboardData     = new MyBillboardData();
                var billboardVertices = new MyBillboardVertexData();

                billboardData.CustomProjectionID = billboard.CustomViewProjection;
                billboardData.Color                     = billboard.Color;
                billboardData.Color.X                  *= billboard.ColorIntensity;
                billboardData.Color.Y                  *= billboard.ColorIntensity;
                billboardData.Color.Z                  *= billboard.ColorIntensity;
                billboardData.AlphaCutout               = billboard.AlphaCutout;
                billboardData.AlphaSaturation           = material.AlphaSaturation;
                billboardData.SoftParticleDistanceScale = billboard.SoftParticleDistanceScale * material.SoftParticleDistanceScale;

                billboardData.Reflective = billboard.Reflectivity;
                Vector3D pos0 = billboard.Position0;
                Vector3D pos1 = billboard.Position1;
                Vector3D pos2 = billboard.Position2;
                Vector3D pos3 = billboard.Position3;

                if (billboard.ParentID != -1)
                {
                    if (MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID) != null)
                    {
                        var matrix = MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID).WorldMatrix;

                        Vector3D.Transform(ref pos0, ref matrix, out pos0);
                        Vector3D.Transform(ref pos1, ref matrix, out pos1);
                        Vector3D.Transform(ref pos2, ref matrix, out pos2);
                        Vector3D.Transform(ref pos3, ref matrix, out pos3);
                    }
                }

                MyEnvironmentMatrices envMatrices = MyRender11.Environment.Matrices;
                if (MyStereoRender.Enable)
                {
                    if (MyStereoRender.RenderRegion == MyStereoRegion.LEFT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesLeftEye;
                    }
                    else if (MyStereoRender.RenderRegion == MyStereoRegion.RIGHT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesRightEye;
                    }
                }

                if (billboard.CustomViewProjection != -1)
                {
                    var billboardViewProjection = MyRenderProxy.BillboardsViewProjectionRead[billboard.CustomViewProjection];

                    //pos0 -= envMatrices.CameraPosition;
                    //pos1 -= envMatrices.CameraPosition;
                    //pos2 -= envMatrices.CameraPosition;
                    //pos3 -= envMatrices.CameraPosition;
                }
                else
                {
                    pos0 -= envMatrices.CameraPosition;
                    pos1 -= envMatrices.CameraPosition;
                    pos2 -= envMatrices.CameraPosition;
                    pos3 -= envMatrices.CameraPosition;
                }

                var normal = Vector3.Cross(pos1 - pos0, pos2 - pos0);
                normal.Normalize();

                billboardData.Normal = normal;

                billboardVertices.V0.Position = pos0;
                billboardVertices.V1.Position = pos1;
                billboardVertices.V2.Position = pos2;
                billboardVertices.V3.Position = pos3;

                var uv0 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv1 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv2 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);
                var uv3 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);

                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);

                    uv0 = uv0 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv1 = uv1 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv2 = uv2 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv3 = uv3 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                }

                billboardVertices.V0.Texcoord = new HalfVector2(uv0);
                billboardVertices.V1.Texcoord = new HalfVector2(uv1);
                billboardVertices.V2.Texcoord = new HalfVector2(uv2);
                billboardVertices.V3.Texcoord = new HalfVector2(uv3);

                pos0.AssertIsValid();
                pos1.AssertIsValid();
                pos2.AssertIsValid();
                pos3.AssertIsValid();


                MyTriangleBillboard triBillboard = billboard as MyTriangleBillboard;
                if (triBillboard != null)
                {
                    billboardVertices.V3.Position = pos2; // second triangle will die in rasterizer

                    billboardVertices.V0.Texcoord = new HalfVector2(triBillboard.UV0);
                    billboardVertices.V1.Texcoord = new HalfVector2(triBillboard.UV1);
                    billboardVertices.V2.Texcoord = new HalfVector2(triBillboard.UV2);

                    billboardData.Normal = triBillboard.Normal0;
                }

                m_arrayDataBillboards.Data[i]   = billboardData;
                m_arrayDataBillboards.Vertex[i] = billboardVertices;

                if (billboard.Window && handleWindow(billboard))
                {
                    m_sorteWindowIndices[windowidx] = i;
                    windowidx++;
                }

                prevTex      = batchTex;
                prevMaterial = material;
                i++;
            }

            // Sort windows data from closer to farest
            int windowCount = WindowCountSafe;

            Array.Sort(m_sorteWindowIndices, 0, windowCount, BillboardComparer);
            for (int it = 0; it < windowCount; it++)
            {
                m_arrayDataWindows.Data[it]   = m_arrayDataBillboards.Data[m_sorteWindowIndices[it]];
                m_arrayDataWindows.Vertex[it] = m_arrayDataBillboards.Vertex[m_sorteWindowIndices[it]];
            }

            return(resetBindings);
        }
        static void Gather()
        {
            // counting sorted billboards
            m_batches.Clear();
            m_sortedNum = 0;

            PreGatherList(MyRenderProxy.BillboardsRead);
            PreGatherList(m_billboardsOnce);

            m_sortedBillboardsNum = m_sortedNum;

            m_unsorted = 0;
            m_sorted   = 0;

            GatherList(MyRenderProxy.BillboardsRead);
            GatherList(m_billboardsOnce);

            Array.Sort(m_sortBuffer, 0, m_sortedNum);
            //Array.Reverse(m_sortBuffer, 0, m_sortedNum);
            //Array.Sort(m_sortBuffer, m_sortedNum, m_unsorted);

            var N = m_sorted + m_unsorted;

            var batch = new MyBillboardBatch();
            //MyAssetTexture prevTexture = null;
            var prevTexId     = TexId.NULL;
            int currentOffset = 0;

            if (N > 0)
            {
                var material = MyTransparentMaterials.GetMaterial(m_sortBuffer[0].Material);

                if (material.UseAtlas)
                {
                    var item = m_atlas.FindElement(material.Texture);
                    prevTexId = item.TextureId;
                }
                else
                {
                    PreloadTexture(material.Texture);
                    //prevTexture = MyTextureManager.GetTextureFast(material.Texture);
                    prevTexId = MyTextures.GetTexture(material.Texture, MyTextureEnum.GUI, true);
                }
            }

            TexId batchTexId = TexId.NULL;
            MyTransparentMaterial prevMaterial = null;

            for (int i = 0; i < N; i++)
            {
                var billboard = m_sortBuffer[i];
                var material  = MyTransparentMaterials.GetMaterial(billboard.Material);

                var billboardData = new MyBillboardData();

                billboardData.CustomProjectionID = billboard.CustomViewProjection;
                billboardData.Color                     = billboard.Color;
                billboardData.Color                    *= billboard.ColorIntensity;
                billboardData.AlphaCutout               = billboard.AlphaCutout;
                billboardData.AlphaSaturation           = material.AlphaSaturation;
                billboardData.SoftParticleDistanceScale = material.SoftParticleDistanceScale;
                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);
                    //billboardData.UvModifiers = new HalfVector4(atlasItem.UvOffsetScale);
                    batchTexId = atlasItem.TextureId;
                }
                else
                {
                    batchTexId = MyTextures.GetTexture(material.Texture, MyTextureEnum.GUI, true);
                }

                billboardData.Reflective = billboard.Reflectivity;
                Vector3D pos0 = billboard.Position0;
                Vector3D pos1 = billboard.Position1;
                Vector3D pos2 = billboard.Position2;
                Vector3D pos3 = billboard.Position3;

                if (billboard.ParentID != -1)
                {
                    if (MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID) != null)
                    {
                        var matrix = MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID).WorldMatrix;

                        Vector3D.Transform(ref pos0, ref matrix, out pos0);
                        Vector3D.Transform(ref pos1, ref matrix, out pos1);
                        Vector3D.Transform(ref pos2, ref matrix, out pos2);
                        Vector3D.Transform(ref pos3, ref matrix, out pos3);
                    }
                }

                if (billboard.CustomViewProjection != -1)
                {
                    var billboardViewProjection = MyRenderProxy.BillboardsViewProjectionRead[billboard.CustomViewProjection];

                    //pos0 -= MyEnvironment.CameraPosition;
                    //pos1 -= MyEnvironment.CameraPosition;
                    //pos2 -= MyEnvironment.CameraPosition;
                    //pos3 -= MyEnvironment.CameraPosition;
                }
                else
                {
                    pos0 -= MyEnvironment.CameraPosition;
                    pos1 -= MyEnvironment.CameraPosition;
                    pos2 -= MyEnvironment.CameraPosition;
                    pos3 -= MyEnvironment.CameraPosition;
                }

                var normal = Vector3.Cross(pos1 - pos0, pos2 - pos0);
                normal.Normalize();

                billboardData.Normal = normal;

                m_vertexData[i * 4 + 0].Position = pos0;
                m_vertexData[i * 4 + 1].Position = pos1;
                m_vertexData[i * 4 + 2].Position = pos2;
                m_vertexData[i * 4 + 3].Position = pos3;

                var uv0 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv1 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv2 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);
                var uv3 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);

                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);

                    uv0 = uv0 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv1 = uv1 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv2 = uv2 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv3 = uv3 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                }

                m_vertexData[i * 4 + 0].Texcoord = new HalfVector2(uv0);
                m_vertexData[i * 4 + 1].Texcoord = new HalfVector2(uv1);
                m_vertexData[i * 4 + 2].Texcoord = new HalfVector2(uv2);
                m_vertexData[i * 4 + 3].Texcoord = new HalfVector2(uv3);

                pos0.AssertIsValid();
                pos1.AssertIsValid();
                pos2.AssertIsValid();
                pos3.AssertIsValid();


                MyTriangleBillboard triBillboard = billboard as MyTriangleBillboard;
                if (triBillboard != null)
                {
                    m_vertexData[i * 4 + 3].Position = pos2; // second triangle will die in rasterizer

                    m_vertexData[i * 4 + 0].Texcoord = new HalfVector2(triBillboard.UV0);
                    m_vertexData[i * 4 + 1].Texcoord = new HalfVector2(triBillboard.UV1);
                    m_vertexData[i * 4 + 2].Texcoord = new HalfVector2(triBillboard.UV2);

                    billboardData.Normal = triBillboard.Normal0; // pew pew pew :O
                }

                m_billboardData[i] = billboardData;

                bool closeBatch = (batchTexId != prevTexId) || ((i == m_sortedNum) && (i > 0));

                if (closeBatch)
                {
                    batch = new MyBillboardBatch();

                    batch.Offset  = currentOffset;
                    batch.Num     = i - currentOffset;
                    batch.Texture = prevTexId != TexId.NULL ? MyTextures.Views[prevTexId.Index] : null;

                    batch.Lit         = prevMaterial.CanBeAffectedByOtherLights;
                    batch.AlphaCutout = prevMaterial.AlphaCutout;

                    m_batches.Add(batch);
                    currentOffset = i;
                }

                prevTexId    = batchTexId;
                prevMaterial = material;
            }

            if (N > 0)
            {
                batch         = new MyBillboardBatch();
                batch.Offset  = currentOffset;
                batch.Num     = N - currentOffset;
                batch.Texture = prevTexId != TexId.NULL ? MyTextures.GetView(prevTexId) : null;

                batch.Lit         = prevMaterial.CanBeAffectedByOtherLights;
                batch.AlphaCutout = prevMaterial.AlphaCutout;

                m_batches.Add(batch);
            }
        }
예제 #3
0
        static bool GatherInternal()
        {
            m_batches.Clear();

            // counting sorted billboards
            ClearBucketCounts();
            PreGatherList(MyRenderProxy.BillboardsRead);
            PreGatherList(m_billboardsOnce);

            int billboardCount = 0;

            for (int j = 0; j < BUCKETS_COUNT; j++)
            {
                billboardCount += m_bucketCounts[j];
            }
            if (billboardCount == 0)
            {
                return(false);
            }

            m_billboardCountSafe = billboardCount > MAX_BILLBOARDS_SIZE ? MAX_BILLBOARDS_SIZE : billboardCount;

            InitGatherList(billboardCount, m_billboardCountSafe);
            InitBucketIndices();

            GatherList(MyRenderProxy.BillboardsRead);
            GatherList(m_billboardsOnce);

            InitBucketIndices();

            int i;

            for (i = 0; i < BUCKETS_COUNT; i++)
            {
                Array.Sort(m_tempBuffer, m_bucketIndices[i], m_bucketCounts[i]);
            }

            bool                  resetBindings = false;
            int                   currentOffset = 0;
            ISrvBindable          prevTex       = null;
            MyTransparentMaterial prevMaterial  = null;

            for (i = 0; i < m_billboardCountSafe; i++)
            {
                MyBillboard           billboard = m_tempBuffer[i];
                MyTransparentMaterial material  = MyTransparentMaterials.GetMaterial(billboard.Material);
                ISrvBindable          batchTex  = null;
                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);
                    batchTex = atlasItem.Texture;
                }
                else
                {
                    MyFileTextureManager texManager = MyManagers.FileTextures;
                    switch (material.TextureType)
                    {
                    case MyTransparentMaterialTextureType.FileTexture:
                        if (material.Texture == null || !m_fileTextures.TryGetValue(material.Texture, out batchTex))
                        {
                            batchTex = texManager.GetTexture(material.Texture, MyFileTextureEnum.GUI, true);
                            if (material.Texture != null)
                            {
                                m_fileTextures.Add(material.Texture, batchTex);
                            }
                            else
                            {
                                MyRenderProxy.Fail("Material: " + material.Name + " is missing a texture.");
                            }
                        }

                        break;

                    case MyTransparentMaterialTextureType.RenderTarget:
                        batchTex      = MyRender11.DrawSpritesOffscreen(material.Name, material.TargetSize.X, material.TargetSize.Y);
                        resetBindings = true;
                        break;

                    default:
                        throw new Exception();
                    }
                }

                bool boundary   = IsBucketBoundary(i);
                bool closeBatch = i > 0 && (batchTex != prevTex || boundary);
                if (closeBatch)
                {
                    AddBatch(i, currentOffset, prevTex, prevMaterial);
                    currentOffset = i;
                }


                var billboardData     = new MyBillboardData();
                var billboardVertices = new MyBillboardVertexData();

                billboardData.CustomProjectionID = billboard.CustomViewProjection;
                billboardData.Color                     = billboard.Color;
                billboardData.Color.X                  *= billboard.ColorIntensity;
                billboardData.Color.Y                  *= billboard.ColorIntensity;
                billboardData.Color.Z                  *= billboard.ColorIntensity;
                billboardData.AlphaCutout               = billboard.AlphaCutout;
                billboardData.AlphaSaturation           = material.AlphaSaturation;
                billboardData.SoftParticleDistanceScale = billboard.SoftParticleDistanceScale * material.SoftParticleDistanceScale;

                billboardData.Reflective = billboard.Reflectivity;
                Vector3D pos0 = billboard.Position0;
                Vector3D pos1 = billboard.Position1;
                Vector3D pos2 = billboard.Position2;
                Vector3D pos3 = billboard.Position3;

                if (billboard.ParentID != -1)
                {
                    var parent = MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID);

                    if (parent != null)
                    {
                        var matrix = parent.WorldMatrix;
                        Vector3D.Transform(ref pos0, ref matrix, out pos0);
                        Vector3D.Transform(ref pos1, ref matrix, out pos1);
                        Vector3D.Transform(ref pos2, ref matrix, out pos2);
                        Vector3D.Transform(ref pos3, ref matrix, out pos3);
                    }
                }

                MyEnvironmentMatrices envMatrices = MyRender11.Environment.Matrices;
                if (MyStereoRender.Enable)
                {
                    if (MyStereoRender.RenderRegion == MyStereoRegion.LEFT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesLeftEye;
                    }
                    else if (MyStereoRender.RenderRegion == MyStereoRegion.RIGHT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesRightEye;
                    }
                }

                if (billboard.CustomViewProjection == -1)
                {
                    pos0 -= envMatrices.CameraPosition;
                    pos1 -= envMatrices.CameraPosition;
                    pos2 -= envMatrices.CameraPosition;
                    pos3 -= envMatrices.CameraPosition;
                }

                var normal = Vector3D.Cross(pos1 - pos0, pos2 - pos0);
                normal.Normalize();

                billboardData.Normal = normal;

                billboardVertices.V0.Position = pos0;
                billboardVertices.V1.Position = pos1;
                billboardVertices.V2.Position = pos2;
                billboardVertices.V3.Position = pos3;

                var uv0 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv1 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv2 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);
                var uv3 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);

                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);

                    uv0 = uv0 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv1 = uv1 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv2 = uv2 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv3 = uv3 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                }

                billboardVertices.V0.Texcoord = new HalfVector2(uv0);
                billboardVertices.V1.Texcoord = new HalfVector2(uv1);
                billboardVertices.V2.Texcoord = new HalfVector2(uv2);
                billboardVertices.V3.Texcoord = new HalfVector2(uv3);

                pos0.AssertIsValid();
                pos1.AssertIsValid();
                pos2.AssertIsValid();
                pos3.AssertIsValid();


                MyTriangleBillboard triBillboard = billboard as MyTriangleBillboard;
                if (triBillboard != null)
                {
                    billboardVertices.V3.Position = pos2; // second triangle will die in rasterizer

                    billboardVertices.V0.Texcoord = new HalfVector2(triBillboard.UV0);
                    billboardVertices.V1.Texcoord = new HalfVector2(triBillboard.UV1);
                    billboardVertices.V2.Texcoord = new HalfVector2(triBillboard.UV2);

                    billboardData.Normal = triBillboard.Normal0;
                }

                m_arrayDataBillboards.Data[i]   = billboardData;
                m_arrayDataBillboards.Vertex[i] = billboardVertices;

                prevTex      = batchTex;
                prevMaterial = material;
            }
            AddBatch(m_billboardCountSafe, currentOffset, prevTex, prevMaterial);

            TransferDataCustomProjections();
            TransferDataBillboards(0, m_billboardCountSafe, ref m_arrayDataBillboards);

            return(resetBindings);
        }
        static void Gather()
        {
            m_batches.Clear();

            // counting sorted billboards
            m_sortedCount   = 0;
            m_unsortedCount = 0;
            m_windowCount   = 0;
            PreGatherList(MyRenderProxy.BillboardsRead);
            PreGatherList(m_billboardsOnce);

            if (BillboardCount == 0)
            {
                return;
            }

            ResizeStorage();

            int sortedIndex   = 0;
            int unsortedIndex = 0;

            GatherList(MyRenderProxy.BillboardsRead, ref sortedIndex, ref unsortedIndex);
            GatherList(m_billboardsOnce, ref sortedIndex, ref unsortedIndex);

            Array.Sort(m_sortedBuffer, 0, m_sortedCount);

            int   i             = 0;
            int   windowidx     = 0;
            var   N             = BillboardCountSafe;
            int   currentOffset = 0;
            TexId prevTexId     = TexId.NULL;
            TexId batchTexId    = TexId.NULL;
            MyTransparentMaterial prevMaterial = null;

            while (true)
            {
                if (i == N)
                {
                    AddBatch(N, currentOffset, prevTexId, prevMaterial);
                    break;
                }

                MyBillboard           billboard = m_sortedBuffer[i];
                MyTransparentMaterial material  = MyTransparentMaterials.GetMaterial(billboard.Material);
                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);
                    batchTexId = atlasItem.TextureId;
                }
                else
                {
                    batchTexId = MyTextures.GetTexture(material.Texture, MyTextureEnum.GUI, true);
                }

                bool closeBatch = i > 0 && (batchTexId != prevTexId || i == m_sortedCount);
                if (closeBatch)
                {
                    AddBatch(i, currentOffset, prevTexId, prevMaterial);
                    currentOffset = i;
                }

                var billboardData     = new MyBillboardData();
                var billboardVertices = new MyBillboardVertexData();

                billboardData.CustomProjectionID = billboard.CustomViewProjection;
                billboardData.Color                     = billboard.Color;
                billboardData.Color.X                  *= billboard.ColorIntensity;
                billboardData.Color.Y                  *= billboard.ColorIntensity;
                billboardData.Color.Z                  *= billboard.ColorIntensity;
                billboardData.AlphaCutout               = billboard.AlphaCutout;
                billboardData.AlphaSaturation           = material.AlphaSaturation;
                billboardData.SoftParticleDistanceScale = billboard.SoftParticleDistanceScale * material.SoftParticleDistanceScale;

                billboardData.Reflective = billboard.Reflectivity;
                Vector3D pos0 = billboard.Position0;
                Vector3D pos1 = billboard.Position1;
                Vector3D pos2 = billboard.Position2;
                Vector3D pos3 = billboard.Position3;

                if (billboard.ParentID != -1)
                {
                    if (MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID) != null)
                    {
                        var matrix = MyIDTracker <MyActor> .FindByID((uint)billboard.ParentID).WorldMatrix;

                        Vector3D.Transform(ref pos0, ref matrix, out pos0);
                        Vector3D.Transform(ref pos1, ref matrix, out pos1);
                        Vector3D.Transform(ref pos2, ref matrix, out pos2);
                        Vector3D.Transform(ref pos3, ref matrix, out pos3);
                    }
                }

                MyEnvironmentMatrices envMatrices = MyRender11.Environment;
                if (MyStereoRender.Enable)
                {
                    if (MyStereoRender.RenderRegion == MyStereoRegion.LEFT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesLeftEye;
                    }
                    else if (MyStereoRender.RenderRegion == MyStereoRegion.RIGHT)
                    {
                        envMatrices = MyStereoRender.EnvMatricesRightEye;
                    }
                }

                if (billboard.CustomViewProjection != -1)
                {
                    var billboardViewProjection = MyRenderProxy.BillboardsViewProjectionRead[billboard.CustomViewProjection];

                    //pos0 -= envMatrices.CameraPosition;
                    //pos1 -= envMatrices.CameraPosition;
                    //pos2 -= envMatrices.CameraPosition;
                    //pos3 -= envMatrices.CameraPosition;
                }
                else
                {
                    pos0 -= envMatrices.CameraPosition;
                    pos1 -= envMatrices.CameraPosition;
                    pos2 -= envMatrices.CameraPosition;
                    pos3 -= envMatrices.CameraPosition;
                }

                var normal = Vector3.Cross(pos1 - pos0, pos2 - pos0);
                normal.Normalize();

                billboardData.Normal = normal;

                billboardVertices.V0.Position = pos0;
                billboardVertices.V1.Position = pos1;
                billboardVertices.V2.Position = pos2;
                billboardVertices.V3.Position = pos3;

                var uv0 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv1 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv2 = new Vector2(material.UVOffset.X + material.UVSize.X * billboard.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);
                var uv3 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y + material.UVSize.Y * billboard.UVSize.Y);

                if (material.UseAtlas)
                {
                    var atlasItem = m_atlas.FindElement(material.Texture);

                    uv0 = uv0 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv1 = uv1 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv2 = uv2 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                    uv3 = uv3 * new Vector2(atlasItem.UvOffsetScale.Z, atlasItem.UvOffsetScale.W) + new Vector2(atlasItem.UvOffsetScale.X, atlasItem.UvOffsetScale.Y);
                }

                billboardVertices.V0.Texcoord = new HalfVector2(uv0);
                billboardVertices.V1.Texcoord = new HalfVector2(uv1);
                billboardVertices.V2.Texcoord = new HalfVector2(uv2);
                billboardVertices.V3.Texcoord = new HalfVector2(uv3);

                pos0.AssertIsValid();
                pos1.AssertIsValid();
                pos2.AssertIsValid();
                pos3.AssertIsValid();


                MyTriangleBillboard triBillboard = billboard as MyTriangleBillboard;
                if (triBillboard != null)
                {
                    billboardVertices.V3.Position = pos2; // second triangle will die in rasterizer

                    billboardVertices.V0.Texcoord = new HalfVector2(triBillboard.UV0);
                    billboardVertices.V1.Texcoord = new HalfVector2(triBillboard.UV1);
                    billboardVertices.V2.Texcoord = new HalfVector2(triBillboard.UV2);

                    billboardData.Normal = triBillboard.Normal0;
                }

                m_arrayDataBillboards.Data[i]   = billboardData;
                m_arrayDataBillboards.Vertex[i] = billboardVertices;

                if (billboard.Window && MyScreenDecals.HasEntityDecals((uint)billboard.ParentID))
                {
                    m_arrayDataWindows.Data[windowidx]   = billboardData;
                    m_arrayDataWindows.Vertex[windowidx] = billboardVertices;
                    windowidx++;
                }

                prevTexId    = batchTexId;
                prevMaterial = material;
                i++;
            }
        }