/** Generate View, Projection, Inverse View, Inverse Projection, ViewProjection and InverseProjection matrixes and matrixes and cameras for the four shadow cascade and RSM. * \param camnode point of view used * \param width of the rendering viewport * \param height of the rendering viewport */ void IrrDriver::computeMatrixesAndCameras(scene::ICameraSceneNode * const camnode, size_t width, size_t height) { if (CVS->isSDSMEnabled()) UpdateSplitAndLightcoordRangeFromComputeShaders(width, height); static_cast<scene::CSceneManager *>(m_scene_manager)->OnAnimate(os::Timer::getTime()); camnode->render(); irr_driver->setProjMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION)); irr_driver->setViewMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW)); irr_driver->genProjViewMatrix(); m_current_screen_size = core::vector2df(float(width), float(height)); const float oldfar = camnode->getFarValue(); const float oldnear = camnode->getNearValue(); float FarValues[] = { shadowSplit[1], shadowSplit[2], shadowSplit[3], shadowSplit[4], }; float NearValues[] = { shadowSplit[0], shadowSplit[1], shadowSplit[2], shadowSplit[3] }; float tmp[16 * 9 + 2]; memcpy(tmp, irr_driver->getViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[16], irr_driver->getProjMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[32], irr_driver->getInvViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[48], irr_driver->getInvProjMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[64], irr_driver->getProjViewMatrix().pointer(), 16 * sizeof(float)); m_suncam->render(); for (unsigned i = 0; i < 4; i++) { if (m_shadow_camnodes[i]) delete m_shadow_camnodes[i]; m_shadow_camnodes[i] = (scene::ICameraSceneNode *) m_suncam->clone(); } sun_ortho_matrix.clear(); const core::matrix4 &SunCamViewMatrix = m_suncam->getViewMatrix(); if (World::getWorld() && World::getWorld()->getTrack()) { // Compute track extent btVector3 btmin, btmax; if (World::getWorld()->getTrack()->getPtrTriangleMesh()) { World::getWorld()->getTrack()->getTriangleMesh().getCollisionShape().getAabb(btTransform::getIdentity(), btmin, btmax); } const Vec3 vmin = btmin, vmax = btmax; core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() - core::vector3df(0, 30, 0)); // Shadow Matrixes and cameras for (unsigned i = 0; i < 4; i++) { core::matrix4 tmp_matrix; camnode->setFarValue(FarValues[i]); camnode->setNearValue(NearValues[i]); camnode->render(); const scene::SViewFrustum *frustrum = camnode->getViewFrustum(); float tmp[24] = { frustrum->getFarLeftDown().X, frustrum->getFarLeftDown().Y, frustrum->getFarLeftDown().Z, frustrum->getFarLeftUp().X, frustrum->getFarLeftUp().Y, frustrum->getFarLeftUp().Z, frustrum->getFarRightDown().X, frustrum->getFarRightDown().Y, frustrum->getFarRightDown().Z, frustrum->getFarRightUp().X, frustrum->getFarRightUp().Y, frustrum->getFarRightUp().Z, frustrum->getNearLeftDown().X, frustrum->getNearLeftDown().Y, frustrum->getNearLeftDown().Z, frustrum->getNearLeftUp().X, frustrum->getNearLeftUp().Y, frustrum->getNearLeftUp().Z, frustrum->getNearRightDown().X, frustrum->getNearRightDown().Y, frustrum->getNearRightDown().Z, frustrum->getNearRightUp().X, frustrum->getNearRightUp().Y, frustrum->getNearRightUp().Z, }; memcpy(m_shadows_cam[i], tmp, 24 * sizeof(float)); std::vector<vector3df> vectors = getFrustrumVertex(*frustrum); tmp_matrix = getTighestFitOrthoProj(SunCamViewMatrix, vectors, m_shadow_scales[i]); m_shadow_camnodes[i]->setProjectionMatrix(tmp_matrix, true); m_shadow_camnodes[i]->render(); sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW)); } // Rsm Matrix and camera if (!m_rsm_matrix_initialized) { if (trackbox.MinEdge.X != trackbox.MaxEdge.X && trackbox.MinEdge.Y != trackbox.MaxEdge.Y && // Cover the case where SunCamViewMatrix is null SunCamViewMatrix.getScale() != core::vector3df(0., 0., 0.)) { SunCamViewMatrix.transformBoxEx(trackbox); core::matrix4 tmp_matrix; tmp_matrix.buildProjectionMatrixOrthoLH(trackbox.MinEdge.X, trackbox.MaxEdge.X, trackbox.MaxEdge.Y, trackbox.MinEdge.Y, 30, trackbox.MaxEdge.Z); m_suncam->setProjectionMatrix(tmp_matrix, true); m_suncam->render(); } rsm_matrix = getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW); m_rsm_matrix_initialized = true; m_rsm_map_available = false; } rh_extend = core::vector3df(128, 64, 128); core::vector3df campos = camnode->getAbsolutePosition(); core::vector3df translation(8 * floor(campos.X / 8), 8 * floor(campos.Y / 8), 8 * floor(campos.Z / 8)); rh_matrix.setTranslation(translation); assert(sun_ortho_matrix.size() == 4); // reset normal camera camnode->setNearValue(oldnear); camnode->setFarValue(oldfar); camnode->render(); size_t size = irr_driver->getShadowViewProj().size(); for (unsigned i = 0; i < size; i++) memcpy(&tmp[16 * i + 80], irr_driver->getShadowViewProj()[i].pointer(), 16 * sizeof(float)); } tmp[144] = float(width); tmp[145] = float(height); glBindBuffer(GL_UNIFORM_BUFFER, SharedObject::ViewProjectionMatrixesUBO); if (CVS->isSDSMEnabled()) { glBufferSubData(GL_UNIFORM_BUFFER, 0, (16 * 5) * sizeof(float), tmp); glBufferSubData(GL_UNIFORM_BUFFER, (16 * 9) * sizeof(float), 2 * sizeof(float), &tmp[144]); } else glBufferSubData(GL_UNIFORM_BUFFER, 0, (16 * 9 + 2) * sizeof(float), tmp); }
void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, size_t width, size_t height) { if (irr_driver->supportsSDSM()) UpdateSplitAndLightcoordRangeFromComputeShaders(width, height); static_cast<scene::CSceneManager *>(m_scene_manager)->OnAnimate(os::Timer::getTime()); camnode->render(); irr_driver->setProjMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_PROJECTION)); irr_driver->setViewMatrix(irr_driver->getVideoDriver()->getTransform(video::ETS_VIEW)); irr_driver->genProjViewMatrix(); m_current_screen_size = core::vector2df(float(width), float(height)); const float oldfar = camnode->getFarValue(); const float oldnear = camnode->getNearValue(); float FarValues[] = { shadowSplit[1], shadowSplit[2], shadowSplit[3], shadowSplit[4], }; float NearValues[] = { shadowSplit[0], shadowSplit[1], shadowSplit[2], shadowSplit[3] }; float tmp[16 * 9 + 2]; memcpy(tmp, irr_driver->getViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[16], irr_driver->getProjMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[32], irr_driver->getInvViewMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[48], irr_driver->getInvProjMatrix().pointer(), 16 * sizeof(float)); memcpy(&tmp[64], irr_driver->getProjViewMatrix().pointer(), 16 * sizeof(float)); m_suncam->render(); const core::vector3df &camdir = (camnode->getTarget() - camnode->getAbsolutePosition()).normalize(); const core::vector3df &sundir = (m_suncam->getTarget() - m_suncam->getAbsolutePosition()).normalize(); const core::vector3df &up = camdir.crossProduct(sundir).normalize(); if (up.getLength()) m_suncam->setUpVector(up); m_suncam->render(); for (unsigned i = 0; i < 4; i++) { if (m_shadow_camnodes[i]) delete m_shadow_camnodes[i]; m_shadow_camnodes[i] = (scene::ICameraSceneNode *) m_suncam->clone(); } const core::matrix4 &SunCamViewMatrix = m_suncam->getViewMatrix(); sun_ortho_matrix.clear(); if (World::getWorld() && World::getWorld()->getTrack()) { btVector3 btmin, btmax; if (World::getWorld()->getTrack()->getPtrTriangleMesh()) { World::getWorld()->getTrack()->getTriangleMesh().getCollisionShape().getAabb(btTransform::getIdentity(), btmin, btmax); } const Vec3 vmin = btmin , vmax = btmax; // Build the 3 ortho projection (for the 3 shadow resolution levels) for (unsigned i = 0; i < 4; i++) { if (!irr_driver->supportsSDSM()) { camnode->setFarValue(FarValues[i]); camnode->setNearValue(NearValues[i]); camnode->render(); } const scene::SViewFrustum *frustrum = camnode->getViewFrustum(); float tmp[24] = { frustrum->getFarLeftDown().X, frustrum->getFarLeftDown().Y, frustrum->getFarLeftDown().Z, frustrum->getFarLeftUp().X, frustrum->getFarLeftUp().Y, frustrum->getFarLeftUp().Z, frustrum->getFarRightDown().X, frustrum->getFarRightDown().Y, frustrum->getFarRightDown().Z, frustrum->getFarRightUp().X, frustrum->getFarRightUp().Y, frustrum->getFarRightUp().Z, frustrum->getNearLeftDown().X, frustrum->getNearLeftDown().Y, frustrum->getNearLeftDown().Z, frustrum->getNearLeftUp().X, frustrum->getNearLeftUp().Y, frustrum->getNearLeftUp().Z, frustrum->getNearRightDown().X, frustrum->getNearRightDown().Y, frustrum->getNearRightDown().Z, frustrum->getNearRightUp().X, frustrum->getNearRightUp().Y, frustrum->getNearRightUp().Z, }; memcpy(m_shadows_cam[i], tmp, 24 * sizeof(float)); const core::aabbox3df smallcambox = camnode-> getViewFrustum()->getBoundingBox(); core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() - core::vector3df(0, 30, 0)); // Set up a nice ortho projection that contains our camera frustum core::aabbox3df box = smallcambox; box = box.intersect(trackbox); std::vector<vector3df> vectors; vectors.push_back(frustrum->getFarLeftDown()); vectors.push_back(frustrum->getFarLeftUp()); vectors.push_back(frustrum->getFarRightDown()); vectors.push_back(frustrum->getFarRightUp()); vectors.push_back(frustrum->getNearLeftDown()); vectors.push_back(frustrum->getNearLeftUp()); vectors.push_back(frustrum->getNearRightDown()); vectors.push_back(frustrum->getNearRightUp()); core::matrix4 tmp_matrix; if (irr_driver->supportsSDSM()){ float left = float(CBB[currentCBB][i].xmin / 4 - 2); float right = float(CBB[currentCBB][i].xmax / 4 + 2); float up = float(CBB[currentCBB][i].ymin / 4 - 2); float down = float(CBB[currentCBB][i].ymax / 4 + 2); // Prevent Matrix without extend if (left != right && up != down) { tmp_matrix.buildProjectionMatrixOrthoLH(left, right, down, up, float(CBB[currentCBB][i].zmin / 4 - 100), float(CBB[currentCBB][i].zmax / 4 + 2)); m_shadow_scales[i] = std::make_pair(right - left, down - up); } } else tmp_matrix = getTighestFitOrthoProj(SunCamViewMatrix, vectors, m_shadow_scales[i]); m_shadow_camnodes[i]->setProjectionMatrix(tmp_matrix , true); m_shadow_camnodes[i]->render(); sun_ortho_matrix.push_back(getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW)); } if (!m_rsm_matrix_initialized) { core::aabbox3df trackbox(vmin.toIrrVector(), vmax.toIrrVector() - core::vector3df(0, 30, 0)); if (trackbox.MinEdge.X != trackbox.MaxEdge.X && trackbox.MinEdge.Y != trackbox.MaxEdge.Y && // Cover the case where SunCamViewMatrix is null SunCamViewMatrix.getScale() != core::vector3df(0., 0., 0.)) { SunCamViewMatrix.transformBoxEx(trackbox); core::matrix4 tmp_matrix; tmp_matrix.buildProjectionMatrixOrthoLH(trackbox.MinEdge.X, trackbox.MaxEdge.X, trackbox.MaxEdge.Y, trackbox.MinEdge.Y, 30, trackbox.MaxEdge.Z); m_suncam->setProjectionMatrix(tmp_matrix, true); m_suncam->render(); } rsm_matrix = getVideoDriver()->getTransform(video::ETS_PROJECTION) * getVideoDriver()->getTransform(video::ETS_VIEW); m_rsm_matrix_initialized = true; m_rsm_map_available = false; } rh_extend = core::vector3df(128, 64, 128); core::vector3df campos = camnode->getAbsolutePosition(); core::vector3df translation(8 * floor(campos.X / 8), 8 * floor(campos.Y / 8), 8 * floor(campos.Z / 8)); rh_matrix.setTranslation(translation); assert(sun_ortho_matrix.size() == 4); camnode->setNearValue(oldnear); camnode->setFarValue(oldfar); camnode->render(); size_t size = irr_driver->getShadowViewProj().size(); for (unsigned i = 0; i < size; i++) memcpy(&tmp[16 * i + 80], irr_driver->getShadowViewProj()[i].pointer(), 16 * sizeof(float)); } tmp[144] = float(width); tmp[145] = float(height); glBindBuffer(GL_UNIFORM_BUFFER, SharedObject::ViewProjectionMatrixesUBO); glBufferSubData(GL_UNIFORM_BUFFER, 0, (16 * 9 + 2) * sizeof(float), tmp); }