Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render Target Offsets With Different Resolutions. Read last post for the conclusion to the problem. #1424

Closed
EthanTheGreat opened this issue Aug 15, 2014 · 13 comments
Labels
Bug The issue is confirmed to be a bug and not intentional behaviour.

Comments

@EthanTheGreat
Copy link

I am using render targets to generate a material for my decal editor. (I hate render targets in general, I am considering just switching to using HTML as an alternative.)

https://dl.dropboxusercontent.com/u/17839069/C_139.png

What you're looking at is basically this: The red and blue 'squares' are rendered as 512x512 each. The whole canvas of the texture is accurately 1024x1024. The problem I'm facing is how the render target wont stretch to the bottom. If you notice, you see the black space on the bottom which tells me the render target is having difficulty with it's sizing.

The lua code that applies to this problem is here:

local renderTarget = GetRenderTargetEx(
matRTPath, // Path of RenderTarget
DECAL_MAT_SIZE, DECAL_MAT_SIZE, // SIZE, Preset to 1024x1024
RT_SIZE_NO_CHANGE, //#### This is the issue, I assume....
MATERIAL_RT_DEPTH_SEPARATE, // Depth of the material, useless for what I'm using it for.
bit.bor( 0x0004, 0x0008 ), // Texture Flags, Clamp S, Clamp T
CREATERENDERTARGETFLAGS_UNFILTERABLE_OK, //
IMAGE_FORMAT_DEFAULT
)

Third argument I believe is the problem. After going through every single ENUM for the RT_SIZE (location is here: http://wiki.garrysmod.com/page/Enums/RT_SIZE) (Also, I restarted my gmod just in case each try) I've come to find that none of the ENUMS accurately stretch the renderTarget to the canvas.

Just to prove to you this is the problem, this link will show you the result of the ENUM: RT_SIZE_FULL_FRAME_BUFFER in the code above: https://dl.dropboxusercontent.com/u/17839069/C_140.png

Again, the blue square is suppose to be 512x512 on the 1024x1024 texture, but as you can see, it's not.

None of the enums work better then RT_SIZE_NO_CHANGE however.

To clarify, my code works perfectly when I use 512x512 instead of 1024x1024 for the SIZE of the render target. However, using lower resolution render targets results in pix-elated layers:
https://dl.dropboxusercontent.com/u/17839069/C_114.png (Clear Example)
https://dl.dropboxusercontent.com/u/17839069/C_119.png (Clear example)
https://dl.dropboxusercontent.com/u/17839069/C_136.png (If you zoom into the side decal)

Please fix. <3

EDIT:
RobotBoy, if you're reading this, accept my friend invite :C
I wrote you out a comment.

SECOND EDIT:
Read the last post for details, I think I found the problem.

@Grocel
Copy link

Grocel commented Aug 15, 2014

I noticed strange offsets in render targets too. Like coordinates near the target's borders not being inside the visible area. I had work to around it with render.SetViewPort( 16, 8, 1024, 512 ) when I used a 1024x512 render target.

@EthanTheGreat
Copy link
Author

Exactly the same issue here. Glad I'm not crazy
:D

EDIT: I'm sure that it's something to do with different screen resolutions. Weird.

@EthanTheGreat
Copy link
Author

After playing around with the resolutions, I came up with a conclusion as to why render targets kept offsetting so weirdly.

https://dl.dropboxusercontent.com/u/17839069/C_142.png
This picture was taken at full screen, as you can see it works. (1920x1080)

https://dl.dropboxusercontent.com/u/17839069/C_143.png
Now, what I assume what's fucking up is the fact that once you run your game any lower resolution (this picture has my game set at 1600x900) the offset position of the game window affects the rendertarget. If you understand how render targets work, it's easier to understand why this does what it does. Vertically it seems to be broken, horizontally seems to be fine.

Please fix this. I realize I could fix this with LUA however I'd much rather have it officially patched.

@EthanTheGreat EthanTheGreat changed the title Render Target's Scaling Seems To Be Off... [BUG] Render Target Offsets With Different Resolutions. Read last post for the conclusion to the problem. Aug 16, 2014
@robotboy655 robotboy655 added the Bug The issue is confirmed to be a bug and not intentional behaviour. label Dec 27, 2014
@robotboy655 robotboy655 changed the title [BUG] Render Target Offsets With Different Resolutions. Read last post for the conclusion to the problem. Render Target Offsets With Different Resolutions. Read last post for the conclusion to the problem. Dec 27, 2014
@DBotThePony
Copy link

DBotThePony commented Sep 25, 2017

Right label - render.SetViewPort can't scale current view port to bigger resolution than current game resolution

@robotboy655

Because i has hit this bug. When i enabled render.SetViewPort usage to my Render Target drawing (https://git.dbot.serealia.ca/Ponyscape-open/PPM2/blob/develop/moon/autorun/ppm2/client/texture_controller.moon#L535-558) it caused massive spam to me at discord and steam about some players are getting cut-offs of their body textures and stuff. (cutoff is a pitch black pixels where they are being drawn beyond the screen bounds)

@thegrb93
Copy link

thegrb93 commented Jun 2, 2019

Yeah this bug sucks

@WinterPhoenix
Copy link

WinterPhoenix commented Oct 10, 2019

So I'm running into the weird offset problem with render.PushRenderTarget. Whatever you draw isn't clipped to screen bounds, at least in the "positive"direction from the Render Target origin, but things are clipped in the "negative" direction of the RT origin.

Example Code, tested with GMod's Screen Resolution set to 1920x1080:

local clippedRT = GetRenderTarget("clipped_example_rt", 4096, 4096)
render.PushRenderTarget(clippedRT, 0, 0, clippedRT:Width(), clippedRT:Height())
	render.OverrideAlphaWriteEnable(true, true)
	render.ClearDepth()
	render.Clear(0, 0, 0, 0)

	cam.Start2D()
		surface.DisableClipping(true)

		surface.SetDrawColor(255, 255, 255, 255)
		surface.DrawRect(0, 0, 512, 512)
		surface.SetDrawColor(255, 0, 0, 255)
		surface.DrawRect(0, 0, 256, 256)
		surface.SetDrawColor(0, 0, 0, 255)
		surface.DrawRect(0, 0, 1, 1)

		surface.DisableClipping(false)
	cam.End2D()

	render.OverrideAlphaWriteEnable(false)
render.PopRenderTarget()

local clippedMat = CreateMaterial("clipped_example_mat", "UnlitGeneric", {
	["$basetexture"] = "color/white",
	["$translucent"] = 1,
	["$vertexcolor"] = 1
})
clippedMat:SetTexture("$basetexture", clippedRT)

hook.Add("HUDPaint", "ClippedExampleDraw", function()
	surface.SetDrawColor(255, 255, 255, 255)
	surface.SetMaterial(clippedMat)
	surface.DrawTexturedRect(0, 0, clippedMat:GetTexture("$basetexture"):Width(), clippedMat:GetTexture("$basetexture"):Height())
end)

With that example, you can see that the boxes are being clipped, using the fact that the red box is supposed to be taking up 1/2 of the space of the white box and that the 1x1 black box is not visible.

There only seems to be one workaround for this, and it's offseting the X and Y origins of the Viewport:

render.PushRenderTarget(clippedRT, 128, 128, clippedRT:Width(), clippedRT:Height())

The underlying issue still remains despite the workaround.

Edit: It doesn't seem as though screen resolution is a factor; it just looks like

offset = powerOf2Size/32

So in this case:

128px offset = 4096px RT size / 32

You may need to subtract 1px from the offset (so if the offset is 128px, make it 127px instead) to prevent the black Render Target background from "bleeding" into the texture.

@Grocel
Copy link

Grocel commented Oct 14, 2019

I had that problem as well and got a pretty good solution via trial and error. It is used in my one of my addons now and looks like this:

	local w, h = self:GetSize() -- w and h can be any power of 2 size

	local workaround_bug_x = w / 64
	local workaround_bug_y = h / 64
	local workaround_bug_w = w + workaround_bug_x * 2 + math.ceil(w / 1024)
	local workaround_bug_h = h + workaround_bug_y * 2 + math.ceil(h / 1024)

	render.PushRenderTarget(self._RT.tex, workaround_bug_x, workaround_bug_y, workaround_bug_w, workaround_bug_h)
		-- render stuff
	render.PopRenderTarget()

It is very accurate (with +/- 1 pixel tolerance) up to 8192, even if w and h are different by a huge margin. The last time I checked it worked for every game resolution as well.

I always wanted to report that problem years ago, but I didn't got the time to prepare a proper reproduction script.

@thegrb93
Copy link

thegrb93 commented Oct 14, 2019

If you're using surface library, this is a known unrelated bug with using rendertargets #3173

The explanation here https://wiki.garrysmod.com/page/surface/DrawTexturedRectUV

@Grocel
Copy link

Grocel commented Oct 15, 2019

I can confirmed that for my case. I think surface.DrawTexturedRect() (WinterPhoenix96's example) is affected aswell.

@robotboy655
Copy link
Contributor

robotboy655 commented Oct 17, 2019

Alright, so the original pictures don't work, but I can tell @WinterPhoenix96's code does write to the render target correctly (without the offset hack) The problem seems to be with the material.

You can verify this yourself via mat_texture_list 1. or

	local matScreen = Material( "models/weapons/v_toolgun/screen" )
	matScreen:SetTexture("$basetexture", clippedRT)
hook.Add( "HUDPaint", "example_hook", function()
		surface.SetDrawColor( 255, 255, 255, 255 )
		surface.SetMaterial( matScreen	)
		surface.DrawTexturedRect( 0, 0, 512, 512 )
	end )

I am assuming here @WinterPhoenix96's issue is the same as @EthanTheGreat's.

It would appear you can fix this by doing the following when creating the material:

local clippedMat = CreateMaterial("clipped_example_mat", "UnlitGeneric", {
		["$basetexture"] = "clipped_example_rt", -- This is the RT name
		["$translucent"] = 1,
		["$vertexcolor"] = 1
	})

With all that being said, is there any issue?

@robotboy655
Copy link
Contributor

I have updated the wiki to include examples about this on relevant pages.

@Grocel
Copy link

Grocel commented Oct 17, 2019

I changed the $basetexture thing on my end as well and I can confirm that everything works fine without any the workarounds now.
You can use do ["$basetexture"] = ITexture:GetName() (was a todo on a wiki example) as well.
I can also confirm that giving CreateMaterial() the same name as the Texture works too, so no need for pre-/suffixes. Although you can keep them if you want.

For context my case is a all custom Texture/Material scenario created with GetRenderTargetEx()/CreateMaterial().

It is able to create large render targets (8k²+) on 1080p game resolution without any noticeable offsets or other glitches:

local tex = GetRenderTargetEx(
	name, w, h,
	RT_SIZE_NO_CHANGE,
	MATERIAL_RT_DEPTH_SEPARATE,
	bit.bor(4, 8, 16, 32, 512, 2048, 8192, 32768),
	0,
	IMAGE_FORMAT_RGBA8888
)

@robotboy655
Copy link
Contributor

So I am closing this as solved then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug The issue is confirmed to be a bug and not intentional behaviour.
Projects
None yet
Development

No branches or pull requests

6 participants