Ejemplo n.º 1
0
/*
* Matrix4_ObliqueNearClipping
*
* Lengyel, Eric. "Oblique View Frustum Depth Projection and Clipping"
* Journal of Game Development, Vol. 1, No. 2 (2005), Charles River Media, pp. 5–16.
*
* Version that works both for perspective and orthographic projections.
*/
void Matrix4_ObliqueNearClipping( const vec3_t normal, const vec_t dist, const mat4_t cm, mat4_t pm )
{
	mat4_t tm1, tm2;
    vec4_t c, q, p;
	vec_t d;

	// The clipping plane in object coordinates
	q[0] = normal[0];
	q[1] = normal[1];
	q[2] = normal[2];
	q[3] = dist;

	// The plane is transformed by the transpose of the inverse of the
	// camera matrix and stored in the resulting eye coordinates
	Matrix4_Invert( cm, tm1 );
	Matrix4_Transpose( tm1, tm2 );
	Matrix4_Multiply_Vector( tm2, q, c );

	if( c[3] >= 0.0f ) {
		// the techinique only works when the w-coordinate is negative
		// (corresponding to the camera being on the negative side of the plane)
		return;
	}

	// Calculate the clip-space corner point opposite the clipping plane
	// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
	// transform it into camera space by multiplying it
	// by the inverse of the projection matrix

	p[0] = Q_sign(c[0]);
	p[1] = Q_sign(c[1]);
	p[2] = 1.0f;
	p[3] = 1.0f;

    // Calculate the scaled plane vector
	Matrix4_Invert( pm, tm1 );
	Matrix4_Multiply_Vector( tm1, p, q );
	d = 2.0f / (c[0] * q[0] + c[1] * q[1] + c[2] * q[2] + c[3] * q[3]);

    // Replace the third row of the projection matrix
    pm[ 2] = c[0] * d - pm[ 3];
    pm[ 6] = c[1] * d - pm[ 7];
    pm[10] = c[2] * d - pm[11];
    pm[14] = c[3] * d - pm[15];
}
Ejemplo n.º 2
0
/*
* RB_ScissorForBounds
*/
bool RB_ScissorForBounds( vec3_t bbox[8], int *x, int *y, int *w, int *h )
{
    int i;
    int ix1, iy1, ix2, iy2;
    float x1, y1, x2, y2;
    vec4_t corner = { 0, 0, 0, 1 }, proj = { 0, 0, 0, 1 }, v = { 0, 0, 0, 1 };
    mat4_t cameraProjectionMatrix;

    Matrix4_Multiply( rb.projectionMatrix, rb.cameraMatrix, cameraProjectionMatrix );

    x1 = y1 = 999999;
    x2 = y2 = -999999;
    for( i = 0; i < 8; i++ )
    {
        // compute and rotate the full bounding box
        VectorCopy( bbox[i], corner );

        Matrix4_Multiply_Vector( cameraProjectionMatrix, corner, proj );

        if( proj[3] ) {
            v[0] = ( proj[0] / proj[3] + 1.0f ) * 0.5f * rb.gl.viewport[2];
            v[1] = ( proj[1] / proj[3] + 1.0f ) * 0.5f * rb.gl.viewport[3];
            v[2] = ( proj[2] / proj[3] + 1.0f ) * 0.5f; // [-1..1] -> [0..1]
        } else {
            v[0] = 999999.0f;
            v[1] = 999999.0f;
            v[2] = 999999.0f;
        }

        x1 = min( x1, v[0] );
        y1 = min( y1, v[1] );
        x2 = max( x2, v[0] );
        y2 = max( y2, v[1] );
    }

    ix1 = max( x1 - 1.0f, 0 );
    ix2 = min( x2 + 1.0f, rb.gl.viewport[2] );
    if( ix1 >= ix2 )
        return false; // FIXME

    iy1 = max( y1 - 1.0f, 0 );
    iy2 = min( y2 + 1.0f, rb.gl.viewport[3] );
    if( iy1 >= iy2 )
        return false; // FIXME

    *x = ix1;
    *y = rb.gl.viewport[3] - iy2;
    *w = ix2 - ix1;
    *h = iy2 - iy1;

    return true;
}
Ejemplo n.º 3
0
void RF_TransformVectorToScreen( const refdef_t *rd, const vec3_t in, vec2_t out )
{
	mat4_t p, m;
	vec4_t temp, temp2;
 	
	if( !rd || !in || !out )
		return;
 	
	temp[0] = in[0];
	temp[1] = in[1];
	temp[2] = in[2];
	temp[3] = 1.0f;
 	
	if( rd->rdflags & RDF_USEORTHO ) {
		Matrix4_OrthogonalProjection( rd->ortho_x, rd->ortho_x, rd->ortho_y, rd->ortho_y,
			-4096.0f, 4096.0f, p );
	}
	else {
		Matrix4_InfinitePerspectiveProjection( rd->fov_x, rd->fov_y, Z_NEAR, rrf.cameraSeparation,
			p, glConfig.depthEpsilon );
	}
 	
	if( rd->rdflags & RDF_FLIPPED ) {
		p[0] = -p[0];
	}
 	
	Matrix4_Modelview( rd->vieworg, rd->viewaxis, m );
 	
	Matrix4_Multiply_Vector( m, temp, temp2 );
	Matrix4_Multiply_Vector( p, temp2, temp );
 	
	if( !temp[3] )
 		return;
 	
	out[0] = rd->x + ( temp[0] / temp[3] + 1.0f ) * rd->width * 0.5f;
	out[1] = glConfig.height - (rd->y + ( temp[1] / temp[3] + 1.0f ) * rd->height * 0.5f);
}
Ejemplo n.º 4
0
/*
* R_FitOccluder
*
* returns farclip value
*/
static float R_FitOccluder( const shadowGroup_t *group, refdef_t *refdef ) {
	int i;
	float x1, x2, y1, y2, z1, z2;
	int ix1, ix2, iy1, iy2, iz1, iz2;
	int sizex = refdef->width, sizey = refdef->height;
	int diffx, diffy;
	mat4_t cameraMatrix, projectionMatrix, cameraProjectionMatrix;
	bool useOrtho = refdef->rdflags & RDF_USEORTHO ? true : false;

	Matrix4_Modelview( refdef->vieworg, refdef->viewaxis, cameraMatrix );

	// use current view settings for first approximation
	if( useOrtho ) {
		Matrix4_OrthogonalProjection( -refdef->ortho_x, refdef->ortho_x, -refdef->ortho_y, refdef->ortho_y,
									  -group->projDist, group->projDist, projectionMatrix );
	} else {
		Matrix4_PerspectiveProjection( refdef->fov_x, refdef->fov_y,
									   Z_NEAR, group->projDist, rf.cameraSeparation, projectionMatrix );
	}

	Matrix4_Multiply( projectionMatrix, cameraMatrix, cameraProjectionMatrix );

	// compute optimal fov to increase depth precision (so that shadow group objects are
	// as close to the nearplane as possible)
	// note that it's suboptimal to use bbox calculated in worldspace (FIXME)
	x1 = y1 = z1 = 999999;
	x2 = y2 = z2 = -999999;
	for( i = 0; i < 8; i++ ) {
		// compute and rotate a full bounding box
		vec3_t v;
		vec4_t temp, temp2;

		temp[0] = ( ( i & 1 ) ? group->mins[0] : group->maxs[0] );
		temp[1] = ( ( i & 2 ) ? group->mins[1] : group->maxs[1] );
		temp[2] = ( ( i & 4 ) ? group->mins[2] : group->maxs[2] );
		temp[3] = 1.0f;

		// transform to screen space
		Matrix4_Multiply_Vector( cameraProjectionMatrix, temp, temp2 );

		if( temp2[3] ) {
			v[0] = ( temp2[0] / temp2[3] + 1.0f ) * 0.5f * refdef->width;
			v[1] = ( temp2[1] / temp2[3] + 1.0f ) * 0.5f * refdef->height;
			v[2] = ( temp2[2] / temp2[3] + 1.0f ) * 0.5f * group->projDist;
		} else {
			v[0] = 999999;
			v[1] = 999999;
			v[2] = 999999;
		}

		x1 = min( x1, v[0] ); y1 = min( y1, v[1] ); z1 = min( z1, v[2] );
		x2 = max( x2, v[0] ); y2 = max( y2, v[1] ); z2 = max( z2, v[2] );
	}

	// give it 1 pixel gap on both sides
	ix1 = x1 - 1.0f; ix2 = x2 + 1.0f;
	iy1 = y1 - 1.0f; iy2 = y2 + 1.0f;
	iz1 = z1 - 1.0f; iz2 = z2 + 1.0f;

	diffx = sizex - min( ix1, sizex - ix2 ) * 2;
	diffy = sizey - min( iy1, sizey - iy2 ) * 2;

	// adjust fov (for perspective projection)
	refdef->fov_x = 2 * RAD2DEG( atan( (float)diffx / (float)sizex ) );
	refdef->fov_y = 2 * RAD2DEG( atan( (float)diffy / (float)sizey ) );

	// adjust ortho clipping settings
	refdef->ortho_x = ix2 - ix1 + SHADOWMAP_ORTHO_NUDGE;
	refdef->ortho_y = iy2 - iy1 + SHADOWMAP_ORTHO_NUDGE;

	return useOrtho ? max( iz1, iz2 ) : group->projDist;
}