public unsafe void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) { var chunkLocalToWorld = chunk.GetNativeArray(LocalToWorldType); var chunkMeshRenderer = chunk.GetNativeArray(MeshRendererType); var chunkMeshReference = chunk.GetNativeArray(LitMeshType); var chunkWorldBoundingSphere = chunk.GetNativeArray(WorldBoundingSphereType); var boundingSphere = chunk.GetChunkComponentData(ChunkWorldBoundingSphereType).Value; var bounds = chunk.GetChunkComponentData(ChunkWorldBoundsType).Value; Entity lighte = SharedLightingRef[chunkIndex]; var lighting = ComponentLightingBGFX[lighte]; Entity rtpe = SharedRenderToPass[chunkIndex]; Assert.IsTrue(ThreadIndex >= 0 && ThreadIndex < MaxPerThreadData); bgfx.Encoder *encoder = PerThreadData[ThreadIndex].encoder; if (encoder == null) { encoder = bgfx.encoder_begin(true); Assert.IsTrue(encoder != null); PerThreadData[ThreadIndex].encoder = encoder; } DynamicBuffer <RenderToPassesEntry> toPasses = BufferRenderToPassesEntry[rtpe]; // we can do this loop either way, passes first or renderers first. // TODO: profile what is better! for (int i = 0; i < toPasses.Length; i++) { Entity ePass = toPasses[i].e; Frustum frustum = default; if (ComponentFrustum.Exists(ePass)) { frustum = ComponentFrustum[ePass]; // TODO, just make frustum a member of pass? if (Culling.Cull(ref boundingSphere, ref frustum) == Culling.CullingResult.Outside) { continue; // nothing to do for this pass } } Assert.IsTrue(encoder != null); var pass = ComponentRenderPass[ePass]; for (int j = 0; j < chunk.Count; j++) { var wbs = chunkWorldBoundingSphere[j]; var meshRenderer = chunkMeshRenderer[j]; var meshRef = chunkMeshReference[j]; var mesh = ComponentSimpleMeshBGFX[meshRef.mesh]; var tx = chunkLocalToWorld[j].Value; if (Culling.Cull(ref wbs, ref frustum) == Culling.CullingResult.Outside) // TODO: fine cull only if rough culling was !Inside { continue; } switch (pass.passType) // TODO: we can hoist this out of the loop { case RenderPassType.ZOnly: SubmitHelper.EncodeZOnly(BGFXSystem, encoder, pass.viewId, ref mesh, ref tx, meshRenderer.startIndex, meshRenderer.indexCount, pass.flipCulling); break; case RenderPassType.ShadowMap: float4 bias = new float4(0); SubmitHelper.EncodeShadowMap(BGFXSystem, encoder, pass.viewId, ref mesh, ref tx, meshRenderer.startIndex, meshRenderer.indexCount, (byte)(pass.flipCulling ^ 0x3), bias); break; case RenderPassType.Transparent: case RenderPassType.Opaque: var material = ComponentLitMaterialBGFX[meshRenderer.material]; SubmitHelper.EncodeLit(BGFXSystem, encoder, pass.viewId, ref mesh, ref tx, ref material, ref lighting, ref pass.viewTransform, meshRenderer.startIndex, meshRenderer.indexCount, pass.flipCulling, ref PerThreadData[ThreadIndex].viewSpaceLightCache); break; default: Assert.IsTrue(false); break; } } } }
protected override void OnUpdate() { var sys = World.GetExistingSystem <RendererBGFXSystem>(); if (!sys.Initialized) { return; } // get all MeshRenderer, cull them, and add them to graph nodes that need them // any mesh renderer MUST have a shared component data that has a list of passes to render to // this list is usually very shared - all opaque meshes will render to all ZOnly and Opaque passes // this shared data is not dynamically updated - other systems are responsible to update them if needed // simple Entities.ForEach((Entity e, ref MeshRenderer mr, ref SimpleMeshReference meshRef, ref LocalToWorld tx, ref WorldBounds wb, ref WorldBoundingSphere wbs) => { if (!EntityManager.HasComponent <RenderToPasses>(e)) { return; } RenderToPasses toPassesRef = EntityManager.GetSharedComponentData <RenderToPasses>(e); DynamicBuffer <RenderToPassesEntry> toPasses = EntityManager.GetBufferRO <RenderToPassesEntry>(toPassesRef.e); for (int i = 0; i < toPasses.Length; i++) { Entity ePass = toPasses[i].e; var pass = EntityManager.GetComponentData <RenderPass>(ePass); if (EntityManager.HasComponent <Frustum>(ePass)) { var frustum = EntityManager.GetComponentData <Frustum>(ePass); if (Culling.Cull(ref wbs, ref frustum) == Culling.CullingResult.Outside) { continue; } // double cull as example only if (Culling.IsCulled(ref wb, ref frustum)) { continue; } } var mesh = EntityManager.GetComponentData <SimpleMeshBGFX>(meshRef.mesh); switch (pass.passType) { case RenderPassType.ZOnly: SubmitHelper.SubmitZOnlyDirect(sys, pass.viewId, ref mesh, ref tx.Value, mr.startIndex, mr.indexCount, pass.flipCulling); break; case RenderPassType.ShadowMap: SubmitHelper.SubmitZOnlyDirect(sys, pass.viewId, ref mesh, ref tx.Value, mr.startIndex, mr.indexCount, (byte)(pass.flipCulling ^ 0x3)); break; case RenderPassType.Transparent: case RenderPassType.Opaque: var material = EntityManager.GetComponentData <SimpleMaterialBGFX>(mr.material); SubmitHelper.SubmitSimpleDirect(sys, pass.viewId, ref mesh, ref tx.Value, ref material, mr.startIndex, mr.indexCount, pass.flipCulling); break; default: Assert.IsTrue(false); break; } } }); }