void SphericalDeformation::setScreenUniforms(ptr<SceneNode> context, ptr<TerrainQuad> q, ptr<Program> prog) const { vec3d p0 = vec3d(q->ox, q->oy, R); vec3d p1 = vec3d(q->ox + q->l, q->oy, R); vec3d p2 = vec3d(q->ox, q->oy + q->l, R); vec3d p3 = vec3d(q->ox + q->l, q->oy + q->l, R); vec3d pc = (p0 + p3) * 0.5; double l0, l1, l2, l3; vec3d v0 = p0.normalize(&l0); vec3d v1 = p1.normalize(&l1); vec3d v2 = p2.normalize(&l2); vec3d v3 = p3.normalize(&l3); if (screenQuadCornersU != NULL) { mat4d deformedCorners = mat4d( v0.x * R, v1.x * R, v2.x * R, v3.x * R, v0.y * R, v1.y * R, v2.y * R, v3.y * R, v0.z * R, v1.z * R, v2.z * R, v3.z * R, 1.0, 1.0, 1.0, 1.0); screenQuadCornersU->setMatrix((localToScreen * deformedCorners).cast<float>()); } if (screenQuadVerticalsU != NULL) { mat4d deformedVerticals = mat4d( v0.x, v1.x, v2.x, v3.x, v0.y, v1.y, v2.y, v3.y, v0.z, v1.z, v2.z, v3.z, 0.0, 0.0, 0.0, 0.0); screenQuadVerticalsU->setMatrix((localToScreen * deformedVerticals).cast<float>()); } if (screenQuadCornerNormsU != NULL) { screenQuadCornerNormsU->set(vec4d(l0, l1, l2, l3).cast<float>()); } if (tangentFrameToWorldU != NULL) { vec3d uz = pc.normalize(); vec3d ux = vec3d::UNIT_Y.crossProduct(uz).normalize(); vec3d uy = uz.crossProduct(ux); mat4d ltow = context->getLocalToWorld(); mat3d tangentFrameToWorld = mat3d( ltow[0][0], ltow[0][1], ltow[0][2], ltow[1][0], ltow[1][1], ltow[1][2], ltow[2][0], ltow[2][1], ltow[2][2]) * mat3d( ux.x, uy.x, uz.x, ux.y, uy.y, uz.y, ux.z, uy.z, uz.z); tangentFrameToWorldU->setMatrix(tangentFrameToWorld.cast<float>()); } }
mat4d CylindricalDeformation::localToDeformedDifferential(const vec3d &localPt, bool clamp) const { float alpha = (float) localPt.y / R; return mat4d(1.0, 0.0, 0.0, localPt.x, 0.0, cos(alpha), -sin(alpha), R * sin(alpha), 0.0, sin(alpha), cos(alpha), - R * cos(alpha), 0.0, 0.0, 0.0, 1.0); }
mat4d SphericalDeformation::deformedToTangentFrame(const vec3d &deformedPt) const { vec3d Uz = deformedPt.normalize(); vec3d Ux = (vec3d::UNIT_Y.crossProduct(Uz)).normalize(); vec3d Uy = Uz.crossProduct(Ux); return mat4d(Ux.x, Ux.y, Ux.z, 0.0, Uy.x, Uy.y, Uy.z, 0.0, Uz.x, Uz.y, Uz.z, -R, 0.0, 0.0, 0.0, 1.0); }
void IkSolver::updateBoneTransforms(const Bone *parent, const Bone &b, const mat4d &base) const { const BoneState &bs = boneStates[b.id]; if (parent == 0) bs.boneToWorld = base * mat4d(bs.rot); else { const Bone::Connection &c = *b.findJointWith(*parent); bs.boneToWorld = base * mat4d(bs.rot) * vmath::translation_matrix(-c.pos); } for (int i = 0; i < (int)b.joints.size(); ++i) { const Bone::Connection &c = b.joints[i]; Bone &bn = *c.to; if (&bn != parent) updateBoneTransforms(&b, bn, bs.boneToWorld * vmath::translation_matrix(c.pos)); } }
mat4d CylindricalDeformation::deformedToTangentFrame(const vec3d &deformedPt) const { vec3d Uz = vec3d(0.0, -deformedPt.y, -deformedPt.z).normalize(); vec3d Ux = vec3d::UNIT_X; vec3d Uy = Uz.crossProduct(Ux); vec3d O = vec3d(deformedPt.x, -Uz.y * R, -Uz.z * R); return mat4d(Ux.x, Ux.y, Ux.z, -O.dotproduct(Ux), Uy.x, Uy.y, Uy.z, -O.dotproduct(Uy), Uz.x, Uz.y, Uz.z, -O.dotproduct(Uz), 0.0, 0.0, 0.0, 1.0); }
void IkSolver::resetPose() { rootPos = rootBone->worldPos; for (int i = 0; i < (int)skeleton.numBones(); ++i) { const Bone &b = skeleton[i]; boneStates[i].boneToWorld = vmath::translation_matrix(b.worldPos) * mat4d(b.defaultOrient); } resetBoneRot(0, *rootBone); //updateBoneTransforms(); }
mat4d SphericalDeformation::localToDeformedDifferential(const vec3d &localPt, bool clamp) const { if (!isFinite(localPt.x) || !isFinite(localPt.y) || !isFinite(localPt.z)) { return mat4d::IDENTITY; } vec3d pt = localPt; if (clamp) { pt.x = pt.x - floor((pt.x + R) / (2.0 * R)) * 2.0 * R; pt.y = pt.y - floor((pt.y + R) / (2.0 * R)) * 2.0 * R; } double l = pt.x*pt.x + pt.y*pt.y + R*R; double c0 = 1.0 / sqrt(l); double c1 = c0 * R / l; return mat4d((pt.y*pt.y + R*R)*c1, -pt.x*pt.y*c1, pt.x*c0, R*pt.x*c0, -pt.x*pt.y*c1, (pt.x*pt.x + R*R)*c1, pt.y*c0, R*pt.y*c0, -pt.x*R*c1, -pt.y*R*c1, R*c0, (R*R)*c0, 0.0, 0.0, 0.0, 1.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; }