Exemple #1
0
        /// <summary>
        /// Sets the specified cull value to the object at results index
        /// </summary>
        /// <param name="value">Value</param>
        /// <param name="index">Results index</param>
        /// <param name="item">Object</param>
        private void SetCullValue(CullData value, int index, ICullable item, bool force)
        {
            if (!this.Objects.ContainsKey(item))
            {
                this.Objects.Add(item, new List <CullData>(index + 1));
            }

            var values = this.Objects[item];

            if (values.Count <= index)
            {
                var valuesToAdd = new CullData[index - values.Count + 1];

                values.AddRange(valuesToAdd);
            }

            if (force)
            {
                // Culled values stay untouched
                if (values[index].Culled)
                {
                    values[index] = value;
                }
            }
            else
            {
                values[index] = value;
            }
        }
Exemple #2
0
    void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale)
    {
        AABB localbound;

        localbound.Center  = this._mesh.mesh.bounds.center;
        localbound.Extents = _mesh.mesh.bounds.extents;

        MaterialPropertyBlock block = new MaterialPropertyBlock();

        var colors = new NativeArray <Vector4>(3, Allocator.Temp);

        colors[0] = (new Vector4(Color.red.r, Color.red.g, Color.red.b, Color.red.a));
        colors[1] = (new Vector4(Color.yellow.r, Color.yellow.g, Color.yellow.b, Color.yellow.a));
        colors[2] = (new Vector4(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a));

        block.SetVectorArray("_Color", colors.ToArray());

        var batchIndex = _batchRendererGroup.AddBatch(_mesh.mesh, 0, _material, 0, ShadowCastingMode.On, true, false,
                                                      new Bounds(Vector3.zero, 1000 * Vector3.one), count, null, null);


        //   _batchRendererGroup.SetInstancingData(batchIndex,count,block);

        int colorArrayIndex = Shader.PropertyToID("_Color_Array");

        float *nativePtr = null;

        var arr4 = _batchRendererGroup.GetBatchVectorArray(batchIndex, colorArrayIndex);

        nativePtr = (float *)arr4.GetUnsafePtr();

        UnsafeUtility.MemCpy(nativePtr, (float *)colors.GetUnsafePtr(), UnsafeUtility.SizeOf <float4>() * count);


        //   colors.Dispose();


        var matrices = _batchRendererGroup.GetBatchMatrices(batchIndex);

        for (int i = 0; i < count; i++)
        {
            matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]);

            var aabb = AABB.Transform(matrices[i], localbound);

            _cullDatas[offset + i] = new CullData()
            {
                bound       = aabb,
                position    = pos[i],
                minDistance = 0,
                maxDistance = 100
            };
        }
    }
Exemple #3
0
        public void UpdateRectangles()
        {
            this.UpdateCullRect();
            for (int n = 0, count = this.list.Count; n < count; ++n)
            {
                CullData data = this.list[n];
                if (!data.IsEnabled || !data.Target)
                {
                    continue;
                }

                data.Update();
            }
        }
Exemple #4
0
        /// <summary>
        /// Performs cull test in the object list against the culling volume
        /// </summary>
        /// <param name="volume">Culling volume</param>
        /// <param name="index">Results index</param>
        /// <param name="objects">Objects list</param>
        /// <returns>Returns true if any object results inside the volume</returns>
        public bool Cull(ICullingVolume volume, int index, IEnumerable <ICullable> objects)
        {
            bool res = false;

            foreach (var item in objects)
            {
                var cull     = item.Cull(volume, out float distance);
                var cullData = new CullData
                {
                    Culled   = cull,
                    Distance = distance,
                };

                this.SetCullValue(cullData, index, item, false);

                if (!cullData.Culled)
                {
                    res = true;
                }
            }

            return(res);
        }
Exemple #5
0
        // NOTE: for performance! (duplicated code)
        public void UpdateVisibles()
        {
            Rect area = this.UpdateCullRect();

            for (int n = 0, count = this.list.Count; n < count; ++n)
            {
                CullData data = this.list[n];
                if (!data.IsEnabled)
                {
                    continue;
                }

                if (!data.IsValid)
                {
                    continue;
                }

                data.Update();

                Rect rect = data.Rect;
                if (area.xMin < rect.xMax && area.xMax > rect.xMin &&
                    area.yMin < rect.yMax && area.yMax > rect.yMin)
                {
                    if (!data.IsActivated)
                    {
                        data.SetActive(true);
                    }
                }
                else
                {
                    if (data.IsActivated)
                    {
                        data.SetActive(false);
                    }
                }
            }
        }
Exemple #6
0
    private void AddBatch(Mesh mesh, Material mat, BatchParameters param, ref int cullOffset)
    {
        MaterialPropertyBlock matBlock = new MaterialPropertyBlock();

        matBlock.SetVectorArray("_PerInstanceColor", param.Colors);
        var batchIndex = this.batchRendererGroup.AddBatch(mesh, 0, mat, 0,
                                                          ShadowCastingMode.On, true, false,
                                                          param.Bnd, param.InstanceCount, matBlock, null);
        var batchMatrices = this.batchRendererGroup.GetBatchMatrices(batchIndex);
        var pos           = new float4(0, 0, 0, 1);

        for (int i = 0; i < param.InstanceCount; i++)
        {
            batchMatrices[i]         = param.Matrices[i];
            cullData[cullOffset + i] = new CullData()
            {
                extents     = 0.5f * param.Bnd.size,
                position    = math.mul(param.Matrices[i], pos).xyz,
                minDistance = 0,
                maxDistance = detailDistance,
            };
        }
        cullOffset += param.InstanceCount;
    }
    void UpdateData()
    {
        AABB localbound;

        localbound.Center  = this._mesh.mesh.bounds.center;
        localbound.Extents = _mesh.mesh.bounds.extents;
        var pos   = new float3[4];
        var rot   = new quaternion[4];
        var scale = new float3[4];

        for (int i = 0; i < 4; i++)
        {
            pos[i]   = new float3(i * 2, updateIndex, 0);
            rot[i]   = quaternion.identity;
            scale[i] = new float3(1, 1, 1);
        }

        _batchRendererGroup.SetInstancingData(updateIndex, 4, null);


        int colorArrayIndex = Shader.PropertyToID("_Color_Array");

        float *nativePtr = null;

        var arr4 = _batchRendererGroup.GetBatchVectorArray(updateIndex, colorArrayIndex);

        nativePtr = (float *)arr4.GetUnsafePtr();

        var colors = new NativeArray <Vector4>(4, Allocator.Temp);

        colors[1] = (new Vector4(Color.red.r, Color.red.g, Color.red.b, Color.red.a));
        colors[2] = (new Vector4(Color.yellow.r, Color.yellow.g, Color.yellow.b, Color.yellow.a));
        colors[0] = (new Vector4(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a));
        colors[3] = Color.cyan;
        UnsafeUtility.MemCpy(nativePtr, (float *)colors.GetUnsafePtr(), UnsafeUtility.SizeOf <float4>() * 4);

        var matrices = _batchRendererGroup.GetBatchMatrices(updateIndex);


        NativeMultiHashMapIterator <int> it;
        CullData cullData;
        bool     has = _cullDic.TryGetFirstValue(updateIndex, out cullData, out it);

        for (int i = 0; i < 4; i++)
        {
            matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]);

            var aabb = AABB.Transform(matrices[i], localbound);

            if (i > 0)
            {
                has = _cullDic.TryGetNextValue(out cullData, ref it);
            }
            if (!has)
            {
                _cullDic.Add(updateIndex, new CullData()
                {
                    bound       = aabb,
                    position    = pos[i],
                    minDistance = 0,
                    maxDistance = 10
                });
            }
            else
            {
                cullData = new CullData()
                {
                    bound       = aabb,
                    position    = pos[i],
                    minDistance = 0,
                    maxDistance = 10
                };
            }
        }

        updateIndex++;
    }
Exemple #8
0
        private void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale)
        {
            var localBound = mesh.bounds;
            var block      = new MaterialPropertyBlock();
            var colors     = new List <Vector4>(count);

            for (int i = 0; i < count; i++)
            {
                colors.Add(new Vector4(Random.value, Random.value, Random.value, Random.value));
            }

            // 因为srp batcher buffer的关系 instance buffer 会混乱
            // block.SetVectorArray(BaseColor_ID, colors);


            //下面的Bounds是需要组合过的
            var batchIndex = batchRendererGroup.AddBatch(
                mesh,
                0,
                material,
                0,
                ShadowCastingMode.On,
                true,
                false,
                new Bounds(Vector3.zero, 1000 * Vector3.one),
                count,
                block,
                null
                );

            var matrices = batchRendererGroup.GetBatchMatrices(batchIndex);

            for (int i = 0; i < count; i++)
            {
                float4x4 tempMatrix = float4x4.TRS(pos[i], rot[i], scale[i]);
                Bounds   aabb       = OtherUtils.Transform(tempMatrix, localBound);
                tempMatrix.c0.w      = colors[i].x;
                tempMatrix.c1.w      = colors[i].y;
                tempMatrix.c2.w      = colors[i].z;
                tempMatrix.c3.w      = colors[i].w;
                matrices[i]          = tempMatrix;
                cullData[offset + i] = new CullData()
                {
                    bound       = aabb,
                    position    = pos[i],
                    minDistance = 0,
                    maxDistance = lodDis
                };
            }

            //-----------------
            for (int i = 0; i < count; i++)
            {
                colors[i] = (new Vector4(Random.value, Random.value, Random.value, Random.value));
            }

            // 因为srp batcher buffer的关系 instance buffer 会混乱
            // block.SetVectorArray(BaseColor_ID, colors);

            //https://docs.unity3d.com/ScriptReference/Rendering.BatchRendererGroup.AddBatch.html
            //下面的Bounds是需要组合过的
            batchIndex = batchRendererGroup.AddBatch(
                lowMesh,
                0,
                material,
                0,
                ShadowCastingMode.On,
                true,
                false,
                new Bounds(Vector3.zero, 1000 * Vector3.one),
                count,
                block,
                null
                );

            matrices = batchRendererGroup.GetBatchMatrices(batchIndex);
            for (int i = 0; i < count; i++)
            {
                var    tempMatrix = float4x4.TRS(pos[i], rot[i], scale[i]);
                Bounds aabb       = OtherUtils.Transform(tempMatrix, localBound);
                tempMatrix.c0.w = colors[i].x;
                tempMatrix.c1.w = colors[i].y;
                tempMatrix.c2.w = colors[i].z;
                tempMatrix.c3.w = colors[i].w;
                matrices[i]     = tempMatrix;
                cullData[offset + count + i] = new CullData()
                {
                    bound       = aabb,
                    position    = pos[i],
                    minDistance = lodDis,
                    maxDistance = 10000,
                };
            }
        }
Exemple #9
0
        public static void Export(GameObject[] gameObjects, string saveFileName, ExportSettings settings)
        {
            MeshConverter.ClearCaches();
            TextureConverter.ClearCaches();
            MaterialConverter.ClearCaches();
            ShaderMappingIO.ClearCaches();

            GraphBuilderInterface.unity2vsg_BeginExport();

            List <PipelineData> storePipelines = new List <PipelineData>();

            bool insideLODGroup = false;
            bool firstNodeAdded = false;

            System.Action <GameObject> processGameObject = null;
            processGameObject = (GameObject go) =>
            {
                // determine the gameObject type
                Transform gotrans = go.transform;

                bool nodeAdded = false;

                // does it have a none identiy local matrix
                if (gotrans.localPosition != Vector3.zero || gotrans.localRotation != Quaternion.identity || gotrans.localScale != Vector3.one)
                {
                    if (firstNodeAdded || !settings.zeroRootTransform)
                    {
                        // add as a transform
                        TransformData transformdata = TransformConverter.CreateTransformData(gotrans);
                        GraphBuilderInterface.unity2vsg_AddTransformNode(transformdata);
                        nodeAdded = true;
                    }
                }

                // do we need to insert a group
                if (!nodeAdded)// && gotrans.childCount > 0)
                {
                    //add as a group
                    GraphBuilderInterface.unity2vsg_AddGroupNode();
                    nodeAdded = true;
                }

                firstNodeAdded = true;
                bool meshexported = false;

                // get the meshrender here so we can check if the LOD exports the the mesh
                MeshFilter   meshFilter   = go.GetComponent <MeshFilter>();
                MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>();

                // does this node have an LOD group
                LODGroup lodgroup = go.GetComponent <LODGroup>();
                if (lodgroup != null && !insideLODGroup)
                {
                    // rather than process the children we figure out which renderers are in which children and add them as LOD children
                    LOD[] lods = lodgroup.GetLODs();
                    if (lods.Length > 0)
                    {
                        // get bounds from first renderer
                        if (lods[0].renderers.Length > 0)
                        {
                            CullData lodCullData = new CullData();
                            Bounds   bounds      = new Bounds(lods[0].renderers[0].bounds.center, lods[0].renderers[0].bounds.size);
                            foreach (Renderer boundsrenderer in lods[0].renderers)
                            {
                                if (boundsrenderer != null)
                                {
                                    bounds.Encapsulate(boundsrenderer.bounds);
                                }
                            }
                            Vector3 center = bounds.center - gotrans.position;
                            CoordSytemConverter.Convert(ref center);
                            lodCullData.center = NativeUtils.ToNative(center);
                            lodCullData.radius = bounds.size.magnitude * 0.5f;
                            GraphBuilderInterface.unity2vsg_AddLODNode(lodCullData);

                            insideLODGroup = true;

                            for (int i = 0; i < lods.Length; i++)
                            {
                                // for now just support one renderer and assume it's under a seperate child gameObject
                                if (lods[i].renderers.Length == 0)
                                {
                                    continue;
                                }

                                LODChildData lodChild = new LODChildData();
                                lodChild.minimumScreenHeightRatio = lods[i].screenRelativeTransitionHeight;
                                GraphBuilderInterface.unity2vsg_AddLODChild(lodChild);

                                foreach (Renderer lodrenderer in lods[i].renderers)
                                {
                                    if (lodrenderer == meshRenderer)
                                    {
                                        meshexported = true;
                                        ExportMesh(meshFilter.sharedMesh, meshRenderer, gotrans, settings, storePipelines);
                                    }
                                    else if (lodrenderer != null)
                                    {
                                        // now process the renderers gameobject, it'll be added to the group we just created by adding an LOD child
                                        processGameObject(lodrenderer.gameObject);
                                    }
                                }

                                GraphBuilderInterface.unity2vsg_EndNode();
                            }

                            insideLODGroup = false;

                            GraphBuilderInterface.unity2vsg_EndNode(); // end the lod node
                        }
                    }
                }
                else
                {
                    // transverse any children
                    for (int i = 0; i < gotrans.childCount; i++)
                    {
                        processGameObject(gotrans.GetChild(i).gameObject);
                    }
                }

                // does it have a mesh
                if (!meshexported && meshFilter && meshFilter.sharedMesh && meshRenderer)
                {
                    Mesh mesh = meshFilter.sharedMesh;
                    ExportMesh(mesh, meshRenderer, gotrans, settings, storePipelines);
                }

                // does this node have a terrain
                Terrain terrain = go.GetComponent <Terrain>();
                if (terrain != null)
                {
                    ExportTerrainMesh(terrain, settings, storePipelines);
                }

                // if we added a group or transform step out
                if (nodeAdded)
                {
                    GraphBuilderInterface.unity2vsg_EndNode();
                }
            };

            foreach (GameObject go in gameObjects)
            {
                processGameObject(go);
            }

            //GraphBuilderInterface.unity2vsg_EndNode(); // step out of convert coord system node

            GraphBuilderInterface.unity2vsg_EndExport(saveFileName);
            NativeLog.PrintReport();
        }
Exemple #10
0
        private static void ExportMesh(Mesh mesh, MeshRenderer meshRenderer, Transform gotrans, ExportSettings settings, List <PipelineData> storePipelines = null)
        {
            bool addedCullGroup = false;

            if (settings.autoAddCullNodes)
            {
                CullData culldata = new CullData();
                Vector3  center   = meshRenderer.bounds.center - gotrans.position;
                CoordSytemConverter.Convert(ref center);
                culldata.center = NativeUtils.ToNative(center);
                culldata.radius = meshRenderer.bounds.size.magnitude * 0.5f;
                GraphBuilderInterface.unity2vsg_AddCullGroupNode(culldata);
                addedCullGroup = true;
            }

            //
            Material[] materials = meshRenderer.sharedMaterials;

            if (mesh != null && mesh.isReadable && mesh.vertexCount > 0 && mesh.GetIndexCount(0) > 0)
            {
                int meshid = mesh.GetInstanceID();

                MeshInfo meshInfo = MeshConverter.GetOrCreateMeshInfo(mesh);

                int subMeshCount = mesh.subMeshCount;

                // shader instance id, Material Data, sub mesh indicies
                Dictionary <int, Dictionary <MaterialInfo, List <int> > > meshMaterials = new Dictionary <int, Dictionary <MaterialInfo, List <int> > >();
                for (int matindex = 0; matindex < materials.Length && matindex < subMeshCount; matindex++)
                {
                    Material mat = materials[matindex];
                    if (mat == null)
                    {
                        continue;
                    }

                    MaterialInfo matdata     = MaterialConverter.GetOrCreateMaterialData(mat);
                    int          matshaderid = matdata.shaderStages.id;

                    if (!meshMaterials.ContainsKey(matshaderid))
                    {
                        meshMaterials.Add(matshaderid, new Dictionary <MaterialInfo, List <int> >());
                    }
                    if (!meshMaterials[matshaderid].ContainsKey(matdata))
                    {
                        meshMaterials[matshaderid].Add(matdata, new List <int>());
                    }

                    meshMaterials[matshaderid][matdata].Add(matindex);
                }

                if (subMeshCount > 1)
                {
                    // create mesh data, if the mesh has already been created we only need to pass the ID to the addGeometry function
                    foreach (int shaderkey in meshMaterials.Keys)
                    {
                        List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[shaderkey].Keys);

                        if (mds.Count == 0)
                        {
                            continue;
                        }

                        // add stategroup and pipeline for shader
                        GraphBuilderInterface.unity2vsg_AddStateGroupNode();

                        PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE
                        pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray());
                        pipelineData.shaderStages       = mds[0].shaderStages.ToNative();
                        pipelineData.useAlpha           = mds[0].useAlpha;
                        pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData));
                        storePipelines.Add(pipelineData);

                        if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1)
                        {
                            GraphBuilderInterface.unity2vsg_AddCommandsNode();

                            VertexBuffersData vertexBuffersData = MeshConverter.GetOrCreateVertexBuffersData(meshInfo);
                            GraphBuilderInterface.unity2vsg_AddBindVertexBuffersCommand(vertexBuffersData);

                            IndexBufferData indexBufferData = MeshConverter.GetOrCreateIndexBufferData(meshInfo);
                            GraphBuilderInterface.unity2vsg_AddBindIndexBufferCommand(indexBufferData);


                            foreach (MaterialInfo md in mds)
                            {
                                BindDescriptors(md, false);

                                foreach (int submeshIndex in meshMaterials[shaderkey][md])
                                {
                                    DrawIndexedData drawIndexedData = MeshConverter.GetOrCreateDrawIndexedData(meshInfo, submeshIndex);
                                    GraphBuilderInterface.unity2vsg_AddDrawIndexedCommand(drawIndexedData);
                                }
                            }

                            GraphBuilderInterface.unity2vsg_EndNode(); // step out of commands node for descriptors and draw indexed commands
                        }
                        GraphBuilderInterface.unity2vsg_EndNode();     // step out of stategroup node for shader
                    }
                }
                else
                {
                    List <int> sids = new List <int>(meshMaterials.Keys);
                    if (sids.Count > 0)
                    {
                        List <MaterialInfo> mds = new List <MaterialInfo>(meshMaterials[sids[0]].Keys);

                        if (mds.Count > 0)
                        {
                            // add stategroup and pipeline for shader
                            GraphBuilderInterface.unity2vsg_AddStateGroupNode();

                            PipelineData pipelineData = NativeUtils.CreatePipelineData(meshInfo); //WE NEED INFO ABOUT THE SHADER SO WE CAN BUILD A PIPLE LINE
                            pipelineData.descriptorBindings = NativeUtils.WrapArray(mds[0].descriptorBindings.ToArray());
                            pipelineData.shaderStages       = mds[0].shaderStages.ToNative();
                            pipelineData.useAlpha           = mds[0].useAlpha;
                            pipelineData.id = NativeUtils.ToNative(NativeUtils.GetIDForPipeline(pipelineData));
                            storePipelines.Add(pipelineData);

                            if (GraphBuilderInterface.unity2vsg_AddBindGraphicsPipelineCommand(pipelineData, 1) == 1)
                            {
                                BindDescriptors(mds[0], true);

                                VertexIndexDrawData vertexIndexDrawData = MeshConverter.GetOrCreateVertexIndexDrawData(meshInfo);
                                GraphBuilderInterface.unity2vsg_AddVertexIndexDrawNode(vertexIndexDrawData);

                                GraphBuilderInterface.unity2vsg_EndNode(); // step out of vertex index draw node
                            }
                            GraphBuilderInterface.unity2vsg_EndNode();     // step out of stategroup node
                        }
                    }
                }
            }
            else
            {
                string reason = mesh == null ? "mesh is null." : (!mesh.isReadable ? "mesh '" + mesh.name + "' is not readable. Please enabled read/write in the models import settings." : "mesh '" + mesh.name + "' has an unknown error.");
                NativeLog.WriteLine("ExportMesh: Unable to export mesh for gameobject " + gotrans.gameObject.name + ", " + reason);
            }

            if (addedCullGroup)
            {
                GraphBuilderInterface.unity2vsg_EndNode();
            }
        }
Exemple #11
0
    public void AddBatch(int offset, int count, float3[] pos, quaternion[] rot, float3[] scale)
    {
        AABB localBond;

        localBond.Center  = this.mesh.bounds.center;
        localBond.Extents = this.mesh.bounds.extents;
        MaterialPropertyBlock block = new MaterialPropertyBlock();
        var colors = new List <Vector4>();

        for (int i = 0; i < count; i++)
        {
            colors.Add(new Vector4(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f)));
        }
        block.SetVectorArray("_Color1", colors);
        var batchIndex = this.batchRendererGroup.AddBatch(
            this.mesh,
            0,
            this.material,
            0,
            ShadowCastingMode.On,
            true,
            false,
            new Bounds(Vector3.zero, 1000 * Vector3.one),
            count,
            block,
            null);
        var matrices = this.batchRendererGroup.GetBatchMatrices(batchIndex);

        for (int i = 0; i < count; i++)
        {
            matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]);
            var aabb = AABB.Transform(matrices[i], localBond);
            cullData[offset + i] = new CullData()
            {
                bound       = aabb,
                position    = pos[i],
                minDistance = 0,
                maxDistance = lodDis,
            };
        }
        for (int i = 0; i < count; i++)
        {
            colors[i] = new Vector4(UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f), UnityEngine.Random.Range(0f, 1f));
        }
        block.SetVectorArray("_Color1", colors);
        batchIndex = this.batchRendererGroup.AddBatch(
            this.lowMesh,
            0,
            this.material,
            0,
            ShadowCastingMode.On,
            true,
            false,
            new Bounds(Vector3.zero, 1000 * Vector3.one),
            count,
            block,
            null);
        matrices = this.batchRendererGroup.GetBatchMatrices(batchIndex);
        for (int i = 0; i < count; i++)
        {
            matrices[i] = float4x4.TRS(pos[i], rot[i], scale[i]);
            var aabb = AABB.Transform(matrices[i], localBond);
            cullData[offset + count + i] = new CullData()
            {
                bound       = aabb,
                position    = pos[i],
                minDistance = lodDis,
                maxDistance = 10000,
            };
        }
    }