PDA

View Full Version : Lines over the grid


Wolfer
03-18-2010, 08:23 AM
Hello!

I use PoRegularCartesianGrid2D to represent a grid of values. Say it's a kind of surface. And I want a polyline to be on that surface. These polylines are cracks and breaks.

Is there a way to do that?

Thanks in advance.

mikeheck
03-18-2010, 05:12 PM
I use PoRegularCartesianGrid2D to represent a grid of values. Say it's a kind of surface. And I want a polyline to be on that surface. These polylines are cracks and breaks.

The simple answer is: just use an SoLineSet (or similar node). But you probably know that already...
Are you really asking how to make sure co-planar lines on a surface are visible? The answer to that is SoPolygonOffset.

-Mike

Wolfer
03-19-2010, 02:12 AM
Hi Mike,

The point is that my surface has a relief and I want polylines to be projected onto that surface. Does SoPolygonOffset really suit? I've read docs and didn't caught the idea.

mikeheck
03-19-2010, 08:57 AM
The point is that my surface has a relief and I want polylines to be projected onto that surface. Does SoPolygonOffset really suit? I've read docs and didn't caught the idea.

Sorry, I assumed that you already had points on the grid. I understand the question now.

You should be able to use the mesh object to interpolate Z values. (I haven't tried this recently.)
Given a PbRegularCartesianGrid2D and an X,Y point with unknown Z value, the code would be approximately this:

SbVec3f pcoord; // parametric [0..1] pos inside cell
PbPixelCell *pCell = (PbPixelCell*)
grid.findContainingCell( SbVec3f(X,Y,0), .01, pcoord );
float ZatXY =
pCell->getValue( pcoord, meshZvalues );


You can also use a pick action to project onto the mesh.
Given an X,Y point and the max Z value of the mesh, we can pick "down" onto the mesh and get the intersection point on the mesh, approximately like this:

SoRayPickAction pickAction( viewport );
pickAction.setRay( SbVec3f(X,Y,2*maxZ), SbVec3f(0,0,-1) );
pickAction.apply( root );
SoPickedPoint *pPPt = pickAction.getPickedPoint();
SbVec3f intersectPt = pPPt->getPoint();
float Zvalue = intersectPt[2];

Wolfer
03-19-2010, 10:57 AM
Thanks Mike, I've got the idea. Just one ambiguity is left in my mind.

E.g. we have a 5-section-polyline which acrosses major portion of a 100x100 grid. The coordinates of 1st and 2nd points of polyline are (1, 1) and (10, 10) respectively. I get Z values for these points with PbPixelCell. Suppose we have got following values:

(1, 1, 5)
(10, 10, 7)

And there is a kind of bump (for example imagine normal distribution:) ) on the grid exactly between (1, 1) and (10, 10) where Z value is 15.

Thus, if I use SoLineSet to define my lines and PbPixelCell to define Z value per vertex my lines would intersect a grid?

And to avoid that negative effect I have to interpolate each segment of polyline with thick interval?

Thanks in advance.

mikeheck
03-19-2010, 04:09 PM
Thus, if I use SoLineSet to define my lines and PbPixelCell to define Z value per vertex my lines would intersect a grid?
And to avoid that negative effect I have to interpolate each segment of polyline with thick interval?

In short, yes. If you project 2 points onto a mesh that is not completely flat, then connect those points with a line, there is a very good chance that the line will not follow the surface of the mesh... There are at least 2 ways to address this, with some trade-offs as usual.

1. Sample and subdivide the line
Break the line into shorter segments that do lie on the surface (a sampling problem). In this case since you have a regular cartesian grid, we know that each cell of the mesh is approximately flat. (Any quad cell can be non-planar, but if there are severely non-planar cells then you probably have other rendering artifacts already...) So a candidate sampling scheme would be to find all the intersections of the line with cell edges and add a vertex (to the line) at each intersection. This isn't too hard since the cell edges are axis aligned and regularly spaced. Note that you may need SoPolygonOffset to make sure that the (now co-planar) line segments are completely visible.

2. Render and "drape" a texture
In more complex cases it can be easier/faster to render the polyline(s) into a texture image (see the SoRenderToTextureProperty node) and render this onto the surface (see the SoTexture2 node). This approach avoids the depth buffer issues with co-planar lines, but the fixed resolution of the texture means that the lines may become blurred if you zoom in close to the surface.

-Mike

Wolfer
03-20-2010, 03:28 AM
Thanks Mike. I must note that you have a talent for explaining complex things. ;)

The 1st way is clear and most obvious solution. The second one seems more... maybe right.

Just one question related to second way.
I create SoLineSet and set it to SoRenderToTextureProperty::node, then I create SoTexture2 and define its renderToTextureProperty property. That's it, I have rendered texture.
My PoRegularCartesianGrid2D has a contouring and filled properties. It means it's colored and has isolines. Will these properties be broken If I put SoTexture2 onto my grid?

Mike, I suppose that my problem is common and may be my solution could be an OI demo? If you are interested in that I could arrange example.

mikeheck
03-22-2010, 05:10 PM
I create SoLineSet and set it to SoRenderToTextureProperty::node, then I create SoTexture2 and define its renderToTextureProperty property. That's it, I have rendered texture.
My PoRegularCartesianGrid2D has a contouring and filled properties. It means it's colored and has isolines. Will these properties be broken If I put SoTexture2 onto my grid?

Mike, I suppose that my problem is common and may be my solution could be an OI demo? If you are interested in that I could arrange example.

Good question. I think it's possible to blend a texture onto the surface in most cases. The texture should have alpha=0 as its background, i.e. everywhere except the lines you want to paint onto the surface. So applying the texture does not modify any pixels on the surface except where the lines are drawn in the texture. That said, it may not be possible to use this technique when using the MeshViz COLOR_TEXTURE_CONTOURING mode (because this mode implicitly applies a texture).

An example showing how to project lines onto a MeshViz surface would be great!

-Mike

Wolfer
03-24-2010, 02:35 AM
Hi Mike,

I'm trying to implement discussed things. I coped with simple line projection task.

The result is:

http://www.mc3dviz.com/openinventor-forum/attachment.php?attachmentid=153&stc=1&d=1269401137

though it's acceptable I want to handle intersection cases and first of all to learn how to render a texture.

Picture above I've got from that function:

SoSeparator* createLineSet( const PbMesh* mesh, const float* zdata)
{
SoCoordinate3* coords = new SoCoordinate3;

// Read coordinates of polyline
std::vector<float> xvertices;
std::vector<float> yvertices;
readPolyline(LINEFILE, xvertices, yvertices);

// Define z-values for polyline vertices
for(size_t i = 0; i < xvertices.size(); ++i)
{
SbVec3f vertex(xvertices[i], yvertices[i], 0.0f); // given X,Y point with unknown Z value
SbVec3f pcoord; // parametric [0..1] pos inside cell

PbPixelCell *pCell = (PbPixelCell*)mesh->findContainingCell( vertex, .01, pcoord );

if(pCell)
{
float ZatXY = pCell->getValue( pcoord, zdata ); // get Z at point X,Y
vertex[2] = ZatXY;
coords->point.set1Value(i, vertex);
}
}

// Define appearance
SoMaterial* material = new SoMaterial;
material->diffuseColor.setValue(0, 0, 1);

SoDrawStyle* style = new SoDrawStyle;
style->lineWidth = 3;

SoLineSet* line = new SoLineSet;

SoSeparator* lineSep = new SoSeparator;
lineSep->addChild(material);
lineSep->addChild(style);
lineSep->addChild(coords);
lineSep->addChild(line);

return lineSep;
}

My scene graph is following:

SoSeparator* meshScene = new SoSeparator;
meshScene->addChild(new SoPolygonOffset);
meshScene->addChild(scale);
meshScene->addChild(mesh);
meshScene->addChild(myList);
meshScene->addChild(myDataMapping);
meshScene->addChild(meshFilled);
meshScene->addChild(meshContouring);
meshScene->addChild(meshLimit);
// Project line onto the mesh
meshScene->addChild(createLineSet(pb_mesh, zdata));
meshScene->addChild(domain);

The whole project with all data used is attached.

Then I tried render line as discussed above:

SoSeparator* createLineSetTexture( const PbMesh* mesh, const float* zdata)
{
// Create node to be rendered
SoSeparator* lineSep = createLineSet(mesh, zdata);

SoRenderToTextureProperty* renderToTexProperty = new SoRenderToTextureProperty;
renderToTexProperty->component = SoRenderToTextureProperty::RGB_TRANSPARENCY;
renderToTexProperty->size.setValue(SbVec2s(512, 512));
renderToTexProperty->updatePolicy = SoRenderToTextureProperty::WHEN_NEEDED;
renderToTexProperty->useAutoMipmap(FALSE);
renderToTexProperty->node.set1Value(0, lineSep);

// Transparent background
SbColor clr;
float t;
clr.setPackedValue(SbColor(1.0f, 1.0f, 1.0f).getPackedValue(1.0f), t);
renderToTexProperty->backgroundColor.setValue(clr);

// Quality if texture
SoComplexity* complexity = new SoComplexity;
complexity->value.setValue(1.);
complexity->textureQuality.setValue(1.);

// Define the texture
SoTexture2* texture = new SoTexture2;
texture->renderToTextureProperty = renderToTexProperty;
texture->model.setValue(SoTexture::BLEND);

SoSeparator* texsep = new SoSeparator;
texsep->addChild(complexity);
texsep->addChild(texture);

return texsep;
}

I'm in a deadlock. Texture isn't seen whatever I do.

Wolfer
03-24-2010, 02:41 AM
MS 2008 Project file exceeds the forum's limit. I uploaded it here:

http://rapidshare.com/files/367413948/qtOIV.zip.html

Alyona
06-30-2011, 12:19 PM
I have the same issue with SoRenderToTextureProperty, did you find the reason?


Thanks in advance,
Alyona

mikeheck
07-01-2011, 12:49 AM
I have the same issue with SoRenderToTextureProperty, did you find the reason?

By "same issue" you mean that you don't get an image in your texture, right?

The most common problem with RenderToTexture is not realizing that it's almost, but not quite, the same as giving a scene graph to a viewer to render. Specifically the viewer will happily create a camera and a light for you, so your scene will be visible. RenderToTexture doesn't do that. There are several (small) problems with Wolfer's program, but that's the main one.

1. The polyline isn't visible because there's no camera with appropriate settings and everything is black anyway because there's no light. The beginning of createLineSetTexture (see previous post) should look more like this:

SoSeparator* createLineSetTexture( const PbMesh* mesh, const float* zdata)
{
// Create node to be rendered
SoSeparator* lineSep = createLineSet(mesh, zdata);

lineSep->setName( "lineSep" );
lineSep->ref(); // To avoid problems with viewAll (applies an action)

// Create and initialize camera
SoOrthographicCamera *pLineCam = new SoOrthographicCamera();
pLineCam->viewAll( lineSep, SbViewportRegion(100,100) );

// Turn off lighting so we get the exact colors we want
SoLightModel *pLightModel = new SoLightModel();
pLightModel->model = SoLightModel::BASE_COLOR;

// Insert new nodes at beginning of scene graph
lineSep->insertChild( pLineCam, 0 );
lineSep->insertChild( pLightModel, 1 );
lineSep->unrefNoDelete();


Couple of minor problems:

2. The "backgroundColor" field of the RenderToTexture node should (usually) be set to the same color as the polyline. This is because when the texture is rendered onto the surface, the color of each visible texel will be interpolated with the colors of its neighbors *even if* those neighbors are invisible (have alpha = 0). Setting the background color to white will produce a small "halo" around the line (which is might be desireable).

3. The "model" field of the SoTexture2 node should be set to DECAL.
This says that the surface color should be replaced by the texture color, but only where the texture's alpha value is greater than zero.

4. The createLineSetTexture function cannot return an SoSeparator.
If the texture node is under a Separator then, by definition, it cannot effect the rendering of the surface.

5. You probably need an SoTexture2Transform to translate/scale the polyline into the correct position. Remember we're mapping a square texture onto a rectangular (more or less) surface and the automatically computed texture coordinates will be 0..1 on the long dimension of the surface and 0..?, where ? is something less than 1 on the other dimension.

I've attached a corrected version of the program. The grid data file is still too big to upload in the forum, so you'll have to get that from here: ftp://ftp.vsg3d.com/outgoing/Forum/Wolfer_grid.zip

http://www.mc3dviz.com/openinventor-forum/attachment.php?attachmentid=257&stc=1&d=1309477596

It works pretty well although there are small gaps in the line almost like there are missing pixels in the rendered image of the polyline. I believe these are artifacts of texture interpolation, but I'm not sure.