Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Surprise T Rex posted:

I was under the impression that this would let me rearrange the order in which scripts on a single object would execute, whereas I have a bunch of objects that are initialized in a random order, but need to make sure that my EventManager object is initialised before any other objects that contain scripts that rely on the EventManager script.


The project isn't very established yet tbh. I was mainly planning to use enable and disable for things like hiding/showing UI elements.

Maybe a different approach to managing subscriptions that doesn’t depend on lifecycle method order between objects?

https://unity3d.com/how-to/architect-with-scriptable-objects <- jump to events

Adbot
ADBOT LOVES YOU

Metos
Nov 25, 2005

Sup Ladies

Surprise T Rex posted:

The project isn't very established yet tbh. I was mainly planning to use enable and disable for things like hiding/showing UI elements.
Great, in that case absolutely scrap the enable\disable stuff and instead put a CanvasGroup on each of them and use CanvasGroup.alpha to turn it invisible rather than turning it on or off. Or more accurately lerp it so it fades away, but small steps.

A parent class that your UI stuff inherit from with Hide() and Show() methods to do that is way cleaner and will save you tons of unexpected null references.

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
Well this memory issue is forcing me to actually manage loaded assets, and that's cool I guess.

I don't know how normal engines do it, but I'm doing it via a tagging system. So things tagged "permanent" get loaded at the start of the game and never unloaded. When I quit the level, I unload everything that isn't marked permanent.

Then, things that are specific to certain missions or whatever get tagged with the mission name so I can preload them when starting those missions.

And anything that isn't preloaded causes a horrible frame hitch when it loads!

Surprise T Rex
Apr 9, 2008

Dinosaur Gum

leper khan posted:

Maybe a different approach to managing subscriptions that doesn’t depend on lifecycle method order between objects?

https://unity3d.com/how-to/architect-with-scriptable-objects <- jump to events

Yeah, that's basically what I want to do. I'd prefer being able to do it 100% in code but I can live with using a ScriptableObject for each event and assigning EventListener components to e.g. my Player GameObject. I'm going to need to look into UnityEvents a little more if I follow that guide (since it doesn't look like you can set up plain old C# Actions in the inspector), but I'm sure it'll all make sense eventually.

I'm still never quite sure if I'm doing things the way Unity wants me to, or whether I'm swimming upstream. :(

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe

Surprise T Rex posted:

Check if(EventManager.Instance != null) before registering events, and then subscribe to those events in both OnEnable() and Start() just in case it wasn't available during OnEnable(). I'd still need to do the subscribing in OnEnable() because otherwise disabling and re-enabling an object would lose the event subscription.

You could also just preface every function in EventManager with calling InitializeEventManagerIfNecessary(), which creates the EventManager if it doesn't exist yet. Then the EventManager's Start method just calls that same initializer.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Surprise T Rex posted:

Yeah, that's basically what I want to do. I'd prefer being able to do it 100% in code but I can live with using a ScriptableObject for each event and assigning EventListener components to e.g. my Player GameObject. I'm going to need to look into UnityEvents a little more if I follow that guide (since it doesn't look like you can set up plain old C# Actions in the inspector), but I'm sure it'll all make sense eventually.

I'm still never quite sure if I'm doing things the way Unity wants me to, or whether I'm swimming upstream. :(

You’re problem of not knowing is exacerbated by different parts of unity telling you different things.

Always keep in mind that the docs are written to minimize support requests. Don’t give into things they say that defy general engineering practice.

Unless it’s specifically from the optimization group. Then do whatever they say, and if you care pay a little attention because they also lay out why doing dumb/crazy things is necessary and why the other things are bad. It’s the one video I may sure to watch from Unite every year.

The practices laid out in the linked doc aren’t necessarily the most performant way of doing what you want, but they’re extremely good for prototyping and/or until your profiling tools tell you you’re falling over from too much method invocation overhead. (You’ll probably not run into that situation)

Surprise T Rex
Apr 9, 2008

Dinosaur Gum

TooMuchAbstraction posted:

You could also just preface every function in EventManager with calling InitializeEventManagerIfNecessary(), which creates the EventManager if it doesn't exist yet. Then the EventManager's Start method just calls that same initializer.

The issue is that there aren't really any methods in the EventManager, there's a lot of
code:
public event Action onPlayerDamaged;
type stuff though. Basically, all it ever does is let other scripts register themselves as event handlers on it (but if it's not initialised, the EventManager.Instance reference is null when I try to register handlers on it), so I'd have to call InitializeEventHandlerIfNecessary on every scrip that tried to listen for one of it's events.


leper khan posted:

You’re problem of not knowing is exacerbated by different parts of unity telling you different things.

Yeah, the general guidelines are really inconsistent, both from Unity themselves and the community.

I might be able to get by using my old approach of doing everything in code, but moving the event subscription/unsubscription from OnEnable and OnDisable to Start and OnDestroy, which as long as I'm not enabling/disabling the GameObjects might be okay... but then I run into issues like "What happens when I don't disable a button, just make its alpha 0, can I still click it?" and so on.

There's a lot of ways to do stuff but its kind of like every way to set things up in Unity works flawlessly up to a point, and then suddenly there's a dealbreaker situation happening and you have to rethink the entire approach.

Omi no Kami
Feb 19, 2014


While we're chatting about events, here's something I've never fully understood: what is the use case for specifically using unity's events framework instead of c# delegates? Unity has been making a big deal of their internal event workflow for a few years, but as far as I can see it's basically just delegates, except easier to drag & drop and configure in the editor/prefab instead of at runtime.

ZombieApostate
Mar 13, 2011
Sorry, I didn't read your post.

I'm too busy replying to what I wish you said

:allears:

Surprise T Rex posted:

The issue is that there aren't really any methods in the EventManager, there's a lot of
code:
public event Action onPlayerDamaged;
type stuff though. Basically, all it ever does is let other scripts register themselves as event handlers on it (but if it's not initialised, the EventManager.Instance reference is null when I try to register handlers on it), so I'd have to call InitializeEventHandlerIfNecessary on every scrip that tried to listen for one of it's events.

Maybe make Instance a Property and put the InitializeEventHandlerIfNecessary call in the get and leave the set blank or something? I'm not really a big C# person, so I don't know how big a faux pas that is.

edit: or maybe a private set. I haven't poked C# in a while.

ZombieApostate fucked around with this message at 16:18 on Sep 11, 2019

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

baby puzzle posted:

Well this memory issue is forcing me to actually manage loaded assets, and that's cool I guess.

I don't know how normal engines do it, but I'm doing it via a tagging system. So things tagged "permanent" get loaded at the start of the game and never unloaded. When I quit the level, I unload everything that isn't marked permanent.

Then, things that are specific to certain missions or whatever get tagged with the mission name so I can preload them when starting those missions.

And anything that isn't preloaded causes a horrible frame hitch when it loads!

If you're AAA half the time its "ditch everything and load it all again" :)

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
How should I tell people that I won't give them free things? Even if they bought other things... I don't want to give you free DLC just for asking nicely.

al-azad
May 28, 2009



baby puzzle posted:

How should I tell people that I won't give them free things? Even if they bought other things... I don't want to give you free DLC just for asking nicely.

How do Steam coupons work for creators? I do appreciate getting coupons if I already own a game. Anodyne 2 had a 20% off coupon if you owned the first which I used immediately.

Stick100
Mar 18, 2003

baby puzzle posted:

My game uses around 500 MB of ram. If a user has 4 gigs of ram, is it possible that they could be running out of memory? They are using Windows 7 64 bit, if that makes a difference.

I have got a crash from a few users that all have 4 gigs of RAM, and it could be caused by allocations failing, but it is very hard to tell from my end.

Out of Memory errors don't always mean you've run out of memory. Windows will sometimes throw out of memory error for completely unrelated things like file access. It appears that when windows/several programs and interfaces can't find a specific error message it will default back to out of memory.

I can't recall specific examples off the top of my head but I've several times in my day job (enterprise programmer) tracked down an "Out of Memory" error (out of memory returned as an error code) only to find it had nothing to do with memory (locks, semaphores, file access, third party software failures).

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
Do y'all have any advice on how to tell if/when you're making your graphics too demanding? I have a 980Ti graphics card, i.e. a pretty dang good one, and I'd like my game to be playable on lesser equipment. Am I pretty much just stuck with "buy a crappy graphics card and make sure the game plays OK on it"? How do you even go about profiling which parts of your scene are more demanding than others?

I'm not super worried about this, but since I have no idea how to tell what is problematic, I'm worried that I may end up having to redo a bunch of work later because I wrote it badly the first time around. Like, there's a sqrt in one of my vertex shaders (used to do a conical falloff in intensity of an effect), and I know that square roots are expensive but I have no idea if this is like "ehh if you can write it easily without using sqrt then do that" thing or if it's a "don't do this unless you absolutely have to" kind of thing.

Stick100
Mar 18, 2003

TooMuchAbstraction posted:

Do y'all have any advice on how to tell if/when you're making your graphics too demanding? I have a 980Ti graphics card, i.e. a pretty dang good one, and I'd like my game to be playable on lesser equipment. Am I pretty much just stuck with "buy a crappy graphics card and make sure the game plays OK on it"? How do you even go about profiling which parts of your scene are more demanding than others?

You should be able to down clock your GPU/CPU which will give you some clue how you game might perform on weaker hardware but of course it won't help you with things like how much video memory/desktop memory you have. The engines have profilers/tools in them.

To fully test you need hardware, good thing is weak hardware is cheap should be able to get a good test platform for something like $349.

If you run your game uncapped you should have a pretty good idea how it will run on weaker hardware. Ex. If your game runs 400 fps+ on a 980ti, then you're probably good on very weak hardware. If it runs right at 60 then you have a pretty good clue that it wouldn't run well on weaker hardware.

Of course you'll need to figure out if your gpu or cpu bottle-necked.

If you have more specific information (platform/engine/performance of your game) we can help more.

Stick100 fucked around with this message at 18:01 on Sep 11, 2019

ZombieApostate
Mar 13, 2011
Sorry, I didn't read your post.

I'm too busy replying to what I wish you said

:allears:
You could try telling it to use the integrated GPU in your CPU.

ynohtna
Feb 16, 2007

backwoods compatible
Illegal Hen
Test your game on a library or internet-cafe computer?

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
Find a friend with a poo poo computer

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
Sounds like this mostly boils down to "you won't know until you try (on crappy hardware)", and then you pretty much just guess about what parts of your game might be problematic, e.g. by disabling shaders until things start working better. Thanks for the recommendations, in particular uncapping framerate and checking what I get on my hardware -- with vsync off I get 270FPS, which doesn't seem to be affected by what's being drawn, so hopefully that means that I'm being CPU-limited by my decade-old Intel i7.

I do also have a laptop (~6-year-old Macbook) that I can test on occasionally, and I can look into downclocking my hardware as well.

quote:

If you have more specific information (platform/engine/performance of your game) we can help more.

Windows/Unity, and no performance issues yet, it's just something that I'm mildly worried about. When it comes to software, I know generally what to keep an eye out for that can be problematic when it comes to performance. Stuff like big-O analysis, synchronization across threads, excessive file I/O, etc. I don't know what the equivalent techniques are for graphics design. I assume that things like number of tris, number of transparent objects, number of textures, and number of operations done in shaders all have an effect on performance, but there may be other things I don't know about and I also don't have a feel for where the danger zone lies. Like, with software, an O(n^3) algorithm is bad but probably not noticeable unless n is huge, while an O(2^n) algorithm is awful and to be avoided at all costs unless n is very small. I don't know how to tell when I'm doing the former vs. the latter in graphics.

Tangentially related: I got that wake effect working, more or less. The particle effect needs refinement (it looks bad when the ship turns) but the basic concept is sound.

Truspeaker
Jan 28, 2009

Surprise T Rex posted:

The issue is that there aren't really any methods in the EventManager, there's a lot of
code:
public event Action onPlayerDamaged;
type stuff though. Basically, all it ever does is let other scripts register themselves as event handlers on it (but if it's not initialised, the EventManager.Instance reference is null when I try to register handlers on it), so I'd have to call InitializeEventHandlerIfNecessary on every scrip that tried to listen for one of it's events.


Yeah, the general guidelines are really inconsistent, both from Unity themselves and the community.

I might be able to get by using my old approach of doing everything in code, but moving the event subscription/unsubscription from OnEnable and OnDisable to Start and OnDestroy, which as long as I'm not enabling/disabling the GameObjects might be okay... but then I run into issues like "What happens when I don't disable a button, just make its alpha 0, can I still click it?" and so on.

There's a lot of ways to do stuff but its kind of like every way to set things up in Unity works flawlessly up to a point, and then suddenly there's a dealbreaker situation happening and you have to rethink the entire approach.

I might be underthinking this, but is there a reason the EventManager itself needs to be a GameObject? Just setup some lazy instantiation for it as a non monobehavior:
code:
 public EventManager Instance { get { if( _instance == null){ _instance = new EventManager(); } return _instance; } } 
Or yeah, changing the script execution order sets it globally, not just within a particular GameObject.

I will say, its probably best to be able to disable your objects when they aren't in use, as it will make the button situation you mentioned much simpler, but also as I recall disabled objects have zero performance cost, though they stick around in memory.

Surprise T Rex
Apr 9, 2008

Dinosaur Gum

Truspeaker posted:

I might be underthinking this, but is there a reason the EventManager itself needs to be a GameObject? Just setup some lazy instantiation for it as a non monobehavior:

Yeah, this realisation came to me while I was eating dinner. I guess I get too caught up in overthinking it and/or doing things "The Unity Way(s)". :shobon:

Thanks for weighing in all, IOU all terrible gifs of my crap tower defense game as payment later down the line.

Surprise T Rex fucked around with this message at 19:43 on Sep 11, 2019

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Omi no Kami posted:

While we're chatting about events, here's something I've never fully understood: what is the use case for specifically using unity's events framework instead of c# delegates? Unity has been making a big deal of their internal event workflow for a few years, but as far as I can see it's basically just delegates, except easier to drag & drop and configure in the editor/prefab instead of at runtime.

It’s mostly that.

Omi no Kami
Feb 19, 2014


leper khan posted:

It’s mostly that.

Thanks, good to know. ^^

FuzzySlippers
Feb 6, 2009

Truspeaker posted:

I might be underthinking this, but is there a reason the EventManager itself needs to be a GameObject? Just setup some lazy instantiation for it as a non monobehavior:
code:
 public EventManager Instance { get { if( _instance == null){ _instance = new EventManager(); } return _instance; } } 
Or yeah, changing the script execution order sets it globally, not just within a particular GameObject.

I will say, its probably best to be able to disable your objects when they aren't in use, as it will make the button situation you mentioned much simpler, but also as I recall disabled objects have zero performance cost, though they stick around in memory.

Yeah none of my manager classes are GameObjects partially to avoid this kind of Unity shenanigans. If you want some easy debugging in the editor you can still get that via editor code. Like my event bus is a normal c# class, but I have a scriptableobject with an editor script that displays info about it in the inspector.

Your Computer
Oct 3, 2008




Grimey Drawer
shot in the dark here; do any y'all wizards have any idea how one would go about implementing custom texture filtering in Unity's Shader Graph?

I messed with this a bit back but Shader Graph was a little wonky then so I just put it aside. Now that it seems pretty fully fledged I figured I'd pick this up again and have a go at recreating my old shader using Shader Graph with custom lighting, filtering and everything. I got stuck pretty much immediately though, as I simply can't figure out how how to do the custom filtering (or if it's even possible, which I'm starting to suspect it might not be) due to how it handles textures and sampling. The whole thing is very confusing and google hasn't brought me any closer to understanding it as I can't find any resources at all explaining how it works.

There's this whole thing about Texture2D objects and SamplerStates and whatnot which apparently is how you're supposed to do it in D3D11, but how to actually make any of this into code beats me. It seems like it would be as "simple" as making some sort of custom SamplerState that defined the custom filtering but all I can find out about SamplerStates is that they use built-in definitions about various filtering algorithms and that doesn't really help me much. Shader Graph has a Sampler State node but all it does is give you a drop-down of built-in filtering types. I also tried slotting in some of my code but the only texture input you can provide is Texture 2D which I honestly don't quite understand what even is, only that it's not a sampler2D :v:

dreamless
Dec 18, 2013



Truspeaker posted:

I might be underthinking this, but is there a reason the EventManager itself needs to be a GameObject? Just setup some lazy instantiation for it as a non monobehavior:
code:
 public EventManager Instance { get { if( _instance == null){ _instance = new EventManager(); } return _instance; } } 

EventManager probably doesn't need this, but sometimes you want your singleton objects as monobehaviors so they can get Update or some of the app lifecycle callbacks, or even just have a thing hanging out in the hierarchy with a debug checkbox you can turn on and off. It all depends on what flavor of cheese you want, but you can do:

code:
 public EventManager Instance { get { if( _instance == null){ _instance = GameObject.FindObjectOfType<EventManager>(); } return _instance; } } 
You'll want some extra checks in case it doesn't exist, your game'll slow to a crawl if it does that search several times a frame. Another thing that would work is to make the events static on the EventManager, so you can do EventManager.onPlayerDamaged += UpdateHealthText; even if there isn't an EventManager.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Your Computer posted:

shot in the dark here; do any y'all wizards have any idea how one would go about implementing custom texture filtering in Unity's Shader Graph?

There's this whole thing about Texture2D objects and SamplerStates and whatnot which apparently is how you're supposed to do it in D3D11, but how to actually make any of this into code beats me. It seems like it would be as "simple" as making some sort of custom SamplerState that defined the custom filtering but all I can find out about SamplerStates is that they use built-in definitions about various filtering algorithms and that doesn't really help me much. Shader Graph has a Sampler State node but all it does is give you a drop-down of built-in filtering types. I also tried slotting in some of my code but the only texture input you can provide is Texture 2D which I honestly don't quite understand what even is, only that it's not a sampler2D :v:

Haven't messed with shader graph before but its been on my todo list, maybe I'll play with it tonight.

My naive guess is there's some way you can reference an offset coordinate in the texture, and then you can math the color values together to do filtering or whatever.

Although this seems to be the kind of thing where you'd be better off just writing a normal shader. You're free to mix and match right? So you could have a normal compiled shader for filtering and shaderGraph shaders for like, fur color or something else.

But there's gotta be a way to do it, it'd be too restrictive to be useful if not?

I dunno I'm talking out my rear end over here

KillHour
Oct 28, 2007


You can get the UV coordinates at the given point and use that to sample the texture 2d manually.

Metos
Nov 25, 2005

Sup Ladies

Surprise T Rex posted:

I might be able to get by using my old approach of doing everything in code, but moving the event subscription/unsubscription from OnEnable and OnDisable to Start and OnDestroy, which as long as I'm not enabling/disabling the GameObjects might be okay... but then I run into issues like "What happens when I don't disable a button, just make its alpha 0, can I still click it?" and so on.
Happy to clear those questions up for you and give it a little bit of an effortpost because I really think you're better of refactoring to this way:

CanvasGroup.interactable = false means you can't click on anything in that canvasgroup, so having one on the top parent of that particular UI that handles the appearing/disappearing ensures you can't click on any buttons you shouldn't be able to.
CanvasGroup.blockRaycasts when true will make the UI elements catch your raycasts which is generally how you click on buttons, and if its false means if you click there it'll go straight through it instead, so turning it off when invisible is also necessary because otherwise you'd actually be clicking on an invisible UI and not realising.

So that gives us a parent class like this:
code:
public class UIBase : MonoBehavior{
   protected CanvasGroup cg;

   protected virtual void Start(){
      cg = GetComponent<CanvasGroup>();
   }

   public void Show(){
      cg.alpha = 1f;
      cg.interactable = true;
      cg.blockRaycasts = true;
   }

   public void Hide(){
      cg.alpha = 0f;
      cg.interactable = false;
      cg.blockRaycasts = false;
   }
}
Looking at my own hierarchy, each one of these different UI parents prefabs has their own CanvasGroup, and when I want each particular UI to show it hides the previously active one and shows the new one.


That's all you need to know to do it that way. Lets you keep your events subscribed, update them even when they're invisible so you won't get frames where the old data displays because its just been turned on and THEN updates, and will avoid nulls when you try and update something but forgot its turned off.

(But next steps make UI fade-in and fade-out rather than popping, if you have DoTween its as easy as changing the cg.alpha lines to cg.DOFade(0f, .3f); and will make a huge difference to the feel)

Metos fucked around with this message at 07:02 on Sep 12, 2019

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Your Computer posted:

shot in the dark here; do any y'all wizards have any idea how one would go about implementing custom texture filtering in Unity's Shader Graph?

Check this out

https://www.youtube.com/watch?v=OakD6vLj4uo

Its not texture filtering but it is lerping between two texture inputs, you do that with the same texture but blend two UV co-ordinates and bam, you've got a stew baby texture filtering :)

E: Also check out built-in SamplerState which does filtering

Zaphod42 fucked around with this message at 01:16 on Sep 12, 2019

Chev
Jul 19, 2010
Switchblade Switcharoo

Your Computer posted:

shot in the dark here; do any y'all wizards have any idea how one would go about implementing custom texture filtering in Unity's Shader Graph?
In Unity like in D3D11, you're limited to the existing samplers. If you want custom filtering, you're gonna have to implement it yourself on top of the existing samplers (usually point filtering). The basics are as follows

Given texture dimensions (width, height) and coordinates (u, v), floor(u*width) and floor(v*height) give you texel position (x, y) (divide it by width/height to get the uv of that texel), and fract(u*width) and fract(v*height) give you the interpolation factors from that texel to the neighbours (x+1, y,) (x, y+1) and, combined, (x+1, y+1). Just sample those four texels with point filtering and implement your own interpolation.

You can do all that with nodes. It's not unity but blender and don't pay too much attention to the node tree since I grouped some of them and it's super small anyway, but here's a test implementing n64-style 3-point filtering I made a couple days ago, just to show it's doable:



EDIT: it's a bit too late tonight but if that can help I can provide an annotated version of the blender file tomorrow.

Chev fucked around with this message at 01:57 on Sep 12, 2019

Your Computer
Oct 3, 2008




Grimey Drawer

KillHour posted:

You can get the UV coordinates at the given point and use that to sample the texture 2d manually.
Sample it using what? :saddowns:

Zaphod42 posted:

Check this out

https://www.youtube.com/watch?v=OakD6vLj4uo

Its not texture filtering but it is lerping between two texture inputs, you do that with the same texture but blend two UV co-ordinates and bam, you've got a stew baby texture filtering :)

E: Also check out built-in SamplerState which does filtering
I'm at a loss at this one too :( As for SamplerState, like I mentioned in the post I'm trying to avoid that because I want to implement my own filtering. Specifically, the weird N64 three point filter:
code:
float4 N64BilinearFilter(sampler2D tex, float2 texcoord, float4 texelsize)
{

	float2 tex_pix_a = float2(1 / texelsize.z, 0);
	float2 tex_pix_b = float2(0, 1 / texelsize.w);
	float2 tex_pix_c = float2(tex_pix_a.x, tex_pix_b.y);
	float2 half_tex = float2(tex_pix_a.x*0.5, tex_pix_b.y*0.5);
	float2 UVCentered = texcoord - half_tex;

	float4 diffuseColor = tex2D(tex, UVCentered);
	float4 sample_a = tex2D(tex, UVCentered + tex_pix_a);
	float4 sample_b = tex2D(tex, UVCentered + tex_pix_b);
	float4 sample_c = tex2D(tex, UVCentered + tex_pix_c);

	float interp_x = modf(UVCentered.x * texelsize.z, texelsize.z);
	float interp_y = modf(UVCentered.y * texelsize.w, texelsize.w);

	if (UVCentered.x < 0)
	{
		interp_x = 1 - interp_x * (-1);
	}
	if (UVCentered.y < 0)
	{
		interp_y = 1 - interp_y * (-1);
	}

	diffuseColor = (diffuseColor + interp_x * (sample_a - diffuseColor) + interp_y * (sample_b - diffuseColor))*(1 - step(1, interp_x + interp_y));
	diffuseColor += (sample_c + (1 - interp_x) * (sample_b - sample_c) + (1 - interp_y) * (sample_a - sample_c))*step(1, interp_x + interp_y);

	return diffuseColor;
}
originally I figured I could just slot the code I already have into a custom function node in Shader Graph but my function takes a sampler2D which it uses with tex2D to sample, and the only texture input Shader Graph gives you is a Texture 2D object which from what I could gather needs to be sampled with SampleTexture2D together with a SamplerState which doesn't leave in any room for custom filtering.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.

Your Computer posted:

Sample it using what? :saddowns:

I'm at a loss at this one too :( As for SamplerState, like I mentioned in the post I'm trying to avoid that because I want to implement my own filtering. Specifically, the weird N64 three point filter:

originally I figured I could just slot the code I already have into a custom function node in Shader Graph but my function takes a sampler2D which it uses with tex2D to sample, and the only texture input Shader Graph gives you is a Texture 2D object which from what I could gather needs to be sampled with SampleTexture2D together with a SamplerState which doesn't leave in any room for custom filtering.

Yeah so if that's how you want to do it then you'll just feed your Texture2D into your custom function node.

The SampleTexture2D outputs color values, you could manipulate the input UV into SampleTexture2D, get a color, then mix that with some other SampleTexture2D color lookup using an adjusted UV, and then mix those using the logic you want to taste. But that'll mean having to do some of it before and some of it after the SampleTexture2D, so you can't do it all in one custom function.

Alternatively though, take the Texture2D and the render UV in as input to your custom function and then manually lookup the color from the texture using the UV and an offset, do the blending right there, and just output the color, so the whole thing is just your one custom function.

But at that point why not just dump the code into a normal shader?

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
Got tired of people pointing out how my ships spin about their middles instead of getting force applied at where their rudders would be if they had them, and this is the result:

https://i.imgur.com/CJOah4n.mp4

Compare the old behavior:

https://i.imgur.com/T95jTBM.mp4

The most noticeable difference between the two of them honestly is that the first one gradually ramps the rotational speed up and down when you're starting/ending turning. That's happening because I don't know how to calculate exactly how much force is needed to land the ship directly on the heading if that force isn't applied as torque about the origin of the ship. So it's smoother, but less responsive. I'm not sure how well that'll play; I feel like it's more important that controls be sharp and responsive than that the ship look good.

Obviously this also still has the ship's butt swinging around when you turn it. The problem I had with applying torque to the rear of the ship is that it was making the ship slide sideways. So, like, if you were facing along +X and tried to turn towards +Z, the ship would turn, but would also slide in the -Z direction. I "fixed" that by simultaneously applying a counter force to the middle of the ship, which prevents sliding but moves the pivot point forwards.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
One nice consequence of that is your wakes look much better just as a result! Nice.

I think something throwing me off is the ship is just turning way too fast for how slow its moving.

Although, 70 knots is pretty fast, isn't it? maybe you need to adjust the water shader or something so there's a greater sense of speed?

TooMuchAbstraction posted:

I feel like it's more important that controls be sharp and responsive than that the ship look good.

Agreed. But there's also a question of simulation or realism vs arcade gameplay. Real huge ships are pretty slow to respond to changes in their inputs.
A certain amount of lag could even be desirable and force you to plan your moves further ahead. Which becomes strategy.

TooMuchAbstraction
Oct 14, 2012

I spent four years making
Waves of Steel
Hell yes I'm going to turn my avatar into an ad for it.
Fun Shoe
Oh yeah, that ship is ridiculously quick, both in absolute speed and turning speed. Realistic speeds for WW2 warships are in the mid-30's, and they took a long time (and a lot of space) to turn around. And you're right, the sense of motion is screwed up by the waves; it's another thing on my to-do list.

Fair point though that the high speed of the ship is throwing off my conception of how clean it looks. Thanks. :shobon:

Your Computer
Oct 3, 2008




Grimey Drawer

Chev posted:

In Unity like in D3D11, you're limited to the existing samplers. If you want custom filtering, you're gonna have to implement it yourself. The basics are as follows

Given texture dimensions (width, height) and coordinates (u, v), floor(u*width) and floor(v*height) give you texel position (x, y) (divide it by width/height to get the uv of that texel), and fract(u*width) and fract(v*height) give you the interpolation factors from that texel to the neighbours (x+1, y,) (x, y+1) and, combined, (x+1, y+1). Just sample those texels with point filtering and implement your own interpolation.

You can do all that with nodes. It's not unity but blender and don't pay too much attention to the node tree since I grouped some of them and it's super small anyway, but here's a test implementing n64-style 3-point filtering I made a couple days ago, just to show it's doable:


well shoot, that shows me for posting without refreshing. That's even the same filtering :v: I'm still completely at a loss when it comes to actual implementation though, I haven't worked with graphs like this before and I was really hoping I could simply use the Custom Function node. If I have to implement the entire algorithm in nodes, where would I even start? Multiple instances of SampleTexture2D with different UV coordinates? It's breaking my brain trying to visualize this as a series of nodes.

first attempt looks like this, so clearly I am doing something wrong but I just have no idea what



Zaphod42 posted:

Alternatively though, take the Texture2D and the render UV in as input to your custom function and then manually lookup the color from the texture using the UV and an offset, do the blending right there, and just output the color, so the whole thing is just your one custom function.

But at that point why not just dump the code into a normal shader?
that was my original idea, but I simply can't figure out how to get any information from Texture2D or indeed what that format even is. It seems like it exists purely to be thrown into SampleTexture2D along with a SamplerState and not meant to be sampled directly, but maybe I'm just missing some way of accessing it.

As for why, well, because it would be neat :v:


e:
:ms: :toot:


I must've messed up the calculations due to the spaghetti that all the nodes turned into, but Zaphod's comment on doing some calculations before and some after made me realize that yeah, I can simply do that. I did the different UV calculations first, split it up into different samplers, then combined their RGB in a custom node to complete the filtering. Thanks y'all!

Your Computer fucked around with this message at 03:05 on Sep 12, 2019

Your Computer
Oct 3, 2008




Grimey Drawer
well now that I understand how it works I can shorten it a little bit more :pram:

Chev
Jul 19, 2010
Switchblade Switcharoo
Aw yeah, seems you've figured it out!

Didn't realize you had access to a node that can integrate custom code. But yeah, to explain a bit:

-Your fundamental mental obstacle was that you can't access texture data without a sampler state. A texture sample always has a sampler state and a texture, it is by definition the combination of those things.

-Yeah, as mentioned, when doing your own filtering you need to take several samples per pixel, as many as you need for your own sampling function (4 for bilinear, 16 for bicubic, etc). So for bilinear you'd take samples T00, T01, T10, T11 to have the whole neighborhood then do A = lerp(T00, T01, dx), B = lerp(T10, T11, dx) and finally lerp(A, B, dy) to get your filtered color.

-To reduce the number of samples you need you can still use the existing samplers. Like, whenever you need a weighted average of four texels you could use a bilinear sampler even if your final filtering isn't bilinear. Some of them fancy modern antialiasing, FXAA and onwards, put that to good use.

For N64 filtering, the paradox is that even though you're emulating 3 point filtering, on modern hardware you still need 4 samples, so what was a performance measure originally is now making the shader a tiny bit more complex. That's just how emulating things go I guess. That's because the pixel shader is going to sample all possible necessary locations. I mean, technically, the shader still can have conditions but that's what it'll do behind the scenes. In the bit of code you found, the condition part is one through the "step" function, which is "if a < b return 0 else return 1". So that code computes the possible colors for both 3-point pairs in a texel neighborhood and then weights them using step, effectivement cooshing between them.

Adbot
ADBOT LOVES YOU

baby puzzle
Jun 3, 2011

I'll Sequence your Storm.
A few of my players are getting a crash and I'm at my wits end trying to fix it. I've been working on this for weeks and I have gotten nowhere.

crash dump files don't tell me anything because there is nothing valid looking in there at all
including pdb didn't work because that just doesn't give a valid crash callstack either
I did manage to get a callstack, when i wrote my own callstack tracking thing
I thought it was a memory thing but I greatly reduced the memory use and that didn't do anything

The crash makes no sense of course, so it is probably some kind of loving memory corruption thing that I would probably need to spend hours actually debugging, which I can't loving do on some ancient netbook running Windows 7 across the world.

I don't even know what to do at this point. I'm just adding more and more logging but these paying customers are tired of sending me this poo poo and having the same result with every attempt to fix it.

e: do I literally need to have one of these people send me their computer?

baby puzzle fucked around with this message at 16:27 on Sep 12, 2019

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply