static unsafe void DrawSegments( NativeArray <SegmentData> segments, World *worldLODs, CameraData camera, int screenWidth, int screenHeight, float2 vanishingPointScreenSpace, RayBuffer.Native rayBufferTopDown, RayBuffer.Native rayBufferLeftRight, RayBuffer rayBufferTopDownManaged, RayBuffer rayBufferLeftRightManaged ) { float2 screen = new float2(screenWidth, screenHeight); Profiler.BeginSample("Segment setup overhead"); DrawSegmentRayJob.DrawContext drawContext = new DrawSegmentRayJob.DrawContext { camera = camera, screen = screen, worldLODs = worldLODs }; NativeArray <DrawSegmentRayJob.SegmentContext> segmentContexts = new NativeArray <DrawSegmentRayJob.SegmentContext>(4, Allocator.TempJob, NativeArrayOptions.ClearMemory); DrawSegmentRayJob.SegmentContext *segmentContextPtr = (DrawSegmentRayJob.SegmentContext *)segmentContexts.GetUnsafePtr(); int totalRays = 0; for (int segmentIndex = 0; segmentIndex < segments.Length; segmentIndex++) { DrawSegmentRayJob.SegmentContext *context = segmentContextPtr + segmentIndex; context->segment = segments[segmentIndex]; totalRays += segments[segmentIndex].RayCount; if (segments[segmentIndex].RayCount <= 0) { continue; } context->axisMappedToY = (segmentIndex > 1) ? 0 : 1; context->segmentRayIndexOffset = 0; if (segmentIndex == 1) { context->segmentRayIndexOffset = segments[0].RayCount; } if (segmentIndex == 3) { context->segmentRayIndexOffset = segments[2].RayCount; } int2 nextFreePixel; if (segmentIndex < 2) { context->activeRayBufferFull = rayBufferTopDown; if (segmentIndex == 0) // top segment { nextFreePixel = int2(clamp(Mathf.RoundToInt(vanishingPointScreenSpace.y), 0, screenHeight - 1), screenHeight - 1); } else // bottom segment { nextFreePixel = int2(0, clamp(Mathf.RoundToInt(vanishingPointScreenSpace.y), 0, screenHeight - 1)); } } else { context->activeRayBufferFull = rayBufferLeftRight; if (segmentIndex == 3) // left segment { nextFreePixel = int2(0, clamp(Mathf.RoundToInt(vanishingPointScreenSpace.x), 0, screenWidth - 1)); } else // right segment { nextFreePixel = int2(clamp(Mathf.RoundToInt(vanishingPointScreenSpace.x), 0, screenWidth - 1), screenWidth - 1); } } context->originalNextFreePixelMin = nextFreePixel.x; context->originalNextFreePixelMax = nextFreePixel.y; context->seenPixelCacheLength = (int)ceil(drawContext.screen[context->axisMappedToY]); } Profiler.EndSample(); rayBufferTopDownManaged.Prepare(segments[0].RayCount + segments[1].RayCount); rayBufferLeftRightManaged.Prepare(segments[2].RayCount + segments[3].RayCount); NativeArray <DrawSegmentRayJob.RayContext> rayContext = new NativeArray <DrawSegmentRayJob.RayContext>( totalRays, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); NativeArray <DrawSegmentRayJob.RayDDAContext> rayDDAContext = new NativeArray <DrawSegmentRayJob.RayDDAContext>( totalRays, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); NativeList <DrawSegmentRayJob.RayContinuation> rayContinuations = new NativeList <DrawSegmentRayJob.RayContinuation>( totalRays, Allocator.TempJob); DrawSegmentRayJob.RaySetupJob raySetupJob = new DrawSegmentRayJob.RaySetupJob() { contexts = segmentContexts, rays = rayContext }; DrawSegmentRayJob.DDASetupJob ddaSetupJob = new DrawSegmentRayJob.DDASetupJob() { raysInput = rayContext, raysOutput = rayDDAContext, drawContext = drawContext, }; DrawSegmentRayJob.TraceToFirstColumnJob firstColumnJob = new DrawSegmentRayJob.TraceToFirstColumnJob { drawContext = drawContext, inRays = rayDDAContext, outRays = rayContinuations.AsParallelWriter() }; DrawSegmentRayJob.RenderJob renderJob = new DrawSegmentRayJob.RenderJob { rays = rayContinuations, DrawingContext = drawContext, }; JobHandle setup = raySetupJob.Schedule(totalRays, 64); JobHandle ddaSetup = ddaSetupJob.Schedule(totalRays, 64, setup); JobHandle firstColumn = firstColumnJob.Schedule(totalRays, 4, ddaSetup); JobHandle render = renderJob.Schedule(totalRays, 1, firstColumn); render.Complete(); rayContext.Dispose(); segmentContexts.Dispose(); rayDDAContext.Dispose(); rayContinuations.Dispose(); rayBufferTopDownManaged.UploadCompletes(); rayBufferLeftRightManaged.UploadCompletes(); }
public unsafe void DrawWorld(Material blitMaterial, World[] worldLODs, Camera camera, Camera actualCamera, float[] LODDistances) { Mesh blitMesh = blitMeshes[bufferIndex]; Debug.DrawLine(new Vector2(0f, 0f), new Vector2(screenWidth, 0f)); Debug.DrawLine(new Vector2(screenWidth, 0f), new Vector2(screenWidth, screenHeight)); Debug.DrawLine(new Vector2(screenWidth, screenHeight), new Vector2(0f, screenHeight)); Debug.DrawLine(new Vector2(0f, screenHeight), new Vector2(0f, 0f)); Profiler.BeginSample("Setup VP"); float3 vanishingPointWorldSpace = CalculateVanishingPointWorld(camera); float2 vanishingPointScreenSpace = ProjectVanishingPointScreenToWorld(camera, vanishingPointWorldSpace); Profiler.EndSample(); float2 screen = new float2(screenWidth, screenHeight); NativeArray <SegmentData> segments = new NativeArray <SegmentData>(4, Allocator.Temp, NativeArrayOptions.ClearMemory); Profiler.BeginSample("Setup segment params"); if (vanishingPointScreenSpace.y < screenHeight) { segments[0] = GetGenericSegmentParameters(camera, screen, vanishingPointScreenSpace, screenHeight - vanishingPointScreenSpace.y, new float2(0, 1), 1, worldLODs[0].DimensionY); } if (vanishingPointScreenSpace.y > 0f) { segments[1] = GetGenericSegmentParameters(camera, screen, vanishingPointScreenSpace, vanishingPointScreenSpace.y, new float2(0, -1), 1, worldLODs[0].DimensionY); } if (vanishingPointScreenSpace.x < screenWidth) { segments[2] = GetGenericSegmentParameters(camera, screen, vanishingPointScreenSpace, screenWidth - vanishingPointScreenSpace.x, new float2(1, 0), 0, worldLODs[0].DimensionY); } if (vanishingPointScreenSpace.x > 0f) { segments[3] = GetGenericSegmentParameters(camera, screen, vanishingPointScreenSpace, vanishingPointScreenSpace.x, new float2(-1, 0), 0, worldLODs[0].DimensionY); } Profiler.EndSample(); RayBuffer activeRaybufferTopDown = rayBufferTopDown[bufferIndex]; RayBuffer activeRaybufferLeftRight = rayBufferLeftRight[bufferIndex]; RayBuffer.Native topDownNative = activeRaybufferTopDown.GetNativeData(Allocator.TempJob); RayBuffer.Native leftRightNative = activeRaybufferLeftRight.GetNativeData(Allocator.TempJob); commandBuffer.Clear(); CameraData camData = new CameraData(camera, LODDistances, screen); Profiler.BeginSample("Draw planes"); fixed(World *worldPtr = worldLODs) { DrawSegments(segments, worldPtr, camData, screenWidth, screenHeight, vanishingPointScreenSpace, topDownNative, leftRightNative, activeRaybufferTopDown, activeRaybufferLeftRight ); } Profiler.EndSample(); topDownNative.Dispose(); leftRightNative.Dispose(); Profiler.BeginSample("Apply textures"); activeRaybufferTopDown.ApplyPartials(commandBuffer); activeRaybufferLeftRight.ApplyPartials(commandBuffer); Profiler.EndSample(); Profiler.BeginSample("Blit raybuffer"); BlitSegments( camera, blitMaterial, blitMesh, activeRaybufferTopDown.FinalTexture, activeRaybufferLeftRight.FinalTexture, segments, vanishingPointScreenSpace, screen, commandBuffer ); Profiler.EndSample(); actualCamera.RemoveAllCommandBuffers(); actualCamera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer); }