render to buffer instead of window

I’ve been trying to get the oculus rift distortion working on my own. The shader involves rendering to a buffer. Some of my code:

mybuffer = base.win.makeTextureBuffer("oculus", 2048, 1024)
mybuffer.setSideBySideStereo(True)
mybuffer.setSort(-100)
base.camLens.setInterocularDistance(5)

but I don’t know how to get the camera to render to the buffer instead of the window.
My intention is to then run a shader on the window that uses data in the buffer.
Any help would be greatly appreciated.

You’d have to create a display region on it using makeDisplayRegion, and call setCamera(base.cam).

If you use the FilterManager class, this sort of setup is all automated.

Thanks. I can get the camera to render to the buffer correctly now, with stereo rendering. It was looking nice, so I tried to apply a shader to see if i could get that working. Since I still have to learn more about shaders I just tried to apply a really simple shader to see if i could get that to work. I tried the example CG shader on the ‘Shader Basics’ page in the documentation. It turned the entire screen white. I tested the shader on a bunch of other sample programs, and the same thing happened every time. I figured that the shader was just weird.
I borrowed bamdastard’s shader from this thread:
[The Oculus Rift Side-by-side-stereo FisheyeLens and Filters)
More specifically, his github:
github.com/ubernaut/OculusRift- … ld-Panda3d
I modified his shader to no longer make things black and white, and then I tested it with some example programs and they worked fine, but upon testing it with my code, the left eye in the buffer goes completely gray, the right eye in the buffer renders normally, and the main screen had bizarre artifacts like having all textures missing, only half of the panda renders, and the ground flashes a bunch of shades of green.

I tried 2 different approaches, each with the same result:
1st try:

loadPrcFileData('', 'win-size 1280 800\nshow-buffers #t')
...
myShader = Shader.load("myfilter.sha", Shader.SL_Cg)
render.set_shader(myShader)
mybuffer = base.win.makeTextureBuffer("oculus", 2048, 1024)
mybuffer.setSideBySideStereo(True)
mybuffer.setSort(-100)
disp = mybuffer.makeDisplayRegion()
disp.setCamera(base.cam)
base.camLens.setInterocularDistance(5)
tex = mybuffer.getTexture()
render.setShader(Shader.load("myfilter.sha"))
render.setShaderInput("tex", tex)

2nd try:

loadPrcFileData('', 'win-size 1280 800\nshow-buffers #t')
...
ShowBase.__init__(self)
mybuffer = base.win.makeTextureBuffer("oculus", 2048, 1024)
mybuffer.setSort(-100)
camn1 = Camera('camleft')
camnp1 = NodePath(camn1)
camnp1.reparentTo(camera)
camnp1.setX(-.1)
camn2 = Camera('camright')
camnp2 = NodePath(camn2)
camnp2.reparentTo(camera)
camnp2.setX(.1)
disp1 = mybuffer.makeDisplayRegion(0,.5,0,1)
disp1.setCamera(camnp1)
disp2 = mybuffer.makeDisplayRegion(.5,1,0,1)
disp2.setCamera(camnp2)
tex = mybuffer.getTexture()
render.setShader(Shader.load("myfilter.sha"))
render.setShaderInput("tex", tex)

I also tried using the Filtermanager class, but it ended up with the same problem that bamdastard ran into.
How do I apply a simple shader with stereo rendering?

You applied the shader to the scene (ie. ‘render’). Instead, create a full-screen quad on render2d and apply your texture and shader onto there, like:

cm = CardMaker('card')
cm.setFrameFullscreenQuad()
card = render2d.attachNewNode(cm.generate())
card.setShader(Shader.load("myfilter.sha"))
card.setShaderInput("tex", texture)

If you had use FilterManager, it will do this set-up for you.

Okay it is working very well now! Thank you so much! Here’s some of my code in case you wanted to see the final result:

loadPrcFileData('', 'win-size 1280 800')
class MyApp(ShowBase):
	def __init__(self):
		ShowBase.__init__(self)
		mybuffer = base.win.makeTextureBuffer("oculus", 1024, 512)
		mybuffer.setSideBySideStereo(True)
		mybuffer.setSort(-100)
		disp = mybuffer.makeDisplayRegion()
		disp.setCamera(base.cam)
		base.camLens.setInterocularDistance(5)

		tex = mybuffer.getTexture()
		tex.setWrapU(Texture.WM_border_color)
		tex.setWrapV(Texture.WM_border_color)
		cm = CardMaker('card')
		cm.setFrameFullscreenQuad()
		card = render2d.attachNewNode(cm.generate())
		card.setShader(Shader.load("myfilter.sha"))
		card.setShaderInput("tex", tex)

		self.disableMouse()
		self.accept("escape",sys.exit)
		self.environ = self.loader.loadModel("models/environment")
		self.environ.reparentTo(self.render)
		self.environ.setScale(0.25, 0.25, 0.25)
		self.environ.setPos(-8, 42, 0)
		self.taskMgr.add(self.spinCameraTask, "SpinCameraTask")
		self.pandaActor = Actor("models/panda-model",{"walk": "models/panda-walk4"})
		self.pandaActor.setScale(0.005, 0.005, 0.005)
		self.pandaActor.reparentTo(self.render)
		self.pandaActor.loop("walk")
		pandaPosInterval1 = self.pandaActor.posInterval(13,Point3(0, -10, 0),startPos=Point3(0, 10, 0))
		pandaPosInterval2 = self.pandaActor.posInterval(13,Point3(0, 10, 0),startPos=Point3(0, -10, 0))
		pandaHprInterval1 = self.pandaActor.hprInterval(3,Point3(180, 0, 0),startHpr=Point3(0, 0, 0))
		pandaHprInterval2 = self.pandaActor.hprInterval(3,Point3(0, 0, 0),startHpr=Point3(180, 0, 0))
		self.pandaPace = Sequence(pandaPosInterval1,pandaHprInterval1,pandaPosInterval2,pandaHprInterval2,name="pandaPace")
		self.pandaPace.loop()
	def spinCameraTask(self, task):
		angleDegrees = task.time * 6.0
		angleRadians = angleDegrees * (pi / 180.0)
		camera.setPos(20 * sin(angleRadians), -20.0 * cos(angleRadians), 10)
		camera.setHpr(angleDegrees, -30, 0)
		return Task.cont

and the shader:

//Cg
void vshader(
    float4 vtx_position : POSITION,
    float2 vtx_texcoord0 : TEXCOORD0,
    out float4 l_position : POSITION,
    out float2 l_texcoord0 : TEXCOORD0,
    uniform float4 texpad_tex,
    uniform float4x4 mat_modelproj)
{
    l_position=mul(mat_modelproj, vtx_position);
    l_texcoord0 = vtx_position.xz * texpad_tex.xy + texpad_tex.xy;
}
void fshader(float2 l_texcoord0 : TEXCOORD0,
             out float4 o_color : COLOR,
             uniform sampler2D k_tex : TEXUNIT0)
{
    float2 distor = float2(1.8,1.2);
    if (l_texcoord0.x < .5) {
        float2 diffed = float2(l_texcoord0.x-.255,l_texcoord0.y-.5);
        float dist = (diffed.x*diffed.x)+(diffed.y*diffed.y);
        float trans = (distor.x*(dist*dist))+(distor.y*(dist))+1;
        float2 res = float2((diffed.x*trans)+.255,(diffed.y*trans)+.5);
        if (res.x < .5) {
            float4 c = tex2D(k_tex, res);
            o_color  = c;
        } else {o_color = float4(0,0,0,1);}
    } else {
        float2 diffed = float2(l_texcoord0.x-.745,l_texcoord0.y-.5);
        float dist = (diffed.x*diffed.x)+(diffed.y*diffed.y);
        float trans = (distor.x*(dist*dist))+(distor.y*(dist))+1;
        float2 res = float2((diffed.x*trans)+.745,(diffed.y*trans)+.5);
        if (res.x > .5) {
            float4 c = tex2D(k_tex, res);
            o_color  = c;
        } else {o_color = float4(0,0,0,1);}
    }
}
1 Like