3 Stimmen

Erstellen von Konturdiagrammen in Opengl unter Verwendung von Gitterdaten und einer 1D-Texturkarte

Ich habe einen Satz von X-, Y- und Z-Werten in einem regelmäßigen Raster, aus dem ich mit C++ eine farbgefüllte Konturdarstellung erstellen muss. Ich habe gegoogelt auf diese für Tage und der Konsens scheint zu sein, dass dies mit einer 1D-Textur-Map in OpenGL erreichbar ist. Ich habe jedoch kein einziges Beispiel dafür gefunden, wie man das tatsächlich macht, und auch das Lesen der OpenGL-Dokumentation bringt mich nicht weiter. Meine Verwirrung läuft auf eine Kernfrage hinaus:

Meine Daten enthalten nicht für jedes Pixel einen X- und Y-Wert. Es handelt sich um ein regelmäßig angeordnetes Raster mit Daten im Abstand von 4 Einheiten auf der X- und Y-Achse und einem positiven ganzzahligen Z-Wert.

Zum Beispiel: (0, 0, 1), (4, 0, 1), (8, 0, 2), (0, 4, 2), (0, 8, 4), (4, 4, 3), usw.

Da die Konturen auf dem Z-Wert basieren würden und es Lücken zwischen den Datenpunkten gibt, stellt sich die Frage, wie durch die Anwendung einer 1D-Textur die Konturierung dieser Daten erreicht werden kann (d. h. wie wird durch die Anwendung einer 1D-Textur zwischen den Rasterpunkten interpoliert)?

Am ehesten habe ich ein Beispiel dafür in der Online-Version des Redbook (http://fly.cc.fer.hr/~unreal/theredbook/chapter09.html) im Beispiel der Teekanne gefunden, aber ich gehe davon aus, dass das Teekannenmodell Daten für jedes Pixel hat und daher keine Interpolation zwischen Datenpunkten erforderlich ist.

Wenn jemand Licht auf meine Frage oder besser noch auf ein konkretes Beispiel für die Arbeit mit einem 1D-Textur-Map auf diese Weise würde ich für immer dankbar sein, wie ich 2 Tage auf dieses Projekt mit wenig zu zeigen, für sie verbrannt habe.

EDITAR:

Der folgende Code wird von mir verwendet, und obwohl er die Punkte an der richtigen Stelle anzeigt, findet keine Interpolation oder Konturierung statt - die Punkte werden einfach als Punkte angezeigt.

//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte   stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
    stripeImage[3*j] = j < 2 ? 0 : 255;
    stripeImage[3*j+1] = 255;
    stripeImage[3*j+2] = 255;
}
glDisable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
float s[4] = { 0,1,0,0 };
glTexGenfv( GL_S, GL_OBJECT_PLANE, s );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_1D );
glBegin(GL_POINTS);

//_coords contains X,Y,Z data - Z is the value that I'm trying to contour
for (int x = 0; x < _coords.size(); ++x)
{
    glTexCoord1f(static_cast<ValueCoord*>(_coords[x])->GetValue());
    glVertex3f(_coords[x]->GetX(), _coords[x]->GetY(), zIndex);
}
glEnd();

7voto

datenwolf Punkte 154484

Die Idee ist, die Z-Koordinate als S-Koordinate in der Textur zu verwenden. Die lineare Interpolation über die Texturkoordinate erzeugt dann die Kontur. Beachten Sie, dass Sie mit einem Shader die XY->Z-Daten in eine 2D-Textur einfügen und einen Shader verwenden können, um den Wert des 2D-Samplers in die Farbrampe der 1D-Textur umzuleiten.

Update: Code-Beispiel

Zunächst müssen wir die Art und Weise, wie Sie Texturen verwenden, ein wenig ändern.

Dazu die Textur vorbereiten:

//Create a 1D image - for this example it's just a red line
int stripeImageWidth = 32;
GLubyte   stripeImage[3*stripeImageWidth];
for (int j = 0; j < stripeImageWidth; j++) {
    stripeImage[3*j] = j*255/32; // use a gradient instead of a line
    stripeImage[3*j+1] = 255;
    stripeImage[3*j+2] = 255;
}

GLuint texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_1D, texID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage1D(GL_TEXTURE_1D, 0, 3, stripeImageWidth, 0, GL_RGB, GL_UNSIGNED_BYTE, stripeImage);

// We want the texture to wrap, so that values outside the range [0, 1] 
// are mapped into a gradient sawtooth
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

Und dies, um es für die Verwendung zu binden.

// The texture coordinate comes from the data, it it not
// generated from the vertex position!!!
glDisable( GL_TEXTURE_GEN_S ); 
glDisable(GL_TEXTURE_2D);
glEnable( GL_TEXTURE_1D );
glBindTexture(GL_TEXTURE_1D, texID);

Nun zu Ihrem konzeptionellen Problem: Sie können aus XYZ-Daten nicht direkt ein Konturdiagramm erstellen. XYZ sind nur spärliche Stichprobenpunkte. Sie müssen die Lücken füllen, zum Beispiel indem Sie die Daten zunächst in ein 2D-Histogramm übertragen. Dazu erstellen Sie ein Gitter mit einer bestimmten Anzahl von Bins in jeder Richtung, die alle mit NaN initialisiert sind (Pseudocode)

float hist2D[bins_x][bins_y] = {NaN, NaN, ...}

dann für jedes XYZ den Z-Wert zu den Bins des Gitters hinzufügen, wenn er nicht NaN ist, andernfalls NaN durch den Z-Wert ersetzen. Anschließend wird ein Laplace-Filter auf das Histogramm angewendet, um die Bins, die noch ein NaN enthalten, zu glätten. Schließlich können Sie das Raster als Konturdiagramm darstellen, indem Sie

glBegin(GL_QUADS);
for(int y=0; y<grid_height; y+=2) for(int x=0; x<grid_width; x+=2) {
    glTexCoord1f(hist2D[x  ][y  ]]); glVertex2i(x  ,y);
    glTexCoord1f(hist2D[x+1][y  ]]); glVertex2i(x+1,y);
    glTexCoord1f(hist2D[x+1][y+1]]); glVertex2i(x+1,y+1);
    glTexCoord1f(hist2D[x  ][y+1]]); glVertex2i(x  ,y+1);
}
glEnd();

oder Sie könnten das Raster als 2D-Textur hochladen und einen Fragment-Shader verwenden, um die Farbrampe indirekt zu erzeugen.

Eine andere Möglichkeit, die Lücken in spärlichen XYZ-Daten zu füllen, besteht darin, das 2D-Voronoi-Diagramm des XY-Sets zu finden und dieses zur Erstellung der Stichprobengeometrie zu verwenden. Die Z-Werte für die Scheitelpunkte wären der abstandsgewichtete Durchschnitt der XYZ-Werte, die zu den sich schneidenden Voronoi-Zellen beitragen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X