protected override void OnUpdate() { Entities.ForEach( (LegacyRigidBody body) => { var entity = GetPrimaryEntity(body.gameObject); // prefer conversions from non-legacy data if they have already been performed if (DstEntityManager.HasComponent <PhysicsVelocity>(entity)) { return; } DstEntityManager.PostProcessTransformComponents( entity, body.transform, body.isKinematic ? BodyMotionType.Kinematic : BodyMotionType.Dynamic ); if (body.gameObject.isStatic) { return; } if (body.interpolation != RigidbodyInterpolation.None) { DstEntityManager.AddOrSetComponent(entity, new PhysicsGraphicalSmoothing()); if (body.interpolation == RigidbodyInterpolation.Interpolate) { DstEntityManager.AddComponentData(entity, new PhysicsGraphicalInterpolationBuffer { PreviousTransform = Math.DecomposeRigidBodyTransform(body.transform.localToWorldMatrix) }); } } // Build mass component var massProperties = MassProperties.UnitSphere; if (DstEntityManager.HasComponent <PhysicsCollider>(entity)) { // Build mass component massProperties = DstEntityManager.GetComponentData <PhysicsCollider>(entity).MassProperties; } // n.b. no way to know if CoM was manually adjusted, so all legacy Rigidbody objects use auto CoM DstEntityManager.AddOrSetComponent(entity, !body.isKinematic ? PhysicsMass.CreateDynamic(massProperties, body.mass) : PhysicsMass.CreateKinematic(massProperties)); DstEntityManager.AddOrSetComponent(entity, new PhysicsVelocity()); if (!body.isKinematic) { DstEntityManager.AddOrSetComponent(entity, new PhysicsDamping { Linear = body.drag, Angular = body.angularDrag }); if (!body.useGravity) { DstEntityManager.AddOrSetComponent(entity, new PhysicsGravityFactor { Value = 0f }); } } else { DstEntityManager.AddOrSetComponent(entity, new PhysicsGravityFactor { Value = 0 }); } } ); }
protected override void OnUpdate() { Entities.ForEach((Canvas canvas) => { var parent = canvas.transform.parent; if (parent != null) { #if UNITY_EDITOR UnityEditor.EditorGUIUtility.PingObject(canvas); #endif throw new NotSupportedException($"{canvas.name} is child of {parent.name}, this is not supported!"); } var entity = GetPrimaryEntity(canvas); var canvasScaler = canvas.GetComponent <CanvasScaler>(); // Build a metadata of the children which are active var count = 0; count = RecurseCountChildren(ref count, canvas.transform); var metadata = new UnsafeHashMap <Entity, bool>(count + 1, Allocator.Persistent); RecurseAddMetadata(ref metadata, canvas.transform); DstEntityManager.AddComponentData(entity, new ChildrenActiveMetadata { Value = metadata }); // Remove unnecessary information DstEntityManager.RemoveComponent <Rotation>(entity); DstEntityManager.RemoveComponent <Translation>(entity); DstEntityManager.RemoveComponent <NonUniformScale>(entity); // Add the root mesh renderering data to the canvas as the root primary renderer DstEntityManager.AddBuffer <RootVertexData>(entity); DstEntityManager.AddBuffer <RootTriangleIndexElement>(entity); // Add a mesh to the canvas so treat it as a renderer. DstEntityManager.AddComponentData(entity, new AddMeshTag { }); // Add a collection of the submesh information DstEntityManager.AddBuffer <SubmeshSliceElement>(entity); DstEntityManager.AddBuffer <SubmeshKeyElement>(entity); switch (canvasScaler.uiScaleMode) { case CanvasScaler.ScaleMode.ScaleWithScreenSize: DstEntityManager.AddComponentData(entity, new ReferenceResolution { Value = canvasScaler.referenceResolution }); // TODO: Should figure out if I want to support shrinking and expanding only... if (canvasScaler.screenMatchMode == CanvasScaler.ScreenMatchMode.MatchWidthOrHeight) { DstEntityManager.AddComponentData(entity, new WidthHeightRatio { Value = canvasScaler.matchWidthOrHeight }); } else { throw new NotSupportedException($"{canvasScaler.screenMatchMode} is not supported yet."); } break; default: throw new NotSupportedException($"{canvasScaler.uiScaleMode} is not supported yet."); } }); }
protected override void OnUpdate() { Entities.ForEach((UnityEngine.Rigidbody2D rigidbody) => { // We don't convert a Rigidbody2D if it's not Simulated. if (!rigidbody.simulated) { return; } var entity = GetPrimaryEntity(rigidbody); var bodyType = rigidbody.bodyType; // There's no components to define a Static rigidbody or its properties. if (bodyType != UnityEngine.RigidbodyType2D.Static) { // Velocity. if (!DstEntityManager.HasComponent <PhysicsVelocity>(entity)) { DstEntityManager.AddComponentData(entity, new PhysicsVelocity { Linear = rigidbody.velocity, Angular = rigidbody.angularVelocity }); } var massProperties = MassProperties.Default; // Fetch mass properties from any available collider. if (DstEntityManager.HasComponent <PhysicsColliderBlob>(entity)) { var collider = DstEntityManager.GetComponentData <PhysicsColliderBlob>(entity).Collider; massProperties = collider.IsCreated ? collider.Value.MassProperties : MassProperties.Default; } // Dynamic. if (bodyType == UnityEngine.RigidbodyType2D.Dynamic) { DstEntityManager.AddOrSetComponent(entity, PhysicsMass.CreateDynamic(massProperties, rigidbody.mass)); if (!DstEntityManager.HasComponent <PhysicsGravity>(entity)) { DstEntityManager.AddComponentData(entity, new PhysicsGravity { Scale = rigidbody.gravityScale }); } if (!DstEntityManager.HasComponent <PhysicsDamping>(entity)) { DstEntityManager.AddComponentData(entity, new PhysicsDamping { Linear = rigidbody.drag, Angular = rigidbody.angularDrag }); } } // Kinematic. else { DstEntityManager.AddOrSetComponent(entity, PhysicsMass.CreateKinematic(massProperties)); } } // Create any colliders associated with this rigidbody entity. m_ColliderConversionSystem.CreateCollider(entity); }); }
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(); } }
protected override void OnUpdate() { Entities.ForEach((Path path) => { var entity = GetPrimaryEntity(path); int numPathNodes = path.GetNumNodes(); PathMap.Add(path.GetInstanceID(), RIndex); RoadSettings roadSettings = path.gameObject.GetComponentInParent <RoadSettings>(); uint spawnPool = 0; if (roadSettings != null) { spawnPool = roadSettings.vehicleSelection; } for (int n = 1; n < numPathNodes; n++) { var rs = new RoadSection(); path.GetSplineSection(n - 1, out rs.p0, out rs.p1, out rs.p2, out rs.p3); rs.arcLength = CatmullRom.ComputeArcLength(rs.p0, rs.p1, rs.p2, rs.p3, 1024); rs.vehicleHalfLen = Constants.VehicleLength / rs.arcLength; rs.vehicleHalfLen /= 2; rs.sortIndex = RIndex; rs.linkNext = RIndex + 1; if (n == numPathNodes - 1) { rs.linkNext = -1; MergeMap[math.round((path.GetReversibleRawPosition(n) + new float3(path.transform.position)) * Constants.NodePositionRounding) / Constants.NodePositionRounding] = RIndex; } rs.linkExtraChance = 0.0f; rs.linkExtra = -1; rs.width = path.width; rs.height = path.height; rs.minSpeed = path.minSpeed; rs.maxSpeed = path.maxSpeed; rs.occupationLimit = math.min(Constants.RoadOccupationSlotsMax, (int)math.round(rs.arcLength / Constants.VehicleLength)); var sectionEnt = CreateAdditionalEntity(path); IdxMap[RIndex] = sectionEnt; if (!path.isOnRamp) { RampMap[math.round((path.GetReversibleRawPosition(n - 1) + new float3(path.transform.position)) * Constants.NodePositionRounding) / Constants.NodePositionRounding] = RIndex; if (n == 1) { int x = 2; // Only spawn in right lane float t = rs.vehicleHalfLen; float pathTime = (n - 1) + t; var spawner = new Spawner(); spawner.Time = math.frac(pathTime); spawner.Direction = math.normalize(path.GetTangent(pathTime)); float3 rightPos = (x - 1) * math.mul(spawner.Direction, Vector3.right) * ((rs.width - Constants.VehicleWidth) / 2.0f); spawner.Position = path.GetWorldPosition(pathTime) + rightPos; spawner.RoadIndex = RIndex; spawner.minSpeed = path.minSpeed; spawner.maxSpeed = path.maxSpeed; var speedInverse = 1.0f / spawner.minSpeed; spawner.random = new Unity.Mathematics.Random((uint)RIndex + 1); spawner.delaySpawn = (int)Constants.VehicleLength + spawner.random.NextInt((int)(speedInverse * 60.0f), (int)(speedInverse * 120.0f)); spawner.LaneIndex = x; spawner.poolSpawn = spawnPool; // Each path will only have one spawner, so use the Primary Entity DstEntityManager.AddComponentData(entity, spawner); } } RIndex++; DstEntityManager.AddComponentData(sectionEnt, rs); } }); // Loop over the paths again to start building the ramps and merges Entities.ForEach((Path path) => { int numPathNodes = path.GetNumNodes(); // Handle On Ramp roads if (path.isOnRamp) { int rsRampIdx = PathMap[path.GetInstanceID()]; float3 rampEntry = math.round((path.GetReversibleRawPosition(0) + new float3(path.transform.position)) * Constants.NodePositionRounding) / Constants.NodePositionRounding; if (RampMap.ContainsKey(rampEntry)) { int rsIndex = RampMap[rampEntry]; if (rsIndex > 0) { rsIndex -= 1; if (IdxMap.ContainsKey(rsIndex)) { Entity ramp = IdxMap[rsIndex]; RoadSection rs = DstEntityManager.GetComponentData <RoadSection>(ramp); if (rs.linkNext == rsIndex + 1) { rs.linkExtra = rsRampIdx; rs.linkExtraChance = path.percentageChanceForOnRamp / 100.0f; DstEntityManager.SetComponentData(ramp, rs); } } } } } // Handle merging roads { int n = 0; float3 pos = math.round((path.GetReversibleRawPosition(n) + new float3(path.transform.position)) * Constants.NodePositionRounding) / Constants.NodePositionRounding; if (MergeMap.ContainsKey(pos)) { int mergeFromIndex = MergeMap[pos]; int mergeToBase = PathMap[path.GetInstanceID()]; if (mergeFromIndex > 0 && mergeFromIndex != mergeToBase + n) { Entity merge = IdxMap[mergeFromIndex]; RoadSection rs = DstEntityManager.GetComponentData <RoadSection>(merge); if (rs.linkNext == -1) { rs.linkNext = mergeToBase + n; DstEntityManager.SetComponentData(merge, rs); } } } } }); RIndex = 0; PathMap.Clear(); RampMap.Clear(); MergeMap.Clear(); IdxMap.Clear(); }
protected override void OnUpdate() { Entities.ForEach((LODGroup lodGroup) => { if (lodGroup.lodCount > 8) { Debug.LogWarning("LODGroup has more than 8 LOD - Not supported", lodGroup); return; } var lodGroupEntity = GetPrimaryEntity(lodGroup); var lodGroupData = new MeshLODGroupComponent(); //@TODO: LOD calculation should respect scale... var worldSpaceSize = LODGroupExtensions.GetWorldSpaceSize(lodGroup); lodGroupData.LocalReferencePoint = lodGroup.localReferencePoint; var lodDistances0 = new float4(float.PositiveInfinity); var lodDistances1 = new float4(float.PositiveInfinity); var lodGroupLODs = lodGroup.GetLODs(); for (int i = 0; i < lodGroup.lodCount; ++i) { float d = worldSpaceSize / lodGroupLODs[i].screenRelativeTransitionHeight; if (i < 4) { lodDistances0[i] = d; } else { lodDistances1[i - 4] = d; } } lodGroupData.LODDistances0 = lodDistances0; lodGroupData.LODDistances1 = lodDistances1; DstEntityManager.AddComponentData(lodGroupEntity, lodGroupData); for (int i = 0; i < lodGroupLODs.Length; ++i) { foreach (var renderer in lodGroupLODs[i].renderers) { if (renderer == null) { Debug.LogWarning("Missing renderer in LOD Group", lodGroup); continue; } DeclareDependency(renderer, lodGroup); DeclareDependency(lodGroup, renderer); foreach (var rendererEntity in GetEntities(renderer)) { if (DstEntityManager.HasComponent <RenderMesh>(rendererEntity)) { var lodComponent = new MeshLODComponent { Group = lodGroupEntity, LODMask = 1 << i }; if (!DstEntityManager.HasComponent <MeshLODComponent>(rendererEntity)) { DstEntityManager.AddComponentData(rendererEntity, lodComponent); } else { var previousLODComponent = DstEntityManager.GetComponentData <MeshLODComponent>(rendererEntity); if (previousLODComponent.Group != lodComponent.Group) { Debug.LogWarning("A renderer can not be in multiple different LODGroup.", renderer); continue; } if ((previousLODComponent.LODMask & (1 << (i - 1))) == 0) { Debug.LogWarning("A renderer that is present in the same LODGroup multiple times must be in consecutive LOD levels.", renderer); } lodComponent.LODMask |= previousLODComponent.LODMask; DstEntityManager.SetComponentData(rendererEntity, lodComponent); } } } } } }); }
protected override void OnUpdate() { Entities.ForEach((HLOD hlod) => { var lodGroup = hlod.GetComponent <LODGroup>(); var hlodEntity = GetPrimaryEntity(hlod); // If conversion of LODGroup failed, skip HLOD conversion too if (!DstEntityManager.HasComponent <MeshLODGroupComponent>(hlodEntity)) { return; } DstEntityManager.AddComponent(hlodEntity, ComponentType.ReadWrite <HLODComponent>()); var LODCount = lodGroup.lodCount; if (LODCount != hlod.LODParentTransforms.Length) { Debug.LogWarning("HLOD out of sync with LODGroup", hlod); return; } for (int i = 0; i != LODCount; i++) { var childGroups = hlod.CalculateLODGroups(i); var HLODMask = 1 << i; foreach (var childGroup in childGroups) { var childLodGroupEntities = GetEntities(childGroup); if (childLodGroupEntities.Count() == 0) { Debug.LogWarning($"Missing child group '{childGroup.gameObject.name}' in LOD group '{hlod.gameObject.name}', this can happen because the child group is disabled."); return; } foreach (var childLodGroupEntity in childLodGroupEntities) { if (DstEntityManager.HasComponent <MeshLODGroupComponent>(childLodGroupEntity)) { var group = DstEntityManager.GetComponentData <MeshLODGroupComponent>(childLodGroupEntity); group.ParentGroup = hlodEntity; group.ParentMask = HLODMask; DstEntityManager.SetComponentData(childLodGroupEntity, group); } } } var outsideRenderers = CalculateRenderersOutsideLODGroups(hlod, i); foreach (var r in outsideRenderers) { foreach (var rendererEntity in GetEntities(r)) { if (DstEntityManager.HasComponent <RenderMesh>(rendererEntity)) { //@TODO: Not quite sure if this makes sense. Test that this behaviour is reasonable. if (DstEntityManager.HasComponent <MeshLODComponent>(rendererEntity)) { continue; } var lodComponent = new MeshLODComponent { Group = hlodEntity, LODMask = HLODMask }; DstEntityManager.AddComponentData(rendererEntity, lodComponent); } } } } }); }
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(); }
protected override void OnUpdate() { var sceneBounds = MinMaxAABB.Empty; var materials = new List <Material>(10); Entities.ForEach((MeshRenderer meshRenderer, MeshFilter meshFilter) => { var entity = GetPrimaryEntity(meshRenderer); var dst = new RenderMesh(); dst.mesh = meshFilter.sharedMesh; dst.castShadows = meshRenderer.shadowCastingMode; dst.receiveShadows = meshRenderer.receiveShadows; dst.layer = meshRenderer.gameObject.layer; //@TODO: Transform system should handle RenderMeshFlippedWindingTag automatically. This should not be the responsibility of the conversion system. float4x4 localToWorld = meshRenderer.transform.localToWorldMatrix; var flipWinding = math.determinant(localToWorld) < 0.0; meshRenderer.GetSharedMaterials(materials); var materialCount = materials.Count; if (materialCount == 1 && AttachToPrimaryEntityForSingleMaterial) { dst.material = materials[0]; dst.subMesh = 0; DstEntityManager.AddSharedComponentData(entity, dst); DstEntityManager.AddComponentData(entity, new PerInstanceCullingTag()); if (flipWinding) { DstEntityManager.AddComponent(entity, ComponentType.ReadWrite <RenderMeshFlippedWindingTag>()); } } else { for (var m = 0; m != materialCount; m++) { var meshEntity = CreateAdditionalEntity(meshRenderer); dst.material = materials[m]; dst.subMesh = m; DstEntityManager.AddSharedComponentData(meshEntity, dst); DstEntityManager.AddComponentData(meshEntity, new PerInstanceCullingTag()); DstEntityManager.AddComponentData(meshEntity, new LocalToWorld { Value = localToWorld }); if (!DstEntityManager.HasComponent <Static>(meshEntity)) { DstEntityManager.AddComponentData(meshEntity, new Parent { Value = entity }); DstEntityManager.AddComponentData(meshEntity, new LocalToParent { Value = float4x4.identity }); } if (flipWinding) { DstEntityManager.AddComponent(meshEntity, ComponentType.ReadWrite <RenderMeshFlippedWindingTag>()); } } } sceneBounds.Encapsulate(meshRenderer.bounds.ToAABB()); }); using (var boundingVolume = DstEntityManager.CreateEntityQuery(typeof(SceneBoundingVolume))) { if (!boundingVolume.IsEmptyIgnoreFilter) { var bounds = boundingVolume.GetSingleton <SceneBoundingVolume>(); bounds.Value.Encapsulate(sceneBounds); boundingVolume.SetSingleton(bounds); } } }
protected override void OnUpdate() { Entities.ForEach((Light light) => { AddHybridComponent(light); var entity = GetPrimaryEntity(light); ConfigureEditorRenderData(entity, light.gameObject, true); #if UNITY_2020_2_OR_NEWER && UNITY_EDITOR // Explicitly store the LightBakingOutput using a component, so we can restore it // at runtime. var bakingOutput = light.bakingOutput; DstEntityManager.AddComponentData(entity, new LightBakingOutputData { Value = bakingOutput }); #endif }); Entities.ForEach((LightProbeProxyVolume group) => { AddHybridComponent(group); }); Entities.ForEach((ReflectionProbe probe) => { AddHybridComponent(probe); }); Entities.ForEach((TextMesh mesh, MeshRenderer renderer) => { AddHybridComponent(mesh); AddHybridComponent(renderer); }); Entities.ForEach((SpriteRenderer sprite) => { AddHybridComponent(sprite); }); Entities.ForEach((VisualEffect vfx) => { AddHybridComponent(vfx); }); Entities.ForEach((ParticleSystem ps, ParticleSystemRenderer ren) => { AddHybridComponent(ps); AddHybridComponent(ren); }); #if SRP_7_0_0_OR_NEWER Entities.ForEach((Volume volume) => { AddHybridComponent(volume); }); // NOTE: Colliders are only converted when a graphics Volume is on the same GameObject to avoid problems with Unity Physics! Entities.ForEach((SphereCollider collider, Volume volume) => { AddHybridComponent(collider); }); Entities.ForEach((BoxCollider collider, Volume volume) => { AddHybridComponent(collider); }); Entities.ForEach((CapsuleCollider collider, Volume volume) => { AddHybridComponent(collider); }); Entities.ForEach((MeshCollider collider, Volume volume) => { AddHybridComponent(collider); }); #endif #if HDRP_7_0_0_OR_NEWER // HDRP specific extra data for Light Entities.ForEach((HDAdditionalLightData light) => { #if UNITY_2020_2_OR_NEWER && UNITY_EDITOR if (light.GetComponent <Light>().lightmapBakeType != LightmapBakeType.Baked) #endif AddHybridComponent(light); }); // HDRP specific extra data for ReflectionProbe Entities.ForEach((HDAdditionalReflectionData reflectionData) => { AddHybridComponent(reflectionData); }); Entities.ForEach((DecalProjector projector) => { AddHybridComponent(projector); }); Entities.ForEach((DensityVolume volume) => { AddHybridComponent(volume); }); Entities.ForEach((PlanarReflectionProbe probe) => { AddHybridComponent(probe); }); //This feature requires a modified HDRP //If ProbeVolumes are enabled, add PROBEVOLUME_CONVERSION //to the project script defines #if PROBEVOLUME_CONVERSION Entities.ForEach((ProbeVolume probe) => { AddHybridComponent(probe); }); #endif #endif #if URP_7_0_0_OR_NEWER // URP specific extra data for Light Entities.ForEach((UniversalAdditionalLightData light) => { #if UNITY_2020_2_OR_NEWER && UNITY_EDITOR if (light.GetComponent <Light>().lightmapBakeType != LightmapBakeType.Baked) #endif AddHybridComponent(light); }); #endif #if HYBRID_ENTITIES_CAMERA_CONVERSION // Camera conversion is disabled by default, because Unity Editor loses track of the main camera if it's put into a subscene Entities.ForEach((Camera camera) => { AddHybridComponent(camera); }); #if HDRP_7_0_0_OR_NEWER Entities.ForEach((HDAdditionalCameraData data) => { AddHybridComponent(data); }); #endif #if URP_7_0_0_OR_NEWER Entities.ForEach((UniversalAdditionalCameraData data) => { AddHybridComponent(data); }); #endif #endif }
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((MeshToBoundingBoxsAuthoring 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.AssociateBlobAssetWithGameObject(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((MeshToBoundingBoxsAuthoring 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)); }); Profiler.EndSample(); blobFactoryPoints.Dispose(); processBlobAssets.Dispose(); } }
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 }); } });
protected override void OnUpdate() { var materials = new List <Material>(10); Entities.ForEach((SkinnedMeshRenderer meshRenderer) => { meshRenderer.GetSharedMaterials(materials); var mesh = meshRenderer.sharedMesh; var root = meshRenderer.rootBone ? meshRenderer.rootBone : meshRenderer.transform; var hasSkinning = mesh == null ? false : mesh.boneWeights.Length > 0 && mesh.bindposes.Length > 0; var hasBlendShapes = mesh == null ? false : mesh.blendShapeCount > 0; var deformedEntity = GetPrimaryEntity(meshRenderer); // Convert Renderers as normal MeshRenderers. MeshRendererConversion.Convert(DstEntityManager, this, k_AttachToPrimaryEntityForSingleMaterial, meshRenderer, mesh, materials, root, meshRenderer.localBounds.ToAABB()); foreach (var rendererEntity in GetEntities(meshRenderer)) { if (DstEntityManager.HasComponent <RenderMesh>(rendererEntity)) { // Add relevant deformation tags to converted render entities and link them to the DeformedEntity. #if ENABLE_COMPUTE_DEFORMATIONS DstEntityManager.AddComponentData(rendererEntity, new DeformedMeshIndex()); #endif DstEntityManager.AddComponentData(rendererEntity, new DeformedEntity { Value = deformedEntity }); if (hasSkinning) { DstEntityManager.AddComponent <SkinningTag>(rendererEntity); } if (hasBlendShapes) { DstEntityManager.AddComponent <BlendShapeTag>(rendererEntity); } } } // Fill the blend shape weights. if (hasBlendShapes && !DstEntityManager.HasComponent <BlendShapeWeight>(deformedEntity)) { DstEntityManager.AddBuffer <BlendShapeWeight>(deformedEntity); var weights = DstEntityManager.GetBuffer <BlendShapeWeight>(deformedEntity); weights.ResizeUninitialized(meshRenderer.sharedMesh.blendShapeCount); for (int i = 0; i < weights.Length; ++i) { weights[i] = new BlendShapeWeight { Value = meshRenderer.GetBlendShapeWeight(i) }; } } // Fill the skin matrices with bindpose skin matrices. if (hasSkinning && !DstEntityManager.HasComponent <SkinMatrix>(deformedEntity)) { var bones = meshRenderer.bones; var rootMatrixInv = root.localToWorldMatrix.inverse; DstEntityManager.AddBuffer <SkinMatrix>(deformedEntity); var skinMatrices = DstEntityManager.GetBuffer <SkinMatrix>(deformedEntity); skinMatrices.ResizeUninitialized(bones.Length); for (int i = 0; i < bones.Length; ++i) { var bindPose = meshRenderer.sharedMesh.bindposes[i]; var boneMatRootSpace = math.mul(rootMatrixInv, bones[i].localToWorldMatrix); var skinMatRootSpace = math.mul(boneMatRootSpace, bindPose); skinMatrices[i] = new SkinMatrix { Value = new float3x4(skinMatRootSpace.c0.xyz, skinMatRootSpace.c1.xyz, skinMatRootSpace.c2.xyz, skinMatRootSpace.c3.xyz) }; } } }); }
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((ColliderAuthoring 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((ColliderAuthoring colliderAuthoring) => { computationContext.GetBlobAsset(hashes.ReinterpretLoad <Hash128>(index++), out var blob); var targetEntity = GetPrimaryEntity(colliderAuthoring); DeclareDependency(colliderAuthoring, colliderAuthoring.transform); 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() { ForEach((LODGroup lodGroup) => { if (lodGroup.lodCount > 8) { Debug.LogWarning("LODGroup has more than 8 LOD - Not supported", lodGroup); return; } var lodGroupEntity = GetPrimaryEntity(lodGroup); var lodGroupData = new MeshLODGroupComponent(); //@TODO: LOD calculation should respect scale... var worldSpaceSize = LODGroupExtensions.GetWorldSpaceSize(lodGroup); lodGroupData.LocalReferencePoint = lodGroup.localReferencePoint; var lodDistances0 = new float4(float.PositiveInfinity); var lodDistances1 = new float4(float.PositiveInfinity); var lodGroupLODs = lodGroup.GetLODs(); for (int i = 0; i < lodGroup.lodCount; ++i) { float d = worldSpaceSize / lodGroupLODs[i].screenRelativeTransitionHeight; if (i < 4) { lodDistances0[i] = d; } else { lodDistances1[i - 4] = d; } } lodGroupData.LODDistances0 = lodDistances0; lodGroupData.LODDistances1 = lodDistances1; DstEntityManager.AddComponentData(lodGroupEntity, lodGroupData); for (int i = 0; i < lodGroupLODs.Length; ++i) { foreach (var renderer in lodGroupLODs[i].renderers) { if (renderer == null) { Debug.LogWarning("Missing renderer in LOD Group", lodGroup); continue; } foreach (var rendererEntity in GetEntities(renderer)) { if (DstEntityManager.HasComponent <RenderMesh>(rendererEntity)) { var lodComponent = new MeshLODComponent { Group = lodGroupEntity, LODMask = 1 << i }; DstEntityManager.AddComponentData(rendererEntity, lodComponent); } } } } }); }