The recent project requires the use of OSG to reconstruct three-dimensional surfaces, so I learned a bit.
First, I first used the method of the Baroque triangle, namely Osgutil::D Elaunaytriangulator, the characteristic of this method is:
1. First must give it a storage of three-dimensional point set of the array, the method will automatically sort these chaotic scattered points, and then use these ordered, in line with the triangular network construction rules of the scatter point to build a triangular network, it should be noted that after Dt->setinputpointarray (coords After this sentence, the order of the values of the array coords has changed, no longer the original coords.
2. To paste the texture again, you must first set a color array to it, it should be noted that the texture of the coordinates are 0~1 range, and is two-dimensional (x, y), so the coords coordinates must be mapped to the X and Y values of the 0~1 range.
3. Must output the normal vector, and use the method vector array to the corresponding geometry assignment
The specific code is as follows:
//create Delaunay Triangle Mesh Object
osg::ref_ptr<osgutil::D elaunaytriangulator> DT = new Osgutil::D elaunaytriangulator ();
dt->setinputpointarray (coords);//assigns it a three-dimensional point set array
dt->setoutputnormalarray (normals);//Output normal vector
//generates a triangulated network
dt->triangulate ();
osg::ref_ptr<osg::Geometry> Geometry = new Osg::geometry ();
//Set coordinates
geometry->setvertexarray (Coords.get ());
//Settings Description
geometry->addprimitiveset (Dt->gettriangles ());
//set Normal
geometry->setnormalarray (Normals.get ());
geometry->setnormalbinding (osg::geometry::bind_per_primitive);
//Set texture coordinates (texture fill)
osg::ref_ptr<osg::Vec2Array> texcoords = computertexturecoords (* ( Coords.get ()));//Get one by one after mapping the range in 0~1 's two-dimensional texture array
geometry->settexcoordarray (0,texcoords.get ());
Try a color fill
osg::ref_ptr<osg::vec4array> Vextexcolorarray = Computepervertexcolor (* (Coords.get ()), getOSGColorTable ()) ;
Geometry->setcolorarray (Vextexcolorarray);
Geometry->setcolorbinding (Osg::geometry::bind_per_vertex);
Preparing texture Images
Create a pair of qimage that give each pixel a predefined color assignment. Finally, save as a PNG image, save by Image.Save (strpath) parameter is to save the full file name, including the path and suffix.
Qimage image (XCOUNT,YCOUNT,QIMAGE::FORMAT_INDEXED8);
qvector<qrgb> colortable = getcolortable ();
Image.setcolortable (colortable);
Interpolateanddrawimage (Veczs,&image,xcount,ycount,xcount,ycount);
QString StrName =:: Getimagepath () + pcontourdata->getname () + ". png";
Image.Save (strName);//Save as PNG image
Start creating textures with PNG images
osg::ref_ptr<osg::image> teximage = Osgdb::readimagefile (strname.tostdstring ());
Osg::ref_ptr<osg::texture2d> tex = new Osg::texture2d;
Tex->setimage (Teximage.get ());
Tex->setdatavariance (osg::object::D ynamic);
osg::ref_ptr<osg::stateset> stateset = new Osg::stateset ();
Stateset->settextureattributeandmodes (0,tex.get (), osg::stateattribute::on);
osg::ref_ptr<osg::geode> Geode = new Osg::geode ();
Geode->adddrawable (Geometry.get ());
Geode->setstateset (Stateset.get ());
Set Matrix transformation matrix
M_prootswitch->addchild (Geode);
By using triangular patches to reconstruct the three-dimensional surface, the effect of texture rendering is already out, but it is important to note that if the point set is a regular grid data, the construction of this method is not suitable and should be used in the way of Osg::heightfield.
Two or four side-shaped patches
This approach is built with the following features:
1 It must be assigned a row number, that is, how many rows of the grid are constructed, using allocate (unsigned int rownum,unsigned int columnnum) function to allocate.
2. It must be given an initial position, specified with Setorigin (const osg::vec3& origin), notice that the z-axis of the three-dimensional vertex array is set to 0, and the smallest x, y in the point set.
3. The interval between each column in the x and Y directions must be specified with Setxinterval (float dx) and setyinterval (float dy).
4. With the initial position, row number, and interval, you can calculate the position of each vertex of the quadrilateral patch, then set the elevation value at each location, with setheight (float height)
The implementation process is as follows, the texture rendering process is similar to triangular patches, just one less step is: Do not need to set the texture coordinates, with simple and easy.
osg::ref_ptr<osg::heightfield> Pheightfield = new Osg::heightfield ();
pheightfield->allocate (Xcount,ycount);
pheightfield->setorigin (OSG::VEC3 (xmin,ymin,0));
pheightfield->setxinterval (Xdelta);
pheightfield->setyinterval (Ydelta);
float x, y;
for (int i = 0; i < Ycount; i++)
{
for (int j = 0; J < Xcount; J + +)
{
x = XMin + J * XDELTA;
y = ymin + i * YDELTA;
double z = Pinterpolater->getinterpolatedz (X,y,input.begin (), Input.end ());
veczs.push_back (-z+zmin);
coords->push_back (Geotogeonormal (osg::vec3f (x,y,0)));
pheightfield->setheight (j,ycount-i-1,-z);//loop to get each vertex and set Z-values for it
}
}
Drawing Texture Images
Qimage image (XCOUNT,YCOUNT,QIMAGE::FORMAT_INDEXED8);
qvector<qrgb> colortable = getcolortable ();
Image.setcolortable (colortable);
Interpolateanddrawimage (Veczs,&image,xcount,ycount,xcount,ycount);
QString StrName =:: Getimagepath () + pcontourdata->getname () + ". png";
Image.Save (StrName);
osg::ref_ptr<osg::image> teximage = Osgdb::readimagefile (strname.tostdstring ());
Osg::ref_ptr<osg::texture2d> tex = new Osg::texture2d;
Tex->setimage (Teximage.get ());
Tex->setdatavariance (osg::object::D ynamic);
osg::ref_ptr<osg::stateset> stateset = new Osg::stateset ();
Stateset->settextureattributeandmodes (0,tex.get (), osg::stateattribute::on);
osg::ref_ptr<osg::geode> Geode = new Osg::geode ();
Geode->adddrawable (New Osg::shapedrawable (Pheightfield.get ()));
Geode->setstateset (Stateset.get ());
Appendix: Three functions used to paste textures:
The first mapping of the true vertex coordinate one by one to the (0~1) range
Osg::ref_ptr<osg::vec2array> cosg3dsurfacenode::computertexturecoords (const Osg::vec3array & VP)
{
osg::ref_ptr<osg::vec2array> texcoords = new Osg::vec2array ();
int nSize = Vp.size ();
float MaxX = vp[0].x ();
float MinX = MaxX;
float Maxy = Vp[0].y ();
float miny = Maxy;
for (int i=0;i<nsize;i++)
{
MaxX = maxx<vp[i].x ()? vp[i].x (): MaxX;
MinX = minx>vp[i].x ()? vp[i].x (): MinX;
Maxy = Maxy<vp[i].y ()? Vp[i].y (): Maxy;
Miny = Miny>vp[i].y ()? Vp[i].y (): Miny;
}
for (int i = 0;i< nSize; i++)
{
float XValue = n (maxx-vp[i].x ())/(Maxx-minx);
float Yvalue = n (maxy-vp[i].y ())/(Maxy-miny);
float Yvalue = n (vp[i].y ()-miny)/(Maxy-miny);
Texcoords->push_back (OSG::VEC2 (Xvalue,yvalue));
}
return texcoords;
}
Second, the color array is obtained by the color configuration file
Qvector<qrgb> cosg3dsurfacenode::getcolortable ()
{
qvector<qrgb> table;
QString Colotpath =:: Getimagepath () + "colorbar.txt";
QFile file (Colotpath);
if (!file.open (qiodevice::readonly))
{
ASSERT (FALSE);
}
Qtextstream Wxstream (&file);
for (int i=0;i<32;i++)
{
Float Rcolor (0.0), Gcolor (0.0), Bcolor (0.0), acolor (1.0);
OSG::VEC4 Vcolor;
wxstream>>rcolor>>gcolor>>bcolor;
Table.push_back (Qrgb (rcolor*255,gcolor*255,bcolor*255));
}
return table;
}
Third, generate texture image, according to color configuration file to the image pixel to assign value
void Cosg3dsurfacenode::interpolateanddrawimage (const std::vector<float>& vecdata,qimage* pImage,int Xcount,int ycount,int imagesizex,int Imagesizey)
{
ASSERT (Xcount > 0);
ASSERT (Ycount > 0);
ASSERT (vecdata.size () = = Xcount * ycount);
float min = vecdata[0];
float max = vecdata[0];
for (int i = 0; i < vecdata.size (); i++)
{
if (Max < vecdata[i]) max = Vecdata[i];
if (min > vecdata[i]) min = vecdata[i];
}
Double colorfactor = getcolortable (). Size ()/(max-min);
Todo image interpolation
for (int i = 0; i < Imagesizex; i++)
{
for (int j = 0; J < Imagesizey; J + +)
{
Pimage->setpixel (I,j, (Vecdata[j*xcount + i]-min) * colorfactor);
}
}
Pimage->save (:: Getimagepath () + "123.png");
}
M_prootswitch->addchild (Geode);
Eventually:
Analysis of two methods for three-dimensional reconstruction of OSG: Triangular Patches (osgutil::D elaunaytriangulator) and four-corner patches (Osg::heightfield)