/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// //@cpp #include "gtp_shader_opticsutil.h" #include "../../../util/math/util_geo_types.h" /////////////////////////////////////////////////////////////////////////////// bool gtp_ShaderOpticsUtil::CalcViewNormalDist( s3d_CUtilVec3f &ViewNormal, float &ViewDist, s3d_CUtilTranslQuatf_cr ViewTransf) { if(ViewTransf.m_Quat == 0) return false; // Clip plane is local z-plane. s3d_CUtilVec3f LocalNormal = s3d_CUtilVec3f(0, 0, 1); // Clip plane in view coordinates. Plane equation is: // Point * ViewNormal + ViewDist = 0. s3d_CUtilMat3x3f TransfMat = ViewTransf.m_Quat.GetMat(); ViewNormal = (TransfMat * LocalNormal).GetNormalized(); ViewDist = - ViewNormal * ViewTransf.m_Transl; // Front side visible?: return ViewDist > 0; } bool gtp_ShaderOpticsUtil::CalcChildCamFull( s3d_CEngGfxCam &ChildCam, void *Exclude, int MaxRecursion, float Coeff, float Precision, bool UseCompactFrustum, s3d_CEngShaderScope *Scope, s3d_CUtilTranslQuatf_cr ViewTransf, s3d_CUtilVec3f_cr ViewNormal, float ViewDist) { s3d_CEngGfxPortion *Portion = Scope->m_Portion; // Check recursion level: if(Portion->m_Cam.m_Recursion >= MaxRecursion) return false; s3d_CUtilTranslQuatf RecTransf = Portion->m_Cam.m_Transf; bool RecReverse = Portion->m_Cam.m_Reverse; s3d_CUtilMat4x4f RecProj = Portion->m_Cam.m_Proj; s3d_CUtilVec4f RecClipPlane; RecClipPlane.m_x = - ViewNormal.m_x; RecClipPlane.m_y = - ViewNormal.m_y; RecClipPlane.m_z = - ViewNormal.m_z; RecClipPlane.m_w = - ViewDist; if(Coeff != 0 && Coeff != 1) { // Calculate extra transformation in view coordinates: float Change = Coeff - 1; // (Assuming that normal vector is normalized:) // NewPoint // = Point + Point-To-Plane-Distance * (ViewNormal * Change) // = Point + (Point * ViewNormal + ViewDist) * (ViewNormal * Change) // = (I + ViewNormal (x) ViewNormal * Change) * Point // + ViewNormal * (ViewDist * Change) // =: ExtraMat * Point + ExtraTransl s3d_CUtilMat3x3f ExtraMat(s3d_CUtilMat3x3f(1) + s3d_CUtilMat3x3f::ByTensorProd( ViewNormal, ViewNormal * Change)); s3d_CUtilVec3f ExtraTransl(ViewNormal * (ViewDist * Change)); // PartQuat maps the view z into the reflected view z: s3d_CUtilVec3f BeforeDirZ(0, 0, 1); s3d_CUtilVec3f AppliedDirZ = ExtraMat.GetColZ().GetNormalized(); s3d_CUtilVec3f DirY(0, 1, 0); s3d_CUtilQuatf PartQuat = s3d_CUtilQuatf::ByPathAlso( AppliedDirZ, BeforeDirZ, DirY, DirY); // (ExtraTransl, ExtraMat) // := (0, RestMat) x (PartTransl, PartQuat) // = (RestMat * PartTransl, RestMat * PartQuat) s3d_CUtilMat3x3f RestMat = ExtraMat * PartQuat.GetInvMat(); s3d_CUtilVec3f PartTransl = RestMat.GetInv() * ExtraTransl; s3d_CUtilTranslQuatf PartTransf(PartTransl, PartQuat); // Apply: RecTransf = RecTransf.ConcatInv(PartTransf); RecProj = s3d_CUtilGeof::ConcatMapTranslMat3(RecProj, 0, RestMat); RecClipPlane = RecClipPlane * s3d_CUtilGeof::GetMapOfInvTransf3(PartTransf); if(Coeff < 0) { RecClipPlane = - RecClipPlane; RecReverse = !RecReverse; } } if(UseCompactFrustum) { // Use the near clipping plane as mirror clipping plane. // // Clipping plane condition: // -> (NewProj * P).z >= - (NewProj * P).w // -> (NewProj.z? + NewProj.w?) * P >= 0 // Only modify Proj.z? // -> (NewProj.z? + Proj.w?) * P >= 0 // // Plane: // -> Plane * P >= 0 // -> NewProj.z? + NewProj.w? = Plane * Fac // -> NewProj.z? = Plane * Fac - Proj.w? // // Choose far clipping plane to include FarPoint // (typically choose plane dir infinity): // NewProj * FarPoint = ~ (0, 0, 1, 1) // -> NewProj.z? * FarPoint = NewProj.w? * FarPoint // -> [Plane * Fac - Proj.w?] * FarPoint = Proj.w? * FarPoint // -> Fac = (Proj.w? * FarPoint * 2) / (Plane * FarPoint) // // Choose FarPoint at infinity in that way // that the complete old frustum is included. // For this, select one frustum vertex at infinity // depending on the plane slope signs. s3d_CUtilVec4f FarPoint( s3d_SysSign(RecClipPlane.m_x), s3d_SysSign(RecClipPlane.m_y), 1, 0); s3d_CUtilVec4f RecProjRowW = RecProj.GetRowW(); float PlaneFac = ((RecProjRowW * FarPoint) * 2) / (RecClipPlane * FarPoint); RecProj.SetRowZ(RecClipPlane * PlaneFac - RecProjRowW); RecClipPlane = 0; } s3d_CUtilVec3f WorldTransl = Portion->m_Cam.m_Transf.ApplyToPoint(ViewTransf.m_Transl); // New camera structure: ChildCam = Portion->m_Cam; ChildCam.m_Exclude = Exclude; ChildCam.m_Recursion = Portion->m_Cam.m_Recursion + 1; ChildCam.m_VisibPoint = WorldTransl; ChildCam.m_Transf = RecTransf; ChildCam.m_Proj = RecProj; ChildCam.m_Reverse = RecReverse; if(Precision > 0) { ChildCam.m_CullPix *= Precision; ChildCam.m_MeshPix *= Precision; ChildCam.m_VisibMeshPix *= Precision; } return true; } bool gtp_ShaderOpticsUtil::CalcChildRange( s3d_CUtilVec3f &SubNeg, s3d_CUtilVec3f &SubPos, s3d_CUtilTranslQuatf_cr ViewTransf, s3d_CUtilVec3f_cr BoundCen, s3d_CUtilVec3f_cr BoundExt, s3d_CEngShaderScope *Scope) { s3d_CEngGfxPortion *Portion = Scope->m_Portion; // Calculate bounding rectangle in screen coordinates: s3d_CUtilMat3x3f TransfMat = ViewTransf.m_Quat.GetMat(); s3d_CUtilVec3f ViewBoundCen = ViewTransf.m_Transl + TransfMat * BoundCen; s3d_CUtilMat3x3f ViewBoundExt = TransfMat.ColGetScaled(BoundExt); s3d_CUtilMat4x4f TotalBoundMap = s3d_CUtilGeof::ConcatMapTranslMat3( Portion->m_Cam.m_Proj, ViewBoundCen, ViewBoundExt); s3d_CUtilVec3f MapMin, MapMax; s3d_CUtilGeof::CalcRangeMapMinusPlusOne3( MapMin, MapMax, -1, +1, TotalBoundMap); MapMin.m_z = -1; // Keep near plane to avoid problems with linked cam. MapMax.m_z = 1; // Look to infinity. if(MapMin.IsAnyCompGe(MapMax)) return false; // Calculate new rendering target rectangle: SubNeg = (MapMin + s3d_CUtilVec3f(1)) * 0.5f; SubPos = (MapMax + s3d_CUtilVec3f(1)) * 0.5f; return true; } void gtp_ShaderOpticsUtil::SnapChildRange( s3d_CUtilVec3f &SubNeg, s3d_CUtilVec3f &SubPos, int SnapWidth, int SnapHeight) { S3D_SYS_ASSERT(SnapWidth > 0 && SnapHeight > 0); float RcpSnapWidth = 1.0f / SnapWidth; float RcpSnapHeight = 1.0f / SnapHeight; SubNeg.m_x = s3d_SysRoundFloor(SubNeg.m_x * SnapWidth) * RcpSnapWidth; SubPos.m_x = s3d_SysRoundCeil(SubPos.m_x * SnapWidth) * RcpSnapWidth; SubNeg.m_y = s3d_SysRoundFloor(SubNeg.m_y * SnapHeight) * RcpSnapHeight; SubPos.m_y = s3d_SysRoundCeil(SubPos.m_y * SnapHeight) * RcpSnapHeight; } void gtp_ShaderOpticsUtil::ApplyRangeToChildCam( s3d_CEngGfxCam &ChildCam, s3d_CUtilMat4x4f &BaseProj, s3d_CUtilVec3f_cr SubNeg, s3d_CUtilVec3f_cr SubPos) { s3d_CUtilVec3f SubDelta = SubPos - SubNeg; s3d_CUtilVec3f SubSum = SubPos + SubNeg; // Calculate new target matrix: s3d_CUtilVec2f SubNegXY(SubNeg.m_x, SubNeg.m_y); s3d_CUtilVec2f SubDeltaXY(SubDelta.m_x, SubDelta.m_y); ChildCam.m_ViewPane.m_Transl = ChildCam.m_ViewPane.m_Transl + SubNegXY.CompMul(ChildCam.m_ViewPane.m_Scale); ChildCam.m_ViewPane.m_Scale = SubDeltaXY.CompMul(ChildCam.m_ViewPane.m_Scale); float ViewDepthDelta = ChildCam.m_ViewDepthEnd - ChildCam.m_ViewDepthStart; ChildCam.m_ViewDepthStart = ChildCam.m_ViewDepthStart + ViewDepthDelta * SubNeg.m_z; // Calculate new projection matrix: s3d_CUtilVec3f ScrScal = s3d_CUtilVec3f(1).CompDiv(SubDelta); s3d_CUtilVec3f ScrOffs = (s3d_CUtilVec3f(1) - SubSum).CompMul(ScrScal); s3d_CUtilMat4x4f ExtraProj = 1; ExtraProj.m_xx = ScrScal.m_x; ExtraProj.m_yy = ScrScal.m_y; ExtraProj.m_zz = ScrScal.m_z; ExtraProj.m_xw = ScrOffs.m_x; ExtraProj.m_yw = ScrOffs.m_y; ExtraProj.m_zw = ScrOffs.m_z; ChildCam.m_Proj = ExtraProj * ChildCam.m_Proj; BaseProj = ExtraProj * BaseProj; } int gtp_ShaderOpticsUtil::RoundToPowerOfTwoDown(int x) { x |= (x >> 16); x |= (x >> 8); x |= (x >> 4); x |= (x >> 2); x |= (x >> 1); return x & ~(x >> 1); } int gtp_ShaderOpticsUtil::RoundToPowerOfTwoUp(int x) { return RoundToPowerOfTwoDown((x << 1) - 1); } ///////////////////////////////////////////////////////////////////////////////