Exemplo n.º 1
0
        private static Ray ComputeIntersectionLine(ref Plane p1, ref Plane p2)
        {
            Ray ray = new Ray();

            ray.Direction = Vector3.Cross(p1.Normal, p2.Normal);
            float num = ray.Direction.LengthSquared();

            ray.Position = Vector3.Cross(-p1.D * p2.Normal + p2.D * p1.Normal, ray.Direction) / num;
            return(ray);
        }
Exemplo n.º 2
0
        internal static void GenerateVertexData(ref Vector3D worldPointA, ref Vector3D worldPointB,
                                                out MyVertexFormatPositionH4[] stream0, out MyVertexFormatTexcoordNormalTangentTexindices[] stream1)
        {
            var worldPosition = (worldPointA + worldPointB) * 0.5f;
            var pointA        = (Vector3)(worldPointA - worldPosition);
            var pointB        = (Vector3)(worldPointB - worldPosition);

            var length = (pointA - pointB).Length() * 10.0f;

            Vector3 lineTangent, normal, binormal;

            lineTangent = pointB - pointA;
            VRageMath.Vector3.Normalize(ref lineTangent, out lineTangent);
            lineTangent.CalculatePerpendicularVector(out normal);
            Vector3.Cross(ref lineTangent, ref normal, out binormal);

            var offsetX = normal * 0.025f;
            var offsetY = binormal * 0.025f;

            List <MyVertexFormatPositionH4> vertexPositionList = new List <MyVertexFormatPositionH4>();
            List <MyVertexFormatTexcoordNormalTangentTexindices> vertexList = new List <MyVertexFormatTexcoordNormalTangentTexindices>();

            Byte4 defaultArrayTexIndex = new Byte4(0, 0, 0, 0);

            unsafe
            {
                Vector3 *points = stackalloc Vector3[2];
                points[0] = pointA;
                points[1] = pointB;
                int vertexCounter = 0;
                for (int i = 0; i < 2; ++i)
                {
                    int   baseVertex = i * 4;
                    float texCoordX  = (i - 0.5f) * length;

                    vertexPositionList.Add(new MyVertexFormatPositionH4(points[i] + offsetX));
                    vertexList.Add(new MyVertexFormatTexcoordNormalTangentTexindices(new Vector2(texCoordX, 0.0f), normal, Vector3.Cross(lineTangent, normal), defaultArrayTexIndex));

                    vertexPositionList.Add(new MyVertexFormatPositionH4(points[i] + offsetY));
                    vertexList.Add(new MyVertexFormatTexcoordNormalTangentTexindices(new Vector2(texCoordX, 0.33333f), binormal, Vector3.Cross(lineTangent, binormal), defaultArrayTexIndex));

                    vertexPositionList.Add(new MyVertexFormatPositionH4(points[i] - offsetX));
                    vertexList.Add(new MyVertexFormatTexcoordNormalTangentTexindices(new Vector2(texCoordX, 0.66667f), -normal, Vector3.Cross(lineTangent, -normal), defaultArrayTexIndex));

                    vertexPositionList.Add(new MyVertexFormatPositionH4(points[i] - offsetY));
                    vertexList.Add(new MyVertexFormatTexcoordNormalTangentTexindices(new Vector2(texCoordX, 1.0f), -binormal, Vector3.Cross(lineTangent, -binormal), defaultArrayTexIndex));
                }
            }

            stream0 = vertexPositionList.ToArray();
            stream1 = vertexList.ToArray();
        }
Exemplo n.º 3
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_atlasedTextures[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;
                if (material.UseAtlas)
                {
                    var atlasItem = m_atlasedTextures[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.UVOffset.X, material.UVOffset.Y + billboard.UVOffset.Y);
                var uv2 = new Vector2(material.UVOffset.X + material.UVSize.X + billboard.UVOffset.X, material.UVOffset.Y + material.UVSize.Y + billboard.UVOffset.Y);
                var uv3 = new Vector2(material.UVOffset.X + billboard.UVOffset.X, material.UVOffset.Y + material.UVSize.Y + billboard.UVOffset.Y);

                if (material.UseAtlas)
                {
                    var atlasItem = m_atlasedTextures[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;

                    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;

                m_batches.Add(batch);
            }
        }
        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++;
            }
        }