void SceneManager::setCameraNode(const string &node) { camera = NULL; cameraNode = node; SceneManager::NodeIterator i = getNodes(node); if (i.hasNext()) { camera = i.next(); } }
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; }
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; }