glumpy / glumpy

Python+Numpy+OpenGL: fast, scalable and beautiful scientific visualization
http://glumpy.github.io
BSD 3-Clause "New" or "Revised" License
1.24k stars 177 forks source link

have trouble with rendering to texture #202

Open jiangwei221 opened 5 years ago

jiangwei221 commented 5 years ago

Hi:

I'm trying to render a Voronoi diagram to numpy array using the rasterizer.

Here is my code:

# -----------------------------------------------------------------------------
# Copyright (c) 2009-2016 Nicolas P. Rougier. All rights reserved.
# Distributed under the (new) BSD License.
# -----------------------------------------------------------------------------

import numpy as np
from glumpy import app, gl, glm, gloo
from glumpy.graphics.filter import Filter
import IPython
import matplotlib.pyplot as plt

cone_vertex = """
uniform mat4 projection;
attribute vec2 translate;
attribute vec3 position;
attribute vec3 color;
varying vec3 v_color;
void main()
{
    v_color = color;
    gl_Position = projection * vec4(position.xy+translate, position.z ,1.0);
}
"""

cone_fragment = """
varying vec3 v_color;
void main()
{
    gl_FragColor = vec4(v_color.rgb, 1.0);
}
"""

borders = Filter(1024, 1024, """
const float epsilon = 1e-3;
vec4 filter(sampler2D original, sampler2D filtered, vec2 texcoord, vec2 texsize)
{
    vec4 center = texture2D(filtered, texcoord);
    vec4 left   = texture2D(filtered, texcoord + vec2(-1.0, 0.0)/texsize);
    vec4 right  = texture2D(filtered, texcoord + vec2(+1.0, 0.0)/texsize);
    vec4 down   = texture2D(filtered, texcoord + vec2( 0.0,-1.0)/texsize);
    vec4 up     = texture2D(filtered, texcoord + vec2( 0.0,+1.0)/texsize);
    vec4 black  = vec4(0,0,0,1);
    float level = 0.5;

    if (length(center-left) > epsilon) {
        return mix(black,right, level);
    } else if (length(center-right) > epsilon) {
        return mix(black, left, level);
    } else if (length(center-down) > epsilon) {
        return mix(black, up,  level);
    } else if (length(center-up) > epsilon) {
        return mix(black, down, level);
    }
    return center;
} """)

window = app.Window(width=1024, height=1024)

texture = np.zeros((1024, 1024, 4),np.float32).view(gloo.TextureFloat2D)
framebuffer = gloo.FrameBuffer(color=[texture])

@window.event
def on_draw(dt):
    window.clear()
    gl.glEnable(gl.GL_DEPTH_TEST)
    cones.draw(gl.GL_TRIANGLES, I)

    framebuffer.activate()
    cones.draw(gl.GL_TRIANGLES, I)
    out_texture = framebuffer.color[0].get()
    framebuffer.deactivate()
    plt.imshow(out_texture)
    plt.show()
    #IPython.embed()
    #assert 0

@window.event
def on_resize(width, height):
    cones['projection'] = glm.ortho(0, width, 0, height, -5, +500)
    borders.viewport = 0,0,width,height

# @window.event
# def on_mouse_motion(x,y,dx,dy):
#     C["translate"][0] = x, window.height-y

def makecone(n=32, radius=1024):
    height = radius / np.tan(45 * np.pi / 180.0)
    V = np.zeros((1+n,3))
    V[0] = 0,0,0
    T = np.linspace(0,2*np.pi,n, endpoint=False)
    V[1:,0] = radius*np.cos(T)
    V[1:,1] = radius*np.sin(T)
    V[1:,2] = -height
    I  = np.repeat([[0,1,2]], n, axis=0).astype(np.uint32)
    I += np.arange(n,dtype=np.uint32).reshape(n,1)
    I[:,0] = 0
    I[-1] = 0,n,1
    return V, I.ravel()

n = 512 # number of cones (= number of points)
p = 32  # faces per cones

cones = gloo.Program(cone_vertex, cone_fragment)
C = np.zeros((n,1+p), [("translate", np.float32, 2),
                       ("position",  np.float32, 3),
                       ("color",     np.float32, 3)]).view(gloo.VertexBuffer)
I = np.zeros((n,3*p), np.uint32).view(gloo.IndexBuffer)
I += (1+p)*np.arange(n, dtype=np.uint32).reshape(n,1)
for i in range(n):
    #x,y = np.random.uniform(0,1024,2)
    x,y = np.random.normal(512,256,2)
    vertices, indices = makecone(p, radius=512)
    if i > 0:
        C["color"][i] = np.random.uniform(0.25,1.00,3)
    else:
        C["color"][0] = 1,1,0
    C["translate"][i] = x,y
    C["position"][i] = vertices
    I[i] += indices.ravel()
cones.bind(C)

app.run()

It can successfully render a Voronoi map to the app window

screen shot 2019-02-07 at 19 57 51

But failed to render correctly to the texture.

screen shot 2019-02-07 at 19 57 24

Thank you for your time!

jiangwei221 commented 5 years ago

MacBook Pro, 10.14.3, Intel Iris Graphics 550 1536 MB

Python 3.6.7 :: Anaconda, Inc.

glumpy 1.0.6 PyOpenGL 3.1.0 PyOpenGL-accelerate 3.1.0

jiangwei221 commented 5 years ago

any suggestion or workaround?

jiangwei221 commented 5 years ago

I think the reason is that I do not have a depth buffer. After attaching the depth buffer:

texture = np.zeros((1024, 1024, 4),np.float32).view(gloo.TextureFloat2D)
depth_buffer = np.zeros((1024, 1024, 1),np.float32).view(gloo.TextureFloat2D)
framebuffer = gloo.FrameBuffer(color=[texture], depth=depth_buffer)

I got the following error:

File "///miniconda3/lib/python3.6/site-packages/glumpy-1.0.6-py3.6-macosx-10.7-x86_64.egg/glumpy/gloo/framebuffer.py", line 423, in _attach
    'FrameBuffer attachments are incomplete.')
RuntimeError: FrameBuffer attachments are incomplete.
jiangwei221 commented 5 years ago

and following code are not working:

texture = gloo.ColorBuffer(1024, 1024)
depth_buffer = gloo.DepthBuffer(1024, 1024)
stencil_buffer = gloo.StencilBuffer(1024, 1024)
framebuffer = gloo.FrameBuffer(color=texture, depth=depth_buffer, stencil=stencil_buffer)
framebuffer.activate()

Error:

miniconda3/lib/python3.6/site-packages/glumpy-1.0.6-py3.6-macosx-10.7-x86_64.egg/glumpy/gloo/framebuffer.py in _attach(self)
    432                                'is not renderable.')
    433         elif res == gl.GL_FRAMEBUFFER_UNSUPPORTED:
--> 434             raise RuntimeError('Combination of internal formats used '
    435                                'by attachments is not supported.')

RuntimeError: Combination of internal formats used by attachments is not supported.
rougier commented 5 years ago

Can you look into the demos the ones that used a framebuffer to check if they're working on your machine?