[osg-users] Strange texture problem - can you help me?

Jochen Saginet jmittnacht at gmx.de
Fri Apr 22 11:47:35 PDT 2011


Hi,

I'm a total beginner in OSG and have a strange Problem that i couldn't solve and I don't know where it comes from. 
In my little program I create a texture with an Image texImgB(16x16px) and a second texture with a bigger Image texImgRG (256x256px). 

h**p://img15.imageshack.us/i/texturesv.png

I created a textureMatrix for each texture, so that the textures will be rendered to a Quad from the Perspective of a Viewer (vProjMat - ProjectionMatrix, vTransMat - Transformation Matrix). The only diffrence between both texture matrices is that I scale the matrix of the texImgRG-Texture by 16 in r,s coordinates. So the texImgRG gets 16x smaler than before:

h**p://img15.imageshack.us/i/correcte.png

Now the problem:
When i render both textures to the quad and blend them together, the texture with the Image texImgB is translated 2px down and left.
Thats the top-right corner of the picture i get from a camera ProjCam (pProjMat - ProjectionMatrix, pTransMat - TransformationMatrix) that looks exactly on the same face as the Viewer. 

h**p://img715.imageshack.us/i/cornerj.png

Why this? And how can i change my code, so that the texture-Images are not Translated to each other? 

Here is my code:

Code:

#include <osg/Node>
#include <osg/Camera>
#include <osg/CameraNode>
#include <osg/Group>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Program>
#include <osgViewer/Viewer>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Matrix>
#include <osg/MatrixTransform>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/TexMat>
#include <osg/StateSet>
#include <osg/PositionAttitudeTransform>  //Bewegungen

#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>

#include <osgGA/TrackballManipulator>

#include <cmath>
#include <iostream>


static osg::Geometry* createQuad(	double breite = 4,			//Breite der Bodenplatte
									double hoehe = 3,			//Höhe der Bodenplatte
									double auflBreite = 10,		//Auflösung der Breite
									double auflHoehe = 10)		//Auflösung der Höhe
{
	double deltaBreite = (breite / auflBreite);
	double deltaHoehe = (hoehe / auflHoehe);
	
	
	osg::Geometry* quadGeometry = new osg::Geometry();
	osg::Vec3Array* quadVertices = new osg::Vec3Array;
	osg::Vec3Array* quadNormals = new osg::Vec3Array;
	osg::Vec4Array* quadColors = new osg::Vec4Array;
	osg::Vec2Array* quadTexcoords = new osg::Vec2Array;
	osg::Vec2 dx_texcoord(1.0f/(float)(auflBreite),0.0f);
    osg::Vec2 dz_texcoord(0.0f,1.0f/(float)(auflHoehe));

	//Vertices über kartesische Koordinaten festlegen
	float vx = 0;
	float vy = 0;
	float vz = 0;
	
	for (int i=0; i<=auflBreite; ++i)
	{
		for (int j=0; j<=auflHoehe; ++j)
		{
			//Vektor-Koordinaten
			vx = (deltaBreite * i)-(breite/2);
			vy = 0;
			vz = (deltaHoehe * j)-(hoehe/2);
			quadVertices->push_back(osg::Vec3(vx,vy,vz));
			quadNormals->push_back( osg::Vec3(0,1,0) );
			quadTexcoords->push_back( osg::Vec2(dx_texcoord*i + dz_texcoord*j));
			quadColors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
		}
	}
	quadGeometry->setVertexArray( quadVertices );
	quadGeometry->setTexCoordArray(0, quadTexcoords);
	quadGeometry->setColorArray(quadColors);
	quadGeometry->setColorBinding(osg::Geometry::BIND_OVERALL);
	quadGeometry->setNormalArray( quadNormals );
	quadGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
	

	//Jewils 4 Vertices zu Primitive "Quad" verbinden
	for (int i=0; i<auflHoehe; ++i)
	{
		for (int j=0; j<auflBreite; ++j)
		{
			osg::DrawElementsUInt* quadPrim = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS, 0);
			quadPrim->push_back(i*(auflBreite+1)+j);
			quadPrim->push_back(i*(auflBreite+1)+j+1);
			quadPrim->push_back((i+1)*(auflBreite+1)+j+1);
			quadPrim->push_back((i+1)*(auflBreite+1)+j);

			quadGeometry->addPrimitiveSet(quadPrim);
		}
	}

    return quadGeometry;
}



//Main-Funktion
int main( int argc, char **argv )
{
	// ArgumentParser, verwaltet Übergebene Argumente
    osg::ArgumentParser arguments(&argc,argv);


	//----------------------------
	//Globale Einstellungen
	//----------------------------
	//Projektor
		double fovyDeg = 20;						//Öffnungswinkel (in Grad) des Projektions-Frustums
		float aspectR = 4.0f/3.0f;					//Aspect Ratio
		float p_dist = 1.0f;						//Abstand des Projektors zum Screen
		float near=0.1f;							//Clipping-Ebenen des Frustums (Nähe)
		float far=100.0f;							//Clipping-Ebenen des Frustums (Ferne)
		float pRotX=0.0f;							//Verschiebung des Projektors in x-Richtung
		arguments.read("--pRotX", pRotX);
		float pRotY=0.0f;							//Verschiebung des Projektors in y-Richtung
		arguments.read("--pRotY", pRotY);
		float pRotZ=0.0f;							//Verschiebung des Projektors in y-Richtung
		arguments.read("--pRotZ", pRotZ);
		float pTransX=0.0f;							//Verschiebung des Projektors in x-Richtung
		arguments.read("--pTransX", pTransX);
		float pTransY=0.0f;							//Verschiebung des Projektors in y-Richtung
		arguments.read("--pTransY", pTransY);
		float pTransZ=0.0f;							//Verschiebung des Projektors in y-Richtung
		arguments.read("--pTransZ", pTransZ);
	//Viewer
		float vTransX=0.0f;							//Verschiebung des Viewers in x-Richtugn
		arguments.read("--vTransX", vTransX);
		float vTransY=0.0f;							//Verschiebung des Viewers in y-Richtugn
		arguments.read("--vTransY", vTransY);
		float vTransZ=0.0f;							//Verschiebung des Viewers in z-Richtugn
		arguments.read("--vTransZ", vTransZ);
	//Texturgröße
		unsigned int tex_width =  4096;
		unsigned int tex_height = 4096;

	//--------------------------------------------------
	// Projektor
	//--------------------------------------------------
	float dx, dz;								//Größe des Bildschirms x-Breite, z-Höhe
	float fovy = (fovyDeg/360)*(2.0*osg::PI);	//FOVy in Rad
	dz= 2.0f*(tan(fovy/2.0)*p_dist);
	dx= aspectR * dz;

	//Projection Matrix des Projektors (Frustum)
	osg::Matrix pProjMat;
	pProjMat.makePerspective(fovyDeg, aspectR, near, far);
	osg::Matrix pProjMatInv = osg::Matrix::inverse(pProjMat); //invertiert

	//Transformations Matrix des Projektors
	osg::Matrix pTransMat;
	pTransMat.makeRotate(-osg::PI/2,osg::X_AXIS);  //Kamera guckt standartmäßig in z-Richtung, wollen aber y! -> 90°Drehung des KS 
	pTransMat = pTransMat * osg::Matrix::rotate(pRotX,osg::X_AXIS,pRotZ,osg::Y_AXIS,-pRotY,osg::Z_AXIS); //Rot des Projektors
	pTransMat = pTransMat * osg::Matrix::translate(osg::Vec3(pTransX,pTransY,pTransZ));	//Verschiebung des Projektors								
	osg::Matrix pTransMatInv = osg::Matrix::inverse(pTransMat); //invertiert


	//--------------------------------------------------
	// VIEWER
	//--------------------------------------------------
	float mc_dist;								//Distanz vom Auge des Betrachters zum Screen
	float mc_left, mc_right, mc_top, mc_bottom; //Ausdehnungs-Parameter des Frustums
	float n_over_d;								//near:mc_dist (Strahlensatz)

	mc_dist=p_dist-vTransY;
	n_over_d=near/mc_dist;
	mc_right	=  n_over_d * (dx/2.0f - vTransX);
	mc_left		= -n_over_d * (dx/2.0f + vTransX);
	mc_top		=  n_over_d * (dz/2.0f - vTransZ);
	mc_bottom	= -n_over_d * (dz/2.0f + vTransZ);

	//Projection Matrix des Views (ViewFrustum)
	osg::Matrix vProjMat;
	vProjMat.makeFrustum(mc_left, mc_right, mc_bottom, mc_top, near, far);
	osg::Matrix vProjMatInv = osg::Matrix::inverse(vProjMat); //invertiert

	//Transformations Matrix des Views
	osg::Matrix vTransMat;
	vTransMat.makeRotate(osg::PI/2,osg::X_AXIS);  //Viewer standartmäßig in z-Richtung, wollen aber y! -> 90°Drehung 
	vTransMat = vTransMat * osg::Matrix::translate(osg::Vec3(vTransX,vTransY,vTransZ));	//Orientierung(oben)
	osg::Matrix vTransMatInv = osg::Matrix::inverse(vTransMat); //invertiert


	//--------------------------------------------------
	// Projektionsgeometrie Transformieren
	//--------------------------------------------------
	//Transformationsmatrix der Projektionsgeometrie
	osg::Matrix sTransMat;
	sTransMat.set(	osg::Matrix::translate(0.0f,2.0f,0.0f)*
					osg::Matrix::scale(1.0f,1.0f,1.0f)*
					osg::Matrix::rotate(0.0f, osg::Z_AXIS));

	osg::Matrix sTransMatInv = osg::Matrix::inverse(sTransMat); //invertiert

//------------------------
//SCREEN - Geometrie auf die Projektion erfolgt
//------------------------
	osg::Geode* geodeScreen = new osg::Geode();
	//Projektionsgeometrie hinzufügen
	geodeScreen->addDrawable(createQuad(4,4,10,10));

	//ProjGeometrie Transformieren
	osg::MatrixTransform* transScreen = new osg::MatrixTransform();  
	transScreen->setMatrix(sTransMat);
	transScreen->addChild(geodeScreen);

	
	//--------------------------------------------------
	// Textur 
	//--------------------------------------------------
	//Bild erstellen, in dem Texturkoordinaten pro Pixel gespeichert werden (Für RGBA -> 4*8Bit)

	//Statemachine erstellen
	osg::StateSet* stateScreen = new osg::StateSet();
	transScreen->setStateSet(stateScreen);	//Textur hinzufügen
	
	// Textur Rot
	//--------------------------------------------------
	//RotWerte: 8Bit
	int imgBreiteRG = 256;
    int imgHoeheRG = 256;
	unsigned char *dataRG;
    dataRG = new unsigned char[imgBreiteRG*imgHoeheRG*4]; //höhe*breite*farbtiefe[R,G,B,Alpha]
    for (int y=0; y<imgHoeheRG; ++y) {
		int border=255;
        for (int x=0; x<imgBreiteRG; ++x) {
			dataRG[x*4+y*imgBreiteRG*4+0] = 255; //Rot-Wert (8bit)
            dataRG[x*4+y*imgBreiteRG*4+1] = border; //Grün-Wert (8bit)
            dataRG[x*4+y*imgBreiteRG*4+2] = border;
            dataRG[x*4+y*imgBreiteRG*4+3] = 255;
			border=0;
        }
    }
	osg::Image* texImgRG = new osg::Image();
	texImgRG->setImage(imgBreiteRG, imgHoeheRG, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, dataRG, osg::Image::USE_NEW_DELETE, 1);

	//Textur für RG-Werte erstellen und Bild einbinden
	osg::Texture2D* texturRG = new osg::Texture2D();
	texturRG->setInternalFormat(GL_RGBA);
	texturRG->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
	texturRG->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
	texturRG->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
	texturRG->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::REPEAT);
	texturRG->setImage(texImgRG);
	stateScreen->setTextureAttributeAndModes(0, texturRG,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	//Decal-Mode setzen
	osg::TexEnv* texEnvRG = new osg::TexEnv();
	texEnvRG->setMode(osg::TexEnv::DECAL);
	stateScreen->setTextureAttributeAndModes(0, texEnvRG,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	//Generiere Texturkoordinaten in x-z-Ebene automatisch
	osg::TexGen* texGenRG = new osg::TexGen();
	texGenRG->setMode(osg::TexGen::EYE_LINEAR);
	texGenRG->setPlane(osg::TexGen::S,osg::Plane(1.0f,0.0f,0.0f,0.0f)); 
	texGenRG->setPlane(osg::TexGen::T,osg::Plane(0.0f,1.0f,0.0f,0.0f));
	texGenRG->setPlane(osg::TexGen::R,osg::Plane(0.0f,0.0f,1.0f,0.0f));
	texGenRG->setPlane(osg::TexGen::Q,osg::Plane(0.0f,0.0f,0.0f,1.0f));
	stateScreen->setTextureAttributeAndModes(0, texGenRG,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)
	
	//Texturmatrix erstellen
	osg::TexMat* texMatRG= new osg::TexMat();
	stateScreen->setTextureAttributeAndModes(0, texMatRG,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	//Textur-Scaling
	osg::Matrix scaleTex1;	//Textur geht von -1 nach 1 wegen vProjMat auf Einheitswürfel, wollen aber von 0 nach 1
	scaleTex1.makeScale(osg::Vec3(0.5f,0.5f,1.0f));		//Texturgröße wird halbiert -> Image verdoppelt sich in Größe 

	osg::Matrix scaleTex2;	//Textur soll 16x in jede Richtung wiederholt werden -> bessere Auflösung
	scaleTex2.makeScale(osg::Vec3(16.0f,16.0f,1.0f));	//Scale-Faktor (x,y,z) 

	//Textur-Trans
	osg::Matrix transTex1;
	transTex1.makeTranslate(osg::Vec3(0.5f,0.5f,0.0f));	//Scale-Faktor (x,y,z)

	texMatRG->setMatrix(sTransMat * vTransMatInv * vProjMat * scaleTex1 * transTex1 * scaleTex2);

	// Textur Blau
	//--------------------------------------------------
	//BlauWerte: 1*8Bit
	int imgBreiteB = 16;
    int imgHoeheB = 16;
	unsigned char *dataB;
    dataB = new unsigned char[imgBreiteB*imgHoeheB*4]; //höhe*breite*farbtiefe[R,G,B,Alpha]
    for (int y=0; y<imgHoeheB; ++y) {
		int border2 = 255;
        for (int x=0; x<imgBreiteB; ++x) {
            dataB[x*4+y*imgBreiteB*4+0] = 0;
            dataB[x*4+y*imgBreiteB*4+1] = border2;
            dataB[x*4+y*imgBreiteB*4+2] = x+(y*imgBreiteB); //Blau-Wert (8bit)
            dataB[x*4+y*imgBreiteB*4+3] = 255;
			border2 = 0;
        }
    }
	osg::Image* texImgB = new osg::Image();
	texImgB->setImage(imgBreiteB, imgHoeheB, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, dataB, osg::Image::USE_NEW_DELETE, 1);

	//Textur für B-Wert erstellen und Bild einbinden
	osg::Texture2D* texturB = new osg::Texture2D();
	texturB->setInternalFormat(GL_RGBA);
	texturB->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
	texturB->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
	texturB->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_BORDER);
	texturB->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_BORDER);
	texturB->setBorderColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
	texturB->setImage(texImgB);
	stateScreen->setTextureAttributeAndModes(1, texturB,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	//Blend-Mode setzen
	osg::TexEnv* texEnvB = new osg::TexEnv();
	texEnvB->setMode(osg::TexEnv::BLEND);
	texEnvB->setColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); //Welche Kanal soll geblendet werden -> hier blau
	stateScreen->setTextureAttributeAndModes(1, texEnvB,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	//Generiere Texturkoordinaten in x-z-Ebene automatisch
	osg::TexGen* texGenB = new osg::TexGen();
	texGenB->setMode(osg::TexGen::EYE_LINEAR);
	texGenB->setPlane(osg::TexGen::S,osg::Plane(1.0f,0.0f,0.0f,0.0f)); 
	texGenB->setPlane(osg::TexGen::T,osg::Plane(0.0f,1.0f,0.0f,0.0f));
	texGenB->setPlane(osg::TexGen::R,osg::Plane(0.0f,0.0f,1.0f,0.0f)); 
	texGenB->setPlane(osg::TexGen::Q,osg::Plane(0.0f,0.0f,0.0f,1.0f));
	stateScreen->setTextureAttributeAndModes(1, texGenB,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)
	
	//Texturmatrix erstellen
	osg::TexMat* texMatB = new osg::TexMat();
	stateScreen->setTextureAttributeAndModes(1, texMatB,osg::StateAttribute::ON); //(TexUnit, Texturtyp, Attribut)

	texMatB->setMatrix(sTransMat * vTransMatInv * vProjMat * scaleTex1 * transTex1);

//--------------------------------------------------
// QUAD für distImg
//--------------------------------------------------
	//Quad zur visualisierung des distImg
	osg::Geode* geodeImgQuad = new osg::Geode();
	geodeImgQuad->addDrawable(createQuad());

	// StateSet mit Texture StateAttributen.
    osg::StateSet* stateImgQuad = new osg::StateSet();
	stateImgQuad->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
	geodeImgQuad->setStateSet(stateImgQuad);

	//Quad transformieren
	osg::MatrixTransform* transImgQuad = new osg::MatrixTransform();
	transImgQuad->setMatrix(osg::Matrix::translate(4.0f, 0.0f, 0.0f));
	transImgQuad->addChild(geodeImgQuad);

	//Textur erstellen
	//--------------------------
    
    osg::Texture2D* textureQuad = new osg::Texture2D;
    textureQuad->setTextureSize(tex_width, tex_height);
    textureQuad->setInternalFormat(GL_RGBA);
	textureQuad->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
	textureQuad->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
    stateImgQuad->setTextureAttributeAndModes(0, textureQuad, osg::StateAttribute::ON);
	
//--------------------------------------------------
// Kamera(Sicht Projektor) - Render2Texture (Rendert verzerrtes Projektorbild auf Textur eines Quads)
//--------------------------------------------------
	osg::CameraNode* projCam = new osg::CameraNode();

	//zum Test auf FBO festlegen
	osg::CameraNode::RenderTargetImplementation renderImplementation = osg::CameraNode::FRAME_BUFFER_OBJECT;

	//Screen soll gerendert werden
	projCam->addChild(transScreen);

	//Lage und Projektion festlegen
	projCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	projCam->setViewMatrix(pTransMat);
	projCam->setProjectionMatrix(pProjMat);

	// set up the background color and clear mask.
	projCam->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f));
	projCam->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	// set up projection.
	projCam->setComputeNearFarMode(osg::CameraNode::DO_NOT_COMPUTE_NEAR_FAR);

	// setze Sichtfenster
	projCam->setViewport(0,0,tex_width,tex_height);

	// Camera vor Haupt-Kamera des viewers rendern lassen
	projCam->setRenderOrder(osg::CameraNode::PRE_RENDER);

	//render-Modus festlegen
	projCam->setRenderTargetImplementation(renderImplementation);
		
	// Bild aus Kameransicht erstellen und speichern
	osg::Image* distImg = new osg::Image();
	distImg->allocateImage(tex_width,tex_height,1,GL_RGBA,GL_UNSIGNED_BYTE);
	projCam->attach(osg::CameraNode::COLOR_BUFFER, distImg);

//--------------------------------------------------
// Scenengraph initialisieren
//--------------------------------------------------
	//Gruppe zur Dartellung des DistortionImages
	osg::Group* imgGroup = new osg::Group();
	imgGroup->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
	imgGroup->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);

	//GeoNodes zu imgGroup hinzuügen
	imgGroup->addChild(transScreen);
	imgGroup->addChild(projCam);

	// Viewer erstellen
	osgViewer::Viewer viewer;
	viewer.setSceneData( imgGroup );
	viewer.setCameraManipulator(new osgGA::TrackballManipulator);

	while (!viewer.done())
	{
		viewer.frame();
		osgDB::writeImageFile(*distImg,"distort.png");
		osgDB::writeImageFile(*texImgB,"texImgB.png");
		osgDB::writeImageFile(*texImgRG,"texImgRG.png");
	}
	return 0;
}






I would be grateful for any help...!

Cheers,
Jochen[/img]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=38739#38739








More information about the osg-users mailing list