title: Understanding the mesh created by Qt3D
body: <p>I create a Qt3D mesh like this:</p>
  
  <pre><code>Qt3DCore::QEntity *newEntity = new Qt3DCore::QEntity();
  Qt3DExtras::QConeMesh *mesh =new Qt3DExtras::QConeMesh();
  mesh-&gt;setTopRadius(0.2);
  mesh-&gt;setBottomRadius(1.0);
  mesh-&gt;setLength(2.0);
  for(int i = 0; i &lt; mesh-&gt;geometry()-&gt;attributes().size(); ++i) {
      mesh-&gt;geometry()-&gt;attributes().at(i)-&gt;buffer()-&gt;setSyncData(true); // To have access to data
  }
  newEntity-&gt;addComponent(mesh);
  </code></pre>
  
  <p>The created mesh looks like this:</p>
  
  <p><a href="https://i.stack.imgur.com/2OHeC.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2OHeC.png" alt="Cone Mesh"></a> <a href="https://i.stack.imgur.com/L8ZlJ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/L8ZlJ.png" alt="Cone Mesh, another view"></a></p>
  
  <hr>
  
  <p>Later in the code, I try to export the above mesh in <a href="https://en.wikipedia.org/wiki/STL_(file_format)#Binary_STL" rel="nofollow noreferrer">STL binary format</a>. To do so, I extract the <strong>geometry</strong> and <strong>transformation</strong> components of the entity:</p>
  
  <pre><code>Qt3DCore::QComponent *compoMesh = nullptr; // place holder for mesh geometry of entity
  Qt3DCore::QComponent *compoTran = nullptr; // place holder for mesh transformation of entity
  QVector&lt;Qt3DCore::QComponent *&gt; compos = newEntity-&gt;components();
  for(int i = 0; i &lt; compos.size(); ++i) {
      if (qobject_cast&lt;Qt3DRender::QGeometryRenderer *&gt;(compos.at(i))) {
          compoMesh = compos.at(i); // mesh geometry component
      } else if (qobject_cast&lt;Qt3DCore::QTransform *&gt;(compos.at(i))) {
          compoTran = compos.at(i); // mesh transformation component
      }
  }
  </code></pre>
  
  <p>Then I get the buffer data containing the vertex positions and normals:</p>
  
  <pre><code>Qt3DRender::QGeometryRenderer *mesh = qobject_cast&lt;Qt3DRender::QGeometryRenderer *&gt;(compoMesh);
  Qt3DRender::QGeometry *geometry = mesh-&gt;geometry();
  QVector&lt;Qt3DRender::QAttribute *&gt; atts = geometry-&gt;attributes();
  </code></pre>
  
  <p>Now, we focus on vertex <strong>positions</strong> attribute and vertex <strong>normals</strong> attribute. We get the <strong>byte offset</strong> and <strong>byte stride</strong> for each, also we check if both are using the same <strong>data buffer</strong>:</p>
  
  <pre><code>for(int i = 0; i &lt; atts.size(); ++i) {
          if(atts.at(i)-&gt;name() == Qt3DRender::QAttribute::defaultPositionAttributeName()) {
              byteOffsetPos = atts.at(i)-&gt;byteOffset();
              byteStridePos = atts.at(i)-&gt;byteStride();
              bufferPtrPos = atts.at(i)-&gt;buffer();
          } else if(atts.at(i)-&gt;name() == Qt3DRender::QAttribute::defaultNormalAttributeName()) {
              byteOffsetNorm = atts.at(i)-&gt;byteOffset();
              byteStrideNorm = atts.at(i)-&gt;byteStride();
              bufferPtrNorm = atts.at(i)-&gt;buffer();
          }
      }
  if(bufferPtrPos != bufferPtrNorm) {
      qDebug() &lt;&lt; __func__ &lt;&lt; "!!! Buffer pointer for position and normal are NOT the same";
      // Throw error here
      }
  </code></pre>
  
  <p>Then I use the <strong>byte offset</strong> and <strong>byte stride</strong> to extract triangles and write them to STL file. However the exported STL is NOT good:</p>
  
  <p><a href="https://i.stack.imgur.com/7yeVh.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/7yeVh.png" alt="The exported STL is NOT good"></a></p>
  
  <hr>
  
  <p>I use the same code for exporting STL of custom meshes which works fine. However when I use the same code to export the Qt3D ready-made meshes like <code>QConeMesh</code>, the exported STL is NOT acceptable. Can anybody give me a hint.</p>
  
  <hr>
  
  <h2>UPDATE</h2>
  
  <p>As noted by @vre I'm going to post the rest of the code for writing triangles to STL file. It's a large code, I try my best to keep it clear and concise:</p>
  
  <p>For getting triangle positions and normals, I loop over attributes and get the <code>VertexBuffer</code> buffer which stores all the positions and normals:</p>
  
  <pre><code>// I loop over attributes to get access to VertexBuffer buffer
  for(int i = 0; i &lt; atts.size(); ++i) {
      Qt3DRender::QBuffer *buffer = atts.at(i)-&gt;buffer();
      QByteArray data = buffer-&gt;data();
      // We focus on VertexBuffer, NOT IndexBuffer!
      if( buffer-&gt;type() == Qt3DRender::QBuffer::VertexBuffer ) {
          // Number of triangles is number of vertices divided by 3:
          quint32 trianglesCount = atts.at(i)-&gt;count() / 3;
  
          // For each triangle, extract vertex positions and normals
          for(int j = 0; j &lt; trianglesCount; ++j) {
              // Index for each triangle positions data
              // Each triangle has 3 vertices, hence 3 factor:
              // We already know byte-offset and byte-stride for positions
              int idxPos  = byteOffsetPos  + j * 3 * byteStridePos ;
              // Index for each triangle normals data
              // Each tirangle has 3 normals (right?), hence 3 factor:
              // We already know byte-offset and byte-stride for normals
              int idxNorm = byteOffsetNorm + j * 3 * byteStrideNorm;
  
              // Get x, y, z positions for 1st vertex
              // I have already checked that attribute base type is float by: `atts.at(i)-&gt;vertexBaseType();`
              QByteArray pos0x = data.mid(idxPos + 0 * sizeof(float), sizeof(float));
              QByteArray pos0y = data.mid(idxPos + 1 * sizeof(float), sizeof(float));
              QByteArray pos0z = data.mid(idxPos + 2 * sizeof(float), sizeof(float));
  
              // Get x, y z for 1st normal
              QByteArray norm0x= data.mid(idxNorm + 0 * sizeof(float), sizeof(float));
              QByteArray norm0y= data.mid(idxNorm + 1 * sizeof(float), sizeof(float));
              QByteArray norm0z= data.mid(idxNorm + 2 * sizeof(float), sizeof(float));
  
              // Get x, y, z positions for 2nd vertex
              QByteArray pos1x = data.mid(idxPos  + 1 * byteStridePos + 0 * sizeof(float), sizeof(float));
              QByteArray pos1y = data.mid(idxPos  + 1 * byteStridePos + 1 * sizeof(float), sizeof(float));
              QByteArray pos1z = data.mid(idxPos  + 1 * byteStridePos + 2 * sizeof(float), sizeof(float));
  
              // Get x, y, z for 2nd normal
              QByteArray norm1x= data.mid(idxNorm + 1 * byteStrideNorm + 0 * sizeof(float), sizeof(float));
              QByteArray norm1y= data.mid(idxNorm + 1 * byteStrideNorm + 1 * sizeof(float), sizeof(float));
              QByteArray norm1z= data.mid(idxNorm + 1 * byteStrideNorm + 2 * sizeof(float), sizeof(float));
  
              // Get x, y, z positions for 3rd vertex
              QByteArray pos2x = data.mid(idxPos  + 2 * byteStridePos + 0 * sizeof(float), sizeof(float));
              QByteArray pos2y = data.mid(idxPos  + 2 * byteStridePos + 1 * sizeof(float), sizeof(float));
              QByteArray pos2z = data.mid(idxPos  + 2 * byteStridePos + 2 * sizeof(float), sizeof(float));
  
              // Get x, y, z for 3rd normal
              QByteArray norm2x= data.mid(idxNorm + 2 * byteStrideNorm+ 0 * sizeof(float), sizeof(float));
              QByteArray norm2y= data.mid(idxNorm + 2 * byteStrideNorm+ 1 * sizeof(float), sizeof(float));
              QByteArray norm2z= data.mid(idxNorm + 2 * byteStrideNorm+ 2 * sizeof(float), sizeof(float));
  
              // Convert x, y, z byte arrays into floats
              float floatPos0x;
              if ( pos0x.size() &gt;= sizeof(floatPos0x) ) {
                  floatPos0x = *reinterpret_cast&lt;const float *&gt;( pos0x.data() );
              }
              float floatPos0y;
              if ( pos0y.size() &gt;= sizeof(floatPos0y) ) {
                  floatPos0y = *reinterpret_cast&lt;const float *&gt;( pos0y.data() );
              }
              float floatPos0z;
              if ( pos0z.size() &gt;= sizeof(floatPos0z) ) {
                  floatPos0z = *reinterpret_cast&lt;const float *&gt;( pos0z.data() );
              }
  
              // Do the rest of byte-array to float conversions:
              // norm0x=&gt;floatNorm0x, norm0y=&gt;floatNorm0y, norm0z=&gt;floatNorm0z
              // pos1x=&gt;floatPos1x, pos1y=&gt;floatPos1y, pos1z=&gt;floatPos1z
              // norm1x=&gt;floatNorm1x, norm1y=&gt;floatNorm1y, norm1z=&gt;floatNorm1z
              // pos2x=&gt;floatPos2x, pos2y=&gt;floatPos2y, pos2z=&gt;floatPos2z
              // norm2x=&gt;floatNorm2x, norm2y=&gt;floatNorm2y, norm2z=&gt;floatNorm2z
  
              // Compose positions matrix before applying transformations
              // I'm going to use `QMatrix4x4` but I have 3 vertices of 3x1
              // Therefore I have to fill out `QMatrix4x4` with zeros and ones
              // Please see this question and its answer: https://stackoverflow.com/q/51979168/3405291
              QMatrix4x4 floatPos4x4 = QMatrix4x4(
                  floatPos0x, floatPos1x, floatPos2x, 0,
                  floatPos0y, floatPos1y, floatPos2y, 0,
                  floatPos0z, floatPos1z, floatPos2z, 0,
                  1         , 1         , 1         , 0
              );
  
              // Apply transformations to positions:
              // We already have transformations component `compoTran` from previous code:
              Qt3DCore::QTransform *tran = qobject_cast&lt;Qt3DCore::QTransform *&gt;(compoTran);
              QMatrix4x4 newFloatPos4x4 = tran-&gt;matrix() * floatPos4x4;
  
              // Get new positions after applying transformations:
              float newFloatPos0x = newFloatPos4x4(0,0);
              float newFloatPos0y = newFloatPos4x4(1,0);
              float newFloatPos0z = newFloatPos4x4(2,0);
  
              float newFloatPos1x = newFloatPos4x4(0,1);
              float newFloatPos1y = newFloatPos4x4(1,1);
              float newFloatPos1z = newFloatPos4x4(2,1);
  
              float newFloatPos2x = newFloatPos4x4(0,2);
              float newFloatPos2y = newFloatPos4x4(1,2);
              float newFloatPos2z = newFloatPos4x4(2,2);
  
              // Convert all the floats (after applying transformations) back to byte array:
              QByteArray newPos0x( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos0x ), sizeof( newFloatPos0x ) );
              QByteArray newPos0y( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos0y ), sizeof( newFloatPos0y ) );
              QByteArray newPos0z( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos0z ), sizeof( newFloatPos0z ) );
  
              QByteArray newPos1x( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos1x ), sizeof( newFloatPos1x ) );
              QByteArray newPos1y( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos1y ), sizeof( newFloatPos1y ) );
              QByteArray newPos1z( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos1z ), sizeof( newFloatPos1z ) );
  
              QByteArray newPos2x( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos2x ), sizeof( newFloatPos2x ) );
              QByteArray newPos2y( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos2y ), sizeof( newFloatPos2y ) );
              QByteArray newPos2z( reinterpret_cast&lt;const char *&gt;( &amp;newFloatPos2z ), sizeof( newFloatPos2z ) );
  
              // Log triangle vertex positions and normals (float numbers)
              // A sample log is posted on this question on StackOverflow
              qDebug() &lt;&lt; __func__ &lt;&lt; " pos 0: x " &lt;&lt; newFloatPos0x &lt;&lt; " y " &lt;&lt; newFloatPos0y &lt;&lt; " z " &lt;&lt; newFloatPos0z;
              qDebug() &lt;&lt; __func__ &lt;&lt; " pos 1: x " &lt;&lt; newFloatPos1x &lt;&lt; " y " &lt;&lt; newFloatPos1y &lt;&lt; " z " &lt;&lt; newFloatPos1z;
              qDebug() &lt;&lt; __func__ &lt;&lt; " pos 2: x " &lt;&lt; newFloatPos2x &lt;&lt; " y " &lt;&lt; newFloatPos2y &lt;&lt; " z " &lt;&lt; newFloatPos2z;
  
              qDebug() &lt;&lt; __func__ &lt;&lt; " norm 0: x " &lt;&lt; floatNorm0x &lt;&lt; " y " &lt;&lt; floatNorm0y &lt;&lt; " z " &lt;&lt; floatNorm0z;
              qDebug() &lt;&lt; __func__ &lt;&lt; " norm 1: x " &lt;&lt; floatNorm1x &lt;&lt; " y " &lt;&lt; floatNorm1y &lt;&lt; " z " &lt;&lt; floatNorm1z;
              qDebug() &lt;&lt; __func__ &lt;&lt; " norm 2: x " &lt;&lt; floatNorm2x &lt;&lt; " y " &lt;&lt; floatNorm2y &lt;&lt; " z " &lt;&lt; floatNorm2z;
  
              // Write the triangle to STL file
              // Note that STL file needs a header which is written in another section of code
              // Note that STL file needs total number of triangles which is written in another section of code
              // Note that STL file needs only one normal vector for each triangle, but here we have 3 normals (for 3 vertices), therefore I'm writing only the 1st normal to STL (is it OK?!)
              // `baStl` is a byte-array containing all the STL data
              // `baStl` byte-array is written to a file in another section of the code
              QBuffer tempBuffer(&amp;baStl);
              tempBuffer.open(QIODevice::Append);
              tempBuffer.write( norm0x   ); // vertex 0 Normal vector
              tempBuffer.write( norm0y   );
              tempBuffer.write( norm0z   );
              tempBuffer.write( newPos0x ); // New vertex 0 position
              tempBuffer.write( newPos0y );
              tempBuffer.write( newPos0z );
              tempBuffer.write( newPos1x ); // New vertex 1 position
              tempBuffer.write( newPos1y );
              tempBuffer.write( newPos1z );
              tempBuffer.write( newPos2x ); // New vertex 2 position
              tempBuffer.write( newPos2y );
              tempBuffer.write( newPos2z );
              tempBuffer.write("aa"); // Attribute byte count: UINT16: 2 bytes: content doesn't matter, just write 2 bytes
              tempBuffer.close();
          }
      }
  }
  </code></pre>
  
  <p>The above code works perfect for custom meshes. I mean when I import a STL file into my Qt3D application and then export it again as STL, the exported STL <strong>is good</strong>. The problem is: when creating Qt3D ready-made meshes like <code>QConeMesh</code>, the exported STL <strong>is screwed up</strong>, I mean the overall geometry is OK, but the triangles are messed up as shown in the above image.</p>
  
  <p>My code logs following values when trying to export a <code>QConeMesh</code>. As can be seen, normal vectors have <strong>unit size</strong> which shows they are actually normals:</p>
  
  <pre>
  ...
  exportStlUtil  pos 0: x  -10.6902  y  -7.55854  z  4.76837e-07
  exportStlUtil  pos 1: x  -12.8579  y  -4.31431  z  2.98023e-07
  exportStlUtil  pos 2: x  -13.6191  y  -0.487476  z  5.96046e-08
  exportStlUtil  norm 0: x  -0.707107  y  0  z  0.707107
  exportStlUtil  norm 1: x  -0.92388  y  0  z  0.382683
  exportStlUtil  norm 2: x  -1  y  0  z  -8.74228e-08
  exportStlUtil  pos 0: x  -12.8579  y  3.33936  z  -1.19209e-07
  exportStlUtil  pos 1: x  -10.6902  y  6.58359  z  -3.57628e-07
  exportStlUtil  pos 2: x  -7.44594  y  8.75132  z  -4.76837e-07
  exportStlUtil  norm 0: x  -0.92388  y  0  z  -0.382683
  exportStlUtil  norm 1: x  -0.707107  y  0  z  -0.707107
  exportStlUtil  norm 2: x  -0.382683  y  0  z  -0.92388
  exportStlUtil  pos 0: x  -3.61911  y  9.51252  z  -4.76837e-07
  exportStlUtil  pos 1: x  0.207723  y  8.75132  z  -4.76837e-07
  exportStlUtil  pos 2: x  3.45196  y  6.58359  z  -3.57628e-07
  exportStlUtil  norm 0: x  1.19249e-08  y  0  z  -1
  exportStlUtil  norm 1: x  0.382684  y  0  z  -0.923879
  exportStlUtil  norm 2: x  0.707107  y  0  z  -0.707107
  exportStlUtil  pos 0: x  5.61968  y  3.33936  z  -1.19209e-07
  exportStlUtil  pos 1: x  6.38089  y  -0.487479  z  5.96046e-08
  exportStlUtil  pos 2: x  6.38089  y  -0.487477  z  0.133333
  exportStlUtil  norm 0: x  0.92388  y  0  z  -0.382683
  exportStlUtil  norm 1: x  1  y  0  z  1.74846e-07
  exportStlUtil  norm 2: x  1  y  0  z  0
  exportStlUtil  pos 0: x  5.61968  y  -4.31431  z  0.133334
  exportStlUtil  pos 1: x  3.45195  y  -7.55854  z  0.133334
  exportStlUtil  pos 2: x  0.207721  y  -9.72627  z  0.133334
  exportStlUtil  norm 0: x  0.92388  y  0  z  0.382683
  exportStlUtil  norm 1: x  0.707107  y  0  z  0.707107
  exportStlUtil  norm 2: x  0.382683  y  0  z  0.92388
  ...
  </pre>