/* * 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; }
/* * Matrix4_Modelview */ void Matrix4_Modelview( const vec3_t viewOrg, const mat3_t viewAxis, mat4_t m ) { mat3_t axis; mat4_t flip, view; #if 0 Matrix4_Identity( flip ); Matrix4_Rotate( flip, -90, 1, 0, 0 ); Matrix4_Rotate( flip, 90, 0, 0, 1 ); #else Vector4Set( &flip[0], 0, 0, -1, 0 ); Vector4Set( &flip[4], -1, 0, 0, 0 ); Vector4Set( &flip[8], 0, 1, 0, 0 ); Vector4Set( &flip[12], 0, 0, 0, 1 ); #endif Matrix3_Copy( viewAxis, axis ); view[0 ] = axis[0]; view[4 ] = axis[1]; view[8 ] = axis[2]; view[12] = -viewOrg[0] * view[0] + -viewOrg[1] * view[4] + -viewOrg[2] * view[8]; view[1 ] = axis[3]; view[5 ] = axis[4]; view[9 ] = axis[5]; view[13] = -viewOrg[0] * view[1] + -viewOrg[1] * view[5] + -viewOrg[2] * view[9]; view[2 ] = axis[6]; view[6 ] = axis[7]; view[10] = axis[8]; view[14] = -viewOrg[0] * view[2] + -viewOrg[1] * view[6] + -viewOrg[2] * view[10]; view[3] = 0; view[7] = 0; view[11] = 0; view[15] = 1; Matrix4_Multiply( flip, view, m ); }
/* * RB_LoadProjectionMatrix */ void RB_LoadProjectionMatrix( const mat4_t m ) { Matrix4_Copy( m, rb.projectionMatrix ); Matrix4_Multiply( m, rb.modelviewMatrix, rb.modelviewProjectionMatrix ); }
/* * RB_LoadObjectMatrix */ void RB_LoadObjectMatrix( const mat4_t m ) { Matrix4_Copy( m, rb.objectMatrix ); Matrix4_MultiplyFast( rb.cameraMatrix, m, rb.modelviewMatrix ); Matrix4_Multiply( rb.projectionMatrix, rb.modelviewMatrix, rb.modelviewProjectionMatrix ); }
/* * 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; }