admin管理员组

文章数量:1357232

on macOS, I want to display a metal rendered texture in a view, and I want the transparent areas of this texture let mouse events propagate through other underlying UI/Apps, like it is the native behavior in macOS (e.g transparent areas of a view go through underlying UI objects)

I'm trying to render metal contents into a CAMEtalLayer (using c# with eto library, but it doesn't matter as I use mostly macOS native objects). I'm able to render the CAMetalLayer in a custom view without problem. The transparent area (for now just a transparent frame with a red circle in center) is correctly display (e.g. I can see underlying macOS UI element through the NSView transparent area) and I see the red circle in center.

The weird thing is that with CAMetalLayer, it seems that the transparent area (e.g. the whole metal texture) block mouse events to propagate through.

If I create the same view with a "classic" CAMetal layer, the transparent area lets mouse events pass through (as this is the normal behavior in MacOS).

Is there a way for my CAMetalLayer transparent area to let mouse events pass through it, so the underlying UI elements (or applications etc.) can handle those mouse events ?

Example in below image. The CAMetalLayer frame is represented by the black rectangle. It is display above an application (Rhino 3D). When I mouse over inside the transparent area of the frame, the underlying app (Rhino 3D) doesn't get mouse move events. If I do the same thing with a CALayer, it works (e.g. The mouse events are propagated to the underlying app)

Here is some trunks of my code: 1 - Create the Metal layer

MetalLayer = new CAMetalLayer
        {
            Device = MetalDevice,
            PixelFormat = MTLPixelFormat.RGBA8Unorm,
            FramebufferOnly = true,
            Opaque = false,
            BackgroundColor = NSColor.Clear.CGColor,
            BorderColor = NSColor.Black.CGColor,
            BorderWidth = 2,
            // BackgroundColor = NSColor.Blue.CGColor,
            // ContentsScale = 2,
            // ShouldRasterize = true,
            ShadowColor = NSColor.Clear.CGColor,
            //FIXME: This does not work has Rhino Microsoft.macOS is V12.3.7 (and on macos 15.3 this is v13.3.0)
            // WantsExtendedDynamicRangeContent = true
        };

2 - Render metal pass (remark : I also tried drawable.present(); but same result)

var drawable = MetalLayer.NextDrawable();
        if (drawable != null)
        {
            var currentTexture = drawable.Texture; // Get Metal texture for drawing
            // REMARK: We must create a new surface at each render loop. If we keep the same surface instance, the radial menu display is blinking (don't know why)
            SkiaSurface?.Dispose();
            // Create Skia surface from Metal texture
            var backendRenderTarget = new GRBackendRenderTarget(
                (int)currentTexture.Width,
                (int)currentTexture.Height,
                1,
                new GRMtlTextureInfo(currentTexture));
            SkiaSurface = SKSurface.Create(GrContext, backendRenderTarget, GRSurfaceOrigin.TopLeft, SKColorType.Rgba8888);
            
           var stopwatchDrawing = Stopwatch.StartNew();
           
            PointF center = new PointF((currentTexture.Width / 2.0f), (currentTexture.Height / 2.0f));

            // Draw something in canvas here...
            var canvas = SkiaSurface.Canvas;
            canvas.Clear(SKColors.Transparent);
            using (var paint = new SKPaint()
            {
                Style = SKPaintStyle.Fill,
                IsAntialias = true,
                Color = SKColors.Red
            })
            {
                canvas.DrawCircle((float)currentTexture.Width / 2, (float)currentTexture.Height / 2, (float)150, paint);
            }

             // Present the drawable
            GrContext.Flush();// Ensure everything is drawn
                        
            // Create a command buffer and render pass for blending
            var commandBuffer = CommandQueue.CommandBuffer();
            var renderPassDescriptor = new MTLRenderPassDescriptor
            {
                ColorAttachments = { [0] = new MTLRenderPassColorAttachmentDescriptor() }
            };
            var colorAttachment = renderPassDescriptor.ColorAttachments[0];
            colorAttachment.Texture = currentTexture;
           
            colorAttachment.LoadAction = MTLLoadAction.Load; // Load the Skia-rendered texture
            colorAttachment.StoreAction = MTLStoreAction.Store;
            colorAttachment.ClearColor = new MTLClearColor(0, 0, 0, 0);

            var renderEncoder = commandBuffer.CreateRenderCommandEncoder(renderPassDescriptor);
            renderEncoder.SetRenderPipelineState(RenderPipelineState);

            // Set vertex and texture coordinate buffers
            renderEncoder.SetVertexBuffer(VertexBuffer, 0, 0);
            renderEncoder.SetVertexBuffer(TexCoordBuffer, 0, 1);
            renderEncoder.SetFragmentTexture(currentTexture, 0);

            // Draw the quad
            renderEncoder.DrawPrimitives(MTLPrimitiveType.TriangleStrip, 0, 4);

            renderEncoder.EndEncoding();

            // Present the drawable
            commandBuffer.PresentDrawable(drawable);
            commandBuffer.Commit();

3 - For information, here is the render pipeline and colorAttachement I'm using

// RGB blending: Standard alpha blending
        colorAttachment.SourceRgbBlendFactor = MTLBlendFactor.SourceAlpha;      // Source RGB * Source.a
        colorAttachment.DestinationRgbBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; // Dest RGB * (1 - Source.a)
        colorAttachment.RgbBlendOperation = MTLBlendOperation.Add;
        // Alpha blending: Source alpha overrides destination alpha
        colorAttachment.SourceAlphaBlendFactor = MTLBlendFactor.One; // Preserve source alpha;            // Source.a * 1.0
        colorAttachment.DestinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha; ;      // Dest.a * 0
        
        colorAttachment.AlphaBlendOperation = MTLBlendOperation.Add;

Any help would be appreciated :-)

本文标签: macosCAMetalLayer transparent area not behaves like in CALayerStack Overflow