Exemplo n.º 1
0
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;
        }
    }
}