
Einführung
Wir haben bereits
ein Beispiel untersucht, in dem ein Quadrat in allen Farben des Regenbogens gemalt wurde. Dennoch gibt es eine andere Technologie, nämlich die Anwendung auf die dreidimensionale Geometrie der sogenannten
Texturkarte oder einfach nur Textur - ein zweidimensionales Rasterbild. In diesem Fall wirkt sich der Effekt nicht auf die Scheitelpunkte der Geometrie aus, sondern die Daten aller Pixel, die während der Rasterung der Szene erhalten werden, ändern sich. Diese Technik kann den Realismus und die Details des endgültigen Bildes erheblich verbessern.
OSG unterstützt verschiedene Texturattribute und Texturierungsmodi. Bevor wir jedoch über Texturen sprechen, lassen Sie uns darüber sprechen, wie OSG mit Bitmap-Bildern umgeht. Für die Arbeit mit Rasterbildern wird eine spezielle Klasse bereitgestellt - osg :: Image, in der Bilddaten gespeichert werden, die letztendlich zur Texturierung des Objekts bestimmt sind.
1. Präsentation von Rasterbilddaten. Osg class :: Image
Der beste Weg, ein Image von der Festplatte zu laden, ist die Verwendung des Aufrufs osgDB :: readImageFile (). Es ist dem Aufruf von osg :: readNodeFile () sehr ähnlich, der uns bereits gelangweilt hat. Wenn wir eine Bitmap mit dem Namen picture.bmp haben, sieht das Laden folgendermaßen aus
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp");
Wenn das Bild korrekt geladen ist, ist der Zeiger gültig, andernfalls gibt die Funktion NULL zurück. Nach dem Herunterladen können wir Bildinformationen mit den folgenden öffentlichen Methoden erhalten
- t (), s () und r () - geben die Breite, Höhe und Tiefe des Bildes zurück.
- data () - gibt einen Zeiger vom Typ unsigned char * auf die "rohen" Bilddaten zurück. Über diesen Zeiger kann der Entwickler direkt auf die Bilddaten reagieren. Mit den Methoden getPixalFormat () und getDataType () können Sie sich ein Bild vom Bilddatenformat machen. Die von ihnen zurückgegebenen Werte entsprechen den Parametern des Formats und des Typs der OpenGL-Funktionen glTexImage * (). Wenn das Bild beispielsweise das Pixelformat GL_RGB hat und der Typ GL_UNSIGNED_BYTE ist, werden drei unabhängige Elemente (vorzeichenlose Bytes) verwendet, um die RGB-Farbkomponente darzustellen

Sie können ein neues Bildobjekt erstellen und Speicher dafür zuweisen.
osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage(s, t, r, GL_RGB, GL_UNSIGNED_BYTE); unsigned char *ptr = image->data();
Hier sind s, t, r Bildgrößen; GL_RGB legt das Pixelformat fest und GL_UNSIGNED_BYTE legt den Datentyp fest, um eine einzelne Farbkomponente zu beschreiben. Ein interner Datenpuffer der erforderlichen Größe wird im Speicher zugewiesen und automatisch zerstört, wenn keine einzige Verknüpfung zu diesem Bild besteht.
Das OSG-Plug-In-System unterstützt das Herunterladen fast aller gängigen Bildformate: * .jpg, * .bmp, * .png, * .tif usw. Diese Liste kann leicht erweitert werden, indem Sie Ihr eigenes Plugin schreiben. Dies ist jedoch ein Thema für eine andere Diskussion.
2. Die Grundlagen der Texturierung
Um eine Textur auf ein dreidimensionales Modell anzuwenden, müssen Sie eine Reihe von Schritten ausführen:
- Definieren Sie die Texturkoordinaten der Scheitelpunkte für das geometrische Objekt (in der Umgebung von 3D-Designern wird dies als UV-Scan bezeichnet).
- Erstellen Sie ein Texturattributobjekt für 1D-, 2D-, 3D- oder kubische Textur.
- Legen Sie ein oder mehrere Bilder für ein Texturattribut fest.
- Fügen Sie der Gruppe von Zuständen, die auf das zu zeichnende Objekt angewendet werden, ein Texturattribut und einen Modus hinzu.
OSG definiert die Klasse osg :: Texture, die alle Arten von Texturen kapselt. Von diesen werden die Unterklassen osg :: Texture1D, osg :: Texture2D, osg :: Texture3D und osg :: TextureCubeMap geerbt, die verschiedene in OpenGL verwendete Texturierungstechniken darstellen.
Die gebräuchlichste osg :: Texture-Klassenmethode ist setImage (), mit der beispielsweise das in der Textur verwendete Bild festgelegt wird
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setImage(image.get());
Sie können das Bildobjekt auch direkt an den Konstruktor der Texturklasse übergeben
osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image.get());
Das Bild kann durch Aufrufen der Methode getImage () aus dem Texturobjekt abgerufen werden.
Ein weiterer wichtiger Punkt ist das Festlegen der Texturkoordinaten für jeden Scheitelpunkt im osg :: Geometry-Objekt. Die Übertragung dieser Koordinaten erfolgt über das Array osg :: Vec2Array und osg :: Vec3Array durch Aufrufen der Methode setTexCoordArray ().
Nach dem Festlegen der Texturkoordinaten müssen wir die Texturschlitznummer (Einheit) festlegen, da OSG das Überlagern mehrerer Texturen mit derselben Geometrie unterstützt. Bei Verwendung einer einzelnen Textur ist die Einheitennummer immer 0. Der folgende Code veranschaulicht beispielsweise das Festlegen der Texturkoordinaten für die Einheit 0 der Geometrie
osf::ref_ptr<osg::Vec2Array> texcoord = new osg::Vec2Array; texcoord->push_back( osg::Vec2(...) ); ... geom->setTexCoordArray(0, texcoord.get());
Danach können wir das Texturattribut zu der Gruppe von Zuständen hinzufügen, den entsprechenden Texturierungsmodus automatisch aktivieren (in unserem Beispiel GL_TEXTURE_2D) und das Attribut auf die Geometrie oder den Knoten anwenden, der diese Geometrie enthält
geom->getOrCreateStateSet()->setTextureAttributeAndModes(texture.get());
Bitte beachten Sie, dass OpenGL die Bilddaten im Grafikspeicher der Grafikkarte verwaltet, sich jedoch das osg :: Image-Objekt zusammen mit denselben Daten im Systemspeicher befindet. Infolgedessen werden wir feststellen, dass wir zwei Kopien derselben Daten gespeichert haben, die den Prozessspeicher belegen. Wenn dieses Image nicht von mehreren Texturattributen gemeinsam genutzt wird, kann es sofort nach der Übertragung durch OpenGL in den Videoadapterspeicher aus dem Systemspeicher gelöscht werden. Die Klasse osg :: Texture bietet die entsprechende Methode, um diese Funktion zu aktivieren.
texture->setUnRefImageDataAfterApply( true );
3. Laden Sie eine 2D-Textur und wenden Sie sie an
Die am häufigsten verwendete Technik ist die 2D-Texturierung - Überlagern eines zweidimensionalen Bildes (oder von zweidimensionalen Bildern) am Rand einer dreidimensionalen Oberfläche. Betrachten Sie das einfachste Beispiel für das Anwenden einer einzelnen Textur auf ein viereckiges Polygon
Texturbeispielmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Texture2D> #include <osg/Geometry> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(-0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) ); vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) ); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; osg::ref_ptr<osg::Image> image = osgDB::readImageFile("../data/Images/lz.rgb"); texture->setImage(image.get()); osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); root->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
Erstellen Sie ein Array von Eckpunkten und Normalen zum Gesicht
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(-0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) ); vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) );
Erstellen Sie ein Array von Texturkoordinaten
osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) );
Der Punkt ist, dass jeder Scheitelpunkt des dreidimensionalen Modells einem Punkt auf der zweidimensionalen Textur entspricht und die Koordinaten der Punkte auf der Textur relativ sind - sie werden auf die tatsächliche Breite und Höhe des Bildes normalisiert. Wir wollen das gesamte geladene Bild auf ein Quadrat strecken, wobei die Ecken des Quadrats den Texturpunkten (0, 0), (0, 1), (1, 1) und (1, 0) entsprechen. Die Reihenfolge der Scheitelpunkte im Scheitelpunktarray muss mit der Reihenfolge der Texturscheitelpunkte übereinstimmen.
Erstellen Sie als Nächstes ein Quadrat und weisen Sie der Geometrie ein Array von Eckpunkten und ein Array von Normalen zu
osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );
Erstellen Sie ein Texturobjekt und laden Sie das dafür verwendete Bild.
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; osg::ref_ptr<osg::Image> image = osgDB::readImageFile("../data/Images/lz.rgb"); texture->setImage(image.get());
Erstellen Sie den Wurzelknoten der Szene und fügen Sie die dort erstellte Geometrie ein
osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get());
und schließlich das Texturattribut auf den Knoten anwenden, in dem die Geometrie platziert ist
root->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get());

Die Klasse osg :: Texture2D bestimmt mithilfe der OpenGL-Funktion gluScaleImage (), ob Texturbildgrößen ein Vielfaches der Zweierpotenz sind (z. B. 64 x 64 oder 256 x 512), und skaliert automatisch Bilder, die für die Größe ungeeignet sind. Es gibt eine setResizeNonPowerOfTwoHint () -Methode, die bestimmt, ob die Bildgröße geändert werden soll oder nicht. Einige Grafikkarten erfordern ein Vielfaches der Größe eines Bildes mit der Potenz von zwei, während die Klasse osg :: Texture2D das Arbeiten mit beliebigen Texturgrößen unterstützt.
Etwas über das Mischen von Texturen
Wie bereits erwähnt, werden die Texturkoordinaten von 0 auf 1 normalisiert. Punkt (0, 0) entspricht der oberen linken Ecke des Bildes und Punkt (1, 1) entspricht der unteren rechten Ecke. Was passiert, wenn Sie Texturkoordinaten größer als eins festlegen?
Standardmäßig wird in OpenGL wie in OSG die Textur in Richtung der Achse wiederholt, der Wert der Texturkoordinate überschreitet eins. Diese Technik wird oft verwendet, um beispielsweise ein Modell einer langen Mauer zu erstellen. Ich verwende eine kleine Textur, die ihre Überlagerung sowohl in der Breite als auch in der Höhe viele Male wiederholt.
Dieses Verhalten kann über die setWrap () -Methode der Klasse osg :: Texture gesteuert werden. Als ersten Parameter verwendet die Methode den Bezeichner der Achse, auf die der Mischmodus angewendet werden soll, beispielsweise als zweiten Parameter
Dieser Code weist die Engine ausdrücklich an, die Textur entlang der s- und r-Achse zu wiederholen, wenn die Texturkoordinatenwerte 1 überschreiten. Eine vollständige Liste der Texturabbildungsmodi:
- WIEDERHOLEN - Wiederholen Sie die Textur.
- SPIEGEL - Wiederholen Sie die Textur und spiegeln Sie sie.
- CLAMP_TO_EDGE - Koordinaten, die über 0 bis 1 hinausgehen, werden an der entsprechenden Kante der Textur gefangen.
- CLAMP_TO_BORDER - Koordinaten, die über 0 bis 1 hinausgehen, geben die vom Benutzer festgelegte Rahmenfarbe an.
4. Rendern zur Textur
Die Textur-Rendering-Technik ermöglicht es dem Entwickler, eine Textur basierend auf einer dreidimensionalen Unterszene oder einem dreidimensionalen Modell zu erstellen und auf die Oberfläche in der Hauptszene anzuwenden. Eine ähnliche Technologie wird oft als Texturbacken bezeichnet.
Um eine Textur dynamisch zu backen, müssen Sie drei Schritte ausführen:
- Erstellen Sie ein Texturobjekt, um es zu rendern.
- Rendern Sie die Szene in eine Textur.
- Verwenden Sie die resultierende Textur wie vorgesehen.
Wir müssen ein leeres Texturobjekt erstellen. Mit OSG können Sie eine leere Textur einer bestimmten Größe erstellen. Mit der Methode setTextureSize () können Sie die Breite und Höhe der Textur sowie die Tiefe als zusätzlichen Parameter festlegen (für 3D-Texturen).
Um eine Textur zu rendern, sollten Sie sie an das Kameraobjekt anhängen, indem Sie die Methode attach () aufrufen, die ein Texturobjekt als Argument verwendet. Darüber hinaus akzeptiert diese Methode ein Argument, das angibt, welcher Teil des Bildpuffers in diese Textur gerendert werden soll. Um beispielsweise einen Farbpuffer in eine Textur zu übertragen, sollten Sie den folgenden Code ausführen
camera->attach( osg::Camera::COLOR_BUFFER, texture.get() );
Weitere Teile des für das Rendern verfügbaren Bildpuffers sind der Tiefenpuffer DEPTH_BUFFER, der Schablonenpuffer STENCIL_BUFFER und zusätzliche Farbpuffer von COLOR_BUFFER0 bis COLOR_BUFFER15. Das Vorhandensein zusätzlicher Farbpuffer und deren Anzahl wird durch das Modell der Grafikkarte bestimmt.
Darüber hinaus müssen Sie für eine Kamera, die in eine Textur gerendert wird, die Parameter der Projektionsmatrix und des Ansichtsfensters festlegen, deren Größe der Größe der Textur entspricht. Die Textur wird aktualisiert, wenn jeder Frame gezeichnet wird. Beachten Sie, dass die Hauptkamera nicht zum Rendern in eine Textur verwendet werden sollte, da sie das Rendern der Hauptszene ermöglicht und Sie nur einen schwarzen Bildschirm erhalten. Diese Anforderung wird möglicherweise nicht nur erfüllt, wenn Sie ein Rendern außerhalb des Bildschirms durchführen.
5. Ein Beispiel für die Implementierung des Renderns in Textur
Um die Rendering-Technik in einer Textur zu demonstrieren, implementieren wir die folgende Aufgabe: Erstellen Sie ein Quadrat, zeichnen Sie eine quadratische Textur darauf und rendern Sie eine animierte Szene in die Textur, natürlich mit der Cessna, die wir lieben. Das Programm, das das Beispiel implementiert, ist ziemlich umfangreich. Ich werde jedoch trotzdem den vollständigen Quellcode angeben.
Texrender Beispielmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Camera> #include <osg/Texture2D> #include <osg/MatrixTransform> #include <osgDB/ReadFile> #include <osgGA/TrackballManipulator> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h"
Um ein Quadrat zu erstellen, schreiben Sie eine separate freie Funktion
osg::Geometry *createQuad(const osg::Vec3 &pos, float w, float h) { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, -h / 2) ); vertices->push_back( pos + osg::Vec3( w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, h / 2) ); vertices->push_back( pos + osg::Vec3(-w / 2, 0.0f, -h / 2) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f)); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); return quad.release(); }
Die Funktion akzeptiert die Position der Mitte des Quadrats und seine geometrischen Abmessungen als Eingabe. Als nächstes wird ein Array von Eckpunkten, ein Array von Normalen und Texturkoordinaten erstellt, wonach die erstellte Geometrie von der Funktion zurückgegeben wird.
Laden Sie im Hauptteil des Hauptprogramms das Modell der Cessna
osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("../data/cessna.osg");
Um dieses Modell zu animieren, erstellen und initialisieren Sie die Rotationstransformation um die Z-Achse
osg::ref_ptr<osg::MatrixTransform> transform1 = new osg::MatrixTransform; transform1->setMatrix(osg::Matrix::rotate(0.0, osg::Vec3(0.0f, 0.0f, 1.0f))); transform1->addChild(sub_model.get());
Erstellen Sie nun ein Modell für die Hauptszene - ein Quadrat, auf dem wir rendern werden
osg::ref_ptr<osg::Geode> model = new osg::Geode; model->addChild(createQuad(osg::Vec3(0.0f, 0.0f, 0.0f), 2.0f, 2.0f));
Erstellen Sie eine leere Textur für ein 1024 x 1024 Pixel großes Quadrat mit einem RGBA-Pixelformat (32-Bit-Dreikomponentenfarbe mit Alphakanal).
int tex_widht = 1024; int tex_height = 1024; osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setTextureSize(tex_widht, tex_height); texture->setInternalFormat(GL_RGBA); texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR); texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
Wenden Sie diese Textur auf das quadratische Modell an.
model->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get());
Erstellen Sie dann eine Kamera, die die Textur backt
osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setViewport(0, 0, tex_widht, tex_height); camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Das Kamera-Ansichtsfenster hat dieselbe Größe wie die Textur. Vergessen Sie außerdem nicht, die Hintergrundfarbe beim Reinigen des Bildschirms und der Reinigungsmaske festzulegen, um sowohl den Farbpuffer als auch den Tiefenpuffer zu löschen. Konfigurieren Sie als Nächstes die Kamera so, dass sie in Textur gerendert wird
camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->attach(osg::Camera::COLOR_BUFFER, texture.get());
Die Renderreihenfolge von PRE_RENDER gibt an, dass diese Kamera vor dem Rendern in der Hauptszene gerendert wird. Geben Sie den FBO als Rendering-Ziel an und hängen Sie unsere Textur an die Kamera an. Jetzt richten wir die Kamera so ein, dass sie in einem absoluten Koordinatensystem arbeitet, und als Szene setzen wir unseren Teilbaum, den wir in eine Textur rendern möchten: eine Rotationstransformation mit einem daran angehängten Cessna-Modell
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->addChild(transform1.get());
Erstellen Sie einen Stammgruppenknoten, indem Sie das Hauptmodell (Quadrat) und eine Kamera-Verarbeitungstextur hinzufügen
osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get()); root->addChild(camera.get());
Erstellen Sie einen Viewer und passen Sie ihn an
osgViewer::Viewer viewer; viewer.setSceneData(root.get()); viewer.setCameraManipulator(new osgGA::TrackballManipulator); viewer.setUpViewOnSingleScreen(0);
Richten Sie die Projektionsmatrix für die Kamera ein - eine perspektivische Projektion durch die Parameter der Schnittpyramide
camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(tex_widht) / static_cast<double>(tex_height), 0.1, 1000.0);
Wir haben eine Ansichtsmatrix erstellt, die die Position der Kamera im Raum in Bezug auf den Ursprung der Sub-Cessna festlegt
float dist = 100.0f; float alpha = 10.0f * 3.14f / 180.0f; osg::Vec3 eye(0.0f, -dist * cosf(alpha), dist * sinf(alpha)); osg::Vec3 center(0.0f, 0.0f, 0.0f); osg::Vec3 up(0.0f, 0.0f, -1.0f); camera->setViewMatrixAsLookAt(eye, center, up);
Zum Schluss animieren und zeigen Sie die Szene an, indem Sie den Drehwinkel des Flugzeugs um die Z-Achse in jedem Bild ändern
float phi = 0.0f; float delta = -0.01f; while (!viewer.done()) { transform1->setMatrix(osg::Matrix::rotate(static_cast<double>(phi), osg::Vec3(0.0f, 0.0f, 1.0f))); viewer.frame(); phi += delta; }
Als Ergebnis erhalten wir ein ziemlich interessantes Bild

In diesem Beispiel haben wir einige Szenenanimationen implementiert. Beachten Sie jedoch, dass das Erweitern der run () - Schleife und das Ändern der Renderparameter vor oder nach dem Rendern des Frames eine unsichere Aktivität ist, um den Zugriff auf Daten aus verschiedenen Streams zu organisieren. Da OSG Multithread-Rendering verwendet, gibt es auch regelmäßige Mechanismen zum Einbetten eigener Aktionen in den Rendering-Prozess, die einen thread-sicheren Zugriff auf Daten ermöglichen.
6. Speichern Sie das Rendering-Ergebnis in einer Datei
OSG unterstützt die Möglichkeit, ein osg :: Image-Objekt an die Kamera anzuhängen und den Inhalt des Bildpuffers im Bilddatenpuffer zu speichern. Danach können diese Daten mit der Funktion osg :: writeImageFile () auf der Festplatte gespeichert werden
osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage( width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE ); camera->attach( osg::Camera::COLOR_BUFFER, image.get() ); ... osgDB::writeImageFile( *image, "saved_image.bmp" );
Fazit
Vielleicht scheint das im Artikel vorgestellte Material trivial zu sein. Es werden jedoch die Grundlagen der Arbeit mit Texturen in OpenSceneGraph beschrieben, auf denen komplexere Techniken für die Arbeit mit dieser Engine basieren, über die wir in Zukunft definitiv sprechen werden.
Fortsetzung folgt...