void Frustum::Enclose(const Frustum& other) { vec3 n = glm::normalize(other._origin - other._at); vec3 u = glm::normalize(cross(other._up, n)); vec3 v = glm::normalize(cross(n, u)); if (_type == Projection::PERSPECTIVE) Orient(_origin, other.GetCenter(), _up); mat4 m = GetViewMatrix(); vec3 p[8]; if (other._type == Projection::PERSPECTIVE) { float dy = other._near * tanf(radians(other._fovy) / 2.0f); float dx = other._ar * dy; vec3 c = other._origin - n * other._near; p[0] = c + u * dx + v * dy; p[1] = c - u * dx + v * dy; p[2] = c - u * dx - v * dy; p[3] = c + u * dx - v * dy; dy = other._far * tanf(glm::radians(other._fovy) / 2.0f); dx = other._ar * dy; c = other._origin - n * other._far; p[4] = c + u * dx + v * dy; p[5] = c - u * dx + v * dy; p[6] = c - u * dx - v * dy; p[7] = c + u * dx - v * dy; } else { vec3 c = other._origin - n * other._near; p[0] = c + u * other._xmax + v * other._ymax; p[1] = c + u * other._xmax + v * other._ymin; p[2] = c + u * other._xmin + v * other._ymax; p[3] = c + u * other._xmin + v * other._ymin; c = other._origin - n * other._far; p[4] = c + u * other._xmax + v * other._ymax; p[5] = c + u * other._xmax + v * other._ymin; p[6] = c + u * other._xmin + v * other._ymax; p[7] = c + u * other._xmin + v * other._ymin; } if (_type == Projection::PERSPECTIVE) { _fovy = 0.0f; _far = 0.0f; _near = std::numeric_limits<float>::max(); float maxHorizAngle = 0.0f; for (int i = 0; i < 8; i++) { vec4 pt = m * vec4(p[i], 1.0f); if (pt.z < 0.0f) { float d = -pt.z; float angle = atanf(fabs(pt.x) / d); if (angle > maxHorizAngle) maxHorizAngle = angle; angle = glm::degrees(atanf(fabs(pt.y) / d)); if (angle * 2.0f > _fovy) _fovy = angle * 2.0f; if (_near > d) _near = d; if (_far < d) _far = d; } } float h = (_near * tanf(glm::radians(_fovy) / 2.0f))*2.0f; float w = (_near * tanf(maxHorizAngle)) * 2.0f; _ar = w / h; } else { _xmin = _ymin = _near = std::numeric_limits<float>::max(); _xmax = _ymax = _far = std::numeric_limits<float>::min(); for (int i = 0; i < 8; i++) { vec4 pt = m * vec4(p[i], 1.0f); if (_xmin > pt.x) _xmin = pt.x; if (_xmax < pt.x) _xmax = pt.x; if (_ymin > pt.y) _ymin = pt.y; if (_ymax < pt.y) _ymax = pt.y; if (_near > -pt.z) _near = -pt.z; if (_far < -pt.z) _far = -pt.z; } } }