3173 lines · 138.0 KB · C++
RawDownload
                        // when assigning a material, search for its presence and, if not found,                        // place it in the first empty slot                        if (crossing.material != 0) {                            for (int j = 0; j < MAX_MATERIALS_PER_VERTEX; j++) {                                if (materials[j] == crossing.material) {                                    materialWeights[j] += 1.0f;                                    totalWeight += 1.0f;                                    break;                                                                    } else if (materials[j] == 0) {                                    materials[j] = crossing.material;                                    materialWeights[j] = 1.0f;                                    totalWeight += 1.0f;                                    break;                                }                            }                        }                    }                    glm::vec3 normal = safeNormalize(axisNormals[0] + axisNormals[1] + axisNormals[2]);                    center /= crossingCount;                                        // use a sequence of Givens rotations to perform a QR decomposition                    // see http://www.cs.rice.edu/~jwarren/papers/techreport02408.pdf                    glm::mat4 r(0.0f);                    glm::vec4 bottom;                    float smallestCosNormal = 1.0f;                    for (int i = 0; i < crossingCount; i++) {                        const EdgeCrossing& crossing = crossings[i];                        bottom = glm::vec4(crossing.normal, glm::dot(crossing.normal, crossing.point - center));                        smallestCosNormal = qMin(smallestCosNormal, glm::dot(crossing.normal, normal));                                                for (int j = 0; j < 4; j++) {                            float angle = glm::atan(-bottom[j], r[j][j]);                            float sina = glm::sin(angle);                            float cosa = glm::cos(angle);                                                        for (int k = 0; k < 4; k++) {                                float tmp = bottom[k];                                bottom[k] = sina * r[k][j] + cosa * tmp;                                r[k][j] = cosa * r[k][j] - sina * tmp;                            }                        }                    }                                        // extract the submatrices, form ata                    glm::mat3 a(r);                    glm::vec3 b(r[3]);                    glm::mat3 atrans = glm::transpose(a);                    glm::mat3 ata = atrans * a;                                        // find the eigenvalues and eigenvectors of ata                    // (see http://en.wikipedia.org/wiki/Jacobi_eigenvalue_algorithm)                    glm::mat3 d = ata;                    glm::quat combinedRotation;                    const int MAX_ITERATIONS = 20;                    for (int i = 0; i < MAX_ITERATIONS; i++) {                        glm::vec3 offDiagonals = glm::abs(glm::vec3(d[1][0], d[2][0], d[2][1]));                        int largestIndex = (offDiagonals[0] > offDiagonals[1]) ? (offDiagonals[0] > offDiagonals[2] ? 0 : 2) :                            (offDiagonals[1] > offDiagonals[2] ? 1 : 2);                        const float DESIRED_PRECISION = 0.00001f;                        if (offDiagonals[largestIndex] < DESIRED_PRECISION) {                            break;                        }                        int largestJ = (largestIndex == 2) ? 1 : 0;                        int largestI = (largestIndex == 0) ? 1 : 2;                         float sjj = d[largestJ][largestJ];                        float sii = d[largestI][largestI];                        float angle = glm::atan(2.0f * d[largestJ][largestI], sjj - sii) / 2.0f;                        glm::quat rotation = glm::angleAxis(angle, largestIndex == 0 ? glm::vec3(0.0f, 0.0f, -1.0f) :                            (largestIndex == 1 ? glm::vec3(0.0f, 1.0f, 0.0f) : glm::vec3(-1.0f, 0.0f, 0.0f)));                        combinedRotation = glm::normalize(rotation * combinedRotation);                        glm::mat3 matrix = glm::mat3_cast(combinedRotation);                        d = matrix * ata * glm::transpose(matrix);                    }                                        // form the singular matrix from the eigenvalues                    const float MIN_SINGULAR_THRESHOLD = 0.1f;                    d[0][0] = (d[0][0] < MIN_SINGULAR_THRESHOLD) ? 0.0f : 1.0f / d[0][0];                    d[1][1] = (d[1][1] < MIN_SINGULAR_THRESHOLD) ? 0.0f : 1.0f / d[1][1];                    d[2][2] = (d[2][2] < MIN_SINGULAR_THRESHOLD) ? 0.0f : 1.0f / d[2][2];                                        // compute the pseudo-inverse, ataplus, and use to find the minimizing solution                    glm::mat3 u = glm::mat3_cast(combinedRotation);                    glm::mat3 ataplus = glm::transpose(u) * d * u;                     glm::vec3 solution = (ataplus * atrans * b) + center;                                        // make sure it doesn't fall beyond the cell boundaries                    center = glm::clamp(solution, 0.0f, 1.0f);                                        if (totalWeight > 0.0f) {                        materialWeights *= (EIGHT_BIT_MAXIMUM / totalWeight);                    }                    VoxelPoint point = { info.minimum + (glm::vec3(clampedX, clampedY, clampedZ) + center) * scale,                        { (quint8)(red / crossingCount), (quint8)(green / crossingCount), (quint8)(blue / crossingCount) },                        { (char)(normal.x * 127.0f), (char)(normal.y * 127.0f), (char)(normal.z * 127.0f) },                        { materials[0], materials[1], materials[2], materials[3] },                        { (quint8)materialWeights[0], (quint8)materialWeights[1], (quint8)materialWeights[2],                            (quint8)materialWeights[3] } };                                        // determine whether we must "crease" by generating directional normals                    const float CREASE_COS_NORMAL = glm::cos(glm::radians(40.0f));                    AxisIndex index(vertices.size(), vertices.size(), vertices.size());                    if (smallestCosNormal > CREASE_COS_NORMAL) {                            vertices.append(point);                                            } else {                        axisNormals[0] = safeNormalize(axisNormals[0]);                        axisNormals[1] = safeNormalize(axisNormals[1]);                        axisNormals[2] = safeNormalize(axisNormals[2]);                        glm::vec3 normalXY(safeNormalize(axisNormals[0] + axisNormals[1]));                        glm::vec3 normalXZ(safeNormalize(axisNormals[0] + axisNormals[2]));                        glm::vec3 normalYZ(safeNormalize(axisNormals[1] + axisNormals[2]));                        if (glm::dot(axisNormals[0], normalXY) > CREASE_COS_NORMAL &&                                glm::dot(axisNormals[1], normalXY) > CREASE_COS_NORMAL) {                            point.setNormal(normalXY);                            vertices.append(point);                                                        point.setNormal(axisNormals[2]);                            index.z = vertices.size();                            vertices.append(point);                                                    } else if (glm::dot(axisNormals[0], normalXZ) > CREASE_COS_NORMAL &&                                glm::dot(axisNormals[2], normalXZ) > CREASE_COS_NORMAL) {                            point.setNormal(normalXZ);                            vertices.append(point);                                                    point.setNormal(axisNormals[1]);                            index.y = vertices.size();                            vertices.append(point);                                                } else if (glm::dot(axisNormals[1], normalYZ) > CREASE_COS_NORMAL &&                                glm::dot(axisNormals[2], normalYZ) > CREASE_COS_NORMAL) {                            point.setNormal(normalYZ);                            vertices.append(point);                                                    point.setNormal(axisNormals[0]);                            index.x = vertices.size();                            vertices.append(point);                                                } else {                            point.setNormal(axisNormals[0]);                            vertices.append(point);                                                        point.setNormal(axisNormals[1]);                            index.y = vertices.size();                            vertices.append(point);                                                        point.setNormal(axisNormals[2]);                            index.z = vertices.size();                            vertices.append(point);                        }                    }                                        // the first x, y, and z are repeated for the boundary edge; past that, we consider generating                    // quads for each edge that includes a transition, using indices of previously generated vertices                    if (x != 0 && y != 0 && z != 0) {                        if (alpha0 != alpha1) {                            quadIndices.insert(qRgb(x, y, z), indices.size());                            quadIndices.insert(qRgb(x, y - 1, z), indices.size());                            quadIndices.insert(qRgb(x, y - 1, z - 1), indices.size());                            quadIndices.insert(qRgb(x, y, z - 1), indices.size());                            indices.append(index.x);                            int index1 = lastLineIndices.at(x).x;                            int index2 = lastPlaneIndices.at((y - 1) * expanded + x).x;                            int index3 = lastPlaneIndices.at(y * expanded + x).x;                            if (alpha0 == 0) { // quad faces negative x                                indices.append(index3);                                indices.append(index2);                                indices.append(index1);                            } else { // quad faces positive x                                indices.append(index1);                                indices.append(index2);                                indices.append(index3);                            }                        }                                                if (alpha0 != alpha2) {                            quadIndices.insert(qRgb(x, y, z), indices.size());                            quadIndices.insert(qRgb(x - 1, y, z), indices.size());                            quadIndices.insert(qRgb(x - 1, y, z - 1), indices.size());                            quadIndices.insert(qRgb(x, y, z - 1), indices.size());                            indices.append(index.y);                            int index1 = lastIndex.y;                            int index2 = lastPlaneIndices.at(y * expanded + x - 1).y;                            int index3 = lastPlaneIndices.at(y * expanded + x).y;                            if (alpha0 == 0) { // quad faces negative y                                indices.append(index1);                                indices.append(index2);                                indices.append(index3);                            } else { // quad faces positive y                                indices.append(index3);                                indices.append(index2);                                indices.append(index1);                            }                        }                                                if (alpha0 != alpha4) {                            quadIndices.insert(qRgb(x, y, z), indices.size());                            quadIndices.insert(qRgb(x - 1, y, z), indices.size());                            quadIndices.insert(qRgb(x - 1, y - 1, z), indices.size());                            quadIndices.insert(qRgb(x, y - 1, z), indices.size());                            indices.append(index.z);                            int index1 = lastIndex.z;                            int index2 = lastLineIndices.at(x - 1).z;                            int index3 = lastLineIndices.at(x).z;                            if (alpha0 == 0) { // quad faces negative z                                indices.append(index3);                                indices.append(index2);                                indices.append(index1);                            } else { // quad faces positive z                                indices.append(index1);                                indices.append(index2);                                indices.append(index3);                            }                        }                    }                    lastIndex = index;                    lineIndices[x] = index;                    planeIndices[y * expanded + x] = index;                                        if (x != 0) {                        colorX++;                    }                }                lineIndices.swap(lastLineIndices);                                if (y != 0) {                    colorY += size;                }            }            planeIndices.swap(lastPlaneIndices);                        if (z != 0) {                colorZ += area;            }        }        buffer = new VoxelBuffer(vertices, indices, hermiteSegments, quadIndices, size,            material ? material->getMaterials() : QVector<SharedObjectPointer>());    }    BufferDataPointer pointer(buffer);    info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));    return STOP_RECURSION;} void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,        MetavoxelInfo& info, const MetavoxelLOD& lod) {    // copy the previous buffers    MetavoxelData expandedPrevious = previous;    while (expandedPrevious.getSize() < data.getSize()) {        expandedPrevious.expand();    }    const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute();    MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute);    if (root) {        data.setRoot(pointBufferAttribute, root);        root->incrementReferenceCount();    }    const AttributePointer& heightfieldBufferAttribute =        Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute();    root = expandedPrevious.getRoot(heightfieldBufferAttribute);    if (root) {        data.setRoot(heightfieldBufferAttribute, root);        root->incrementReferenceCount();    }    const AttributePointer& voxelBufferAttribute =        Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute();    root = expandedPrevious.getRoot(voxelBufferAttribute);    if (root) {        data.setRoot(voxelBufferAttribute, root);        root->incrementReferenceCount();    }        PointAugmentVisitor pointAugmentVisitor(lod);    data.guideToDifferent(expandedPrevious, pointAugmentVisitor);        HeightfieldRegionVisitor heightfieldRegionVisitor(lod);    data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);        HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions,        heightfieldRegionVisitor.regionBounds);    data.guide(heightfieldUpdateVisitor);        VoxelAugmentVisitor voxelAugmentVisitor(lod);    data.guideToDifferent(expandedPrevious, voxelAugmentVisitor);} class SpannerSimulateVisitor : public SpannerVisitor {public:        SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod);        virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); private:        float _deltaTime;}; SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod) :    SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),        QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(), lod),    _deltaTime(deltaTime) {} bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {    spanner->getRenderer()->simulate(_deltaTime);    return true;} void DefaultMetavoxelRendererImplementation::simulate(MetavoxelData& data, float deltaTime,        MetavoxelInfo& info, const MetavoxelLOD& lod) {    SpannerSimulateVisitor spannerSimulateVisitor(deltaTime, lod);    data.guide(spannerSimulateVisitor);} class SpannerRenderVisitor : public SpannerVisitor {public:        SpannerRenderVisitor(const MetavoxelLOD& lod);        virtual int visit(MetavoxelInfo& info);    virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize); private:        int _containmentDepth;}; SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) :    SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),        QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(),        lod, encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())),    _containmentDepth(INT_MAX) {} int SpannerRenderVisitor::visit(MetavoxelInfo& info) {    if (_containmentDepth >= _depth) {        Frustum::IntersectionType intersection = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType(            info.getBounds());        if (intersection == Frustum::NO_INTERSECTION) {            return STOP_RECURSION;        }        _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;    }    return SpannerVisitor::visit(info);} bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {    const glm::vec4 OPAQUE_WHITE(1.0f, 1.0f, 1.0f, 1.0f);    spanner->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize);    return true;} class BufferRenderVisitor : public MetavoxelVisitor {public:        BufferRenderVisitor(const AttributePointer& attribute);        virtual int visit(MetavoxelInfo& info); private:        int _order;    int _containmentDepth;}; BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) :    MetavoxelVisitor(QVector<AttributePointer>() << attribute),    _order(encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())),    _containmentDepth(INT_MAX) {} int BufferRenderVisitor::visit(MetavoxelInfo& info) {    if (_containmentDepth >= _depth) {        Frustum::IntersectionType intersection = Application::getInstance()->getMetavoxels()->getFrustum().getIntersectionType(            info.getBounds());        if (intersection == Frustum::NO_INTERSECTION) {            return STOP_RECURSION;        }        _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;    }    if (!info.isLeaf) {        return _order;    }    BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();    if (buffer) {        buffer->render();    }    return STOP_RECURSION;} void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {    SpannerRenderVisitor spannerRenderVisitor(lod);    data.guide(spannerRenderVisitor);        int viewport[4];    glGetIntegerv(GL_VIEWPORT, viewport);    const int VIEWPORT_WIDTH_INDEX = 2;    const int VIEWPORT_HEIGHT_INDEX = 3;    float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];    float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];    float viewportDiagonal = sqrtf(viewportWidth * viewportWidth + viewportHeight * viewportHeight);    float worldDiagonal = glm::distance(Application::getInstance()->getDisplayViewFrustum()->getNearBottomLeft(),        Application::getInstance()->getDisplayViewFrustum()->getNearTopRight());     _pointProgram.bind();    _pointProgram.setUniformValue(_pointScaleLocation, viewportDiagonal *        Application::getInstance()->getDisplayViewFrustum()->getNearClip() / worldDiagonal);            glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_COLOR_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);     glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);     glDisable(GL_BLEND);        BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute());    data.guide(pointRenderVisitor);        glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);        glDisableClientState(GL_COLOR_ARRAY);    glDisableClientState(GL_NORMAL_ARRAY);        _pointProgram.release();        Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);        glEnable(GL_CULL_FACE);    glEnable(GL_ALPHA_TEST);    glAlphaFunc(GL_EQUAL, 0.0f);        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);        if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) {        _baseHeightfieldProgram.bind();                glEnableClientState(GL_TEXTURE_COORD_ARRAY);                BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute());        data.guide(heightfieldRenderVisitor);                glDisableClientState(GL_TEXTURE_COORD_ARRAY);                    _baseHeightfieldProgram.release();    }        if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) {        glEnableClientState(GL_COLOR_ARRAY);        glEnableClientState(GL_NORMAL_ARRAY);                _baseVoxelProgram.bind();                BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute());        data.guide(voxelRenderVisitor);                _baseVoxelProgram.release();                glDisableClientState(GL_COLOR_ARRAY);        glDisableClientState(GL_NORMAL_ARRAY);    }        glDisable(GL_ALPHA_TEST);    glDisable(GL_CULL_FACE);    glEnable(GL_BLEND);            glDisableClientState(GL_VERTEX_ARRAY);        Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);} void DefaultMetavoxelRendererImplementation::loadSplatProgram(const char* type,        ProgramObject& program, SplatLocations& locations) {    program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +        "shaders/metavoxel_" + type + "_splat.vert");    program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +        "shaders/metavoxel_" + type + "_splat.frag");    program.link();        program.bind();    program.setUniformValue("heightMap", 0);    program.setUniformValue("textureMap", 1);    program.setUniformValueArray("diffuseMaps", SPLAT_TEXTURE_UNITS, SPLAT_COUNT);    locations.heightScale = program.uniformLocation("heightScale");    locations.textureScale = program.uniformLocation("textureScale");    locations.splatTextureOffset = program.uniformLocation("splatTextureOffset");    locations.splatTextureScalesS = program.uniformLocation("splatTextureScalesS");    locations.splatTextureScalesT = program.uniformLocation("splatTextureScalesT");    locations.textureValueMinima = program.uniformLocation("textureValueMinima");    locations.textureValueMaxima = program.uniformLocation("textureValueMaxima");    locations.materials = program.attributeLocation("materials");    locations.materialWeights = program.attributeLocation("materialWeights");    program.release();} ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram;int DefaultMetavoxelRendererImplementation::_pointScaleLocation;ProgramObject DefaultMetavoxelRendererImplementation::_baseHeightfieldProgram;int DefaultMetavoxelRendererImplementation::_baseHeightScaleLocation;

Lines 2501–3000 of 3173. Previous lines