Exemplo n.º 1
0
void SceneManager::setCameraNode(const string &node)
{
    camera = NULL;
    cameraNode = node;
    SceneManager::NodeIterator i = getNodes(node);
    if (i.hasNext()) {
        camera = i.next();
    }
}
Exemplo n.º 2
0
ptr<SceneNode> SceneManager::getCameraNode()
{
    if (camera == NULL || camera->owner != this) {
        camera = NULL;
        SceneManager::NodeIterator i = getNodes(cameraNode);
        if (i.hasNext()) {
            camera = i.next();
        }
    }
    return camera;
}
Exemplo n.º 3
0
bool DrawOceanTask::Impl::run()
{
    if (Logger::DEBUG_LOGGER != NULL) {
        Logger::DEBUG_LOGGER->log("OCEAN", "DrawOcean");
    }
    ptr<FrameBuffer> fb = SceneManager::getCurrentFrameBuffer();
    ptr<Program> prog = SceneManager::getCurrentProgram();

    if (o->nbWavesU == NULL) {
        o->nbWavesU = prog->getUniform1f("nbWaves");
        o->wavesU = prog->getUniformSampler("wavesSampler");
        o->cameraToOceanU = prog->getUniformMatrix4f("cameraToOcean");
        o->screenToCameraU = prog->getUniformMatrix4f("screenToCamera");
        o->cameraToScreenU = prog->getUniformMatrix4f("cameraToScreen");
        o->oceanToCameraU = prog->getUniformMatrix3f("oceanToCamera");
        o->oceanToWorldU = prog->getUniformMatrix4f("oceanToWorld");
        o->oceanCameraPosU = prog->getUniform3f("oceanCameraPos");
        o->oceanSunDirU = prog->getUniform3f("oceanSunDir");
        o->horizon1U = prog->getUniform3f("horizon1");
        o->horizon2U = prog->getUniform3f("horizon2");
        o->timeU = prog->getUniform1f("time");
        o->radiusU = prog->getUniform1f("radius");
        o->heightOffsetU = prog->getUniform1f("heightOffset");
        o->lodsU = prog->getUniform4f("lods");

        assert(o->nbWavesU != NULL);
        o->generateWaves();
    }

    vector< ptr<TileSampler> > uniforms;
    SceneNode::FieldIterator ui = n->getFields();
    while (ui.hasNext()) {
        ptr<TileSampler> u = ui.next().cast<TileSampler>();
        if (u != NULL && u->getTerrain(0) != NULL) {
            u->setTileMap();
        }
    }

    // compute ltoo = localToOcean transform, where ocean frame = tangent space at
    // camera projection on sphere o->radius in local space
    mat4d ctol = n->getLocalToCamera().inverse();
    vec3d cl = ctol * vec3d::ZERO; // camera in local space

    if ((o->radius == 0.0 && cl.z > o->zmin) ||
        (o->radius > 0.0 && cl.length() > o->radius + o->zmin) ||
        (o->radius < 0.0 && vec2d(cl.y, cl.z).length() < -o->radius - o->zmin))
    {
        o->oldLtoo = mat4d::IDENTITY;
        o->offset = vec3d::ZERO;
        return true;
    }

    vec3d ux, uy, uz, oo;

    if (o->radius == 0.0) {
        // flat ocean
        ux = vec3d::UNIT_X;
        uy = vec3d::UNIT_Y;
        uz = vec3d::UNIT_Z;
        oo = vec3d(cl.x, cl.y, 0.0);
    } else if (o->radius > 0.0) {
        // spherical ocean
        uz = cl.normalize(); // unit z vector of ocean frame, in local space
        if (o->oldLtoo != mat4d::IDENTITY) {
            ux = vec3d(o->oldLtoo[1][0], o->oldLtoo[1][1], o->oldLtoo[1][2]).crossProduct(uz).normalize();
        } else {
            ux = vec3d::UNIT_Z.crossProduct(uz).normalize();
        }
        uy = uz.crossProduct(ux); // unit y vector
        oo = uz * o->radius; // origin of ocean frame, in local space
    } else {
        // cylindrical ocean
        uz = vec3d(0.0, -cl.y, -cl.z).normalize();
        ux = vec3d::UNIT_X;
        uy = uz.crossProduct(ux);
        oo = vec3d(cl.x, 0.0, 0.0) + uz * o->radius;
    }

    mat4d ltoo = mat4d(
        ux.x, ux.y, ux.z, -ux.dotproduct(oo),
        uy.x, uy.y, uy.z, -uy.dotproduct(oo),
        uz.x, uz.y, uz.z, -uz.dotproduct(oo),
        0.0,  0.0,  0.0,  1.0);
    // compute ctoo = cameraToOcean transform
    mat4d ctoo = ltoo * ctol;

    if (o->oldLtoo != mat4d::IDENTITY) {
        vec3d delta = ltoo * (o->oldLtoo.inverse() * vec3d::ZERO);
        o->offset += delta;
    }
    o->oldLtoo = ltoo;

    mat4d ctos = n->getOwner()->getCameraToScreen();
    mat4d stoc = ctos.inverse();
    vec3d oc = ctoo * vec3d::ZERO;

    if (o->oceanSunDirU != NULL) {
        // TODO how to get sun dir in a better way?
        SceneManager::NodeIterator i = n->getOwner()->getNodes("light");
        if (i.hasNext()) {
            ptr<SceneNode> l = i.next();
            vec3d worldSunDir = l->getLocalToParent() * vec3d::ZERO;
            vec3d oceanSunDir = ltoo.mat3x3() * (n->getWorldToLocal().mat3x3() * worldSunDir);
            o->oceanSunDirU->set(oceanSunDir.cast<float>());
        }
    }

    vec4<GLint> screen = fb->getViewport();

    vec4d frustum[6];
    SceneManager::getFrustumPlanes(ctos, frustum);
    vec3d left = frustum[0].xyz().normalize();
    vec3d right = frustum[1].xyz().normalize();
    float fov = (float) safe_acos(-left.dotproduct(right));
    float pixelSize = atan(tan(fov / 2.0f) / (screen.w / 2.0f)); // angle under which a screen pixel is viewed from the camera

    o->cameraToOceanU->setMatrix(ctoo.cast<float>());
    o->screenToCameraU->setMatrix(stoc.cast<float>());
    o->cameraToScreenU->setMatrix(ctos.cast<float>());
    o->oceanToCameraU->setMatrix(ctoo.inverse().mat3x3().cast<float>());
    o->oceanCameraPosU->set(vec3f(float(-o->offset.x), float(-o->offset.y), float(oc.z)));
    if (o->oceanToWorldU != NULL) {
        o->oceanToWorldU->setMatrix((n->getLocalToWorld() * ltoo.inverse()).cast<float>());
    }

    if (o->horizon1U != NULL) {
        float h = oc.z;
        vec3d A0 = (ctoo * vec4d((stoc * vec4d(0.0, 0.0, 0.0, 1.0)).xyz(), 0.0)).xyz();
        vec3d dA = (ctoo * vec4d((stoc * vec4d(1.0, 0.0, 0.0, 0.0)).xyz(), 0.0)).xyz();
        vec3d B = (ctoo * vec4d((stoc * vec4d(0.0, 1.0, 0.0, 0.0)).xyz(), 0.0)).xyz();
        if (o->radius == 0.0) {
            o->horizon1U->set(vec3f(-(h * 1e-6 + A0.z) / B.z, -dA.z / B.z, 0.0));
            o->horizon2U->set(vec3f::ZERO);
        } else {
            double h1 = h * (h + 2.0 * o->radius);
            double h2 = (h + o->radius) * (h + o->radius);
            double alpha = B.dotproduct(B) * h1 - B.z * B.z * h2;
            double beta0 = (A0.dotproduct(B) * h1 - B.z * A0.z * h2) / alpha;
            double beta1 = (dA.dotproduct(B) * h1 - B.z * dA.z * h2) / alpha;
            double gamma0 = (A0.dotproduct(A0) * h1 - A0.z * A0.z * h2) / alpha;
            double gamma1 = (A0.dotproduct(dA) * h1 - A0.z * dA.z * h2) / alpha;
            double gamma2 = (dA.dotproduct(dA) * h1 - dA.z * dA.z * h2) / alpha;
            o->horizon1U->set(vec3f(-beta0, -beta1, 0.0));
            o->horizon2U->set(vec3f(beta0 * beta0 - gamma0, 2.0 * (beta0 * beta1 - gamma1), beta1 * beta1 - gamma2));
        }
    }

    o->timeU->set(n->getOwner()->getTime() * 1e-6);
    if (o->radiusU != NULL) {
        o->radiusU->set(o->radius < 0.0 ? -o->radius : o->radius);
    }
    o->heightOffsetU->set(-o->meanHeight);
    o->lodsU->set(vec4f(o->resolution,
            pixelSize * o->resolution,
            log(o->lambdaMin) / log(2.0f),
            (o->nbWavesU->get() - 1.0f) / (log(o->lambdaMax) / log(2.0f) -  log(o->lambdaMin) / log(2.0f))));

    if (o->screenGrid == NULL || o->screenWidth != screen.z || o->screenHeight != screen.w) {
        o->screenWidth = screen.z;
        o->screenHeight = screen.w;
        o->screenGrid = new Mesh<vec2f, unsigned int>(TRIANGLES, GPU_STATIC);
        o->screenGrid->addAttributeType(0, 2, A32F, false);

        float f = 1.25f;
        int NX = int(f * screen.z / o->resolution);
        int NY = int(f * screen.w / o->resolution);
        for (int i = 0; i < NY; ++i) {
            for (int j = 0; j < NX; ++j) {
                o->screenGrid->addVertex(vec2f(2.0*f*j/(NX-1.0f)-f, 2.0*f*i/(NY-1.0f)-f));
            }
        }
        for (int i = 0; i < NY-1; ++i) {
            for (int j = 0; j < NX-1; ++j) {
                o->screenGrid->addIndice(i*NX+j);
                o->screenGrid->addIndice(i*NX+j+1);
                o->screenGrid->addIndice((i+1)*NX+j);
                o->screenGrid->addIndice((i+1)*NX+j);
                o->screenGrid->addIndice(i*NX+j+1);
                o->screenGrid->addIndice((i+1)*NX+j+1);
            }
        }
    }

    fb->draw(prog, *(o->screenGrid));

    return true;
}