UnrealScript only code for rendering view weapon at a different fov over DrawClippedActor Limitation: DrawClippedActor will use Viewspace Location as Worldspace Location as far as lighting is concerned. So best one can do is to use AIGetLightLevel to modify unlit brightness of weapon. You need to replace all ConvertVectorToCoordinates functions as DrawClippedActor will mess with rootframes Coords/Uncoords. --han 2021 ---------------------------------- // PawnOwner.Default.FovAngle == 75 simulated function Vector CalcViewspaceDrawOffset( float FovAngle ) { local Vector WorldspaceWeaponBob; local Vector ViewspaceWeaponBob; local Vector ViewspaceWeaponViewOffset; local float WeaponViewOffsetScale; local Pawn PawnOwner; PawnOwner = Pawn(Owner); // Weapon offset. WeaponViewOffsetScale = 0.9/FovAngle; ViewspaceWeaponViewOffset = WeaponViewOffsetScale*PlayerViewOffset; // Dampened Bob. WorldspaceWeaponBob.X = (1.00-1.00*BobDamping)*PawnOwner.WalkBob.X; WorldspaceWeaponBob.Y = (1.00-1.00*BobDamping)*PawnOwner.WalkBob.Y; WorldspaceWeaponBob.Z = (0.55-0.55*BobDamping)*PawnOwner.WalkBob.Z; ViewspaceWeaponBob = WorldspaceWeaponBob< 0) && bDrawMuzzleFlash && Level.bHighDetailMode && (MFTexture != None) ) { MuzzleScale = Default.MuzzleScale * Canvas.ClipX/640.0; if ( !bSetFlashTime ) { bSetFlashTime = true; FlashTime = Level.TimeSeconds + FlashLength; } else if ( FlashTime < Level.TimeSeconds ) bMuzzleFlash = 0; if ( bMuzzleFlash > 0 ) { if ( Hand == 0 ) Canvas.SetPos(Canvas.ClipX/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipX * (-0.2 * Default.FireOffset.Y * FlashO), Canvas.ClipY/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipY * (FlashY + FlashC)); else Canvas.SetPos(Canvas.ClipX/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipX * (Hand * Default.FireOffset.Y * FlashO), Canvas.ClipY/2 - 0.5 * MuzzleScale * FlashS + Canvas.ClipY * FlashY); Canvas.Style = 3; Canvas.DrawIcon(MFTexture, MuzzleScale); Canvas.Style = 1; } } else bSetFlashTime = false; //FovAngle = PlayerOwner.Default.FovAngle; FovAngle = 75.0; //SetLocation( CalcViewspaceDrawOffset(FovAngle) ); SetLocation( CalcViewspaceDrawOffset(75.0) ); //NewRot = Pawn(Owner).ViewRotation; NewRot = rot(0,0,0); /* if ( Hand == 0 ) NewRot.Roll = -2.0 * Default.Rotation.Roll; else NewRot.Roll = Default.Rotation.Roll * Hand; */ SetRotation( NewRot ); // We place an imaginary 4:3 box whichs has 75 deg horizontal fov which touches the top and bottom on the viewport. BoxXL = Canvas.ClipY*4.0/3.0; // Afterwards we calculate the required horizontal fov for the actual viewport width to match this FovAngle = 360.0/Pi*atan( Canvas.ClipX/BoxXL*tan(Pi*FovAngle/360.0) ); // FOV is baed on Viewports.Actor.FovAngle. SavedFovAngle = Canvas.Viewport.Actor.FovAngle; if ( !bSticksAndStones ) { Canvas.Viewport.Actor.FovAngle = FovAngle; } // Estimate lighting using AIGetLightLevel. Scaleglow = 2.0*PlayerOwner.AIGetLightLevel( PlayerOwner.Location ); // !! PlayerOwner needs to be !bUnlit. AmbientGlow = 0; bUnlit = true; Canvas.DrawClippedActor( Self, false, Canvas.ClipX, Canvas.ClipY, Canvas.OrgX, Canvas.OrgY, false ); // Restore FovAngle. Canvas.Viewport.Actor.FovAngle = SavedFovAngle; // Reset Location to be close to player again. SetLocation( Owner.Location ); } ---------------------------------- // // Transform a Point by a coordinate system // final static function Vector TransformPointBy( Coords C, Vector P ) { local Vector Temp, Result; Temp = P-C.Origin; Result.X = Temp dot C.XAxis; Result.Y = Temp dot C.YAxis; Result.Z = Temp dot C.ZAxis; return Result; } // // Transform a directional vector by a coordinate system. // final static function Vector TransformVectorBy( Coords C, Vector V ) { local Vector Result; Result.X = V dot C.XAxis; Result.Y = V dot C.YAxis; Result.Z = V dot C.ZAxis; return Result; } // // Return this coordinate system's transpose. // If the coordinate system is orthogonal, this is equivalent to its inverse. // final static function Coords TransposeCoords( Coords C ) { local Coords Result; Result.Origin = TransformVectorBy( C, -C.Origin ); Result.XAxis.X = C.XAxis.X; Result.XAxis.Y = C.YAxis.X; Result.XAxis.Z = C.ZAxis.X; Result.YAxis.X = C.XAxis.Y; Result.YAxis.Y = C.YAxis.Y; Result.YAxis.Z = C.ZAxis.Y; Result.ZAxis.X = C.XAxis.Z; Result.ZAxis.Y = C.YAxis.Z; Result.ZAxis.Z = C.ZAxis.Z; return Result; } // // Transform this coordinate system by another coordinate system. // final static operator(34) Coords *=( out Coords C, Coords TransformCoords ) { //!! Proper solution: //C.Origin = Origin.TransformPointBy( TransformCoords.Inverse().Transpose() ); // Fast solution assuming orthogonal coordinate system: C.Origin = TransformPointBy ( TransformCoords, C.Origin ); C.XAxis = TransformVectorBy( TransformCoords, C.XAxis ); C.YAxis = TransformVectorBy( TransformCoords, C.YAxis ); C.ZAxis = TransformVectorBy( TransformCoords, C.ZAxis ); return C; } final static operator(16) Coords *( Coords C, Coords TransformCoords ) { return C *= TransformCoords; } // // Translate. // final static operator(34) Coords *=( out Coords C, Vector V ) { C.Origin -= V; return C; } final static operator(16) Coords *( Coords C, Vector V ) { return C *= V; } // // Transform this coordinate system by a pitch-yaw-roll rotation. // final static operator(34) Coords *=( out Coords C, Rotator R ) { local float RadianYaw, RadianPitch, RadianRoll; local float CosYaw, SinYaw, CosPitch, SinPitch, CosRoll, SinRoll; local Coords YawRotation, PitchRotation, RollRotation; // Possible minor precission improvement: Map angles into [-32768,+32767]. RadianYaw = float(R.Yaw &0xFFFF)*PI/32768.0; RadianPitch = float(R.Pitch&0xFFFF)*PI/32768.0; RadianRoll = float(R.Roll &0xFFFF)*PI/32768.0; CosYaw = Cos( RadianYaw ); SinYaw = Sin( RadianYaw ); CosPitch = Cos( RadianPitch ); SinPitch = Sin( RadianPitch ); CosRoll = Cos( RadianRoll ); SinRoll = Sin( RadianRoll ); YawRotation.XAxis.X = CosYaw; YawRotation.XAxis.Y = SinYaw; YawRotation.YAxis.X = -SinYaw; YawRotation.YAxis.Y = CosYaw; YawRotation.ZAxis.Z = 1.0; PitchRotation.XAxis.X = CosPitch; PitchRotation.XAxis.Z = SinPitch; PitchRotation.YAxis.Y = 1.0; PitchRotation.ZAxis.X = -SinPitch; PitchRotation.ZAxis.Z = CosPitch; RollRotation.XAxis.X = 1.0; RollRotation.YAxis.Y = CosRoll; RollRotation.YAxis.Z = -SinRoll; RollRotation.ZAxis.Y = SinRoll; RollRotation.ZAxis.Z = CosRoll; C *= YawRotation; C *= PitchRotation; C *= RollRotation; return C; } final static operator(16) Coords *( Coords C, Rotator R ) { return C *= R; } // // Detranslate. // final static operator(34) Coords /=( out Coords C, Vector V ) { C.Origin += V; return C; } final static operator(16) Coords /( Coords C, Vector V ) { return C /= V; } // // Detransform this coordinate system by a pitch-yaw-roll rotation. // final static operator(34) Coords /=( out Coords C, Rotator R ) { local float RadianRoll, RadianPitch, RadianYaw; local float CosRoll, SinRoll, CosPitch, SinPitch, CosYaw, SinYaw; local Coords RollRotation, PitchRotation, YawRotation; // Possible minor precission improvement: Map angles into [-32768,+32767]. RadianRoll = float(R.Roll &0xFFFF)*PI/32768.0; RadianPitch = float(R.Pitch&0xFFFF)*PI/32768.0; RadianYaw = float(R.Yaw &0xFFFF)*PI/32768.0; CosRoll = Cos( RadianRoll ); SinRoll = Sin( RadianRoll ); CosPitch = Cos( RadianPitch ); SinPitch = Sin( RadianPitch ); CosYaw = Cos( RadianYaw ); SinYaw = Sin( RadianYaw ); RollRotation.XAxis.X = 1.0; RollRotation.YAxis.Y = CosRoll; RollRotation.YAxis.Z = SinRoll; RollRotation.ZAxis.Y = -SinRoll; RollRotation.ZAxis.Z = CosRoll; PitchRotation.XAxis.X = CosPitch; PitchRotation.XAxis.Z = -SinPitch; PitchRotation.YAxis.Y = 1.0; PitchRotation.ZAxis.X = SinPitch; PitchRotation.ZAxis.Z = CosPitch; YawRotation.XAxis.X = CosYaw; YawRotation.XAxis.Y = -SinYaw; YawRotation.YAxis.X = SinYaw; YawRotation.YAxis.Y = CosYaw; YawRotation.ZAxis.Z = 1.0; C *= RollRotation; C *= PitchRotation; C *= YawRotation; return C; } final static operator(16) Coords /( Coords C, Rotator R ) { return C /= R; } // // Computes Worldspace to Viewspace transform. // final static function Coords ComputeRenderCoords( Vector Location, Rotator Rotation ) { local Coords ViewCoords; ViewCoords.Origin = vect(0,0,0); ViewCoords.XAxis = vect(0,1,0); ViewCoords.YAxis = vect(0,0,-1); ViewCoords.ZAxis = vect(1,0,0); return (ViewCoords/Rotation)/Location; } // // Computes Viewspace to Worldspace transform. // final static function Coords ComputeRenderUncoords( Vector Location, Rotator Rotation ) { return TransposeCoords( ComputeRenderCoords(Location,Rotation) ); } ---------------------------------- // // This assumes RootWindows render area to be the entire screen (RenderX,RenderY,RenderWidth,RenderHeight)==(0,0,Width,Height). // These variables are private, so in case you are using SetRenderViewport, save these aside and adjust calculations. // // Optimization is left as an exercise to the reader. --han // function bool _ConvertVectorToCoordinates( Vector WorldspaceLocation, out float RelativeX, out float RelativeY ) { local Coords WorldspaceToViewspace; local Vector ViewspaceLocation; local RootWindow RootWindow; local PlayerPawn PlayerPawn; local Actor ViewActor; local Vector CameraLocation; local Rotator CameraRotation; local float RootX, RootY; local float ProjZ; local bool bResult; RootWindow = GetRootWindow(); // !! Can be calculated outside and reused. PlayerPawn = RootWindow.GetPlayerPawn(); // !! Can be calculated outside and reused. ViewActor = PlayerPawn; CameraLocation = PlayerPawn.Location; CameraRotation = PlayerPawn.Rotation; // !! Sic. PlayerPawn.PlayerCalcView( ViewActor, CameraLocation, CameraRotation ); // !! Really should be calculated outside and reused. WorldspaceToViewspace = ComputeRenderCoords( CameraLocation, CameraRotation ); // !! Really should be calculated outside and reused. ViewspaceLocation = TransformPointBy( WorldspaceToViewspace, WorldspaceLocation ); //Log( Sprintf("Origin=%s,XAxis=%s,YAxis=%s,ZAxis=%s",WorldspaceToViewspace.Origin,WorldspaceToViewspace.XAxis,WorldspaceToViewspace.YAxis,WorldspaceToViewspace.ZAxis)$"ViewspaceLocation="$ViewspaceLocation ); // Matches C++ implementation, should probably still calculate 2D projection. -han if ( ViewspaceLocation.Z<=1.0 ) { RootX = 0.5*RootWindow.Width; RootY = 0.5*RootWindow.Height; bResult = false; } else { ProjZ = 0.5*RootWindow.Width/tan(PlayerPawn.FovAngle*Pi/360.0); // !! Can be calculated otuside and reused. RootX = 0.5*RootWindow.Width +ViewspaceLocation.X*ProjZ/ViewspaceLocation.Z; RootY = 0.5*RootWindow.Height+ViewspaceLocation.Y*ProjZ/ViewspaceLocation.Z; bResult = true; } ConvertCoordinates( RootWindow, RootX, RootY, Self, RelativeX, RelativeY ); return bResult; }