ply:EyeAngles varying with antialiasing?

Hi,
I’m having some strange issues with my RT Scopes. They’re being rendered using render.RenderView from the RenderScene hook. For their angle, I’m just using ply:EyeAngles().

Unscoped:

Suit Zoom:

RT Scope ( 2X MSAA ):

And here comes the good part.
RT Scope ( No MSAA ):

All from the same angle.

The only thing that changed was LOD in the RT Scope.
see:

https://a.pomf.cat/ywvyic.png

[editline]20th February 2017[/editline]

Also, use EyeAngles() when rendering things according to eyeangles as that’s set to the render angles internally, making it better.

Does the EyePos imprecision problem not apply to EyeAngles?

I can assure you, it’s not just the LOD. Check out this video:
[video]https://youtu.be/0MbvDbg_cnQ[/video]

For whatever reason, the scope aims up and left after changing the AA to 0x. This could very well be due to dumb things I do in my attachment code, but I’m not entirely sure.

Code:



if not ATTACHMENT then
	ATTACHMENT = {}
end

ATTACHMENT.Name = "7X Scope"
--ATTACHMENT.ID = "base" -- normally this is just your filename
ATTACHMENT.Description = { TFA.AttachmentColors["="], "7x zoom", TFA.AttachmentColors["-"], "30% higher zoom time",  TFA.AttachmentColors["-"], "10% slower aimed walking" }
ATTACHMENT.Icon = "entities/ins2_si_mosin.png" --Revers to label, please give it an icon though!  This should be the path to a png, like "entities/tfa_ammo_match.png"
ATTACHMENT.ShortName = "MOSN"

local fov = 90 / 7 / 2 -- Default FOV / Scope Zoom / screenscale

ATTACHMENT.WeaponTable = {
	["VElements"] = {
		["scope_mosin"] = {
			["active"] = true
		},
		["sights_folded"] = {
			["active"] = false
		},
		["scope_mosin_lens"] = {
			["active"] = true
		}
	},
	["WElements"] = {
		["scope_mosin"] = {
			["active"] = true
		},
		["sights_folded"] = {
			["active"] = false
		}
	},
	["IronSightsPos"] = function( wep, val ) return wep.IronSightsPos_Mosin or val, true end,
	["IronSightsAng"] = function( wep, val ) return wep.IronSightsAng_Mosin or val, true end,
	["IronSightsSensitivity"] = function(wep,val)
		local res = val * wep:Get3DSensitivity( )
		return res, false, true
	end ,
	["Secondary"] = {
		["IronFOV"] = function( wep, val ) return val * 0.9 end,
		["ScopeZoom"] = function( wep, val ) return 8.7 end
	},
	["IronSightTime"] = function( wep, val ) return val * 1.30 end,
	["IronSightMoveSpeed"] = function(stat) return stat * 0.9 end,
	["RTScopeFOV"] = fov,
	["RTOpaque"] = -1,
	["RTMaterialOverride"] = -1
}

local shadowborder = 256

local cd = {}

local myret
local myshad
local debugcv = GetConVar("cl_tfa_debug_rt")

function ATTACHMENT:Attach(wep)
	if not IsValid(wep) then return end
	wep.RTCodeOld = wep.RTCodeOld or wep.RTCode
	wep.RTCode = function( myself , rt, scrw, scrh)
		if not IsValid(myself.Owner) then return end
		cam.Start3D()
		local att, ts
		if wep:VMIV() then
			att = wep.OwnerViewModel:GetAttachment( wep.RTAttachment_Mosin or 0 )
		end
		if att and att.Pos then
			if not wep.LastOwnerPos then
				wep.LastOwnerPos = wep.Owner:GetShootPos()
			end

			local owoff = wep.Owner:GetShootPos() - wep.LastOwnerPos
			wep.LastOwnerPos = wep.Owner:GetShootPos()
			local pos = att.Pos - owoff
			ts = pos:ToScreen()
		end
		cam.End3D()
		if not myret then
			myret = Material("models/weapons/tfa_ins2/optics/mosin_crosshair")
		end
		if not myshad then
			myshad = Material( "vgui/scope_shadowmask_test")
		end

		render.OverrideAlphaWriteEnable(true, true)
		surface.SetDrawColor(color_white)
		surface.DrawRect(-512, -512, 1024, 1024)
		render.OverrideAlphaWriteEnable(true, true)
		local ang = myself.Owner:EyeAngles()
		if wep.ScopeAngleTransforms_Mosin then
			ang:RotateAroundAxis(ang:Right(), wep.ScopeAngleTransforms_Mosin.p )
			ang:RotateAroundAxis(ang:Up(), wep.ScopeAngleTransforms_Mosin.y )
			ang:RotateAroundAxis(ang:Forward(), wep.ScopeAngleTransforms_Mosin.r )
		end
		cd.angles = ang
		cd.origin = myself.Owner:GetShootPos()
		cd.x = 0
		cd.y = 0
		cd.w = scrw
		cd.h = scrh
		cd.fov = fov
		cd.drawviewmodel = false
		cd.drawhud = false
		render.Clear(0, 0, 0, 255, true, true)
		render.SetScissorRect(0, 0, scrw, scrh, true)

		if myself.CLIronSightsProgress > 0.005 then
			render.RenderView(cd)
		end

		render.SetScissorRect(0, 0, scrw, scrh, false)
		render.OverrideAlphaWriteEnable(false, true)
		cam.Start2D()
		if ts then
			local rttw, rtth = ScrW(), ScrH()
			local scrpos = ts

			scrpos.x = scrpos.x / scrw
			scrpos.y = scrpos.y / scrh

			scrpos.x = scrpos.x - 0.5
			scrpos.y = scrpos.y - 0.5
			if wep.ScopeOverlayTransforms_Mosin then
				scrpos.x = scrpos.x + wep.ScopeOverlayTransforms_Mosin[1]
				scrpos.y = scrpos.y + wep.ScopeOverlayTransforms_Mosin[2]
			end
			scrpos.x = scrpos.x * rttw
			scrpos.y = scrpos.y * rtth
			scrpos.x = math.Clamp(scrpos.x, -1024, 1024)
			scrpos.y = math.Clamp(scrpos.y, -1024, 1024)

			if wep.ScopeOverlayTransformMultiplier_Mosin then
				scrpos.x = scrpos.x * wep.ScopeOverlayTransformMultiplier_Mosin
				scrpos.y = scrpos.y * wep.ScopeOverlayTransformMultiplier_Mosin
			end

			if not self.scrpos then
				self.scrpos = scrpos
			end

			self.scrpos.x = math.Approach(self.scrpos.x, scrpos.x, (scrpos.x - self.scrpos.x) * FrameTime() * 10)
			self.scrpos.y = math.Approach(self.scrpos.y, scrpos.y, (scrpos.y - self.scrpos.y) * FrameTime() * 10)
			scrpos = self.scrpos

			local rtow, rtoh = 0, 0
			if wep.RTScopeOffset_Mosin then
				rtow = self.RTScopeOffset_Mosin[1] * rttw
				rtoh = self.RTScopeOffset_Mosin[2] * rtth
			end
			local rtw, rth = rttw * 1, rtth * 1
			if self.RTScopeScale_Mosin then
				rtw = rtw * self.RTScopeScale_Mosin[1]
				rth = rth * self.RTScopeScale_Mosin[2]
			end
			local distfac = math.pow( 1 - math.Clamp( ( att.Pos:Distance( wep.Owner:GetShootPos() ) - ( wep.ScopeDistanceMin_Mosin or 4 ) ) / ( wep.ScopeDistanceRange_Mosin or 8 ), 0, 1 ), 1 )
			rtw = Lerp( distfac, rtw * 0.1, rtw * 2 )
			rth = Lerp( distfac, rth * 0.1, rth * 2 )
			local cpos = Vector( -scrpos.x + rttw / 2, -scrpos.y + rtth / 2, 0 )
			cpos.x = math.Round(cpos.x)
			cpos.y = math.Round(cpos.y)

			surface.SetMaterial(myret)
			surface.SetDrawColor(color_white)
			if debugcv and debugcv:GetBool() then
				surface.DrawTexturedRect( rttw / 2 - rtw / 4 + rtow, rtth / 2 - rth / 4 + rtoh, rtw / 2, rth / 2)
			else
				surface.DrawTexturedRect( cpos.x - rtw / 4 + rtow, cpos.y - rth / 4 + rtoh, rtw / 2, rth / 2)

				surface.SetMaterial(myshad)
				surface.SetDrawColor(color_white)
				surface.DrawTexturedRect( cpos.x - rtw / 2, cpos.y - rth / 2, rtw, rth )

				surface.SetDrawColor(color_black)
				surface.DrawRect( cpos.x - rtw / 2 - 2047, cpos.y - 1024, 2048, 2048)
				surface.DrawRect( cpos.x + rtw / 2 - 1, cpos.y - 1024, 2048, 2048)
				surface.DrawRect( cpos.x - 1024, cpos.y - rtw / 2 - 2047, 2048, 2048)
				surface.DrawRect( cpos.x - 1024, cpos.y + rtw / 2 - 1, 2048, 2048)
			end
		else
			local rttw, rtth = ScrW(), ScrH()
			surface.SetMaterial(myret)
			surface.SetDrawColor(color_white)
			surface.DrawTexturedRect(0,0,rttw,rtth)
			surface.SetMaterial(myshad)
			surface.SetDrawColor(color_white)
			surface.DrawTexturedRect(-shadowborder, -shadowborder, shadowborder * 2 + rttw , shadowborder * 2 + rtth )
		end
		draw.NoTexture()
		surface.SetDrawColor(ColorAlpha(color_black, 255 * (1 - myself.CLIronSightsProgress)))
		surface.DrawRect(0, 0, scrw, scrh)
		cam.End2D()
	end
end

function ATTACHMENT:Detach(wep)
	if not IsValid(wep) then return end
	wep.RTCode = wep.RTCodeOld
	wep.RTCodeOld = nil
end

if not TFA_ATTACHMENT_ISUPDATING then
	TFAUpdateAttachments()
end


The RTCode is the important bit.

Did you at least try EyeAngles alone?

There’s no such thing as EyePos imprecision - EyePos/EyeAngles is literally a binding to get current (last if not in a frame - or complete gibberish) render space position/angles

Yes, exact same issue.

I meant it returning the value from the previous rendering context it was used in, as noted here: https://github.com/Facepunch/garrysmod-issues/issues/2516

It probably won’t help, but it’s proper to use EyePos() instead of GetShootPos() when rendering at an origin. If that doesn’t work I would suggest removing some code that you might think has something wrong with it. Sorry if I can’t help :frowning:

i’m not sure what you mean, EyePos is only ever supposed to used in rendering contexts, using it elsewhere would definintely not work properly.

The bug appears in render contexts.

Eh this might be a silly question, but does the problem persist after restarting your game? When changing resolution and/or AA in source games, I pretty much always restart my game because things break.

It most definitely persists. 0xAA will consistently misalign the scope from the real EyeAngles.

I put together a small test code that worked fine for me, both with and without AA. Could you please test it and see if it works? The code you posted above is missing a lot of crucial info to be testable.

You can hide the RT by holding down sprint.

[lua]
local rtName, rtWidth, rtHeight = “_testRT”, ScrW() / 4, ScrH() / 4

local rtTexture = GetRenderTarget(rtName, rtWidth, rtHeight, false)

local shouldDraw = true

hook.Add(“HUDPaint”, “TestRT”, function()
if LocalPlayer():KeyDown(IN_SPEED) then return end

render.PushRenderTarget(rtTexture)

render.Clear(0, 0, 0, 255, true)

render.RenderView({
    x = 0,
    y = 0,
    w = rtWidth,
    h = rtHeight,
    fov = 10,
    drawhud = false,
    drawviewmodel = false,
    dopostprocess = true,
    drawmonitors = true
 })

render.PopRenderTarget()

local scrw, scrh = ScrW(), ScrH()
render.DrawTextureToScreenRect(rtTexture, scrw * 0.5 - rtWidth * 0.5, scrh * 0.5 - rtHeight * 0.5, rtWidth, rtHeight)

end)
[/lua]

I found out what was wrong with the code I posted, and it gets quite weird. By accident, I was drawing the RT at the width of “scrw” instead of “ScrW.” For reference, scrw was set to ScrW() *before *pushing the render target. However, through a strange glitch that only happened when AA was on, ScrW() was supplying returning the rendertarget width even without being inside the RT; thus, my incorrect code only worked due to a glitch between render contexts. The angle had nothing to do with anything, which I should’ve realized sooner, but I was blinded by what I thought was wrong.

Edit:

It is worth noting, however, that EyeAngles() will return an incorrect value when called before the actual 3D render operation starts. For some reason, I didn’t encounter this in my testing, but most other people did.