Draw 2D transparent image in 3D world

Hello,

I am trying to draw a 2D transparent image (loaded at the start) into the 3D world, like a glass window where is possible to look through. The image has to remain fixed in a certain location, so that when I navigate with ofEasyCam it keeps the same orientation.

I already tried to draw a 3D rectangle and applying the texture on it with bind() and unbind() (see code below), but it doesn’t work. It makes the rectangle transparent black without any texture.

Is there anyone who can help me with this?

Thanks,
Poiex

  
img.getTextureReference().bind();  
		  
		ofPushMatrix();  
		plane_col.set(0,0,255,180);  
		ofEnableAlphaBlending();  
		ofMesh plane;  
		// v1  
		ofVec3f v1(0, 0, selectedState.z);  
		plane.addVertex( v1 );  
		plane.addColor( plane_col );  
		ofVec3f normal1 = v1;  
		normal1.normalize();  
		plane.addNormal( normal1 );  
		// v2  
		ofVec3f v2(640, 0, selectedState.z);  
		plane.addVertex( v2 );  
		plane.addColor( plane_col );  
		ofVec3f normal2 = v2;  
		normal2.normalize();  
		plane.addNormal( normal2 );  
		// v3  
		ofVec3f v3(640, 350, selectedState.z);  
		plane.addVertex( v3 );  
		plane.addColor( plane_col );  
		ofVec3f normal3 = v3;  
		normal3.normalize();  
		plane.addNormal( normal3 );  
		// v4  
		ofVec3f v4(0, 350, selectedState.z);  
		plane.addVertex( v4 );  
		plane.addColor( plane_col );  
		ofVec3f normal4 = v4;  
		normal4.normalize();  
		plane.addNormal( normal4 );  
		  
		plane.addTriangle(0, 1, 2);  
		plane.addTriangle(2, 3, 0);  
		plane.draw();  
		ofDisableAlphaBlending();  
		ofPopMatrix();  
		  
		img.getTextureReference().unbind();  
  

Hi,

I think you are probably missing some code to link the vertex of your mex with the texture coordinates.

You should do something like:

texture.bind();
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f);
glVertex2f(x0,y0,z0);
glTexCoord2f(1.0f,0.0f);
glVertex2f(x1,y1,z1);
glTexCoord2f(1.0f,1.0f);
glVertex2f(x2,y2,z2);
glTexCoord2f(0.0f,1.0f);
glVertex2f(x3,y3,z3);
glEnd();
texture.unbind();

To link the corners of the quad to the cornes of the texture.

Hey Poiex,

a couple of things:

  1. are you trying to draw a picture with alpha transparency ? In that case, you want to make sure to enable alpha blending before you start to draw.
  
ofEnableAlphaBlending();  

  1. If you draw textures with alpha transparency, it is important to draw them in the right order - think of it as if you were drawing layers in photoshop, where you first start with drawing the layer furthest away from (you=the camera), then the next one closer, then the next one closer, etc.

The reason you need to sort alpha-enabled textures is depth-masking, which is an optimisation that your graphics card does in the background. Whenever the graphics card draws something, it tests every fragment’s depth value and will only draw a fragment (= a “pixel”) if it is nearer=closer to the camera than the fragment that was in the framebuffer at this position before.

Imagine you’d draw a transparent image very close to your camera: you’d have a framebuffer full of transparent (alpha=zero) pixels, but their depth value would be incredibly close to the camera. If you now try to draw anything “behind” your transparent image, the GPU will throw these fragments away, because your framebuffer is full of fragments with very near depth values, and anything “behind”=further away will fail the depth test.

  1. if you just want to draw an image, you don’t have to issue vertex draw commands, openFrameworks takes care of these things for you (and does them very well optimised) just issue the command:
  
img.draw()  

It will do all the binding / and unbinding for you - and it will use textures, automatically. If you want to draw the image to a certain size, issue:

  
img.draw(640,350)  

and if you want to push your image back on the z-axis, depending on your selectedState, issue these commands:

  
  
ofPushMatrix();  
ofTranslate(0,0,selectedState.z);  
img.draw(640,350);  
ofPopMatrix();  
  

  1. If you are interested having objects keep a certain orientation towards the camera, I suggest looking up “Billboarding” as a technique. There is also a pretty good example, “*billboardRotationExample*” from the openFrameworks example directory that you might find helpful.

Cheers
#

Tim

Many thanks guys. After having merged all the suggestions I came up with this solution:

  
  
void setup(){  
        ofColor planeColor(255,255,255,220);  
	  
	plane.addVertex( ofVec3f(0,0,0) );  
	plane.addTexCoord( ofVec2f(0,0) );  
	plane.addColor(planeColor);  
	plane.addVertex( ofVec3f(0,0,0) );  
	plane.addTexCoord( ofVec2f(640,0) );  
	plane.addColor(planeColor);  
	plane.addVertex( ofVec3f(0,0,0) );  
	plane.addTexCoord( ofVec2f(640,350) );  
	plane.addColor(planeColor);  
	plane.addVertex( ofVec3f(0,0,0) );  
	plane.addTexCoord( ofVec2f(0,350) );  
	plane.addColor(planeColor);  
}  
  
void update(){  
        // v1 - selectedState.z is a variable since the plane moves  
	ofVec3f v1(0,0,selectedState.z);  
	plane.setVertex(0,v1);  
	ofVec3f vn1 = v1;  
	vn1.normalize();  
	plane.addNormal(vn1);  
	// v2  
	ofVec3f v2(640, 0, selectedState.z);  
	plane.setVertex(1,v2);  
	ofVec3f vn2 = v2;  
	vn2.normalize();  
	plane.addNormal(vn2);  
	// v3  
	ofVec3f v3(640, 350, selectedState.z);  
	plane.setVertex(2,v3);  
	ofVec3f vn3 = v3;  
	vn3.normalize();  
	plane.addNormal(vn3);  
	// v4  
	ofVec3f v4(0, 350, selectedState.z);  
	plane.setVertex(3,v4);  
	ofVec3f vn4 = v4;  
	vn4.normalize();  
	plane.addNormal(vn4);  
  
	plane.addTriangle(0, 1, 2);  
	plane.addTriangle(2, 3, 0);  
}  
  
void draw(){  
        ofEnableAlphaBlending();  
	imgPlane.getTextureReference().bind();  
	plane.draw();  
	imgPlane.getTextureReference().unbind();  
	ofDisableAlphaBlending();  
}  
  

I think the inclusion of the normals is necessary to have the transparency.