Beispiel #1
0
static int32_t kdBinGetNodes(const kdTree &tree, const kdNode *node, u::vector<kdBinPlane> &planes,
    u::vector<kdBinNode> &nodes, u::vector<kdBinLeaf> &leafs)
{
    if (node->isLeaf())
        return kdBinInsertLeaf(node, leafs);

    // We only care about the distance and axis type for the plane.
    kdBinPlane binPlane;
    binPlane.d = node->m_splitPlane.d;
    for (size_t i = 0; i < 3; i++) {
        if (m::abs(node->m_splitPlane.n[i]) > m::kEpsilon) {
            binPlane.type = i;
            break;
        }
    }
    planes.push_back(binPlane);
    const size_t planeIndex = planes.size() - 1;
    const size_t nodeIndex = nodes.size();
    kdBinNode binNode;
    binNode.plane = planeIndex;
    binNode.sphereRadius = node->m_sphereRadius;
    binNode.sphereOrigin = node->m_sphereOrigin;
    nodes.push_back(binNode);

    nodes[nodeIndex].children[0] = kdBinGetNodes(tree, node->m_front, planes, nodes, leafs);
    nodes[nodeIndex].children[1] = kdBinGetNodes(tree, node->m_back, planes, nodes, leafs);

    return nodeIndex;
}
Beispiel #2
0
static void kdBinCreateTangents(u::vector<kdBinVertex> &vertices, const u::vector<kdBinTriangle> &triangles) {
    // Computing Tangent Space Basis Vectors for an Arbitrary Mesh (Lengyel’s Method)
    // Section 7.8 (or in Section 6.8 of the second edition).
    const size_t vertexCount = vertices.size();
    const size_t triangleCount = triangles.size();
    u::vector<m::vec3> normals(vertexCount);
    u::vector<m::vec3> tangents(vertexCount);
    u::vector<m::vec3> bitangents(vertexCount);
    m::vec3 normal;
    m::vec3 tangent;
    m::vec3 bitangent;

    for (size_t i = 0; i < triangleCount; i++) {
        kdBinCalculateTangent(triangles, vertices, i, normal, tangent, bitangent);
        const size_t x = triangles[i].v[0];
        const size_t y = triangles[i].v[1];
        const size_t z = triangles[i].v[2];

        normals[x] += normal;
        normals[y] += normal;
        normals[z] += normal;
        tangents[x] += tangent;
        tangents[y] += tangent;
        tangents[z] += tangent;
        bitangents[x] += bitangent;
        bitangents[y] += bitangent;
        bitangents[z] += bitangent;
    }

    for (size_t i = 0; i < vertexCount; i++) {
        // Gram-Schmidt orthogonalize
        // http://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process
        vertices[i].normal = normals[i].normalized();
        const m::vec3 &n = vertices[i].normal;
        m::vec3 t = tangents[i];
        m::vec3 tangent = (t - n * (n * t)).normalized();

        if (!tangent.isNormalized()) {
            // Couldn't calculate vertex tangent for vertex, so we fill it in along
            // the x axis.
            tangent = m::vec3::xAxis;
            t = tangent;
        }

        // bitangents are only stored by handness in the W component (-1.0f or 1.0f).
        vertices[i].tangent = m::vec4(tangent, (((n ^ t) * bitangents[i]) < 0.0f) ? -1.0f : 1.0f);
    }
}
Beispiel #3
0
bool write(const u::vector<unsigned char> &data, const u::string &file, const char *mode) {
    auto fp = u::fopen(file, mode);
    if (!fp)
        return false;
    if (fwrite(&data[0], data.size(), 1, fp.get()) != 1)
        return false;
    return true;
}
Beispiel #4
0
static uint32_t kdBinAddTexture(u::vector<kdBinTexture> &textures, const u::string &texturePath) {
    uint32_t index = 0;
    for (const auto &it : textures) {
        if (it.name == texturePath)
            return index;
        index++;
    }
    kdBinTexture texture;
    // Truncate the string if it doesn't fit
    const size_t length = u::min(sizeof texture.name - 1, texturePath.size());
    memcpy(texture.name, (const void *)texturePath.c_str(), length);
    texture.name[length] = '\0';
    textures.push_back(texture);
    return textures.size() - 1;
}
Beispiel #5
0
void kdNode::split(const kdTree *tree, const u::vector<int> &tris, m::axis axis,
    u::vector<int> &frontList, u::vector<int> &backList, u::vector<int> &splitList, m::plane &plane) const
{
    const size_t triangleCount = tris.size();
    plane = findSplittingPlane(tree, tris, axis);
    for (size_t i = 0; i < triangleCount; i++) {
        switch (tree->testTriangle(tris[i], plane)) {
        case kPolyPlaneCoplanar:
        case kPolyPlaneSplit:
            splitList.push_back(tris[i]);
            break;
        case kPolyPlaneFront:
            frontList.push_back(tris[i]);
            break;
        case kPolyPlaneBack:
            backList.push_back(tris[i]);
            break;
        }
    }
}
Beispiel #6
0
bool kdNode::calculateSphere(const kdTree *tree, const u::vector<int> &tris) {
    const size_t triangleCount = tris.size();
    m::vec3 min;
    m::vec3 max;
    for (size_t i = 0; i < triangleCount; i++) {
        const int index = tris[i];
        for (size_t j = 0; j < 3; j++) {
            const size_t vertexIndex = tree->m_triangles[index].m_vertices[j];
            const m::vec3 *v = &tree->m_vertices[vertexIndex];
            if (v->x < min.x) min.x = v->x;
            if (v->y < min.y) min.y = v->y;
            if (v->z < min.z) min.z = v->z;
            if (v->x > max.x) max.x = v->x;
            if (v->y > max.y) max.y = v->y;
            if (v->z > max.z) max.z = v->z;
        }
    }
    const m::vec3 mid = (max - min) * 0.5f;
    m_sphereOrigin = min + mid;
    m_sphereRadius = mid.abs();

    return m_sphereRadius <= kdTree::kMaxTraceDistance;
}
Beispiel #7
0
m::plane kdNode::findSplittingPlane(const kdTree *tree, const u::vector<int> &tris, m::axis axis) const {
    const size_t triangleCount = tris.size();
    // every vertex component is stored depending on `axis' axis in the following
    // vector. The vector gets sorted and the median is chosen as the splitting
    // plane.
    u::vector<float> coords(triangleCount * 3); // 3 vertices for a triangle

    size_t k = 0;
    for (size_t i = 0; i < triangleCount; i++) {
        for (size_t j = 0; j < 3; j++) {
            const int index = tree->m_triangles[tris[i]].m_vertices[j];
            const m::vec3 &vec = tree->m_vertices[index];
            coords[k++] = vec[axis];
        }
    }

    // sort coordinates for a L1 median estimation, this keeps us rather
    // robust against vertex outliers.
    u::sort(coords.begin(), coords.end(), [](float a, float b) { return a < b; });
    const float split = coords[coords.size() / 2]; // median like
    const m::vec3 point(m::vec3::getAxis(axis) * split);
    const m::vec3 normal(m::vec3::getAxis(axis));
    return m::plane(point, normal);
}
Beispiel #8
0
static int32_t kdBinInsertLeaf(const kdNode *leaf, u::vector<kdBinLeaf> &leafs) {
    kdBinLeaf binLeaf;
    binLeaf.triangles.insert(binLeaf.triangles.begin(), leaf->m_triangles.begin(), leaf->m_triangles.end());
    leafs.push_back(binLeaf);
    return -(int32_t)leafs.size(); // leaf indices are stored with negative index
}
Beispiel #9
0
kdNode::kdNode(kdTree *tree, const u::vector<int> &tris, size_t recursionDepth)
    : m_front(nullptr)
    , m_back(nullptr)
    , m_sphereRadius(0.0f)
{
    const size_t triangleCount = tris.size();

    if (recursionDepth > tree->m_depth)
        tree->m_depth = recursionDepth;
    if (recursionDepth > kdTree::kMaxRecursionDepth)
        return;

    tree->m_nodeCount++;

    if (!calculateSphere(tree, tris)) {
        u::Log::err("[world] => level geometry is too large: collision detection and rendering may not work");
        return;
    }

    u::vector<int> fx, fy, fz; // front
    u::vector<int> bx, by, bz; // back
    u::vector<int> sx, sy, sz; // split
    u::vector<int> *const frontList[3] = { &fx, &fy, &fz };
    u::vector<int> *const backList[3] = { &bx, &by, &bz };
    u::vector<int> *const splitList[3] = { &sx, &sy, &sz };

    m::plane plane[3];
    float ratio[3];
    size_t best = recursionDepth % 3;

    // find a plane which gives a good balanced node
    for (size_t i = 0; i < 3; i++) {
        split(tree, tris, m::axis(i), *frontList[i], *backList[i], *splitList[i], plane[i]);
        const size_t fsize = (*frontList[i]).size();
        const size_t bsize = (*backList[i]).size();
        if (fsize > bsize)
            ratio[i] = (float)bsize / (float)fsize;
        else
            ratio[i] = (float)fsize / (float)bsize;
    }

    float bestRatio = 0.0f;
    for (size_t i = 0; i < 3; i++) {
        if (ratio[i] > bestRatio) {
            best = i;
            bestRatio = ratio[i];
        }
    }

    m_splitPlane = plane[best];

    // when there isn't many triangles left, create a leaf. In doing so we can
    // continue to create further subdivisions.
    if (frontList[best]->size() == 0 || backList[best]->size() == 0 || triangleCount <= kdTree::kMaxTrianglesPerLeaf) {
        // create subspace with `triangleCount` polygons
        m_triangles.insert(m_triangles.begin(), tris.begin(), tris.end());
        tree->m_leafCount++;
        return;
    }

    // insert the split triangles on both sides of the plane.
    frontList[best]->insert(frontList[best]->end(), splitList[best]->begin(), splitList[best]->end());
    backList[best]->insert(backList[best]->end(), splitList[best]->begin(), splitList[best]->end());

    // recurse
    m_front = new kdNode(tree, *frontList[best], recursionDepth + 1);
    m_back = new kdNode(tree, *backList[best], recursionDepth + 1);
}