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); }
/* * 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; }