saving viewport glsl and its zbuffer

I working on a short film, you can find some renders at here: http://www.etyekfilm.hu/averylittlewarrior/index.html

But! I want to make it as full realtime render. Yes, using glsl. All project is planned for glsl render.

So that I cant now with Blender:

-saving the glsl viewport
-saving its zbuffer for using in post depth of field effect
-motion blur with glsl - I have no idea how can I make this :frowning: maybe I can render the movie at 250 frames per second and converting it to 25 fps… this is a real motion blur technique :slight_smile:

Another big problem: because I use alpha test materials for the plants, I cant use internal render… :frowning: So I cant save the zbuffer or motion blur vectors from the internal render… :frowning:
(Internal render cant render correct zbuffer for alpha materials.)

I have no ideas on the motion blurring, but grabbing the glsl viewport and the zbuffer isn’t very hard. Simply use glReadPixels() (even works correctly with alpha materials).

Unfortunately it’s pretty slow to save this buffer to an image. Below is a script that creates 2 new images inside blender (show_glsl and show_z, they can be found in the UV/Image editor window). I haven’t found a way to make this any faster.

import Blender
from Blender import Image, Window
from Blender.BGL import *

# width and height of 3d-view
windows = Window.GetScreenInfo()
for w in windows:
    if w['type'] == Window.Types.VIEW3D:
        xmin, ymin, xmax, ymax = w['vertices']
        width = xmax-xmin
        height = ymax-ymin

# reading buffers
zbuf = Buffer(GL_FLOAT, [width*height])
glReadPixels(xmin, ymin, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, zbuf)
colbuf = Buffer(GL_FLOAT, [width*height, 4])
glReadPixels(xmin, ymin, width, height, GL_RGBA, GL_FLOAT, colbuf)

# creating images
try:
    img_z = Image.Get('show_z')
except:
    img_z = Image.New('show_z', width, height, 32)
try:
    img_col = Image.Get('show_glsl')
except:
    img_col = Image.New('show_glsl', width, height, 32)

# progress bar
progress = 0
progress_text = "Drawing"
Window.DrawProgressBar(progress, progress_text)

# used to calculate relative z-values
zmin = min(zbuf)
zmax = max(zbuf)
zmult = 1.0/(zmax-zmin)

for y in xrange(height):
    # updating progress bar
    current_progress = round((float(y)/(height-1))*100)
    if current_progress-10>=progress*100:
        progress = current_progress/100.0
        Window.DrawProgressBar(progress, progress_text)
    
    for x in xrange(width):
        # drawing images
        i = y*width + x
        z = (zbuf<i>-zmin)*zmult
        r,g,b,a = colbuf[i]
        img_z.setPixelF(x,y,(z,z,z,1.0))
        img_col.setPixelF(x,y,(r,g,b,1.0))
Window.DrawProgressBar(1,progress_text)

Hopefully this helps you a bit.

[I]Edit:
the script generates an images of the relative z-buffer (always ranges from pure white to pure black). If you want the absolute z-buffer, just replace
z = (zbuf[i]-zmin)*zmult
with:
z = zbuf[i]

wow, big thank you, it works
yes, it is slow, but maybe a good start

very sad we cant use glsl for rendering animations :frowning:

now my next problem: how can I set the viewport size to the render setting size? and it must show the camera view only…

I cant code python :frowning:

It is impossible to set the size of the viewport with python (this might be possible in blender 2.5, but not in 2.4x).
I did find a way to speed up the capturing of the glsl viewport. It requires the installation of PIL and a full python installation, but is much faster.

import Blender, bpy, array
from Blender import Window, Draw
from Blender.BGL import *
from PIL import Image

# user settings
path = "C:/myFolder/"

# stores the old viewport setup
def situation():
    old = {
    'cframe': Blender.Get('curframe'),
    }
    return old

# collects general data
def initiate():
    global width, height, xmin, ymin, wid, tf, frames
    
    # changing to camera view
    Window.CameraView()
    
    # width and height of 3d-view
    windows = Window.GetScreenInfo()
    for w in windows:
        if w['type'] == Window.Types.VIEW3D:
            xmin, ymin, xmax, ymax = w['vertices']
            width = xmax-xmin
            height = ymax-ymin
            wid = w['id']
    
    # reading animation settings
    scn = bpy.data.scenes.active
    context = scn.getRenderingContext()
    tf = context.eFrame - context.sFrame + 1
    frames = range(context.sFrame, context.eFrame+1)
    
# returns the viewport buffers
def getBuffers():
    colbuf = Buffer(GL_BYTE, [width*height*4])
    glReadPixels(xmin, ymin, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colbuf)
        
    return colbuf

def render():
    counter = 0
    for f in frames:
        # changing frame
        Blender.Set('curframe', f)
        Blender.Redraw()
        
        # display progress
        counter += 1
        progress = min(0.9, float(counter)/tf)
        Window.DrawProgressBar(progress, "Frame %i/%i"%(counter,tf))
        
        # saving images
        colbuf = getBuffers()
        mode = 'RGBA'
        buff_img = Image.fromstring(mode, (width, height), array.array('B', colbuf.list), 'raw', mode, 0, -1)
        buff_img.save(path+"viewport_glsl"+str(f)+".png")

# restoring the old situation of the viewport
def cleanup(old):
    Blender.Set('curframe', old['cframe'])
    Window.QAdd(wid, Draw.PAD0, 1)
    Window.QHandle(wid)
    Blender.Redraw()

# main control centre
def main():
    Window.DrawProgressBar(0, "Collecting data")
    old = situation()
    initiate()
    render()
    cleanup(old)
    Window.DrawProgressBar(1, "Finished")

main()

You need to set the path in line 7 to an existing folder on your computer. So far it only saves the glsl view, not yet the zbuffer. Somehow saving the zbuffer keeps crashing on me, and I don’t have time to investigate right now.
The script saves the entire animation (all frames, as set in blender’s render panel). To get the correct image size, you’ll have to size the 3d-viewport manually. The script already switches to camera view automatically, but it can’t change the offset and zoom of the view.

So I don’t know if this is going to be a viable solution.

i saved some anim with your new script, check your private messages

somewhere I found a script that can save the game engine frames… so maybe from game engine the saving easyer?
but unfortunately in game engine there is no many blender function like subsurt or constraints… so I cant use game engine to save… this is sad, because in game engine I can use many good effects like DoF, glow etc…

Since 2.49 modifiers work in the game engine,
check the release log:
http://www.blender.org/development/release-logs/blender-249/

So, you can use subsurf in the game engine. I have no idea about constraints though.

Ps, I’m glad to read that you’re still working on this project, I’m waiting to see it finished.

wow it works really :slight_smile:
good, thank yo

I don’t have experience with coding for the game-engine, but I was wondering why you don’t use the viewport render button for the glsl pass. It’s at the far right of the 3d-view header.
This isn’t a solution for the zbuffer, but it will give good and fast results for the colour pass.

Unfortunately I don’t have time this weekend to do some coding, but I’ll get back to you at the end of Monday.

Of course I have try it… It is very slow when I use many textures. I think it re-send all textures to the video card on every frame… :frowning:
Another and bigger problem: it works totally bad with higher resolution… I get distorted result in this case.
Sad…

But I can use this to save zbuffer with a trick: using a special material with a blend texture. The blend textures will show the distance of every pixel if I use proper coordinate mapping.

Bad new… I have try some things now with realtime render… But I think I cant make this movie with realtime… :frowning:
I think we need very much things to work. :frowning:

I dont want to stole your time, thank you for the help.

Maybe you could do it in Max…

Pity you can’t get it to work. Things might improve in 2.5, but that’s of course no help right now.
If you want to try if things are better in the game engine, you’d probably better post in the game engine forum. There are more people over there with knowledge on scripting in the game engine than there are in this forum.
Good luck.