Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Ortographic camera screenshot with RenderTexture using URP camera and DOTS fails.

Discussion in 'Graphics for ECS' started by muntes, May 8, 2023.

  1. muntes

    muntes

    Joined:
    Nov 24, 2021
    Posts:
    20
    When I try to generate an image using camera.Render() on a RenderTexture I get:

    "InvalidOperationException: The previously scheduled job LocalToWorldSystem:ComputeChildLocalToWorldJob writes to the ComponentTypeHandle<Unity.Collections.NativeText.ReadOnly> ComputeChildLocalToWorldJob.JobData.LocalToWorldTypeHandleRW. You are trying to schedule a new job EmitDrawCommandsJob, which reads from the same ComponentTypeHandle<Unity.Collections.NativeText.ReadOnly> (via EmitDrawCommandsJob.LocalToWorld). To guarantee safety, you must include LocalToWorldSystem:ComputeChildLocalToWorldJob as a dependency of the newly scheduled job.
    Unity.Jobs.LowLevel.Unsafe.JobsUtility.ScheduleParallelForDeferArraySize (Unity.Jobs.LowLevel.Unsafe.JobsUtility+JobScheduleParameters& parameters, System.Int32 innerloopBatchCount, System.Void* listData, System.Void* listDataAtomicSafetyHandle) (at <07b4fb2b5af74e479c2c24afaabbcaa4>:0)"

    Considering the fact I call this function from WithStructuralChanges().Run(). What should I add to it?


    PS: The image generation is not in entities context is old mono behavior logic which should work for DOTS and non-dots calls.

    Am I missing something? Does in the background camera.Render() from URP cameras work with DOTS jobs?


    Setup:
    The elements in the camera are only entities.
    URP camera set as orthographic

    protected override void OnUpdate()
    {
    var deltaTime = World.Time.DeltaTime;
    Entities.ForEach((ref Entity entity, ref HolderVersion hv, ref MeshLODGroupComponent mlgc, in WaitingForLOD toGenerateLod) =>
    {
    toGenerateLod.CreationDate = deltaTime + toGenerateLod.CreationDate;
    if (!(toGenerateLod.CreationDate >= _interval)) return; // I want a delay between instantiation and LOD generation.

    var element = LodCreator.GetEntityViaId(hv.Id);
    if (!element.isSome) return;

    element.value.GetComponent<RenderingHolder>().CreateLod1(entity); //This calls RenderToTexture which should add the texture to a mesh quad.

    _entityManager.RemoveComponent<WaitingForLOD>(entity);
    }).WithStructuralChanges().Run();
    }


    private static Disposable<RenderTexture> RenderToTexture(Camera camera, int width, int height, Vector3 position, Quaternion rotation)
    {
    camera.gameObject.SetActive(true);
    var renderTexture = RenderTexture.GetTemporary(width, height, 24, DEFAULT_RENDER_TEXTURE_FORMAT);
    renderTexture.antiAliasing = 1;
    var transform = camera.transform;
    transform.position = position;
    transform.rotation = rotation;
    camera.targetTexture = renderTexture;

    camera.Render(); // THIS IS WHERE THE ISSUE OCCURS

    camera.targetTexture = null;

    string savePath = "Screenshot"; // THIS IS ONLY FOR DEBUG PURPOSES. The texture is blank.
    if (!Directory.Exists(savePath))
    Directory.CreateDirectory(savePath);

    string fileName = $"{System.DateTime.Now:yyyy-MM-dd_HH-mm-ss}{Random.Range(0, 1000000).ToString()}.png";
    string filePath = Path.Combine(savePath, fileName);
    byte[] bytes = renderTexture.ToTexture2D(false).EncodeToPNG();
    File.WriteAllBytes(filePath, bytes);

    camera.gameObject.SetActive(false);
    return Disposable<RenderTexture>.Borrow(renderTexture, RenderTexture.ReleaseTemporary);
    }

    Thanks for your attention.