spheremesh.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:12k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // mesh.cpp
  2. //
  3. // Copyright (C) 2000, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <cmath>
  10. #include <celmath/mathlib.h>
  11. #include <celmath/vecmath.h>
  12. #include "gl.h"
  13. #include "glext.h"
  14. #include "spheremesh.h"
  15. SphereMesh::SphereMesh(float radius, int _nRings, int _nSlices) :
  16.     vertices(NULL), normals(NULL), texCoords(NULL), indices(NULL)
  17. {
  18.     createSphere(radius, _nRings, _nSlices);
  19. }
  20. SphereMesh::SphereMesh(Vec3f size, int _nRings, int _nSlices) :
  21.     vertices(NULL), normals(NULL), texCoords(NULL), indices(NULL)
  22. {
  23.     createSphere(1.0f, _nRings, _nSlices);
  24.     scale(size);
  25. }
  26. SphereMesh::SphereMesh(Vec3f size,
  27.                        const DisplacementMap& dispmap,
  28.                        float height) :
  29.     vertices(NULL), normals(NULL), texCoords(NULL), indices(NULL)
  30. {
  31.     createSphere(1.0f, dispmap.getHeight(), dispmap.getWidth());
  32.     scale(size);
  33.     displace(dispmap, height);
  34.     generateNormals();
  35.     fixNormals();
  36. }
  37. SphereMesh::SphereMesh(Vec3f size,
  38.                        int _nRings, int _nSlices,
  39.                        DisplacementMapFunc func,
  40.                        void* info)
  41. {
  42.     createSphere(1.0f, _nRings, _nSlices);
  43.     scale(size);
  44.     displace(func, info);
  45.     generateNormals();
  46.     fixNormals();
  47. }
  48. SphereMesh::~SphereMesh()
  49. {
  50.     if (vertices != NULL)
  51.         delete[] vertices;
  52.     if (normals != NULL)
  53.         delete[] normals;
  54.     if (texCoords != NULL)
  55.         delete[] texCoords;
  56.     if (indices != NULL)
  57.         delete[] indices;
  58. }
  59. void SphereMesh::createSphere(float radius, int _nRings, int _nSlices)
  60. {
  61.     nRings = _nRings;
  62.     nSlices = _nSlices;
  63.     nVertices = nRings * (nSlices + 1);
  64.     vertices = new float[nVertices * 3];
  65.     normals = new float[nVertices * 3];
  66.     texCoords = new float[nVertices * 2];
  67.     nIndices = (nRings - 1) * (nSlices + 1) * 2;
  68.     indices = new unsigned short[nIndices];
  69.     tangents = new float[nVertices * 3];
  70.     int i;
  71.     for (i = 0; i < nRings; i++)
  72.     {
  73.         float phi = ((float) i / (float) (nRings - 1) - 0.5f) * (float) PI;
  74.         for (int j = 0; j <= nSlices; j++)
  75.         {
  76.             float theta = (float) j / (float) nSlices * (float) PI * 2;
  77.             int n = i * (nSlices + 1) + j;
  78.             float x = (float) (cos(phi) * cos(theta));
  79.             float y = (float) sin(phi);
  80.             float z = (float) (cos(phi) * sin(theta));
  81.             vertices[n * 3]      = x * radius;
  82.             vertices[n * 3 + 1]  = y * radius;
  83.             vertices[n * 3 + 2]  = z * radius;
  84.             normals[n * 3]       = x;
  85.             normals[n * 3 + 1]   = y;
  86.             normals[n * 3 + 2]   = z;
  87.             texCoords[n * 2]     = 1.0f - (float) j / (float) nSlices;
  88.             texCoords[n * 2 + 1] = 1.0f - (float) i / (float) (nRings - 1);
  89.             // Compute the tangent--required for bump mapping
  90.             float tx = (float) (sin(phi) * sin(theta));
  91.             float ty = (float) -cos(phi);
  92.             float tz = (float) (sin(phi) * cos(theta));
  93.             tangents[n * 3]      = tx;
  94.             tangents[n * 3 + 1]  = ty;
  95.             tangents[n * 3 + 2]  = tz;
  96.         }
  97.     }
  98.     for (i = 0; i < nRings - 1; i++)
  99.     {
  100.         for (int j = 0; j <= nSlices; j++)
  101.         {
  102.             int n = i * (nSlices + 1) + j;
  103.             indices[n * 2 + 0] = i * (nSlices + 1) + j;
  104.             indices[n * 2 + 1] = (i + 1) * (nSlices + 1) + j;
  105.         }
  106.     }
  107. }
  108. // Generate vertex normals for a quad mesh by averaging face normals
  109. void SphereMesh::generateNormals()
  110. {
  111.     int nQuads = nSlices * (nRings - 1);
  112.     Vec3f* faceNormals = new Vec3f[nQuads];
  113.     int i;
  114.     // Compute face normals for the mesh
  115.     for (i = 0; i < nRings - 1; i++)
  116.     {
  117.         for (int j = 0; j < nSlices; j++)
  118.         {
  119.             float* p0 = vertices + (i * (nSlices + 1) + j) * 3;
  120.             float* p1 = vertices + ((i + 1) * (nSlices + 1) + j) * 3;
  121.             float* p2 = vertices + ((i + 1) * (nSlices + 1) + j + 1) * 3;
  122.             float* p3 = vertices + (i * (nSlices + 1) + j + 1) * 3;
  123.             // Compute the face normal.  Watch out for degenerate (zero-length)
  124.             // edges.  If there are two degenerate edges, the entire face must
  125.             // be degenerate and we'll handle that later
  126.             Vec3f v0(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]);
  127.             Vec3f v1(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
  128.             if (v0.length() < 1e-6f)
  129.             {
  130.                 v0 = Vec3f(p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]);
  131.                 v1 = Vec3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
  132.             }
  133.             else if (v1.length() < 1e-6f)
  134.             {
  135.                 v0 = Vec3f(p3[0] - p2[0], p3[1] - p2[1], p3[2] - p2[2]);
  136.                 v1 = Vec3f(p0[0] - p3[0], p0[1] - p3[1], p0[2] - p3[2]);
  137.             }
  138.             Vec3f faceNormal = cross(v0, v1);
  139.             float length = faceNormal.length();
  140.             if (length != 0)
  141.                 faceNormal *= (1 / length);
  142.             faceNormals[i * nSlices + j] = faceNormal;
  143.         }
  144.     }
  145.     int* faceCounts = new int[nVertices];
  146.     for (i = 0; i < nVertices; i++)
  147.     {
  148.         faceCounts[i] = 0;
  149.         normals[i * 3] = 0;
  150.         normals[i * 3 + 1] = 0;
  151.         normals[i * 3 + 2] = 0;
  152.     }
  153.     for (i = 1; i < nRings - 1; i++)
  154.     {
  155.         for (int j = 0; j <= nSlices; j++)
  156.         {
  157.             int vertex = i * (nSlices + 1) + j;
  158.             faceCounts[vertex] = 4;
  159.             int face = (i - 1) * nSlices + j % nSlices;
  160.             normals[vertex * 3]     += faceNormals[face].x;
  161.             normals[vertex * 3 + 1] += faceNormals[face].y;
  162.             normals[vertex * 3 + 2] += faceNormals[face].z;
  163.             face = (i - 1) * nSlices + (j + nSlices - 1) % nSlices;
  164.             normals[vertex * 3]     += faceNormals[face].x;
  165.             normals[vertex * 3 + 1] += faceNormals[face].y;
  166.             normals[vertex * 3 + 2] += faceNormals[face].z;
  167.             face = i * nSlices + (j + nSlices - 1) % nSlices;
  168.             normals[vertex * 3]     += faceNormals[face].x;
  169.             normals[vertex * 3 + 1] += faceNormals[face].y;
  170.             normals[vertex * 3 + 2] += faceNormals[face].z;
  171.             face = i * nSlices + j % nSlices;
  172.             normals[vertex * 3]     += faceNormals[face].x;
  173.             normals[vertex * 3 + 1] += faceNormals[face].y;
  174.             normals[vertex * 3 + 2] += faceNormals[face].z;
  175.         }
  176.     }
  177.     // Compute normals at the poles
  178.     for (i = 0; i <= nSlices; i++)
  179.     {
  180.         int vertex = i;
  181.         int j;
  182.         faceCounts[vertex] = nSlices;
  183.         for (j = 0; j < nSlices; j++)
  184.         {
  185.             int face = j;
  186.             normals[vertex * 3]     += faceNormals[face].x;
  187.             normals[vertex * 3 + 1] += faceNormals[face].y;
  188.             normals[vertex * 3 + 2] += faceNormals[face].z;
  189.         }
  190.         vertex = (nRings - 1) * (nSlices + 1) + i;
  191.         faceCounts[vertex] = nSlices;
  192.         for (j = 0; j < nSlices; j++)
  193.         {
  194.             int face = nQuads - j - 1;
  195.             normals[vertex * 3]     += faceNormals[face].x;
  196.             normals[vertex * 3 + 1] += faceNormals[face].y;
  197.             normals[vertex * 3 + 2] += faceNormals[face].z;
  198.         }
  199.     }
  200.     for (i = 0; i < nVertices; i++)
  201.     {
  202.         if (faceCounts[i] > 0)
  203.         {
  204.             float s = 1.0f / (float) faceCounts[i];
  205.             float nx = normals[i * 3] * s;
  206.             float ny = normals[i * 3 + 1] * s;
  207.             float nz = normals[i * 3 + 2] * s;
  208.             float length = (float) sqrt(nx * nx + ny * ny + nz * nz);
  209.             if (length > 0)
  210.             {
  211.                 length = 1 / length;
  212.                 normals[i * 3]     = nx * length;
  213.                 normals[i * 3 + 1] = ny * length;
  214.                 normals[i * 3 + 2] = nz * length;
  215.             }
  216.         }
  217.     }
  218.     delete[] faceCounts;
  219.     delete[] faceNormals;
  220. }
  221. // Fix up the normals along the seam at longitude zero
  222. void SphereMesh::fixNormals()
  223. {
  224.     for (int i = 0; i < nRings; i++)
  225.     {
  226.         float* v0 = normals + (i * (nSlices + 1)) * 3;
  227.         float* v1 = normals + ((i + 1) * (nSlices + 1) - 1) * 3;
  228.         Vec3f n0(v0[0], v0[1], v0[2]);
  229.         Vec3f n1(v0[0], v0[1], v0[2]);
  230.         Vec3f normal = n0 + n1;
  231.         normal.normalize();
  232.         v0[0] = normal.x;
  233.         v0[1] = normal.y;
  234.         v0[2] = normal.z;
  235.         v1[0] = normal.x;
  236.         v1[1] = normal.y;
  237.         v1[2] = normal.z;
  238.     }
  239. }
  240. void SphereMesh::scale(Vec3f s)
  241. {
  242.     int i;
  243.     for (i = 0; i < nVertices; i++)
  244.     {
  245.         vertices[i * 3]     *= s.x;
  246.         vertices[i * 3 + 1] *= s.y;
  247.         vertices[i * 3 + 2] *= s.z;
  248.     }
  249.     // Modify the normals
  250.     if (normals != NULL)
  251.     {
  252.         // TODO: Make a fast special case for uniform scale factors, where
  253.         // renormalization is not required.
  254.         Vec3f is(1.0f / s.x, 1.0f / s.y, 1.0f / s.z);
  255.         for (i = 0; i < nVertices; i++)
  256.         {
  257.             int n = i * 3;
  258.             Vec3f normal(normals[n] * is.x, normals[n + 1] * is.y, normals[n + 2] * is.z);
  259.             normal.normalize();
  260.             normals[n]     = normal.x;
  261.             normals[n + 1] = normal.y;
  262.             normals[n + 2] = normal.z;
  263.         }
  264.     }
  265. }
  266. void SphereMesh::displace(const DisplacementMap& dispmap,
  267.                           float height)
  268. {
  269.     // assert(dispMap.getWidth() == nSlices);
  270.     // assert(dispMap.getHeight() == nRings);
  271.     for (int i = 0; i < nRings; i++)
  272.     {
  273.         for (int j = 0; j <= nSlices; j++)
  274.         {
  275.             int n = (i * (nSlices + 1) + j) * 3;
  276.             /*
  277.             float theta = (float) j / (float) nSlices * (float) PI * 2;
  278.             float x = (float) (cos(phi) * cos(theta));
  279.             float y = (float) sin(phi);
  280.             float z = (float) (cos(phi) * sin(theta));
  281.             */
  282.             Vec3f normal(normals[n], normals[n + 1], normals[n + 2]);
  283.             int k = (j == nSlices) ? 0 : j;
  284.             Vec3f v = normal * dispmap.getDisplacement(k, i) * height;
  285.             vertices[n] += v.x;
  286.             vertices[n + 1] += v.y;
  287.             vertices[n + 2] += v.z;
  288.         }
  289.     }
  290. }
  291. void SphereMesh::displace(DisplacementMapFunc func, void* info)
  292. {
  293.     for (int i = 0; i < nRings; i++)
  294.     {
  295.         float v = (float) i / (float) (nRings - 1);
  296.         for (int j = 0; j <= nSlices; j++)
  297.         {
  298.             float u = (float) j / (float) nSlices;
  299.             int n = (i * (nSlices + 1) + j) * 3;
  300.             Vec3f normal(normals[n], normals[n + 1], normals[n + 2]);
  301.             Vec3f vert = normal * func(u, v, info);
  302.             vertices[n] += vert.x;
  303.             vertices[n + 1] += vert.y;
  304.             vertices[n + 2] += vert.z;
  305.         }
  306.     }
  307. }
  308. Mesh* SphereMesh::convertToMesh() const
  309. {
  310.     uint32 stride = 32;
  311.     Mesh::VertexAttribute attributes[3];
  312.     attributes[0] = Mesh::VertexAttribute(Mesh::Position, Mesh::Float3, 0);
  313.     attributes[1] = Mesh::VertexAttribute(Mesh::Normal, Mesh::Float3, 12);
  314.     attributes[2] = Mesh::VertexAttribute(Mesh::Texture0, Mesh::Float2, 24);
  315.     Mesh* mesh = new Mesh();
  316.     mesh->setVertexDescription(Mesh::VertexDescription(stride, 3, attributes));
  317.     // Copy the vertex data from the separate position, normal, and texture coordinate
  318.     // arrays into a single array.
  319.     char* vertexData = new char[stride * nVertices];
  320.     int i;
  321.     for (i = 0; i < nVertices; i++)
  322.     {
  323.         float* vertex = reinterpret_cast<float*>(vertexData + stride * i);
  324.         vertex[0] = vertices[i * 3];
  325.         vertex[1] = vertices[i * 3 + 1];
  326.         vertex[2] = vertices[i * 3 + 2];
  327.         vertex[3] = normals[i * 3];
  328.         vertex[4] = normals[i * 3 + 1];
  329.         vertex[5] = normals[i * 3 + 2];
  330.         vertex[6] = texCoords[i * 2];
  331.         vertex[7] = texCoords[i * 2 + 1];
  332.     }
  333.     mesh->setVertices(nVertices, vertexData);
  334.     for (i = 0; i < nRings - 1; i++)
  335.     {
  336.         uint32* indexData = new uint32[(nSlices + 1) * 2];
  337.         for (int j = 0; j <= nSlices; j++)
  338.         {
  339.             indexData[j * 2 + 0] = i * (nSlices + 1) + j;
  340.             indexData[j * 2 + 1] = (i + 1) * (nSlices + 1) + j;
  341.         }
  342.         mesh->addGroup(Mesh::TriStrip, ~0u, (nSlices + 1) * 2, indexData);
  343.     }
  344.     return mesh;
  345. }