Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering artifact with scaled textures #5261

Open
ghost opened this issue Jul 6, 2017 · 4 comments
Open

Rendering artifact with scaled textures #5261

ghost opened this issue Jul 6, 2017 · 4 comments
Labels
Component: graphics kivy/graphics

Comments

@ghost
Copy link

ghost commented Jul 6, 2017

Versions

  • Python: 3.6.1
  • OS: Tested on Ubuntu 16.04 and Win7pro
  • Kivy: 1.10
  • Kivy installation method: pip

Description

A rendering artifact appears when image textures are scaled. This test case is two 100x100 PNGs, when overlaid they align to fill the 100x100 pixels exactly (top/bottom half transparent). This works as expected when not scaling, but with scaling there is an unexpected artifact.

Code and Logs

The below examples reproduce the issue on my systems using different approaches.

Example 1

from kivy.base import runTouchApp
from kivy.lang import Builder

runTouchApp(Builder.load_string('''
FloatLayout:
    AsyncImage:
        source: 'http://i.imgur.com/KKva3Os.png'
        allow_stretch: True
    AsyncImage:
        source: 'http://i.imgur.com/ILBfKkJ.png'
        allow_stretch: True
'''))

Example 2

This is correct on load, not when scaled

from kivy.base import runTouchApp
from kivy.lang import Builder

runTouchApp(Builder.load_string('''
Scatter:
    size_hint: None, None
    FloatLayout:
        AsyncImage:
            source: 'http://i.imgur.com/KKva3Os.png'
        AsyncImage:
            source: 'http://i.imgur.com/ILBfKkJ.png'
'''))

Example 3

This is correct on load, not when scaled

from kivy.app import App
from kivy.lang import Builder
from kivy.loader import Loader

KV = '''
Scatter:
    tx1: None
    tx2: None
    size_hint: None, None
    canvas:
        Rectangle:
            texture: self.tx1
            size: self.size
        Rectangle:
            texture: self.tx2
            size: self.size        
'''

class TestApp(App):
    def build(self):
        def handler1(proxy):
            setattr(self.root, 'tx1', proxy.image.texture)
        def handler2(proxy):
            setattr(self.root, 'tx2', proxy.image.texture)

        img1 = Loader.image('http://i.imgur.com/KKva3Os.png')
        img1.bind(on_load=handler1)

        img2 = Loader.image('http://i.imgur.com/ILBfKkJ.png')
        img2.bind(on_load=handler2)

        return Builder.load_string(KV)

TestApp().run()
@tito
Copy link
Member

tito commented Jul 13, 2017

I think it is the same kind of issue that beginner have when scaling down/up image with opacity. The opacity layer is also stretched, and leads to issue with transparency;
One way to test is in your case, both of your picture should have RGB full red, and A only partially filled with white, the rest with black. Then when OpenGL will stretch the image, the opacity layer (A) will be blended (from black to white in the middle) and the base color will be the red; otherwise it will be black if you don't have any information, that's where the glitch happen.

@tito
Copy link
Member

tito commented Jul 13, 2017

Weird. The blending always happen with black. I changed both of your image to have one image with full blue, and only half transparent on the bottom, and the other with red and half transparent to the top. I double-checked that the PNG itself does have correctly the blue and red on the transparent part. But it doesn't solve the issue O_o. Also checked with SDL2 or ImageIO (osx) provider.

Just one half image give this when scaled:
capture d ecran 2017-07-13 a 15 34 31

And for informations, this is the sources images:
kkva3os
ilbfkkj

And source code:

from kivy.base import runTouchApp
from kivy.lang import Builder

runTouchApp(Builder.load_string('''

FloatLayout:
    canvas.before:
        Color:
            rgba: 0, 1, 0, 1
        Rectangle:
            pos: 0, 0
            size: self.size
    
    Scatter:
        size_hint: None, None
        canvas.before:
            Color:
                rgba: 0, 1, 0, 1
            Rectangle:
                pos: 0, 0
                size: self.size
        FloatLayout:
            Image:
                source: '/Users/tito/Downloads/KKva3Os.png'
            #Image:
            #    source: '/Users/tito/Downloads/ILBfKkJ.png'
'''))

@tito
Copy link
Member

tito commented Jul 13, 2017

I don't have much time to try solving this, but maybe ask on any OpenGL forum, they may help. Also you can use a tool like apitrace to see the order of GL operations.

@ghost
Copy link
Author

ghost commented Jul 14, 2017

Thanks for testing - I'm just reporting, no rush in my end. Seems like this is because Kivy uses post-multiplied alpha. Changing to pre-multiplied reduces the artifact (mine, yours w/premultiplication of pngs), but of course it breaks everything else. Unfortunately I don't know if this this is even the expected result -- is it possible that a separate issue is preventing it from being completely sharp?

diff --git a/kivy/graphics/instructions.pyx b/kivy/graphics/instructions.pyx
index 0e1c77c6..9549641b 100644
--- a/kivy/graphics/instructions.pyx
+++ b/kivy/graphics/instructions.pyx
@@ -33,8 +33,9 @@ cdef void reset_gl_context():
     cgl.glEnable(GL_BLEND)
     cgl.glDisable(GL_DEPTH_TEST)
     cgl.glEnable(GL_STENCIL_TEST)
-    cgl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
-    cgl.glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE)
+    cgl.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
+    cgl.glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA,
+                            GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
     cgl.glActiveTexture(GL_TEXTURE0)
     cgl.glPixelStorei(GL_UNPACK_ALIGNMENT, 1)

It may be possible to add env/config option so advanced users can bake their assets accordingly... but it needs more work than an "if" here.

Eric Haines has a good article on the subject: http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/

@Julian-O Julian-O added the Component: graphics kivy/graphics label Nov 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: graphics kivy/graphics
Projects
None yet
Development

No branches or pull requests

2 participants