3D video texture

How can I mix two videos and then use the resulting frame(s) to texture a model, using its own pre-made UV map. Maybe rendering to an FBO first?

Or even simpler, how can I map one video the a UV mapped 3D file?

I’m starting with the 3DmodelLoaderExample.

I already looked in this thread, but couldn’t get it right:
Apply video to 3d shape:
http://forum.openframeworks.cc/t/apply-video-to-3d-shape/2959/0

Thank you!

Hey, I did just that recently and it’s quite simple. You don’t need FBOs or VBOs or anything (actually I think the 3ds lib that ofx3DSLoader wraps internally uses VBOs, but that doesn’t matter).

All you need to do is:

  
  
myVideo.getTextureReference().bind();  
my3DModel.draw();  
myVIdeo.getTextureReference().unbind();  

This assumes that your 3d model already has embedded UV coordinates exported from 3d software.

Now there is a problem, actually a generic problem in openGL / OF / textures. 3ds stores the UV coordinates as 0…1 (which makes sense, because you don’t want your texture mapping to change depending on the resolution of texture you use!). But by default OF stores your texture as a GL_TEXTURE_RECTANGLE_ARB which uses UV coordinates as (0…width, 0…height). So as of OF006 you can call ofDisableArbTex() to disable GL_TEXTURE_RECTANGLE_ARB and stick with GL_TEXTURE_2D. So now your texture coordinates are 0…1, problem solved? nope :stuck_out_tongue:

Even though GL_TEXTURE_2D does make the UV coordinates 0…1, it also puts your texture in the closest power of 2 texture. E.g. a 1280x720 video will be placed inside a 2048 x 1024 texture. So all the 0…1 texture coordinates get messed up. E.g. when your 3D model says ‘this vertex has UV (1, 0.5)’ you’d expect it to be the right-most column of your texture, and halfway down your texture. But actually you get something completely different because of all the padding!. I.e. the rightmost column of the padded texture, and halfway down the padded texture.

So there are two solutions.

  1. a simple hack, just call ofDisableArbTex() before loading your video, and hack ofTexture to remove all instances of ofNextPow2();

  2. A better solution (which I hope will make it into OF someday) is to scale all UV coordinates to the range of 0…1 no matter if they are RECT textures, or non-square textures which have been placed inside larger textures. In the code below hasTex is a pointer to an ofBaseHasTexture (so it could be an ofImage, ofVideoPlayer, ofVideoGrabber etc.)

  
  
void bind() {  
    ofTexture &tex = hasTex->getTextureReference();  
    tex.bind();  
      
    glMatrixMode(GL_TEXTURE);  
    glPushMatrix();  
    glLoadIdentity();  
      
    ofTextureData texData = tex.getTextureData();  
    if(texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB) {  
        glScalef(tex.getWidth(), tex.getHeight(), 1.0f);  
    } else {  
        glScalef(tex.getWidth() / texData.tex_w, tex.getHeight() / texData.tex_h, 1.0f);  
    }  
      
    glMatrixMode(GL_MODELVIEW);       
}  
  
void unbind() {  
    hasTex->getTextureReference().unbind();  
      
    glMatrixMode(GL_TEXTURE);  
    glPopMatrix();  
    glMatrixMode(GL_MODELVIEW);       
}  
  

Hi, memo, thank you very much for the solution!

I got the video onto the model ok.
So I’m trying to change ofTexture.cpp as you mentioned on option 2. How should I declare hasTex on the .h file?

As for mixing some more OF graphics, such as live video blended the the video player, is there a way? I could already bind alright a video grabber, but it replaces the video player.
That’s where I thought the FBO could come in handy.

Hi Alexandre, actually the second option doesn’t involve a hack to ofTexture at all, it works externally. So those bind() and unbind() methods would be in your testApp or texture manager class:

  
  
void testApp::bindMyTexture() {  
    ofTexture &tex = myVideo.getTextureReference();  
    tex.bind();  
      
    glMatrixMode(GL_TEXTURE);  
    glPushMatrix();  
    glLoadIdentity();  
      
    ofTextureData texData = tex.getTextureData();  
    if(texData.textureTarget == GL_TEXTURE_RECTANGLE_ARB) {  
        glScalef(tex.getWidth(), tex.getHeight(), 1.0f);  
    } else {  
        glScalef(tex.getWidth() / texData.tex_w, tex.getHeight() / texData.tex_h, 1.0f);  
    }  
      
    glMatrixMode(GL_MODELVIEW);       
}  
  
void testApp::unbindMyTexture() {  
    myVideo.getTextureReference().unbind();  
      
    glMatrixMode(GL_TEXTURE);  
    glPopMatrix();  
    glMatrixMode(GL_MODELVIEW);       
}  
  

I’ve proposed mods to the core to include this
http://github.com/memo/openFrameworks/c-…-5ea1924fe4

the idea is, you’ll be able to call ofEnableNormalizedTexCoords(), then when you bind() a texture, you are garanteed that all UV coordinates for that texture will be 0…1 even if using TEXTURE_RECT or non-pow2 TEXTURE_2D placed inside a larger pow2 texture.

until those mods are in the core, you can just use the code pasted above.

and yes, if you did want to mix videos or videoGrabber etc then the best thing to do is render them all to an FBO with the blending modes you want, then do the same to the FBO instead of myVideo when binding and unbinding.

Sounds like Quase-Cinema is gaining some awesome new features! :wink:

Oh, ok. Great, memo!

These methods are for a video installation I’m doing, but the ideas and source code will sure make their way into Quase-Cinema :wink:

Works like a charm! Thank you, memo!

Here’s the outcome of this project:

"Pangeia" - Alexandre Rangel e Rodrigo Paglieri

http://www.youtube.com/watch?v=LzpM6Gzfx9U

On the exhibition “Semicircle” in Brasília’s National Museum until 26/April/2010.

Feijoada - http://pt.wikipedia.org/wiki/Feijoada / http://en.wikipedia.org/wiki/Feijoada