예제 #1
0
        protected override void OnUpdate()
        {
            if (GetEntityQuery(ComponentType.ReadOnly <UnityEngine.Shader>()).CalculateEntityCount() == 0)
            {
                return;
            }
            if (!TryGetBuildConfigurationComponent <DotsRuntimeBuildProfile>(out var profile))
            {
                return;
            }
            bool includeAllPlatform = false;

            if (TryGetBuildConfigurationComponent <TinyShaderSettings>(out var shaderSettings))
            {
                includeAllPlatform = shaderSettings.PackageShadersForAllPlatforms;
            }
            var platforms = ShaderCompilerClient.GetSupportedPlatforms(profile.Target, includeAllPlatform);
            var context   = new BlobAssetComputationContext <ShaderSettings, PrecompiledShaderPipeline>(BlobAssetStore, 128, Allocator.Temp);

            Entities.ForEach((UnityEngine.Shader uShader) =>
            {
                if (MaterialConversion.GetMaterialType(uShader) != MaterialConversion.SupportedMaterialType.Custom)
                {
                    return;
                }

                var entity = GetPrimaryEntity(uShader);

                // Note: all shader stages are in a single source file
                string filepath = Path.GetFullPath(AssetDatabase.GetAssetPath(uShader));
                if (!File.Exists(filepath))
                {
                    throw new InvalidDataException($"Could not open shader file '{filepath}'");
                }
                string shaderSrc = File.ReadAllText(filepath);

                if (m_Client == null)
                {
                    InitShaderCompiler();
                }

                m_Client.Preprocess(shaderSrc, filepath, uShader.name, out string hlslSrc, out int startLine, out uint[] includeHash);
                Hash128 includeHash128 = new Hash128(includeHash[0], includeHash[1], includeHash[2], includeHash[3]);
                Hash128 hash           = new Hash128();
                unsafe
                {
                    fixed(char *p = shaderSrc)
                    {
                        UnityEngine.HashUnsafeUtilities.ComputeHash128(p, (ulong)shaderSrc.Length, &hash);
                        UnityEngine.HashUtilities.AppendHash(ref includeHash128, ref hash);
                    }
                }

                context.AssociateBlobAssetWithUnityObject(hash, uShader);
                if (context.NeedToComputeBlobAsset(hash))
                {
                    context.AddBlobAssetToCompute(hash, default);
                    var blobAsset = m_Client.CompileShaderForPlatforms(hlslSrc, platforms, filepath, startLine, uShader.name);
                    if (!blobAsset.IsCreated)
                    {
                        return;
                    }

                    context.AddComputedBlobAsset(hash, blobAsset);
                }

                context.GetBlobAsset(hash, out var shaderBlob);
                DstEntityManager.AddComponentData(entity, new CustomShader {
                    Status = ShaderStatus.Invalid, Name = Path.GetFileNameWithoutExtension(filepath)
                });
                DstEntityManager.AddComponentData(entity, new ShaderBinData {
                    shaders = shaderBlob
                });
            });

            ShutdownShaderCompiler();

            context.Dispose();
        }
        private void ConvertCompoundColliders()
        {
            Profiler.BeginSample("ConvertCompoundColliders");

            m_nativeColliders  = new NativeList <Collider>(128, Allocator.TempJob);
            m_nativeTransforms = new NativeList <RigidTransform>(128, Allocator.TempJob);
            m_compoundRanges   = new NativeList <int2>(128, Allocator.TempJob);

            //Step 1: Find all colliders and construct parallel arrays
            m_authorings.Clear();
            Entities.WithNone <DontConvertColliderTag>().ForEach((LatiosColliderAuthoring colliderAuthoring) =>
            {
                //Do stuff
                if (colliderAuthoring.colliderType == AuthoringColliderTypes.None)
                {
                    return;
                }
                if (colliderAuthoring.generateFromChildren)
                {
                    m_unityColliders.Clear();
                    colliderAuthoring.GetComponentsInChildren(m_unityColliders);
                    try
                    {
                        CreateChildrenColliders(colliderAuthoring, m_unityColliders, m_nativeColliders, m_nativeTransforms, m_compoundRanges);
                    }
                    catch (Exception e)
                    {
                        DisposeAndThrow(e);
                    }
                }
                else
                {
                    try
                    {
                        CreateChildrenColliders(colliderAuthoring, colliderAuthoring.colliders, m_nativeColliders, m_nativeTransforms, m_compoundRanges);
                    }
                    catch (Exception e)
                    {
                        DisposeAndThrow(e);
                    }
                }
                m_authorings.Add(colliderAuthoring);
            });

            if (m_authorings.Count > 0)
            {
                using (var computationContext = new BlobAssetComputationContext <CompoundColliderComputationData, CompoundColliderBlob>(BlobAssetStore, 128, Allocator.Temp))
                {
                    //Step 2: Compute hashes
                    var hashes = new NativeArray <ColliderTransformHashPair>(m_compoundRanges.Length, Allocator.TempJob);
                    new ComputeCompoundHashesJob
                    {
                        colliders  = m_nativeColliders,
                        transforms = m_nativeTransforms,
                        ranges     = m_compoundRanges,
                        hashes     = hashes
                    }.ScheduleParallel(m_compoundRanges.Length, 1, default).Complete();

                    //Step 3: Check hashes against computationContext to see if blobs need to be built
                    for (int i = 0; i < m_authorings.Count; i++)
                    {
                        var hash = hashes.ReinterpretLoad <Hash128>(i);
                        computationContext.AssociateBlobAssetWithUnityObject(hash, m_authorings[i].gameObject);
                        if (computationContext.NeedToComputeBlobAsset(hash))
                        {
                            computationContext.AddBlobAssetToCompute(hash, new CompoundColliderComputationData
                            {
                                hash  = hash,
                                index = i
                            });
                        }
                    }

                    //Step 4: Dispatch builder job
                    using (var computationData = computationContext.GetSettings(Allocator.TempJob))
                    {
                        new ComputeCompoundBlobs
                        {
                            colliders       = m_nativeColliders,
                            transforms      = m_nativeTransforms,
                            ranges          = m_compoundRanges,
                            computationData = computationData
                        }.ScheduleParallel(computationData.Length, 1, default).Complete();

                        foreach (var data in computationData)
                        {
                            computationContext.AddComputedBlobAsset(data.hash, data.blob);
                        }
                    }

                    //Step 5: Build Collider component
                    var index = 0;
                    Entities.ForEach((LatiosColliderAuthoring colliderAuthoring) =>
                    {
                        computationContext.GetBlobAsset(hashes.ReinterpretLoad <Hash128>(index++), out var blob);

                        var targetEntity = GetPrimaryEntity(colliderAuthoring);

                        float3 scale = colliderAuthoring.transform.lossyScale;
                        if (scale.x != scale.y || scale.x != scale.z)
                        {
                            throw new InvalidOperationException(
                                $"GameObject Conversion Error: Failed to convert {colliderAuthoring}. Only uniform scale is permitted on Compound colliders.");
                        }

                        Collider icdCompound = new CompoundCollider
                        {
                            compoundColliderBlob = blob,
                            scale = scale.x
                        };
                        DstEntityManager.AddComponentData(targetEntity, icdCompound);
                    });

                    hashes.Dispose();
                }
            }

            m_nativeColliders.Dispose();
            m_nativeTransforms.Dispose();
            m_compoundRanges.Dispose();

            Profiler.EndSample();
        }
    protected override void OnUpdate()
    {
        var blobFactoryPoints = new NativeList <float3>(Allocator.TempJob);
        int curPointIndex     = 0;
        var vertices          = new List <Vector3>(4096);
        var processBlobAssets = new NativeList <Hash128>(32, Allocator.Temp);

        Profiler.BeginSample("Conv_BuildHashAndPush");

        using (var context = new BlobAssetComputationContext <MeshBBFactorySettings, MeshBBBlobAsset>(BlobAssetStore, 128, Allocator.Temp))
        {
            // First step: for all changed GameObjects we compute the hash of their blob asset then get the asset or register its computation
            Entities.ForEach((MeshToBoundingBoxAuthoring auth) =>
            {
                // Compute the blob asset hash based on Authoring properties
                var hasMesh      = auth.Mesh != null;
                var meshHashCode = hasMesh ? auth.Mesh.GetHashCode() : 0;
                var hash         = new Hash128((uint)meshHashCode, (uint)auth.MeshScale.GetHashCode(), 0, 0);

                // Query the context to determine if we need to build the BlobAsset
                processBlobAssets.Add(hash);
                context.AssociateBlobAssetWithUnityObject(hash, auth.gameObject);
                if (context.NeedToComputeBlobAsset(hash))
                {
                    Profiler.BeginSample("CopyVertices");

                    float xp = float.MinValue, yp = float.MinValue, zp = float.MinValue;
                    float xn = float.MaxValue, yn = float.MaxValue, zn = float.MaxValue;

                    // Copy the mesh vertices into the point array
                    if (hasMesh)
                    {
                        auth.Mesh.GetVertices(vertices);
                        for (int i = 0; i < vertices.Count; i++)
                        {
                            var p = vertices[i];
                            xp    = math.max(p.x, xp);
                            yp    = math.max(p.y, yp);
                            zp    = math.max(p.z, zp);
                            xn    = math.min(p.x, xn);
                            yn    = math.min(p.y, yn);
                            zn    = math.min(p.z, zn);
                            blobFactoryPoints.Add(new float3(p.x, p.y, p.z));
                        }
                    }
                    else
                    {
                        xp = yp = zp = xn = yn = zn = 0;
                    }

                    Profiler.EndSample();

                    // Record this blob asset for computation
                    var vertexCount = hasMesh ? auth.Mesh.vertexCount : 0;
                    var setting     = new MeshBBFactorySettings {
                        Hash = hash, MeshScale = auth.MeshScale, PointStartIndex = curPointIndex, PointCount = vertexCount, MinBoundingBox = new float3(xn, yn, zn), MaxBoundingBox = new float3(xp, yp, zp)
                    };
                    curPointIndex += vertexCount;

                    context.AddBlobAssetToCompute(hash, setting);
                }
            });

            Profiler.EndSample();

            Profiler.BeginSample("Conv_CreateBlobAssets");

            using (var settings = context.GetSettings(Allocator.TempJob))
            {
                // Step two, compute BlobAssets
                var job = new ComputeMeshBBAssetJob(settings, blobFactoryPoints.AsArray());
                job.Schedule(job.Settings.Length, 1).Complete();

                for (int i = 0; i < settings.Length; i++)
                {
                    context.AddComputedBlobAsset(settings[i].Hash, job.BlobAssets[i]);
                }
                job.BlobAssets.Dispose();
            }

            Profiler.EndSample();

            Profiler.BeginSample("Conv_CreateECS");

            // Third step, create the ECS component with the associated blob asset
            var index = 0;
            Entities.ForEach((MeshToBoundingBoxAuthoring auth) =>
            {
                context.GetBlobAsset(processBlobAssets[index++], out var blob);

                // Create the ECS component for the given GameObject
                var entity = GetPrimaryEntity(auth);

                DstEntityManager.AddComponentData(entity, new MeshBBComponent(blob));
                DstEntityManager.AddComponentData(entity, new Translation {
                    Value = auth.transform.position
                });
            });

            Profiler.EndSample();
            blobFactoryPoints.Dispose();
            processBlobAssets.Dispose();
        }
    }
예제 #4
0
        protected override void OnUpdate()
        {
            var processBlobAssets    = new NativeList <Hash128>(Constants.PositionCount, Allocator.Temp);
            var blobFactoryPositions = new NativeList <float3>(Allocator.TempJob);
            var blobLength           = 0;
            int currentIndex         = 0;

            using (var positionContext = new BlobAssetComputationContext <SequenceSettings, SequentialPositionsBlobAsset>(BlobAssetStore, 32, Allocator.Temp)) {
                Entities.ForEach((T spawner) =>
                {
                    var filePathHash = (uint)spawner.FilePath.GetHashCode();
                    var isFirst      = true;
                    var dataLength   = -1;
                    for (var i = 0; i < Constants.PositionCount; ++i)
                    {
                        var hash = new Hash128(filePathHash, (uint)i, 0, 0);
                        processBlobAssets.Add(hash);
                        positionContext.AssociateBlobAssetWithUnityObject(hash, spawner.gameObject);
                        if (positionContext.NeedToComputeBlobAsset(hash))
                        {
                            if (isFirst)
                            {
                                isFirst       = false;
                                currentIndex  = blobLength;
                                var readToEnd = File.ReadAllLines(Path.Combine(Application.streamingAssetsPath, spawner.FilePath));
                                dataLength    = readToEnd.Length - (spawner.HasHeader ? 1 : 0);
                                blobLength   += Constants.PositionCount * dataLength;
                                blobFactoryPositions.Resize(blobLength, NativeArrayOptions.UninitializedMemory);
                                Fill(blobFactoryPositions, readToEnd, spawner.HasHeader, currentIndex);
                            }
                            var sequentialSettings = new SequenceSettings
                            {
                                Hash       = hash,
                                StartIndex = currentIndex + i * dataLength,
                                Count      = dataLength
                            };
                            positionContext.AddBlobAssetToCompute(hash, sequentialSettings);
                        }
                    }
                });

                using (var positionSettings = positionContext.GetSettings(Allocator.TempJob)) {
                    var positionJob = new ComputeSequentialPositionAssetJob(positionSettings, blobFactoryPositions);
                    positionJob.Schedule(positionJob.Settings.Length, 1).Complete();
                    for (var i = 0; i < positionSettings.Length; ++i)
                    {
                        positionContext.AddComputedBlobAsset(positionSettings[i].Hash, positionJob.BlobAssets[i]);
                    }
                    positionJob.BlobAssets.Dispose();
                }

                blobFactoryPositions.Dispose();

                var settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, BlobAssetStore);
                var index    = 0;
                Entities.ForEach((T spawner) =>
                {
                    var prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(spawner.Prefab, settings);
                    DstEntityManager.AddComponent <SequenceIndex>(prefab);
                    DstEntityManager.AddComponentData(prefab, new SequenceFrequency {
                        Value = spawner.FrequencyOfSequence
                    });
                    using (var instances = DstEntityManager.Instantiate(prefab, Constants.PositionCount, Allocator.Temp)) {
                        for (var i = 0; i < instances.Length; ++i)
                        {
                            positionContext.GetBlobAsset(processBlobAssets[index], out var positionBlob);
                            DstEntityManager.AddComponentData(instances[i], new SequentialPositions {
                                BlobData = positionBlob,
                                Parent   = GetPrimaryEntity(spawner)
                            });
                            ++index;
                        }
                        InitHelenHayes(instances);
                    }
                });

                processBlobAssets.Dispose();
            }
        }
        void ConvertBatchedClips()
        {
            var clipList = new List <AudioClip>();

            using (var computationContext = new BlobAssetComputationContext <AudioClipComputationData, AudioClipBlob>(BlobAssetStore, 128, Allocator.Temp))
            {
                var hashes     = new NativeList <Hash128>(Allocator.Persistent);
                var jobs       = new List <ComputeAudioClipHashesJob>();
                var jobHandles = new NativeList <JobHandle>(Allocator.Persistent);
                Entities.ForEach((AudioSourceAuthoring authoring) =>
                {
                    if (authoring.clip != null)
                    {
                        int frequency = authoring.clip.frequency;
                        var arr       = new float[authoring.clip.samples * authoring.clip.channels];
                        authoring.clip.GetData(arr, 0);
                        var job = new ComputeAudioClipHashesJob
                        {
                            samples   = new NativeArray <float>(arr, Allocator.Persistent),
                            hash      = new NativeReference <uint2>(Allocator.Persistent),
                            frequency = frequency
                        };
                        jobs.Add(job);
                        jobHandles.Add(job.Schedule());
                    }
                });
                JobHandle.CompleteAll(jobHandles);
                jobHandles.Dispose();

                int index = 0;
                Entities.ForEach((AudioSourceAuthoring authoring) =>
                {
                    if (authoring.clip != null)
                    {
                        var hash =
                            new Hash128(jobs[index].hash.Value.x, jobs[index].hash.Value.y, (uint)authoring.clip.channels, (uint)math.select(0, authoring.voices,
                                                                                                                                             authoring.looping));
                        computationContext.AssociateBlobAssetWithUnityObject(hash, authoring.gameObject);
                        if (computationContext.NeedToComputeBlobAsset(hash))
                        {
                            computationContext.AddBlobAssetToCompute(hash, new AudioClipComputationData {
                                hash = hash, index = index
                            });
                        }
                        index++;
                        clipList.Add(authoring.clip);
                        hashes.Add(hash);
                    }
                });
                foreach (var job in jobs)
                {
                    job.samples.Dispose();
                    job.hash.Dispose();
                }
                using (var computationDataArray = computationContext.GetSettings(Allocator.TempJob))
                {
                    var samples       = new NativeList <float>(Allocator.TempJob);
                    var ranges        = new NativeArray <int2>(computationDataArray.Length, Allocator.TempJob);
                    var rates         = new NativeArray <int>(computationDataArray.Length, Allocator.TempJob);
                    var channelCounts = new NativeArray <int>(computationDataArray.Length, Allocator.TempJob);
                    var offsets       = new NativeArray <int>(computationDataArray.Length, Allocator.TempJob);
                    var names         = new NativeArray <FixedString128>(computationDataArray.Length, Allocator.TempJob);
                    for (int i = 0; i < computationDataArray.Length; i++)
                    {
                        var clip           = clipList[computationDataArray[i].index];
                        var samplesManaged = new float[clip.samples * clip.channels];
                        clip.GetData(samplesManaged, 0);
                        var samplesUnmanaged = new NativeArray <float>(samplesManaged, Allocator.Temp);
                        ranges[i] = new int2(samples.Length, samplesUnmanaged.Length);
                        samples.AddRange(samplesUnmanaged);
                        rates[i]         = clip.frequency;
                        channelCounts[i] = clip.channels;
                        offsets[i]       = (int)computationDataArray[i].hash.Value.w;
                        names[i]         = clip.name;
                    }
                    new ComputeAudioClipBlobsJob
                    {
                        samples              = samples,
                        ranges               = ranges,
                        rates                = rates,
                        channelCounts        = channelCounts,
                        computationDataArray = computationDataArray,
                        offsetCounts         = offsets,
                        names                = names
                    }.ScheduleParallel(ranges.Length, 1, default).Complete();
                    foreach (var data in computationDataArray)
                    {
                        computationContext.AddComputedBlobAsset(data.hash, data.blob);
                    }
                    samples.Dispose();
                    ranges.Dispose();
                    rates.Dispose();
                    channelCounts.Dispose();
                    offsets.Dispose();
                    names.Dispose();

                    index = 0;
                    Entities.ForEach((AudioSourceAuthoring authoring) =>
                    {
                        if (authoring.clip != null)
                        {
                            var hash = hashes[index];
                            computationContext.GetBlobAsset(hash, out var blob);

                            var entity = GetPrimaryEntity(authoring);
                            if (!authoring.looping)
                            {
                                DstEntityManager.AddComponentData(entity, new AudioSourceOneShot
                                {
                                    clip            = blob,
                                    innerRange      = authoring.innerRange,
                                    outerRange      = authoring.outerRange,
                                    rangeFadeMargin = authoring.rangeFadeMargin,
                                    volume          = authoring.volume
                                });
                                if (authoring.autoDestroyOnFinish)
                                {
                                    DstEntityManager.AddComponent <AudioSourceDestroyOneShotWhenFinished>(entity);
                                }
                            }
                            else
                            {
                                DstEntityManager.AddComponentData(entity, new AudioSourceLooped
                                {
                                    m_clip          = blob,
                                    innerRange      = authoring.innerRange,
                                    outerRange      = authoring.outerRange,
                                    rangeFadeMargin = authoring.rangeFadeMargin,
                                    volume          = authoring.volume,
                                });
                            }
                            if (authoring.useCone)
                            {
                                DstEntityManager.AddComponentData(entity, new AudioSourceEmitterCone
                                {
                                    cosInnerAngle         = math.cos(math.radians(authoring.innerAngle)),
                                    cosOuterAngle         = math.cos(math.radians(authoring.outerAngle)),
                                    outerAngleAttenuation = authoring.outerAngleVolume
                                });
                            }
                            index++;
                        }
                    });
                }
                hashes.Dispose();
            }
        }
예제 #6
0
        public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
        {
            using (var context = new BlobAssetComputationContext <SequentialHelenHayesSettings, SequentialPositionsBlobAsset>(conversionSystem.BlobAssetStore, 1, Allocator.Temp)) {
                var hash = new Hash128((uint)FilePath.GetHashCode(), 0, 0, 0);
                context.AssociateBlobAssetWithUnityObject(hash, gameObject);
                if (context.NeedToComputeBlobAsset(hash))
                {
                    var indexes = new NativeArray <int>(Constants.PositionCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
                    indexes[Constants.FrontHeadIndex]     = FrontHeadIndex;
                    indexes[Constants.TopHeadIndex]       = TopHeadIndex;
                    indexes[Constants.RearHeadIndex]      = RearHeadIndex;
                    indexes[Constants.RightOffsetIndex]   = RightOffsetIndex;
                    indexes[Constants.VSacralIndex]       = VSacralIndex;
                    indexes[Constants.LeftShoulderIndex]  = LeftShoulderIndex;
                    indexes[Constants.LeftElbowIndex]     = LeftElbowIndex;
                    indexes[Constants.LeftWristIndex]     = LeftWristIndex;
                    indexes[Constants.RightShoulderIndex] = RightShoulderIndex;
                    indexes[Constants.RightElbowIndex]    = RightElbowIndex;
                    indexes[Constants.RightWristIndex]    = RightWristIndex;
                    indexes[Constants.LeftAsisIndex]      = LeftAsisIndex;
                    indexes[Constants.LeftTightIndex]     = LeftTightIndex;
                    indexes[Constants.LeftKneeIndex]      = LeftKneeIndex;
                    indexes[Constants.LeftKneeMedIndex]   = LeftKneeMedIndex;
                    indexes[Constants.LeftShankIndex]     = LeftShankIndex;
                    indexes[Constants.LeftAnkleIndex]     = LeftAnkleIndex;
                    indexes[Constants.LeftAnkleMedIndex]  = LeftAnkleMedIndex;
                    indexes[Constants.LeftHeelIndex]      = LeftHeelIndex;
                    indexes[Constants.LeftToeIndex]       = LeftToeIndex;
                    indexes[Constants.RightAsisIndex]     = RightAsisIndex;
                    indexes[Constants.RightTightIndex]    = RightTightIndex;
                    indexes[Constants.RightKneeIndex]     = RightKneeIndex;
                    indexes[Constants.RightKneeMedIndex]  = RightKneeMedIndex;
                    indexes[Constants.RightShankIndex]    = RightShankIndex;
                    indexes[Constants.RightAnkleIndex]    = RightAnkleIndex;
                    indexes[Constants.RightAnkleMedIndex] = RightAnkleMedIndex;
                    indexes[Constants.RightHeelIndex]     = RightHeelIndex;
                    indexes[Constants.RightToeIndex]      = RightToeIndex;
                    Assert.AreEqual(29, indexes.Distinct().Count());

                    var readToEnd  = File.ReadAllLines(Path.Combine(Application.streamingAssetsPath, FilePath));
                    var headSkip   = (HasHeader ? 1 : 0);
                    var dataLength = readToEnd.Length - headSkip;

                    var positions = new NativeArray <float3>(dataLength * Constants.PositionCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
                    for (var i = 0; i < dataLength; ++i)
                    {
                        var data = Array.ConvertAll(readToEnd[i + headSkip].Split(','), (string s) => { if (float.TryParse(s, out var f))
                                                                                                        {
                                                                                                            return(f);
                                                                                                        }
                                                                                                        else
                                                                                                        {
                                                                                                            return(float.NaN);
                                                                                                        } });
                        for (var j = 0; j < Constants.PositionCount; ++j)
                        {
                            // Convert coordinate system, and 0.001f means milli metre to metre
                            positions[i * Constants.PositionCount + j] = new float3(data[j * 3], data[j * 3 + 2], data[j * 3 + 1]) * 0.001f;
                        }
                    }

                    context.AddBlobAssetToCompute(hash, new SequentialHelenHayesSettings());
                    var job = new SequentialHelenHayesJob(positions, indexes);
                    job.Schedule().Complete();
                    context.AddComputedBlobAsset(hash, job.BlobAssets[0]);
                    job.BlobAssets.Dispose();
                }

                context.GetBlobAsset(hash, out var blob);
                dstManager.AddComponentData(entity, new SequentialHelenHayesData {
                    BlobData = blob
                });
            }
        }
        public void BlobPerOwnerTest()
        {
            var go0 = new GameObject("GO 0");
            var go1 = new GameObject("GO 1");

            var k0 = FromInt(0);
            var k1 = FromInt(1);
            var k2 = FromInt(2);
            var k3 = FromInt(3);
            var k4 = FromInt(4);

            // Associate k0, k2, k4 with GO0, k0, k1, k2 with GO1
            using (var context = new BlobAssetComputationContext <int, int>(m_Store, 16, Allocator.Temp))
                using (var processList = new NativeList <Hash128>(16, Allocator.Temp))
                {
                    // Simulate BlobAsset operations with GO0
                    processList.Add(k0);
                    Assert.IsTrue(context.NeedToComputeBlobAsset(k0));
                    var blobAsset = BlobAssetReference <int> .Create(0);

                    context.AddComputedBlobAsset(k0, blobAsset);

                    processList.Add(k2);
                    Assert.IsTrue(context.NeedToComputeBlobAsset(k2));
                    blobAsset = BlobAssetReference <int> .Create(2);

                    context.AddComputedBlobAsset(k2, blobAsset);

                    processList.Add(k4);
                    Assert.IsTrue(context.NeedToComputeBlobAsset(k4));
                    blobAsset = BlobAssetReference <int> .Create(4);

                    context.AddComputedBlobAsset(k4, blobAsset);

                    // Simulate BlobAsset operation with GO1
                    processList.Add(k0);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k0));

                    processList.Add(k1);
                    Assert.IsTrue(context.NeedToComputeBlobAsset(k1));
                    blobAsset = BlobAssetReference <int> .Create(1);

                    context.AddComputedBlobAsset(k1, blobAsset);

                    processList.Add(k2);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k2));

                    // Associate the BlobAssets with GO0
                    context.AssociateBlobAssetWithGameObject(k0, go0);
                    context.AssociateBlobAssetWithGameObject(k2, go0);
                    context.AssociateBlobAssetWithGameObject(k4, go0);

                    // Associate the BlobAssets with GO1
                    context.AssociateBlobAssetWithGameObject(k0, go1);
                    context.AssociateBlobAssetWithGameObject(k1, go1);
                    context.AssociateBlobAssetWithGameObject(k2, go1);

                    // Check the BlobAsset are retrieved correctly
                    var replayIndex = 0;
                    context.GetBlobAsset(processList[replayIndex++], out var res);
                    Assert.AreEqual(0, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(2, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(4, res.Value);
                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(0, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(1, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(2, res.Value);
                }

            // Check the GO-BlobAsset associations
            m_Store.GetBlobAssetsOfGameObject(go0, Allocator.Temp, out var hashes);
            Assert.AreEqual(3, hashes.Length);
            Assert.IsTrue(hashes.Contains(k0));
            Assert.IsTrue(hashes.Contains(k2));
            Assert.IsTrue(hashes.Contains(k4));
            hashes.Dispose();

            m_Store.GetBlobAssetsOfGameObject(go1, Allocator.Temp, out hashes);
            Assert.AreEqual(3, hashes.Length);
            Assert.IsTrue(hashes.Contains(k0));
            Assert.IsTrue(hashes.Contains(k1));
            Assert.IsTrue(hashes.Contains(k2));
            hashes.Dispose();

            // 2, 1, 2, 0, 1 as expected RefCounter for k0...4
            Assert.AreEqual(2, m_Store.GetBlobAssetRefCounter(k0));
            Assert.AreEqual(1, m_Store.GetBlobAssetRefCounter(k1));
            Assert.AreEqual(2, m_Store.GetBlobAssetRefCounter(k2));
            Assert.AreEqual(0, m_Store.GetBlobAssetRefCounter(k3));
            Assert.AreEqual(1, m_Store.GetBlobAssetRefCounter(k4));

            // Associate k1, k2, k3 with GO0 and k3, k4 with GO1
            using (var context = new BlobAssetComputationContext <int, int>(m_Store, 16, Allocator.Temp))
                using (var processList = new NativeList <Hash128>(16, Allocator.Temp))
                {
                    // Simulate BlobAsset operations with GO0
                    processList.Add(k1);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k1));

                    processList.Add(k2);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k2));

                    processList.Add(k3);
                    Assert.IsTrue(context.NeedToComputeBlobAsset(k3));
                    var blobAsset = BlobAssetReference <int> .Create(3);

                    context.AddComputedBlobAsset(k3, blobAsset);

                    // Simulate BlobAsset operations with GO1
                    processList.Add(k3);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k3));

                    processList.Add(k4);
                    Assert.IsFalse(context.NeedToComputeBlobAsset(k4));

                    // Associate the BlobAssets with GO0
                    context.AssociateBlobAssetWithGameObject(k1, go0);
                    context.AssociateBlobAssetWithGameObject(k2, go0);
                    context.AssociateBlobAssetWithGameObject(k3, go0);

                    // Associate the BlobAssets with GO1
                    context.AssociateBlobAssetWithGameObject(k3, go1);
                    context.AssociateBlobAssetWithGameObject(k4, go1);

                    // Check BlobAsset are retrieved correctly
                    var replayIndex = 0;
                    context.GetBlobAsset(processList[replayIndex++], out var res);
                    Assert.AreEqual(1, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(2, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(3, res.Value);
                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(3, res.Value);

                    context.GetBlobAsset(processList[replayIndex++], out res);
                    Assert.AreEqual(4, res.Value);
                }

            // Check the GO-BlobAsset associations
            m_Store.GetBlobAssetsOfGameObject(go0, Allocator.Temp, out hashes);
            Assert.AreEqual(3, hashes.Length);
            Assert.IsTrue(hashes.Contains(k1));
            Assert.IsTrue(hashes.Contains(k2));
            Assert.IsTrue(hashes.Contains(k3));
            hashes.Dispose();

            m_Store.GetBlobAssetsOfGameObject(go1, Allocator.Temp, out hashes);
            Assert.AreEqual(2, hashes.Length);
            Assert.IsTrue(hashes.Contains(k3));
            Assert.IsTrue(hashes.Contains(k4));
            hashes.Dispose();

            // 0, 1, 1, 2, 1 as expected RefCounter for k0...4
            Assert.AreEqual(0, m_Store.GetBlobAssetRefCounter(k0));
            Assert.AreEqual(1, m_Store.GetBlobAssetRefCounter(k1));
            Assert.AreEqual(1, m_Store.GetBlobAssetRefCounter(k2));
            Assert.AreEqual(2, m_Store.GetBlobAssetRefCounter(k3));
            Assert.AreEqual(1, m_Store.GetBlobAssetRefCounter(k4));

            // BlobAsset of k0 is not used by any UnityObject anymore, is should have been removed from the store
            Assert.IsFalse(m_Store.Contains <int>(k0));

            // Cleanup
            Object.DestroyImmediate(go0);
        }
 protected override void OnUpdate() =>
 BlobComputationContext = new BlobAssetComputationContext <int, Collider>(BlobAssetStore, 128, Allocator.TempJob);
예제 #9
0
        protected override void OnUpdate()
        {
            var simpleMeshContext = new BlobAssetComputationContext <UMeshSettings, SimpleMeshData>(BlobAssetStore, 128, Allocator.Temp);
            var litMeshContext    = new BlobAssetComputationContext <UMeshSettings, LitMeshData>(BlobAssetStore, 128, Allocator.Temp);

            JobHandle combinedJH  = new JobHandle();
            int       simpleIndex = 0;
            int       litIndex    = 0;

            // Init blobasset arrays
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                CheckForMeshLimitations(uMesh);
                var entity = GetPrimaryEntity(uMesh);
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    simpleIndex++;
                }
                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    litIndex++;
                }
            });
            NativeArray <BlobAssetReference <SimpleMeshData> > simpleblobs = new NativeArray <BlobAssetReference <SimpleMeshData> >(simpleIndex, Allocator.TempJob);
            NativeArray <BlobAssetReference <LitMeshData> >    litblobs    = new NativeArray <BlobAssetReference <LitMeshData> >(litIndex, Allocator.TempJob);

            simpleIndex = 0;
            litIndex    = 0;

            // Check which blob assets to re-compute
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                var hash = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(), (uint)uMesh.subMeshCount.GetHashCode(), 0);

                var entity = GetPrimaryEntity(uMesh);

                //Schedule blob asset recomputation jobs
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    simpleMeshContext.AssociateBlobAssetWithUnityObject(hash, uMesh);
                    if (simpleMeshContext.NeedToComputeBlobAsset(hash))
                    {
                        var singleMeshData = new UMeshDataCache();
                        singleMeshData.RetrieveSimpleMeshData(uMesh);

                        UMeshSettings uMeshSettings = new UMeshSettings(hash, uMesh, simpleIndex++);
                        simpleMeshContext.AddBlobAssetToCompute(hash, uMeshSettings);
                        var job    = new SimpleMeshConversionJob(uMeshSettings, singleMeshData, simpleblobs);
                        combinedJH = JobHandle.CombineDependencies(combinedJH, job.Schedule(combinedJH));
                    }
                }
                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    litMeshContext.AssociateBlobAssetWithUnityObject(hash, uMesh);
                    if (litMeshContext.NeedToComputeBlobAsset(hash))
                    {
                        var litMeshData = new UMeshDataCache();
                        if (DstEntityManager.HasComponent <NeedGenerateGPUSkinnedMeshRenderer>(entity))
                        {
                            litMeshData.RetrieveLitSkinnedMeshData(uMesh, entity, DstEntityManager);
                        }
                        else
                        {
                            litMeshData.RetrieveLitMeshData(uMesh);
                        }

                        UMeshSettings uMeshSettings = new UMeshSettings(hash, uMesh, litIndex++);
                        litMeshContext.AddBlobAssetToCompute(hash, uMeshSettings);
                        var job    = new LitMeshConversionJob(uMeshSettings, litMeshData, litblobs);
                        combinedJH = JobHandle.CombineDependencies(combinedJH, job.Schedule(combinedJH));
                    }
                }
            });

            // Re-compute the new blob assets
            combinedJH.Complete();

            // Update the BlobAssetStore
            using (var simpleMeshSettings = simpleMeshContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < simpleMeshSettings.Length; i++)
                {
                    simpleMeshContext.AddComputedBlobAsset(simpleMeshSettings[i].hash, simpleblobs[simpleMeshSettings[i].blobIndex]);
                }
            }
            using (var litMeshSettings = litMeshContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < litMeshSettings.Length; i++)
                {
                    litMeshContext.AddComputedBlobAsset(litMeshSettings[i].hash, litblobs[litMeshSettings[i].blobIndex]);
                }
            }

            // Use blob assets in the conversion
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                var entity     = GetPrimaryEntity(uMesh);
                bool addBounds = false;
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    simpleMeshContext.GetBlobAsset(new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(), (uint)uMesh.subMeshCount.GetHashCode(), 0), out var blob);
                    DstEntityManager.AddComponentData(entity, new SimpleMeshRenderData()
                    {
                        Mesh = blob
                    });
                    addBounds = true;
                }
                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    litMeshContext.GetBlobAsset(new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(), (uint)uMesh.subMeshCount.GetHashCode(), 0), out var blob);
                    DstEntityManager.AddComponentData(entity, new LitMeshRenderData()
                    {
                        Mesh = blob
                    });
                    addBounds = true;
                }
                if (addBounds)
                {
                    DstEntityManager.AddComponentData(entity, new MeshBounds
                    {
                        Bounds = new AABB
                        {
                            Center  = uMesh.bounds.center,
                            Extents = uMesh.bounds.extents
                        }
                    });
                }
            });

            simpleMeshContext.Dispose();
            litMeshContext.Dispose();
            simpleblobs.Dispose();
            litblobs.Dispose();
        }
예제 #10
0
        protected override void OnUpdate()
        {
            var simpleMeshContext  = new BlobAssetComputationContext <UMeshSettings, SimpleMeshData>(BlobAssetStore, 128, Allocator.Temp);
            var litMeshContext     = new BlobAssetComputationContext <UMeshSettings, LitMeshData>(BlobAssetStore, 128, Allocator.Temp);
            var blendShapeContext  = new BlobAssetComputationContext <UMeshSettings, BlendShapeData>(BlobAssetStore, 128, Allocator.Temp);
            var skinnedMeshContext = new BlobAssetComputationContext <UMeshSettings, SkinnedMeshData>(BlobAssetStore, 128, Allocator.Temp);

            JobHandle combinedJH       = new JobHandle();
            int       simpleIndex      = 0;
            int       litIndex         = 0;
            int       blendShapeIndex  = 0;
            int       skinnedMeshIndex = 0;

            // Init blobasset arrays
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                CheckForMeshLimitations(uMesh);
                var entity = GetPrimaryEntity(uMesh);
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    simpleIndex++;
                }
                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    litIndex++;
                }
                if (uMesh.blendShapeCount > 0)
                {
                    blendShapeIndex++;
                }
                if (uMesh.boneWeights.Length > 0)
                {
                    skinnedMeshIndex++;
                }
            });
            NativeArray <BlobAssetReference <SimpleMeshData> >  simpleblobs      = new NativeArray <BlobAssetReference <SimpleMeshData> >(simpleIndex, Allocator.TempJob);
            NativeArray <BlobAssetReference <LitMeshData> >     litblobs         = new NativeArray <BlobAssetReference <LitMeshData> >(litIndex, Allocator.TempJob);
            NativeArray <BlobAssetReference <BlendShapeData> >  blendshapeblobs  = new NativeArray <BlobAssetReference <BlendShapeData> >(blendShapeIndex, Allocator.TempJob);
            NativeArray <BlobAssetReference <SkinnedMeshData> > skinnedMeshBlobs = new NativeArray <BlobAssetReference <SkinnedMeshData> >(litIndex, Allocator.TempJob);

            simpleIndex      = 0;
            litIndex         = 0;
            blendShapeIndex  = 0;
            skinnedMeshIndex = 0;

            // Check which blob assets to re-compute
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                var verticesHash = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                               (uint)uMesh.subMeshCount.GetHashCode(), 0);
                uint boneCount      = (uint)uMesh.bindposes.Length;
                var skinnedDataHash = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                                  (uint)uMesh.subMeshCount.GetHashCode(), (uint)boneCount.GetHashCode());

                var entity = GetPrimaryEntity(uMesh);

                //Schedule blob asset recomputation jobs
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    simpleMeshContext.AssociateBlobAssetWithUnityObject(verticesHash, uMesh);
                    if (simpleMeshContext.NeedToComputeBlobAsset(verticesHash))
                    {
                        var simpleMeshData = new UMeshDataCache();
                        if (boneCount > 0)
                        {
                            simpleMeshData.RetrieveSkinnedMeshData(uMesh, entity, DstEntityManager, false);
                            if (skinnedMeshContext.NeedToComputeBlobAsset(skinnedDataHash))
                            {
                                UMeshSettings uSkinnedMeshSettings = new UMeshSettings(skinnedDataHash, uMesh, skinnedMeshIndex++);
                                skinnedMeshContext.AddBlobAssetToCompute(skinnedDataHash, uSkinnedMeshSettings);
                                var skinningJob = new SkinningDataConversionJob(simpleMeshData, uSkinnedMeshSettings.blobIndex, skinnedMeshBlobs);
                                combinedJH      = JobHandle.CombineDependencies(combinedJH, skinningJob.Schedule(combinedJH));
                            }
                        }
                        else
                        {
                            simpleMeshData.RetrieveSimpleMeshData(uMesh);
                        }

                        UMeshSettings uMeshSettings = new UMeshSettings(verticesHash, uMesh, simpleIndex++);
                        simpleMeshContext.AddBlobAssetToCompute(verticesHash, uMeshSettings);
                        var job    = new SimpleMeshConversionJob(simpleMeshData, uMeshSettings.blobIndex, simpleblobs);
                        combinedJH = JobHandle.CombineDependencies(combinedJH, job.Schedule(combinedJH));
                    }
                }

                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    litMeshContext.AssociateBlobAssetWithUnityObject(verticesHash, uMesh);
                    if (litMeshContext.NeedToComputeBlobAsset(verticesHash))
                    {
                        var litMeshData = new UMeshDataCache();
                        if (boneCount > 0)
                        {
                            litMeshData.RetrieveSkinnedMeshData(uMesh, entity, DstEntityManager, true);
                            if (skinnedMeshContext.NeedToComputeBlobAsset(skinnedDataHash))
                            {
                                UMeshSettings uSkinnedMeshSettings = new UMeshSettings(skinnedDataHash, uMesh, skinnedMeshIndex++);
                                skinnedMeshContext.AddBlobAssetToCompute(skinnedDataHash, uSkinnedMeshSettings);
                                var skinningJob = new SkinningDataConversionJob(litMeshData, uSkinnedMeshSettings.blobIndex, skinnedMeshBlobs);
                                combinedJH      = JobHandle.CombineDependencies(combinedJH, skinningJob.Schedule(combinedJH));
                            }
                        }
                        else
                        {
                            litMeshData.RetrieveLitMeshData(uMesh);
                        }

                        UMeshSettings uMeshSettings = new UMeshSettings(verticesHash, uMesh, litIndex++);
                        litMeshContext.AddBlobAssetToCompute(verticesHash, uMeshSettings);
                        var job    = new LitMeshConversionJob(litMeshData, uMeshSettings.blobIndex, litblobs);
                        combinedJH = JobHandle.CombineDependencies(combinedJH, job.Schedule(combinedJH));
                    }
                }

                if (uMesh.blendShapeCount > 0)
                {
                    verticesHash = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                               (uint)uMesh.subMeshCount.GetHashCode(), (uint)uMesh.blendShapeCount);
                    blendShapeContext.AssociateBlobAssetWithUnityObject(verticesHash, uMesh);
                    if (blendShapeContext.NeedToComputeBlobAsset(verticesHash))
                    {
                        var blendShapeDataCache = new UBlendShapeDataCache();
                        blendShapeDataCache.RetrieveBlendShapeData(uMesh);

                        UMeshSettings uMeshSettings = new UMeshSettings(verticesHash, uMesh, blendShapeIndex++);
                        blendShapeContext.AddBlobAssetToCompute(verticesHash, uMeshSettings);

                        var job    = new BlendShapeConversionJob(uMeshSettings, blendShapeDataCache, blendshapeblobs);
                        combinedJH = JobHandle.CombineDependencies(combinedJH, job.Schedule(combinedJH));
                    }
                }
            });

            // Re-compute the new blob assets
            combinedJH.Complete();

            // Update the BlobAssetStore
            using (var simpleMeshSettings = simpleMeshContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < simpleMeshSettings.Length; i++)
                {
                    simpleMeshContext.AddComputedBlobAsset(simpleMeshSettings[i].hash, simpleblobs[simpleMeshSettings[i].blobIndex]);
                }
            }
            using (var litMeshSettings = litMeshContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < litMeshSettings.Length; i++)
                {
                    litMeshContext.AddComputedBlobAsset(litMeshSettings[i].hash, litblobs[litMeshSettings[i].blobIndex]);
                }
            }
            using (var meshSettings = blendShapeContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < meshSettings.Length; i++)
                {
                    blendShapeContext.AddComputedBlobAsset(meshSettings[i].hash, blendshapeblobs[meshSettings[i].blobIndex]);
                }
            }
            using (var meshSettings = skinnedMeshContext.GetSettings(Allocator.TempJob))
            {
                for (int i = 0; i < meshSettings.Length; i++)
                {
                    skinnedMeshContext.AddComputedBlobAsset(meshSettings[i].hash, skinnedMeshBlobs[meshSettings[i].blobIndex]);
                }
            }

            // Use blob assets in the conversion
            Entities.ForEach((UnityEngine.Mesh uMesh) =>
            {
                var entity     = GetPrimaryEntity(uMesh);
                bool addBounds = false;
                if (DstEntityManager.HasComponent <SimpleMeshRenderData>(entity))
                {
                    Hash128 hash128 = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                                  (uint)uMesh.subMeshCount.GetHashCode(), 0);
                    simpleMeshContext.GetBlobAsset(hash128, out var blob);
                    DstEntityManager.AddComponentData(entity, new SimpleMeshRenderData()
                    {
                        Mesh = blob
                    });

                    addBounds = true;
                }
                if (DstEntityManager.HasComponent <LitMeshRenderData>(entity))
                {
                    Hash128 hash128 = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                                  (uint)uMesh.subMeshCount.GetHashCode(), 0);
                    litMeshContext.GetBlobAsset(hash128, out var blob);
                    DstEntityManager.AddComponentData(entity, new LitMeshRenderData()
                    {
                        Mesh = blob
                    });

                    addBounds = true;
                }
                if (addBounds)
                {
                    DstEntityManager.AddComponentData(entity, new MeshBounds
                    {
                        Bounds = new AABB
                        {
                            Center  = uMesh.bounds.center,
                            Extents = uMesh.bounds.extents
                        }
                    });
                }
                if (uMesh.blendShapeCount > 0)
                {
                    Hash128 hash128 = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                                  (uint)uMesh.subMeshCount.GetHashCode(), (uint)uMesh.blendShapeCount);
                    blendShapeContext.GetBlobAsset(hash128, out var blendShapeBlob);
                    DstEntityManager.AddComponentData(entity, new MeshBlendShapeData()
                    {
                        BlendShapeDataRef = blendShapeBlob
                    });
                }

                if (uMesh.bindposes.Length > 0)
                {
                    var skinnedDataHash = new Hash128((uint)uMesh.GetHashCode(), (uint)uMesh.vertexCount.GetHashCode(),
                                                      (uint)uMesh.subMeshCount.GetHashCode(), (uint)uMesh.bindposes.Length.GetHashCode());
                    skinnedMeshContext.GetBlobAsset(skinnedDataHash, out var skinnedMeshBlob);
                    DstEntityManager.AddComponentData(entity, new SkinnedMeshRenderData()
                    {
                        SkinnedMeshDataRef = skinnedMeshBlob
                    });
                }
            });

            simpleMeshContext.Dispose();
            litMeshContext.Dispose();
            blendShapeContext.Dispose();
            simpleblobs.Dispose();
            litblobs.Dispose();
            blendshapeblobs.Dispose();
            skinnedMeshBlobs.Dispose();
        }
예제 #11
0
        protected override void OnUpdate()
        {
            using (var context = new BlobAssetComputationContext <int, GhostPrefabMetaData>(BlobAssetStore, 16, Allocator.Temp))
            {
                Entities.ForEach((GhostAuthoringComponent ghostAuthoring) =>
                {
                    bool isPrefab = !ghostAuthoring.gameObject.scene.IsValid() || ghostAuthoring.ForcePrefabConversion;
                    var target    = GetConversionTarget(this, isPrefab);
                    // Check if the ghost is valid before starting to process
                    if (String.IsNullOrEmpty(ghostAuthoring.prefabId))
                    {
                        throw new InvalidOperationException($"The ghost {ghostAuthoring.gameObject.name} is not a valid prefab, all ghosts must be the top-level GameObject in a prefab. Ghost instances in scenes must be instances of such prefabs and changes should be made on the prefab asset, not the prefab instance");
                    }

                    if (!isPrefab && ghostAuthoring.DefaultGhostMode == GhostAuthoringComponent.GhostMode.OwnerPredicted && target != NetcodeConversionTarget.Server)
                    {
                        throw new InvalidOperationException($"Cannot convert a owner predicted ghost {ghostAuthoring.Name} as a scene instance");
                    }

                    if (!isPrefab && DstEntityManager.World.GetExistingSystem <ClientSimulationSystemGroup>() != null)
                    {
                        throw new InvalidOperationException($"The ghost {ghostAuthoring.gameObject.name} cannot be created on the client, either put it in a sub-scene or spawn it on the server only");
                    }

                    if (ghostAuthoring.prefabId.Length != 32)
                    {
                        throw new InvalidOperationException("Invalid guid for ghost prefab type");
                    }

                    // All ghosts should have a linked entity group
                    DeclareLinkedEntityGroup(ghostAuthoring.gameObject);
                    var entity = GetPrimaryEntity(ghostAuthoring);

                    // Generate a ghost type component so the ghost can be identified by mathcing prefab asset guid
                    var ghostType   = new GhostTypeComponent();
                    ghostType.guid0 = Convert.ToUInt32(ghostAuthoring.prefabId.Substring(0, 8), 16);
                    ghostType.guid1 = Convert.ToUInt32(ghostAuthoring.prefabId.Substring(8, 8), 16);
                    ghostType.guid2 = Convert.ToUInt32(ghostAuthoring.prefabId.Substring(16, 8), 16);
                    ghostType.guid3 = Convert.ToUInt32(ghostAuthoring.prefabId.Substring(24, 8), 16);
                    DstEntityManager.AddComponentData(entity, ghostType);

                    // FIXME: maybe stripping should be individual systems running before this to make sure it can be changed in a way that always triggers a reconvert - and to avoid reflection
                    var components = DstEntityManager.GetComponentTypes(entity);
                    if (target != NetcodeConversionTarget.Client)
                    {
                        // If this ghost should be usable on a server we must add a shared ghost type to make sure different ghost types
                        // with the same archetype end up in different chunks. If conversion is client and server the client needs to remove
                        // this at runtime
                        DstEntityManager.AddSharedComponentData(entity, new SharedGhostTypeComponent {
                            SharedValue = ghostType
                        });
                    }
                    if (target != NetcodeConversionTarget.Server)
                    {
                        // Converting to client or client and server, if client and server this should be stripped from servers at runtime
                        DstEntityManager.AddComponentData(entity, new SnapshotData());
                        DstEntityManager.AddBuffer <SnapshotDataBuffer>(entity);
                    }
                    // All types have the ghost components
                    DstEntityManager.AddComponentData(entity, new GhostComponent());
                    // No need to add the predicted ghost component for interpolated only ghosts if the data is only used by the client
                    if (target != NetcodeConversionTarget.Client || ghostAuthoring.SupportedGhostModes != GhostAuthoringComponent.GhostModeMask.Interpolated)
                    {
                        DstEntityManager.AddComponentData(entity, new PredictedGhostComponent());
                    }
                    if (target == NetcodeConversionTarget.Server)
                    {
                        // If converting server-only data we can remove all components which are not used on the server
                        foreach (var comp in components)
                        {
                            var attr = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                            if (attr != null && (attr.PrefabType & GhostPrefabType.Server) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                        }
                    }
                    else if (target == NetcodeConversionTarget.Client)
                    {
                        // If converting client-only data we can remove all components which are not used on the client
                        // If the ghost is interpolated only we can also remove all componens which are not used on interpolated clients,
                        // and if it is predicted only we can remove everything which is not used on predicted clients
                        foreach (var comp in components)
                        {
                            var attr = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                            if (attr == null)
                            {
                                continue;
                            }
                            if ((attr.PrefabType & GhostPrefabType.Client) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                            else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Interpolated && (attr.PrefabType & GhostPrefabType.InterpolatedClient) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                            else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Predicted && (attr.PrefabType & GhostPrefabType.PredictedClient) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                        }
                    }
                    // Even if converting for client and server we can remove components which are only for predicted clients when
                    // the ghost is always interpolated, or components which are only for interpolated clients if the ghost is always
                    // predicted
                    else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Interpolated)
                    {
                        foreach (var comp in components)
                        {
                            var attr = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                            if (attr != null && (attr.PrefabType & (GhostPrefabType.InterpolatedClient | GhostPrefabType.Server)) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                        }
                    }
                    else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Predicted)
                    {
                        foreach (var comp in components)
                        {
                            var attr = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                            if (attr != null && (attr.PrefabType & (GhostPrefabType.PredictedClient | GhostPrefabType.Server)) == 0)
                            {
                                DstEntityManager.RemoveComponent(entity, comp);
                            }
                        }
                    }

                    // This logic needs to match the logic creating LinkedEntityGroups, gather a list of all child entities
                    var linkedEntities  = new NativeList <Entity>(1, Allocator.Temp);
                    var selfAndChildren = ghostAuthoring.gameObject.GetComponentsInChildren <Transform>(true);
                    foreach (var transform in selfAndChildren)
                    {
                        foreach (var child in GetEntities(transform.gameObject))
                        {
                            if (DstEntityManager.Exists(child))
                            {
                                linkedEntities.Add(child);
                            }
                        }
                    }
                    // Mark all child entities as ghost children, entity 0 is the root and hsould not be marked
                    for (int i = 1; i < linkedEntities.Length; ++i)
                    {
                        DstEntityManager.AddComponentData(linkedEntities[i], default(GhostChildEntityComponent));
                    }

                    if (isPrefab)
                    {
                        var contentHash = TypeHash.FNV1A64(ghostAuthoring.Importance);
                        contentHash     = TypeHash.CombineFNV1A64(contentHash, TypeHash.FNV1A64((int)ghostAuthoring.SupportedGhostModes));
                        contentHash     = TypeHash.CombineFNV1A64(contentHash, TypeHash.FNV1A64((int)ghostAuthoring.DefaultGhostMode));
                        contentHash     = TypeHash.CombineFNV1A64(contentHash, TypeHash.FNV1A64((int)ghostAuthoring.OptimizationMode));
                        contentHash     = TypeHash.CombineFNV1A64(contentHash, TypeHash.FNV1A64(ghostAuthoring.Name.ToString()));
                        foreach (var comp in components)
                        {
                            contentHash = TypeHash.CombineFNV1A64(contentHash, TypeManager.GetTypeInfo(comp.TypeIndex).StableTypeHash);
                            var attr    = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                            if (attr != null)
                            {
                                contentHash = TypeHash.CombineFNV1A64(contentHash, TypeHash.FNV1A64((int)attr.PrefabType));
                            }
                        }
                        var blobHash = new Unity.Entities.Hash128(ghostType.guid0 ^ (uint)(contentHash >> 32), ghostType.guid1 ^ (uint)(contentHash), ghostType.guid2, ghostType.guid3);
                        context.AssociateBlobAssetWithUnityObject(blobHash, ghostAuthoring.gameObject);
                        if (context.NeedToComputeBlobAsset(blobHash))
                        {
                            var builder  = new BlobBuilder(Allocator.Temp);
                            ref var root = ref builder.ConstructRoot <GhostPrefabMetaData>();

                            // Store importance, supported modes, default mode and name in the meta data blob asset
                            root.Importance     = ghostAuthoring.Importance;
                            root.SupportedModes = GhostPrefabMetaData.GhostMode.Both;
                            root.DefaultMode    = GhostPrefabMetaData.GhostMode.Interpolated;
                            if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Interpolated)
                            {
                                root.SupportedModes = GhostPrefabMetaData.GhostMode.Interpolated;
                            }
                            else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Predicted)
                            {
                                root.SupportedModes = GhostPrefabMetaData.GhostMode.Predicted;
                                root.DefaultMode    = GhostPrefabMetaData.GhostMode.Predicted;
                            }
                            else if (ghostAuthoring.DefaultGhostMode == GhostAuthoringComponent.GhostMode.OwnerPredicted)
                            {
                                if (!DstEntityManager.HasComponent <GhostOwnerComponent>(entity))
                                {
                                    throw new InvalidOperationException("OwnerPrediction mode can only be used on prefabs which have a GhostOwnerComponent");
                                }
                                root.DefaultMode = GhostPrefabMetaData.GhostMode.Both;
                            }
                            else if (ghostAuthoring.DefaultGhostMode == GhostAuthoringComponent.GhostMode.Predicted)
                            {
                                root.DefaultMode = GhostPrefabMetaData.GhostMode.Predicted;
                            }
                            root.StaticOptimization = (ghostAuthoring.OptimizationMode == GhostAuthoringComponent.GhostOptimizationMode.Static);
                            builder.AllocateString(ref root.Name, ghostAuthoring.Name);

                            var serverComponents      = new NativeList <ulong>(components.Length, Allocator.Temp);
                            var removeOnServer        = new NativeList <ulong>(components.Length, Allocator.Temp);
                            var removeOnClient        = new NativeList <ulong>(components.Length, Allocator.Temp);
                            var disableOnPredicted    = new NativeList <ulong>(components.Length, Allocator.Temp);
                            var disableOnInterpolated = new NativeList <ulong>(components.Length, Allocator.Temp);

                            // Snapshot data buffers should be removed from the server, and shared ghost type from the client
                            removeOnServer.Add(TypeManager.GetTypeInfo(ComponentType.ReadWrite <SnapshotData>().TypeIndex).StableTypeHash);
                            removeOnServer.Add(TypeManager.GetTypeInfo(ComponentType.ReadWrite <SnapshotDataBuffer>().TypeIndex).StableTypeHash);
                            removeOnClient.Add(TypeManager.GetTypeInfo(ComponentType.ReadWrite <SharedGhostTypeComponent>().TypeIndex).StableTypeHash);

                            // If both interpolated and predicted clients are supported the interpolated client needs to disable the prediction component
                            // If the ghost is interpolated only the prediction component can be removed on clients
                            if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.All)
                            {
                                disableOnInterpolated.Add(TypeManager.GetTypeInfo(ComponentType.ReadWrite <PredictedGhostComponent>().TypeIndex).StableTypeHash);
                            }
                            else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Interpolated)
                            {
                                removeOnClient.Add(TypeManager.GetTypeInfo(ComponentType.ReadWrite <PredictedGhostComponent>().TypeIndex).StableTypeHash);
                            }

                            foreach (var comp in components)
                            {
                                var hash = TypeManager.GetTypeInfo(comp.TypeIndex).StableTypeHash;
                                var attr = comp.GetManagedType().GetCustomAttribute <GhostComponentAttribute>();
                                if (attr == null)
                                {
                                    serverComponents.Add(hash);
                                    continue;
                                }
                                if ((attr.PrefabType & GhostPrefabType.Server) == 0)
                                {
                                    removeOnServer.Add(hash);
                                }
                                else
                                {
                                    serverComponents.Add(hash);
                                }

                                // If something is not used on the client, remove it. Make sure to include things that is interpolated only if ghost
                                // is predicted only and the other way around
                                if ((attr.PrefabType & GhostPrefabType.Client) == 0)
                                {
                                    removeOnClient.Add(hash);
                                }
                                else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Interpolated &&
                                         (attr.PrefabType & GhostPrefabType.InterpolatedClient) == 0)
                                {
                                    removeOnClient.Add(hash);
                                }
                                else if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.Predicted &&
                                         (attr.PrefabType & GhostPrefabType.PredictedClient) == 0)
                                {
                                    removeOnClient.Add(hash);
                                }

                                // If the prefab only supports a single mode on the client there is no need to enable / disable, if is handled by the
                                // previous loop removing components on the client instead
                                if (ghostAuthoring.SupportedGhostModes == GhostAuthoringComponent.GhostModeMask.All)
                                {
                                    // Components available on predicted but not interpolated should be disabled on interpolated clients
                                    if ((attr.PrefabType & GhostPrefabType.InterpolatedClient) == 0 && (attr.PrefabType & GhostPrefabType.PredictedClient) != 0)
                                    {
                                        disableOnInterpolated.Add(hash);
                                    }
                                    if ((attr.PrefabType & GhostPrefabType.InterpolatedClient) != 0 && (attr.PrefabType & GhostPrefabType.PredictedClient) == 0)
                                    {
                                        disableOnPredicted.Add(hash);
                                    }
                                }
                            }
                            var blobServerComponents = builder.Allocate(ref root.ServerComponentList, serverComponents.Length);
                            for (int i = 0; i < serverComponents.Length; ++i)
                            {
                                blobServerComponents[i] = serverComponents[i];
                            }

                            // A pre-spawned instance can be created in ClientServer even if the prefab is not, so anything which should
                            // be usable on the server needs to know what to remove from the server version
                            if (target != NetcodeConversionTarget.Client)
                            {
                                // Client only data never needs information about the server
                                var blobRemoveOnServer = builder.Allocate(ref root.RemoveOnServer, removeOnServer.Length);
                                for (int i = 0; i < removeOnServer.Length; ++i)
                                {
                                    blobRemoveOnServer[i] = removeOnServer[i];
                                }
                            }
                            else
                            {
                                builder.Allocate(ref root.RemoveOnServer, 0);
                            }
                            if (target != NetcodeConversionTarget.Server)
                            {
                                var blobRemoveOnClient = builder.Allocate(ref root.RemoveOnClient, removeOnClient.Length);
                                for (int i = 0; i < removeOnClient.Length; ++i)
                                {
                                    blobRemoveOnClient[i] = removeOnClient[i];
                                }
                            }
                            else
                            {
                                builder.Allocate(ref root.RemoveOnClient, 0);
                            }

                            if (target != NetcodeConversionTarget.Server)
                            {
                                // The data for interpolated / predicted diff is required unless this is server-only
                                var blobDisableOnPredicted = builder.Allocate(ref root.DisableOnPredictedClient, disableOnPredicted.Length);
                                for (int i = 0; i < disableOnPredicted.Length; ++i)
                                {
                                    blobDisableOnPredicted[i] = disableOnPredicted[i];
                                }
                                var blobDisableOnInterpolated = builder.Allocate(ref root.DisableOnInterpolatedClient, disableOnInterpolated.Length);
                                for (int i = 0; i < disableOnInterpolated.Length; ++i)
                                {
                                    blobDisableOnInterpolated[i] = disableOnInterpolated[i];
                                }
                            }
                            else
                            {
                                builder.Allocate(ref root.DisableOnPredictedClient, 0);
                                builder.Allocate(ref root.DisableOnInterpolatedClient, 0);
                            }

                            var blobAsset = builder.CreateBlobAssetReference <GhostPrefabMetaData>(Allocator.Persistent);
                            context.AddComputedBlobAsset(blobHash, blobAsset);
                        }
                        context.GetBlobAsset(blobHash, out var blob);
                        DstEntityManager.AddComponentData(entity, new GhostPrefabMetaDataComponent {
                            Value = blob
                        });
                    }
                });