OpenSceneGraph: Conceptos b√°sicos de textura

imagen

Introduccion


Ya hemos examinado un ejemplo en el que pintaron un cuadrado con todos los colores del arcoíris. Sin embargo, existe otra tecnología, a saber, la aplicación a la geometría tridimensional del llamado mapa de textura o simplemente textura: una imagen ráster bidimensional. En este caso, el efecto no está en los vértices de la geometría, sino que se modifican los datos de todos los píxeles obtenidos cuando se rasteriza la escena. Esta técnica puede aumentar significativamente el realismo y los detalles de la imagen final.

OSG admite varios atributos de textura y modos de textura. Pero, antes de hablar sobre texturas, hablemos sobre c√≥mo OSG maneja las im√°genes de mapa de bits. Para trabajar con im√°genes r√°ster, se proporciona una clase especial: osg :: Image, que almacena los datos de la imagen en su interior, destinados, en √ļltima instancia, a texturizar el objeto.

1. Presentación de datos de imagen ráster. Clase Osg :: Imagen


La mejor manera de cargar una imagen desde el disco es usar la llamada osgDB :: readImageFile (). Es muy similar a la llamada osg :: readNodeFile () que ya nos ha aburrido. Si tenemos un mapa de bits llamado picture.bmp, entonces cargarlo se verá así

osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); 

Si la imagen se carga correctamente, el puntero ser√° v√°lido; de lo contrario, la funci√≥n devolver√° NULL. Despu√©s de la descarga, podemos obtener informaci√≥n de la imagen utilizando los siguientes m√©todos p√ļblicos

  1. t (), s () y r (): devuelve el ancho, la altura y la profundidad de la imagen.
  2. data (): devuelve un puntero de tipo unsigned char * a los datos de la imagen "en bruto". A través de este puntero, el desarrollador puede actuar directamente sobre los datos de la imagen. Puede hacerse una idea del formato de datos de imagen utilizando los métodos getPixalFormat () y getDataType (). Los valores devueltos por ellos son equivalentes a los parámetros del formato y tipo de las funciones de OpenGL glTexImage * (). Por ejemplo, si la imagen tiene el formato de píxel GL_RGB y el tipo es GL_UNSIGNED_BYTE, se utilizan tres elementos independientes (bytes sin signo) para representar el componente de color RGB



Puede crear un nuevo objeto de imagen y asignarle memoria.

 osg::ref_ptr<osg::Image> image = new osg::Image; image->allocateImage(s, t, r, GL_RGB, GL_UNSIGNED_BYTE); unsigned char *ptr = image->data(); //         

Aqu√≠ s, t, r son tama√Īos de imagen; GL_RGB establece el formato de p√≠xel y GL_UNSIGNED_BYTE establece el tipo de datos para describir un solo componente de color. Se asigna un b√ļfer de datos interno del tama√Īo requerido en la memoria y se destruye autom√°ticamente si no hay un solo enlace a esta imagen.

El sistema de complemento OSG admite la descarga de casi todos los formatos de imagen populares: * .jpg, * .bmp, * .png, * .tif, etc. Esta lista es fácil de expandir escribiendo su propio complemento, pero este es un tema para otra discusión.

2. Los fundamentos de la textura


Para aplicar textura a un modelo tridimensional, debe realizar una serie de pasos:

  1. Defina las coordenadas de textura de los v√©rtices para el objeto geom√©trico (en el entorno de los dise√Īadores 3D, esto se llama escaneo UV).
  2. Cree un objeto de atributo de textura para 1D, 2D, 3D o textura c√ļbica.
  3. Establezca una o m√°s im√°genes para un atributo de textura.
  4. Adjunte un atributo y modo de textura al conjunto de estados aplicados al objeto que se est√° dibujando.

OSG define la clase osg :: Texture, que encapsula todo tipo de texturas. Las subclases osg :: Texture1D, osg :: Texture2D, osg :: Texture3D y osg :: TextureCubeMap se heredan de él, lo que representa varias técnicas de texturas adoptadas en OpenGL.

El m√©todo m√°s com√ļn de la clase osg :: Texture es setImage (), que establece la imagen utilizada en la textura, por ejemplo

 osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; texture->setImage(image.get()); 

o puede pasar el objeto de imagen directamente al constructor de la clase de textura

 osg::ref_ptr<osg::Image> image = osgDB::readImageFile("picture.bmp"); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image.get()); 

La imagen se puede recuperar del objeto de textura llamando al método getImage ().

Otro punto importante es establecer las coordenadas de textura para cada vértice en el objeto osg :: Geometry. La transferencia de estas coordenadas ocurre a través de la matriz osg :: Vec2Array y osg :: Vec3Array llamando al método setTexCoordArray ().

Despu√©s de establecer las coordenadas de textura, necesitamos establecer el n√ļmero de ranura de textura (unidad), ya que OSG admite la superposici√≥n de m√ļltiples texturas en la misma geometr√≠a. Cuando se usa una textura √ļnica, el n√ļmero de unidad es siempre 0. Por ejemplo, el siguiente c√≥digo ilustra la configuraci√≥n de las coordenadas de textura para la unidad 0 de la geometr√≠a

 osf::ref_ptr<osg::Vec2Array> texcoord = new osg::Vec2Array; texcoord->push_back( osg::Vec2(...) ); ... geom->setTexCoordArray(0, texcoord.get()); 

Después de eso, podemos agregar el atributo de textura al conjunto de estados, activando automáticamente el modo de textura correspondiente (en nuestro ejemplo GL_TEXTURE_2D) y aplicar el atributo a la geometría o nodo que contiene esta geometría

 geom->getOrCreateStateSet()->setTextureAttributeAndModes(texture.get()); 

Tenga en cuenta que OpenGL gestiona los datos de la imagen en la memoria gráfica de la tarjeta de video, pero el objeto osg :: Image junto con los mismos datos se encuentra en la memoria del sistema. Como resultado, encontraremos el hecho de que hemos almacenado dos copias de los mismos datos, ocupando la memoria del proceso. Si esta imagen no es compartida por varios atributos de textura, se puede eliminar de la memoria del sistema inmediatamente después de que OpenGL la transfiera a la memoria del adaptador de video. La clase osg :: Texture proporciona el método apropiado para habilitar esta función.

 texture->setUnRefImageDataAfterApply( true ); 

3. Cargue y aplique una textura 2D


La t√©cnica m√°s utilizada es el texturizado 2D: superposici√≥n de una imagen (o im√°genes) bidimensional en el borde de una superficie tridimensional. Considere el ejemplo m√°s simple de aplicar una textura √ļnica a un pol√≠gono cuadrangular

Ejemplo de textura
main.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(); } 


Crea una matriz de vértices y normales a la cara

 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) ); 

Crea una matriz de coordenadas de textura

 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) ); 

El punto es que cada vértice del modelo tridimensional corresponde a un punto en la textura bidimensional, y las coordenadas de los puntos en la textura son relativas: están normalizadas al ancho y la altura reales de la imagen. Queremos estirar toda la imagen cargada en un cuadrado, respectivamente, las esquinas del cuadrado corresponderán a los puntos de textura (0, 0), (0, 1), (1, 1) y (1, 0). El orden de los vértices en la matriz de vértices debe coincidir con el orden de los vértices de textura.

Luego, crea un cuadrado, asignando a la geometría una matriz de vértices y una matriz de normales

 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) ); 

Cree un objeto de textura y cargue la imagen utilizada para ello.

 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()); 

Crea el nodo raíz de la escena y coloca la geometría que creamos allí

 osg::ref_ptr<osg::Geode> root = new osg::Geode; root->addDrawable(quad.get()); 

y finalmente aplique el atributo de textura al nodo en el que se coloca la geometría

 root->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); 



La clase osg :: Texture2D determina si los tama√Īos de imagen de textura son m√ļltiplos de una potencia de dos (por ejemplo, 64x64 o 256x512), escalando autom√°ticamente las im√°genes que no son apropiadas para el tama√Īo, en realidad usando la funci√≥n OpenGL gluScaleImage (). Existe un m√©todo setResizeNonPowerOfTwoHint () que determina si se debe cambiar el tama√Īo de la imagen o no. Algunas tarjetas de video requieren un m√ļltiplo del tama√Īo de una imagen de la potencia de dos, mientras que la clase osg :: Texture2D admite trabajar con un tama√Īo de textura arbitrario.

Algo sobre la mezcla de texturas


Como ya dijimos, las coordenadas de textura se normalizan de 0 a 1. El punto (0, 0) corresponde a la esquina superior izquierda de la imagen, y el punto (1, 1) corresponde a la esquina inferior derecha. ¬ŅQu√© sucede si establece coordenadas de textura mayores que uno?

Por defecto, en OpenGL, como en OSG, la textura se repetir√° en la direcci√≥n del eje, el valor de la coordenada de textura exceder√° uno. Esta t√©cnica se usa a menudo, por ejemplo, para crear un modelo de una pared de ladrillo larga, utilizo una textura peque√Īa, repitiendo su superposici√≥n muchas veces tanto en ancho como en altura.

Este comportamiento se puede controlar mediante el método setWrap () de la clase osg :: Texture. Como primer parámetro, el método toma el identificador del eje al que debe aplicarse el modo de mezcla, pasado como el segundo parámetro, por ejemplo

 //     s texture->setWrap( osg::Texture::WRAP_S, osg::Texture::REPEAT ); //     r texture->setWrap( osg::Texture::WRAP_R, osg::Texture::REPEAT ); 

Este código le dice explícitamente al motor que repita la textura a lo largo de los ejes syr si los valores de coordenadas de textura exceden 1. Una lista completa de modos de mapeo de textura:

  1. REPETIR - repite la textura.
  2. ESPEJO - repita la textura, reflej√°ndola.
  3. CLAMP_TO_EDGE: las coordenadas que van m√°s all√° de 0 a 1 se ajustan al borde correspondiente de la textura.
  4. CLAMP_TO_BORDER: las coordenadas que van m√°s all√° de 0 a 1 proporcionar√°n el color del borde establecido por el usuario.

4. Renderizado a textura


La técnica de representación de texturas permite al desarrollador crear una textura basada en una subescena o modelo tridimensional y aplicarla a la superficie de la escena principal. Una tecnología similar a menudo se llama textura "hornear".

Para hornear din√°micamente una textura, debe completar tres pasos:

  1. Cree un objeto de textura para representarlo.
  2. Renderiza la escena en una textura.
  3. Use la textura resultante seg√ļn lo previsto.

Debemos crear un objeto de textura vac√≠o. OSG le permite crear una textura vac√≠a de un tama√Īo determinado. El m√©todo setTextureSize () le permite establecer el ancho y el alto de la textura, as√≠ como la profundidad como un par√°metro adicional (para texturas 3D).

Para renderizar a una textura, debe adjuntarla al objeto de la c√°mara llamando al m√©todo attach (), que toma un objeto de textura como argumento. Adem√°s, este m√©todo acepta un argumento que indica qu√© parte del b√ļfer de trama se debe representar en esta textura. Por ejemplo, para transferir un b√ļfer de color a una textura, debe ejecutar el siguiente c√≥digo

 camera->attach( osg::Camera::COLOR_BUFFER, texture.get() ); 

Otras partes del b√ļfer de trama disponibles para renderizar incluyen el b√ļfer de profundidad DEPTH_BUFFER, el b√ļfer de plantilla STENCIL_BUFFER y los b√ļferes de color adicionales de COLOR_BUFFER0 a COLOR_BUFFER15. La presencia de buffers de color adicionales y su n√ļmero est√° determinado por el modelo de la tarjeta de video.

Adem√°s, para una c√°mara que se convierte en una textura, debe establecer los par√°metros de la matriz de proyecci√≥n y la vista, cuyo tama√Īo corresponde al tama√Īo de la textura. La textura se actualizar√° a medida que se dibuja cada cuadro. Tenga en cuenta que la c√°mara principal no debe usarse para renderizar en una textura, ya que proporciona la representaci√≥n de la escena principal y solo obtiene una pantalla en negro. Es posible que este requisito no se cumpla solo cuando realice el procesamiento fuera de la pantalla.

5. Un ejemplo de la implementación de renderizado a textura


Para demostrar la técnica de renderizado en una textura, implementamos la siguiente tarea: crear un cuadrado, dibujar una textura cuadrada en él y renderizar una escena animada en la textura, por supuesto con el cessna que amamos. El programa que implementa el ejemplo es bastante voluminoso. Sin embargo, le daré su código fuente completo de todos modos.

Ejemplo de Texrender
main.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" //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ 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(); } //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("../data/cessna.osg"); 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()); osg::ref_ptr<osg::Geode> model = new osg::Geode; model->addChild(createQuad(osg::Vec3(0.0f, 0.0f, 0.0f), 2.0f, 2.0f)); 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); model->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); 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); camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->addChild(transform1.get()); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get()); root->addChild(camera.get()); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); viewer.setCameraManipulator(new osgGA::TrackballManipulator); viewer.setUpViewOnSingleScreen(0); camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(tex_widht) / static_cast<double>(tex_height), 0.1, 1000.0); 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); 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; } return 0; } 


Para crear un cuadrado, escriba una función libre separada

 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(); } 

La función acepta la posición del centro del cuadrado y sus dimensiones geométricas como entrada. A continuación, se crea una matriz de vértices, una matriz de normales y coordenadas de textura, después de lo cual la geometría creada se devuelve de la función.

En el cuerpo del programa principal, cargue el modelo de cessna

 osg::ref_ptr<osg::Node> sub_model = osgDB::readNodeFile("../data/cessna.osg"); 

Para animar este modelo, cree e inicialice la transformación de rotación alrededor del eje Z

 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()); 

Ahora cree un modelo para la escena principal: un cuadrado en el que representaremos

 osg::ref_ptr<osg::Geode> model = new osg::Geode; model->addChild(createQuad(osg::Vec3(0.0f, 0.0f, 0.0f), 2.0f, 2.0f)); 

Cree una textura vacía para un cuadrado de 1024x1024 píxeles con un formato de píxel RGBA (color de tres componentes de 32 bits con canal alfa)

 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); 

Aplica esta textura al modelo cuadrado.

 model->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture.get()); 

Luego crea una c√°mara que hornee la textura

 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); 

La vista de la c√°mara tiene el mismo tama√Īo que la textura. Adem√°s, no olvide establecer el color de fondo al limpiar la pantalla y la m√°scara de limpieza, lo que indica que debe borrar tanto el b√ļfer de color como el b√ļfer de profundidad. Luego, configure la c√°mara para renderizar a textura

 camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->attach(osg::Camera::COLOR_BUFFER, texture.get()); 

El orden de renderizado de PRE_RENDER indica que esta cámara está renderizando antes de renderizar a la escena principal. Especifique el FBO como el objetivo de representación y adjunte nuestra textura a la cámara. Ahora configuramos la cámara para que funcione en un sistema de coordenadas absoluto y, como escena, configuramos nuestro subárbol, que queremos convertir en una textura: transformación de rotación con un modelo Cessna adjunto

 camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->addChild(transform1.get()); 

Cree un nodo de grupo raíz agregando el modelo principal (cuadrado) y una textura de procesamiento de cámara.

 osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(model.get()); root->addChild(camera.get()); 

Crea y personaliza un visor

 osgViewer::Viewer viewer; viewer.setSceneData(root.get()); viewer.setCameraManipulator(new osgGA::TrackballManipulator); viewer.setUpViewOnSingleScreen(0); 

Configure la matriz de proyección para la cámara: una proyección en perspectiva a través de los parámetros de la pirámide de recorte

 camera->setProjectionMatrixAsPerspective(30.0, static_cast<double>(tex_widht) / static_cast<double>(tex_height), 0.1, 1000.0); 

Configuramos una matriz de vista que establece la posición de la cámara en el espacio con respecto al origen de la subcesa

 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); 

Finalmente, anime y muestre la escena, cambiando el ángulo de rotación de la aeronave alrededor del eje Z en cada cuadro

 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; } 

Como resultado, obtenemos una imagen bastante interesante



En este ejemplo, implementamos algunas animaciones de escena, pero recuerde que expandir el ciclo run () y cambiar los par√°metros de representaci√≥n antes o despu√©s de representar el cuadro es una actividad insegura en t√©rminos de organizar el acceso a los datos de diferentes flujos. Dado que OSG utiliza la representaci√≥n de subprocesos m√ļltiples, tambi√©n existen mecanismos regulares para incorporar sus propias acciones en el proceso de representaci√≥n, que proporcionan acceso seguro a los datos.

6. Guardar el resultado de la representación en un archivo


OSG admite la capacidad de adjuntar un objeto osg :: Image a la c√°mara y guardar el contenido del b√ļfer de cuadros en el b√ļfer de datos de imagen. Despu√©s de eso, es posible guardar estos datos en el disco usando la funci√≥n osg :: writeImageFile ()

 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" ); 

Conclusión


Quizás el material presentado en el artículo parece trivial. Sin embargo, describe los conceptos básicos de trabajar con texturas en OpenSceneGraph, en el que se basan técnicas más complejas para trabajar con este motor, de las que definitivamente hablaremos en el futuro.

Continuar√° ...

Source: https://habr.com/ru/post/437624/


All Articles