void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, float nearDepth, float farDepth) { assert(nearDepth < farDepth); // Orient the keylight frustum const auto& direction = glm::normalize(_light->getDirection()); glm::quat orientation; if (direction == IDENTITY_UP) { orientation = glm::quat(glm::mat3(-IDENTITY_RIGHT, IDENTITY_FRONT, -IDENTITY_UP)); } else if (direction == -IDENTITY_UP) { orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_FRONT, IDENTITY_UP)); } else { auto side = glm::normalize(glm::cross(direction, IDENTITY_UP)); auto up = glm::normalize(glm::cross(side, direction)); orientation = glm::quat_cast(glm::mat3(side, up, -direction)); } _frustum->setOrientation(orientation); // Position the keylight frustum _frustum->setPosition(viewFrustum.getPosition() - (nearDepth + farDepth)*direction); const Transform view{ _frustum->getView()}; const Transform viewInverse{ view.getInverseMatrix() }; auto nearCorners = viewFrustum.getCorners(nearDepth); auto farCorners = viewFrustum.getCorners(farDepth); vec3 min{ viewInverse.transform(nearCorners.bottomLeft) }; vec3 max{ min }; // Expand keylight frustum to fit view frustum auto fitFrustum = [&min, &max, &viewInverse](const vec3& viewCorner) { const auto corner = viewInverse.transform(viewCorner); min.x = glm::min(min.x, corner.x); min.y = glm::min(min.y, corner.y); min.z = glm::min(min.z, corner.z); max.x = glm::max(max.x, corner.x); max.y = glm::max(max.y, corner.y); max.z = glm::max(max.z, corner.z); }; fitFrustum(nearCorners.bottomRight); fitFrustum(nearCorners.topLeft); fitFrustum(nearCorners.topRight); fitFrustum(farCorners.bottomLeft); fitFrustum(farCorners.bottomRight); fitFrustum(farCorners.topLeft); fitFrustum(farCorners.topRight); glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, -max.z, -min.z); _frustum->setProjection(ortho); // Calculate the frustum's internal state _frustum->calculate(); // Update the buffer _schemaBuffer.edit<Schema>().projection = ortho; _schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix(); }
QVariantMap Camera::getViewFrustum() { ViewFrustum frustum; loadViewFrustum(frustum); QVariantMap result; result["position"].setValue(frustum.getPosition()); result["orientation"].setValue(frustum.getOrientation()); result["projection"].setValue(frustum.getProjection()); result["centerRadius"].setValue(frustum.getCenterRadius()); result["fieldOfView"].setValue(frustum.getFieldOfView()); result["aspectRatio"].setValue(frustum.getAspectRatio()); return result; }
int ItemSpatialTree::selectCells(CellSelection& selection, const ViewFrustum& frustum, float lodAngle) const { auto worldPlanes = frustum.getPlanes(); FrustumSelector selector; for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) { ::Plane octPlane; octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH)); selector.frustum[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient()); } selector.eyePos = evalCoordf(frustum.getPosition(), ROOT_DEPTH); selector.setAngle(glm::radians(lodAngle)); return Octree::select(selection, selector); }
void ConicalViewFrustum::set(const ViewFrustum& viewFrustum) { // The ConicalViewFrustum has two parts: a central sphere (same as ViewFrustum) and a circular cone that bounds the frustum part. // Why? Because approximate intersection tests are much faster to compute for a cone than for a frustum. _position = viewFrustum.getPosition(); _radius = viewFrustum.getCenterRadius(); _farClip = viewFrustum.getFarClip(); auto topLeft = viewFrustum.getNearTopLeft() - _position; auto topRight = viewFrustum.getNearTopRight() - _position; auto bottomLeft = viewFrustum.getNearBottomLeft() - _position; auto bottomRight = viewFrustum.getNearBottomRight() - _position; auto centerAxis = 0.25f * (topLeft + topRight + bottomLeft + bottomRight); // Take the average _direction = glm::normalize(centerAxis); _angle = std::max(std::max(angleBetween(_direction, topLeft), angleBetween(_direction, topRight)), std::max(angleBetween(_direction, bottomLeft), angleBetween(_direction, bottomRight))); }
float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const { glm::vec3 center = _cube.calcCenter(); glm::vec3 temp = viewFrustum.getPosition() - center; float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp)); return distanceToVoxelCenter; }
// Calculates the distance to the furthest point of the voxel to the camera // does as much math as possible in voxel scale and then scales up to TREE_SCALE at end float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const { glm::vec3 furthestPoint; viewFrustum.getFurthestPointFromCamera(_cube, furthestPoint); glm::vec3 temp = viewFrustum.getPosition() - furthestPoint; return sqrtf(glm::dot(temp, temp)); }