void GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount, MeshData& meshData) { meshData.Vertices.clear(); meshData.Indices.clear(); // // Build Stacks. // float stackHeight = height / stackCount; // Amount to increment radius as we move up each stack level from bottom to top. float radiusStep = (topRadius - bottomRadius) / stackCount; UINT ringCount = stackCount+1; // Compute vertices for each stack ring starting at the bottom and moving up. for(UINT i = 0; i < ringCount; ++i) { float y = -0.5f*height + i*stackHeight; float r = bottomRadius + i*radiusStep; // vertices of ring float dTheta = 2.0f*XM_PI/sliceCount; for(UINT j = 0; j <= sliceCount; ++j) { Vertex vertex; float c = cosf(j*dTheta); float s = sinf(j*dTheta); vertex.Position = XMFLOAT3(r*c, y, r*s); vertex.TexC.x = (float)j/sliceCount; vertex.TexC.y = 1.0f - (float)i/stackCount; // Cylinder can be parameterized as follows, where we introduce v // parameter that goes in the same direction as the v tex-coord // so that the bitangent goes in the same direction as the v tex-coord. // Let r0 be the bottom radius and let r1 be the top radius. // y(v) = h - hv for v in [0,1]. // r(v) = r1 + (r0-r1)v // // x(t, v) = r(v)*cos(t) // y(t, v) = h - hv // z(t, v) = r(v)*sin(t) // // dx/dt = -r(v)*sin(t) // dy/dt = 0 // dz/dt = +r(v)*cos(t) // // dx/dv = (r0-r1)*cos(t) // dy/dv = -h // dz/dv = (r0-r1)*sin(t) // This is unit length. vertex.TangentU = XMFLOAT3(-s, 0.0f, c); float dr = bottomRadius-topRadius; XMFLOAT3 bitangent(dr*c, -height, dr*s); XMVECTOR T = XMLoadFloat3(&vertex.TangentU); XMVECTOR B = XMLoadFloat3(&bitangent); XMVECTOR N = XMVector3Normalize(XMVector3Cross(T, B)); XMStoreFloat3(&vertex.Normal, N); meshData.Vertices.push_back(vertex); } } // Add one because we duplicate the first and last vertex per ring // since the texture coordinates are different. UINT ringVertexCount = sliceCount+1; // Compute indices for each stack. for(UINT i = 0; i < stackCount; ++i) { for(UINT j = 0; j < sliceCount; ++j) { meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j+1); } } BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData); BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData); }
void TextureProjection::emitTextureCoordinates (std::size_t width, std::size_t height, Winding& w, const Vector3& normal, const Matrix4& localToWorld) { if (w.size() < 3) { return; } Matrix4 local2tex = m_texdef.getTransform((float) width, (float) height); { Matrix4 xyz2st; // we don't care if it's not normalised... basisForNormal(matrix4_transformed_direction(localToWorld, normal), xyz2st); matrix4_multiply_by_matrix4(local2tex, xyz2st); } Vector3 tangent(local2tex.getTransposed().x().getVector3().getNormalised()); Vector3 bitangent(local2tex.getTransposed().y().getVector3().getNormalised()); matrix4_multiply_by_matrix4(local2tex, localToWorld); for (Winding::iterator i = w.begin(); i != w.end(); ++i) { Vector3 texcoord = matrix4_transformed_point(local2tex, (*i).vertex); (*i).texcoord[0] = texcoord[0]; (*i).texcoord[1] = texcoord[1]; (*i).tangent = tangent; (*i).bitangent = bitangent; } }
bool Mesh::CreateCylinder(float bottomRadius, float topRadius, float height, u32 sliceCount, u32 stackCount, Mesh& mesh) { mesh.m_vertices.clear(); mesh.m_indices.clear(); float stackHeight = height / stackCount; float radiusStep = (topRadius - bottomRadius) / stackCount; u32 ringCount = stackCount + 1; // Compute vertices for (u32 i = 0; i < ringCount; ++i) { float y = -0.5f * height + i * stackHeight; float r = bottomRadius + i * radiusStep; // Vertics of ring float dTheta = 2.0f * FARLOR_PI / sliceCount; for (u32 j = 0; j < sliceCount; ++j) { VertexPositionUVNormal vertex; float c = cosf(j * dTheta); float s = sinf(j * dTheta); vertex.m_position = Vector3(r * c, y, r * s); vertex.m_uv.x = (float)j / sliceCount; vertex.m_uv.y = 1.0f - (float)i / stackCount; Vector3 tangent(-1.0f * s, 0.0f, c); float dr = bottomRadius - topRadius; Vector3 bitangent(dr * c, -1.0f * height, dr * s); vertex.m_normal = tangent.Cross(bitangent).Normalized(); } } u32 ringVertexCount = sliceCount + 1; for (u32 i = 0; i < stackCount; ++i) { for (u32 j = 0; j < stackCount; ++j) { mesh.m_indices.push_back(i*ringVertexCount + j); mesh.m_indices.push_back((i+1)*ringVertexCount + j); mesh.m_indices.push_back((i+1)*ringVertexCount + j+1); mesh.m_indices.push_back(i*ringVertexCount + j); mesh.m_indices.push_back((i+1)*ringVertexCount + j+1); mesh.m_indices.push_back(i*ringVertexCount + j+1); } } // No end cap geometry yet, need to do!! return true; }
GLuint Bitangents(std::vector<T>& dest) const { unsigned k = 0, n = _vertex_count(); dest.resize(n * 3); Vec3f bitangent(Normalized(_v)); for(unsigned i=0; i!=n; ++i) { dest[k++] = T(bitangent.x()); dest[k++] = T(bitangent.y()); dest[k++] = T(bitangent.z()); } // assert(k == dest.size()); // 3 values per vertex return 3; }
void GeometryGenerator::CreateCylinder(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount, MeshData& meshData) { meshData.Vertices.clear(); meshData.Indices.clear(); float stackHeight = height / stackCount; float radiusStep = (topRadius - bottomRadius) / stackCount; UINT ringCount = stackCount+1; for(UINT i = 0; i < ringCount; ++i) { float y = -0.5f*height + i*stackHeight; float r = bottomRadius + i*radiusStep; float dTheta = 2.0f*XM_PI/sliceCount; for(UINT j = 0; j <= sliceCount; ++j) { Vertex vertex; float c = cosf(j*dTheta); float s = sinf(j*dTheta); vertex.Position = glm::vec3(r*c, y, r*s); vertex.TexC.x = (float)j/sliceCount; vertex.TexC.y = 1.0f - (float)i/stackCount; vertex.TangentU = glm::vec3(-s, 0.0f, c); float dr = bottomRadius-topRadius; glm::vec3 bitangent(dr*c, -height, dr*s); glm::vec3 T = vertex.TangentU; glm::vec3 B = bitangent; glm::vec3 N = glm::normalize(glm::cross(T, B)); vertex.Normal = N; meshData.Vertices.push_back(vertex); } } UINT ringVertexCount = sliceCount+1; for(UINT i = 0; i < stackCount; ++i) { for(UINT j = 0; j < sliceCount; ++j) { meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j); meshData.Indices.push_back((i+1)*ringVertexCount + j+1); meshData.Indices.push_back(i*ringVertexCount + j+1); } } BuildCylinderTopCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData); BuildCylinderBottomCap(bottomRadius, topRadius, height, sliceCount, stackCount, meshData); }
double integrateD(const KernelD & F, const Element & e) { double result = 0.0; // Get the quadrature rules for azimuthal and polar integrations namespace mpl = boost::mpl; typedef typename mpl::at<rules_map, mpl::int_<PhiPoints> >::type PhiPolicy; typedef typename mpl::at<rules_map, mpl::int_<ThetaPoints> >::type ThetaPolicy; QuadratureRule<PhiPolicy> phiRule; QuadratureRule<ThetaPolicy> thetaRule; int upper_phi = PhiPoints / 2; // Upper limit for loop on phi points int upper_theta = ThetaPoints / 2; // Upper limit for loop on theta points // Extract relevant data from Element int nVertices = e.nVertices(); Eigen::Vector3d normal = e.normal(); Sphere sph = e.sphere(); Eigen::Matrix3Xd vertices = e.vertices(); Eigen::Matrix3Xd arcs = e.arcs(); // Calculation of the tangent and the bitangent (binormal) vectors // Tangent, Bitangent and Normal form a local reference frame: // T <-> x; B <-> y; N <-> z Eigen::Vector3d tangent, bitangent; tangent_and_bitangent(normal, tangent, bitangent); std::vector<double> theta(nVertices), phi(nVertices), phinumb(nVertices+1); std::vector<int> numb(nVertices+1); // Clean-up heap crap std::fill_n(theta.begin(), nVertices, 0.0); std::fill_n(phi.begin(), nVertices, 0.0); std::fill_n(numb.begin(), nVertices+1, 0); std::fill_n(phinumb.begin(), nVertices+1, 0.0); // Populate arrays and redefine tangent and bitangent e.spherical_polygon(tangent, bitangent, theta, phi, phinumb, numb); // Actual integration occurs here for (int i = 0; i < nVertices; ++i) { // Loop on edges double phiLower = phinumb[i]; // Lower vertex of edge double phiUpper = phinumb[i+1]; // Upper vertex of edge double phiA = (phiUpper - phiLower) / 2.0; double phiB = (phiUpper + phiLower) / 2.0; double thetaLower = theta[numb[i]]; double thetaUpper = theta[numb[i+1]]; double thetaMax = 0.0; Eigen::Vector3d oc = (arcs.col(i) - sph.center) / sph.radius; double oc_norm = oc.norm(); double oc_norm2 = std::pow(oc_norm, 2); for (int j = 0; j < upper_phi; ++j) { // Loop on Gaussian points: phi integration for (int k = 0; k <= 1; ++k) { double ph = (2*k - 1) * phiA * phiRule.abscissa(j) + phiB; double cos_phi = std::cos(ph); double sin_phi = std::sin(ph); if (oc_norm2 < 1.0e-07) { // This should check if oc_norm2 is zero double cotg_thmax = (std::sin(ph-phiLower) / std::tan(thetaUpper) + std::sin(phiUpper-ph) / std::tan( thetaLower)) / std::sin(phiUpper - phiLower); thetaMax = std::atan(1.0 / cotg_thmax); } else { Eigen::Vector3d scratch; scratch << tangent.dot(oc), bitangent.dot(oc), normal.dot(oc); double aa = std::pow(tangent.dot(oc)*cos_phi + bitangent.dot(oc)*sin_phi, 2) + std::pow(normal.dot(oc), 2); double bb = -normal.dot(oc) * oc_norm2; double cc = std::pow(oc_norm2, 2) - std::pow(tangent.dot(oc)*cos_phi + bitangent.dot(oc)*sin_phi, 2); double ds = std::pow(bb, 2) - aa*cc; if (ds < 0.0) ds = 0.0; double cs = (-bb + std::sqrt(ds)) / aa; if (cs > 1.0) cs = 1.0; if (cs < -1.0) cs = 1.0; thetaMax = std::acos(cs); } double thetaA = thetaMax / 2.0; double scratch = 0.0; if (!(thetaMax < 1.0e-08)) { for (int l = 0; l < upper_theta; ++l) { // Loop on Gaussian points: theta integration for (int m = 0; m <= 1; ++m) { double th = (2*m - 1) * thetaA * thetaRule.abscissa(l) + thetaA; double cos_theta = std::cos(th); double sin_theta = std::sin(th); Eigen::Vector3d point; point(0) = tangent(0) * sin_theta * cos_phi + bitangent(0) * sin_theta * sin_phi + normal(0) * (cos_theta - 1.0); point(1) = tangent(1) * sin_theta * cos_phi + bitangent(1) * sin_theta * sin_phi + normal(1) * (cos_theta - 1.0); point(2) = tangent(2) * sin_theta * cos_phi + bitangent(2) * sin_theta * sin_phi + normal(2) * (cos_theta - 1.0); double value = F(e.normal(), Eigen::Vector3d::Zero(), point); // Evaluate integrand at Gaussian point scratch += std::pow(sph.radius, 2) * value * sin_theta * thetaA * thetaRule.weight(l); } } result += scratch * phiA * phiRule.weight(j); } } } } return result; }
void mesh::calculateTangents() { std::vector<float> tans(3*vertCount, 0); std::vector<float> bitans(3*vertCount, 0); tangents.resize(4 * vertCount); //calculate tentative tangents and bitangents for each triangle for (int i = 0; i < triCount; i++) { //find the vertices of the current triangle, and their UV coords int vi1 = triangles[3*i]; int vi2 = triangles[3*i + 1]; int vi3 = triangles[3*i + 2]; glm::vec3 vert0(vertices[3*vi1], vertices[3*vi1 + 1], vertices[3*vi1 + 2]); glm::vec3 vert1(vertices[3*vi2], vertices[3*vi2 + 1], vertices[3*vi2 + 2]); glm::vec3 vert2(vertices[3*vi3], vertices[3*vi3 + 1], vertices[3*vi3 + 2]); glm::vec2 uv0(texCoords[2*vi1], texCoords[2*vi1 + 1]); glm::vec2 uv1(texCoords[2*vi2], texCoords[2*vi2 + 1]); glm::vec2 uv2(texCoords[2*vi3], texCoords[2*vi3 + 1]); //differences in position and UV coords glm::vec3 dPos1 = vert1 - vert0; glm::vec3 dPos2 = vert2 - vert0; glm::vec2 dUV1 = uv1 - uv0; glm::vec2 dUV2 = uv2 - uv0; //calculate and store the tangent and bitangent float coeff = 1.0f / (dUV1.x * dUV2.y - dUV1.y * dUV2.x); glm::vec3 tan = dPos1 * dUV2.y - dPos2 * dUV1.y; glm::vec3 bitan = dPos2 * dUV1.x - dPos1 * dUV2.x; tan *= coeff; bitan *= coeff; tans[3*vi1] += tan.x; tans[3*vi1 + 1] += tan.y; tans[3*vi1 + 2] += tan.z; tans[3*vi2] += tan.x; tans[3*vi2 + 1] += tan.y; tans[3*vi2 + 2] += tan.z; tans[3*vi3] += tan.x; tans[3*vi3 + 1] += tan.y; tans[3*vi3 + 2] += tan.z; bitans[3*vi1] += bitan.x; bitans[3*vi1 + 1] += bitan.y; bitans[3*vi1 + 2] += bitan.z; bitans[3*vi2] += bitan.x; bitans[3*vi2 + 1] += bitan.y; bitans[3*vi2 + 2] += bitan.z; bitans[3*vi3] += bitan.x; bitans[3*vi3 + 1] += bitan.y; bitans[3*vi3 + 2] += bitan.z; } //find the final tangent (and bitangent) for each vertex for (int j = 0; j < vertCount; j++) { glm::vec3 normal (normals[3*j], normals[3*j + 1], normals[3*j + 2]); glm::vec3 tangent (tans[3*j], tans[3*j + 1], tans[3*j + 2]); glm::vec3 bitangent (bitans[3*j], bitans[3*j + 1], bitans[3*j + 2]); glm::normalize(tangent); glm::normalize(bitangent); //orthagonalize glm::vec3 tangent_orth(normal); tangent_orth *= glm::dot(normal, tangent); tangent_orth = tangent - tangent_orth; glm::normalize(tangent_orth); //compute handedness float handedness = 1.0f; glm::vec3 nCrossT = glm::cross(normal, tangent_orth); if(glm::dot(nCrossT, bitangent) > 0) { handedness = 1.0f; } else { handedness = -1.0f; } //store the orthagonalized tangent and handedness tangents[4*j] = tangent_orth.x; tangents[4*j + 1] = tangent_orth.y; tangents[4*j + 2] = tangent_orth.z; tangents[4*j + 3] = handedness; } }