|
Raenir Salazar posted:I think they are, making it an array instead actually makes it about 2.2s faster. Largely negating the time of the second pass. Cool. Still looking for other potential problems, but in the meantime one thing you could try is pulling the results of some of the repeated calculations into temporary variables. Theoretically the compiler could be doing this for you, but I'm not sure how aggressive the C# compiler is about it. I'm talking about the things like the repeated ocurences of stuff like "y * maxWidth + x". It may or may not have any effect at all. e: y * maxWidth, for example could be pulled out of the inner loop entirely and only be recalculated when the value y changes. chglcu fucked around with this message at 05:06 on Oct 28, 2021 |
# ? Oct 28, 2021 05:03 |
|
|
# ? May 25, 2024 00:18 |
|
chglcu posted:Cool. Still looking for other potential problems, but in the meantime one thing you could try is pulling the results of some of the repeated calculations into temporary variables. Theoretically the compiler could be doing this for you, but I'm not sure how aggressive the C# compiler is about it. I'm talking about the things like the repeated ocurences of stuff like "y * maxWidth + x". It may or may not have any effect at all. That's an idea, I'll take a look. Another possibility might be the UnionFind; there's a different out out there here but I'm not sure how it is supposed to be used in practice. Is it like Label where I just instantiate a whole bunch of these or is it just supposed to be the one? Does Count() return the Root if the former?
|
# ? Oct 28, 2021 05:08 |
|
Raenir Salazar posted:That's an idea, I'll take a look. I'll have to read the article a bit more in depth to answer that one. I'm not previously familiar with the algorithm.
|
# ? Oct 28, 2021 05:16 |
|
chglcu posted:I'll have to read the article a bit more in depth to answer that one. I'm not previously familiar with the algorithm. No problem, only if you have the time and feel like it.
|
# ? Oct 28, 2021 05:18 |
|
Raenir Salazar posted:No problem, only if you have the time and feel like it. Heh, I'll see how far I make it tonight. It's getting a bit close to my bedtime now. The 2.2 seconds (or whatever remains after the dictionary to array change) in your second pass is probably mostly due to the recursive root lookup. You're doing that lookup every pixel when it could be done once per label. You could lookup the real roots in a step before that pass 2 loop and probably cut that down quite a bit. chglcu fucked around with this message at 05:30 on Oct 28, 2021 |
# ? Oct 28, 2021 05:26 |
|
chglcu posted:Heh, I'll see how far I make it tonight. It's getting a bit close to my bedtime now. Thanks! It's getting close to my bed time too, as for the recursive root lookup; I think each time it happens it sets the root so successive lookups *should* be assigned because it updates the root no? Or am I misunderstanding it? If not, I will try to recompute the roots for the Labels before filling my new label array. code:
For the previous suggestion though I think the compiler is doing some sort of optimization because changing the code only results in a very slight, 0.03s improvement. Code, I went and whole hogged it. code:
Raenir Salazar fucked around with this message at 05:44 on Oct 28, 2021 |
# ? Oct 28, 2021 05:41 |
|
Raenir Salazar posted:Thanks! It's getting close to my bed time too, as for the recursive root lookup; I think each time it happens it sets the root so successive lookups *should* be assigned because it updates the root no? Or am I misunderstanding it? If not, I will try to recompute the roots for the Labels before filling my new label array. It will still call the nested GetRoot() each time, since this.Root.GetRoot() won't be returning this most of the time. this.Root == this will only ever be true for one of the labels, as I'm understanding it. Something like this would avoid recaculating it each time (though it does still do a null check each time, which could be avoided by doing this a bit differently, though it's more of a change): code:
As for the other optimizations, yeah, the compiler was probably taking care of most of it, though I would be surprised if it pulled y * maxWidth out of the inner loop on its own (I don't think the C++ compiler will). From looking over that UnionFind article, I don't know that the approach it's talking about will help with optimizing the speed of building the initial data set you're currently working on. It sounds like its more about making use of the data later faster, which may or may not matter with the size of your data set (number of labels in your case, I believe?), but probably want someone with a brain that's still fully functional to confirm that. chglcu fucked around with this message at 06:03 on Oct 28, 2021 |
# ? Oct 28, 2021 06:00 |
|
Your Union implementation is wrong - when you join two elements, you need to find the roots of each tree and join those, rather than just joining the elements you're given. The Find implementation is correct, but probably isn't optimal - I wouldn't expect the compiler or jitter to attempt to inline recursive calls, so you're paying function call overhead every time even when you're only one step from the root. Look up and implement one of the iterative Find implementations instead. Lastly, you're allocating each label in a separate allocation which means they're going to be scattered around the heap. Consider making Label a value type, have an array that holds all the labels, and refer to each label purely by index in that array. If you set up your struct so that when it's zero-initialized, that correctly indicates a new label that hasn't been joined with anything yet, you can totally skip initializing labels and just keep a counter referring to the first unused one. For example: code:
(If you're clever, you can then notice that parentIndex and rank are never used at the same time, and you just need the bool and one int. If you're really clever, you can store the bool in one bit of the int as long as you're never going to need more than 2^31 different pre-merge labels).
|
# ? Oct 28, 2021 06:38 |
|
I can't immediately tell from the code, did you ever actually migrate it to a scanline-based floodfill algorithm? Because if not that's still going to be a huge saving. Also, I really appreciate that you're making an effort to do this, because I feel like many AAA games (e.g. XCom 2) don't give a gently caress that they take 30 seconds to prepare a level that should be the work of [negligible fraction] seconds.
|
# ? Oct 28, 2021 13:16 |
|
roomforthetuna posted:I can't immediately tell from the code, did you ever actually migrate it to a scanline-based floodfill algorithm? Because if not that's still going to be a huge saving. I'm currently using Connected Component Labeling which I understand is basically like scanline; but should be better. It scans through every pixel, assigns a label; keeps track of which labels are basically equivalent and then on a second pass merges them. The "One component at a time" version is basically scanline floodfill. Which in hindsight when I tried it I might've been able to get it to go faster with the optimizations that were suggested to me since then for the two pass. I'd have to go and look but its presumably not absurdly faster since its checking lots of pixels redundantly. And yeah I'm generally fairly interested in performance, some of the neat tricks I see every once in a while just really impresses me and just feels like the best way to improve as a programmer isn't just using the right algorithm but also finding ways to squeeze good performance out of it. Jabor posted:Your Union implementation is wrong - when you join two elements, you need to find the roots of each tree and join those, rather than just joining the elements you're given. Thanks for noticing this. As for the value type idea I found that when I did that for previous experiments for the else block it didn't do a whole lot, like 0.1s improvement but I'll try it. To clarify which Union implementation is wrong, the one from Here? Or is it the other one? I'm currently using the one I linked from CodeProject. quote:(If you're clever, you can then notice that parentIndex and rank are never used at the same time, and you just need the bool and one int. If you're really clever, you can store the bool in one bit of the int as long as you're never going to need more than 2^31 different pre-merge labels). One step at a time before we potentially engage in witch craft! I think the first step is fixing the Union code, as chglcu notes maybe the code from the codeproject article might not be what I want. But the code from the medium article/github confuses me as its unclear to me if its the same usage as the other. github link, medium article describing it It seems like in the Medium article they seem to know their data ahead of time so they preallocate the structure with the size of their data, and then start performing union operations on those indexes? I'm not sure if this structure is equivalent to the one I implemented/copied and just need to use it the same way. It's really unclear to me and other people when I google it seem to use a similar implementation; or something entirely different. Like is it: code:
code:
code:
|
# ? Oct 28, 2021 16:14 |
|
I'm looking into adding Steam Workshop support to my game. I already support modding in general, so this is just to make it easier for players to access mods. From reading through Steam's guide, it sounds like the steps involved are basically:
Is that accurate? I'm assuming that the process of finding and subscribing to mods is done by the user in the Steam client, so I don't need to build a mod browser in-game. That sounds like a lot of work that I'd prefer to avoid, personally. I would prefer not to curate the workshop, so that I'm not in the loop every time someone wants to change things. However, I fully expect that people will try to add objectionable mods for my game, specifically mods showing Nazi / white supremacist / Imperial Japanese symbols. If I use a non-curated workshop, do I have any moderator powers as the owner of the game?
|
# ? Oct 28, 2021 19:00 |
|
As luck would have it, I'm actually doing something at work that involves union-find. Anyway, I'd suggest using the struct, and implementing the operations (MakeSet, Find, and Union) as per this article: https://en.wikipedia.org/wiki/Disjoint-set_data_structure#Operations You're probably better off implementing them as functions rather than methods (or make the whole forest a class and implement them as methods on that). Use the versions that aren't recursive, like this one: code:
code:
HappyHippo fucked around with this message at 21:01 on Oct 28, 2021 |
# ? Oct 28, 2021 20:57 |
|
TooMuchAbstraction posted:I'm looking into adding Steam Workshop support to my game. I already support modding in general, so this is just to make it easier for players to access mods. From reading through Steam's guide, it sounds like the steps involved are basically: Many games put the mod uploading in a separate tool rather than the game itself, but I don't think there are any strict requirements about that. While not required, I think it's nice when a game can react to new Workshop subscriptions without having to relaunch the game. Moderating the Workshop is described on the Community Moderation page of the Steamworks documentation.
|
# ? Oct 28, 2021 23:23 |
|
Peewi posted:Many games put the mod uploading in a separate tool rather than the game itself, but I don't think there are any strict requirements about that. Thanks, sounds like my understanding is basically correct, which is good. Good call on being able to refresh subscriptions. My game has a very fast launch time (basically nothing loads until you actually go into a level), but given that I already have the ability to turn mods on and off without relaunching, I might as well also review the subscription list on the fly as well. Regarding moderation: that's a shame, that I don't have dictatorial control over content. What happens if someone uploads mods that add the Confederate flag? Or even the Imperial Japanese Navy flag? An awful lot of people don't know how problematic the rising sunburst flag is. One last question: how does testing work? I'd need to be able to add workshop mods without actually making all that stuff public...
|
# ? Oct 29, 2021 00:06 |
|
People are gonna do that poo poo whether you like it or not and you're not going to be able to police all of it.
|
# ? Oct 29, 2021 00:51 |
|
To be clear, the Union implementation in that CodeProject article is wrong. It might be sufficient for the exact use case the article author applies it to - proving that it is could be tricky. It's not correct as a general implementation. The wikipedia article HappyHippo linked is fantastic, it's a much better reference on UnionFind than any random hands-on tutorials you're going to see floating around. I would recommend implementing it yourself based on the wikipedia article - it's a good learning experience. -- On performance, the big secret (and it's not really a secret) is that having lots of tiny little object instances sucks for performance. They're great for having flexibility and being able to rapidly iterate on things through the design phase, but once you know exactly what you're doing and you know it needs to be high-performance, you really want to get away from objects and focus on a more data-oriented programming model. As a rather trite example, when you have an image, you don't model it as a big list of pointers to individually-allocated Pixel objects - instead it's a big array containing the pixel data directly.
|
# ? Oct 29, 2021 00:53 |
|
TooMuchAbstraction posted:One last question: how does testing work? I'd need to be able to add workshop mods without actually making all that stuff public... https://partner.steamgames.com/doc/features/workshop There's a "Running a private beta" section at the bottom.
|
# ? Oct 29, 2021 01:24 |
|
Peewi posted:https://partner.steamgames.com/doc/features/workshop of course, thank you for having better reading comprehension skills than I do!
|
# ? Oct 29, 2021 03:35 |
|
Alrighty I took a crack at it using the wiki article that HappyHippo linked and without cheating. I started with the assumption that I do need some sort of array to store nodes and that this needs to be preallocated; if I ever need more than the amount allocated probably best to do the reallocate by multiplying the size by 2 or something. code:
I opened up paint and did some trivial examples by hand and it seems to work? @Jabor I'm not quite sure what isChild is for, as it seems like whenever I assign a new label I can just set the parentIndex to itself and that should work? I'll go and attempt to integrate it and let you know if it explodes. e: Seems to run and is a whole second faster; first+second passes now take 4.15s. That suggests to me first pass maybe takes 3s and second pass is now down to 1s or similar as that inner-if statement: code:
Assuming this worked and didn't horribly fail in a non-crashy way. second pass is now: code:
e2: Apparently according to my profiler; the total runtime of my Start() is about 7.5s; with about 5.2s being Start() itself (with 4s being the twopass algo, 1.2s being everything else) and then 2s being my coroutine attempt to save an image to disk in a non-blocking way but it seems like that didn't work? Raenir Salazar fucked around with this message at 06:19 on Oct 29, 2021 |
# ? Oct 29, 2021 05:17 |
|
A coroutine is still going to block code execution unless you specifically yield back to the main program. You need an async disk write with a callback to notify you when it's done.
|
# ? Oct 29, 2021 07:14 |
|
KillHour posted:A coroutine is still going to block code execution unless you specifically yield back to the main program. You need an async disk write with a callback to notify you when it's done. Yeah the tutorial script here: https://docs.unity3d.com/ScriptReference/WaitForEndOfFrame.html seems to clarify that all this coroutine does is pushes execution until after some other stuff is done. Hrm. e: Wow, there's... Not a whole lot of information out there, this is unfortunate. Raenir Salazar fucked around with this message at 07:56 on Oct 29, 2021 |
# ? Oct 29, 2021 07:29 |
|
Raenir Salazar posted:@Jabor I'm not quite sure what isChild is for, as it seems like whenever I assign a new label I can just set the parentIndex to itself and that should work? The idea is that you don't need to initialize anything at all - since the 0 state already represents "a self-contained tree that hasn't been joined to anything". That way you don't need to touch the labels array if you're just creating new values, only when you're actually unioning things. If you're not using it just delete it from the struct, making your array fit the same number of entries in less memory will improve your cache hit rate and thus performance. Raenir Salazar posted:
This is wrong - if you're joining a small X tree to a larger Y tree, now all the parents of the actual node being joined will be dropped. You could just do a three-line swap with a temporary variable: code:
code:
|
# ? Oct 29, 2021 09:58 |
|
Ah for some reason I thought InNodeX and RootNodeY were identical but forgot that RootNodeX is the result of the Find operation on InNodeX. Thanks for catching that. e: I am just having ZERO luck getting asynchronous "write a texture to disk" functionality to work, something always pops up to make it not really work; with currently my original coroutine implementation so far working best. I tried making a Unity Job but needing to do .Complete() on the job handler basically makes it not work since I did it right away and I want this to be in my static texture generator class so I don't really have a convenient option of putting it into late update; maybe shoving it into a coroutine would work but that seems like overcomplicating it. I'll try .Net C# stuff next like File.WriteAllBytesAsync since maybe all I need to do is pass it the raw byte data from my Texture2D? 2 seconds to print my images isn't the end of the world but it'd be nice to print these textures in the background as I complete various steps of the generation process for debugging purposes without it contributing to editor lag. edit 2, successeroo: code:
I had trouble with getting various attempts at asynchronous code to work, but this seems to work. From 3.5s to 0.5s to run the "save to disk" block. e again: I had the world's stupidest bug. code:
As my labels seemed to weirdly converge to a random number. e whatever: WHAT THE HECK IS THIS. Probably my shader code e: Apparently it was my shaders, solution was to divide by id.x and id.y by 4. code:
e: Some trial and error and I think it has to do with the stride of my input data for the label; which is 16 bytes. e: Confirmed! By stride for the size of each element was 16 bytes, but according to the documentation the stride of an int is 4 bytes so my data was 4x larger than it was supposed to be, which weirdly resulted in my shader just painting it 4 times. By removing the division by 4 and setting the stride to 4 it works perfectly now. Somehow I figured this out, its a good feeling. Yeeeeeeeeeeeeeeeeeeeeeah! With rerandomized colours! Raenir Salazar fucked around with this message at 07:58 on Oct 30, 2021 |
# ? Oct 29, 2021 16:18 |
|
For some reason *three pixels* aren't right. The code seems to result in 3 additional water pixels and 3 less land pixels out of 34,000,000. This is perplexing, I'm currently working on outputting the exact results of the labelling process to compare with the pre-labelling silhouette process to see which 3 pixels are wrong. e: It could be that the Paint.Net magic wand tool isn't properly selecting all the right pixels but it would be weird to me for it to only be 3. e2, found the errant pixels; now to figure out why these 2 regions (it's a region of 2 pixels and a region of 1 pixel some distance away) weren't categorized properly. e3: Solved! It was something *extremely* silly and never would have caught it otherwise. I had: code:
code:
Raenir Salazar fucked around with this message at 03:55 on Nov 4, 2021 |
# ? Nov 4, 2021 03:19 |
|
Hello, I have a potential contract to create a political game with similar functionality to the PeaceMaker game, but on a different topic (Climate) with some visual novel elements: http://www.peacemakergame.com Normally I'd just do this in Ren'Py (python based visual novel engine) but this needs to be web based and can't be dependent on large plug-ins. Basically the game has events you respond to, policies you implement, characters that advise and comment, and polling of various interest groups .. oh and the excitement of budgeting! So I need to find a decent toolset for creating a responsive web app. Ren'Py's HTML version isn't stable so that's not an option. Unity's web stuff requires the WebGL thing, and I'm pretty sure this has to work on Chromebooks. Looking at LiveCode and Flutter as well as some visual novel engines designed for HTML (Tuesday-js) etc. Suggestions?
|
# ? Nov 6, 2021 19:16 |
|
VideoGameVet posted:Looking at LiveCode and Flutter as well as some visual novel engines designed for HTML (Tuesday-js) etc. So that's my negative suggestion. My positive suggestion is to just use raw Typescript or Javascript, it's pretty functional these days, and all the frameworks basically just add an additional layer that constrains what you can do, is a potential source of bugs, and is a source of risk (i.e. the framework gets a new version that isn't backwards compatible, it fixes some bugs, and you have to decide whether to migrate or not). Progressive Web Apps are also sufficiently mainstream now that for Android at least they're pretty viable as a "looks like it's running a real app" thing. (My understanding is that iPhone support at the installation level is still a bit dubious.) roomforthetuna fucked around with this message at 20:15 on Nov 6, 2021 |
# ? Nov 6, 2021 20:08 |
|
I want to make a game. I guess ill do a pong clone to learn. Rust is good for games right? Any frameworks?
|
# ? Nov 7, 2021 00:59 |
|
I feel it doesn't really get any better than Unity3D or Unreal for making your first games; the engine does a lot of stuff for you that you'd have to do from scratch and get frustrated by if you're programming without an engine. Apparently Rust is similar to C++ so maybe you should check out Unreal and work with Blueprints? One thing I did when I was a games programming instructor (for a highschool) was basically just modified existing Unity3D tutorials; so you could take Unreal tutorials and once you finish them, think of ways you'd like to extend them to be more fun or interesting or have more options.
|
# ? Nov 7, 2021 01:04 |
|
i also bought a lil wacom and aseprite for doing pixel assets. whats a good cheap/free music program? i wanna make some dope music a la my favorite games like secret of mana or sonic the hedgehog im thinking rust because i want to learn rust not just for games. i feel lilikeke it would be a good langauge to learn since amazon has leaned into it and it would help my career (day job im a dev making some real time web app serious business applications or whatever)
|
# ? Nov 7, 2021 01:31 |
|
if your day job is web dev you should consider checking out html5/javascript stuff like pixi.js, three.js, etc., and consider building your game with electron. rust has node-js interop via neon, and electron makes it easy to run stuff you can't normally run on the web, like a client side node-js module that runs rust code, alongside the rest of your web stuff it also makes the UI really easy to make
|
# ? Nov 7, 2021 01:43 |
|
As a language, Rust is poised to be excellent for game develepment, insofar as it can be used for both high-level abstractions and high-performance bit-twiddling, and most importantly, it does all that without a garbage collector. However, the game dev tooling ecosystem in Rust is nowhere near as robust as the established commercial tools. It all depends on how much extra work you're willing to put in to make up for that lack of parity. You might check out Are We Game Yet? to get a sense of the state of the art.
|
# ? Nov 7, 2021 02:09 |
|
ok ill check out pixi.js (there is also phaser too i think) thank you for the 'are we game yet' link. that is super helpful. anyone have any suggestions for music making apps? i messed around with garage band when it came out 15 years ago and made a couple songs so thats about the extent of my knowledge. i found lmms and it seems alright.
|
# ? Nov 7, 2021 15:28 |
|
VideoGameVet posted:
Godot's web support is pretty good, and their DSL is pretty close to python
|
# ? Nov 7, 2021 16:06 |
|
barkbell posted:ok ill check out pixi.js (there is also phaser too i think) Music making is a deep rabbit hole. There are a million different approaches to it, but the key is to just pick one bit of software and commit to learning it. Idk anything about lmms but it seems fine. I personally use Ableton but the specific software honesty isn’t that important. Experiment with that, explore your options as far as instrument plugins, and have a good time. If you’re specifically interested in making very authentic chiptune music like from the 16-bit days, there are instrument plugins (search “chiptune plugin” or “sega genesis plugin” or whatever to get started) that will emulate those sounds if you like.
|
# ? Nov 7, 2021 16:53 |
|
barkbell posted:anyone have any suggestions for music making apps? i messed around with garage band when it came out 15 years ago and made a couple songs so thats about the extent of my knowledge. i found lmms and it seems alright. personally, i like Reaper - it's compact, multiplatform, pretty cheap for a DAW and pretty easy on the system resources too. plus, it has a nice collection of lightweight but super useful VST plugins covering all the basics. the only drawback is you don't get any VST instruments out of the box (unlike, say, FL Studio or Logic). however, there's buttloads of free and quality vsts to be found online, so it's not that big of a dealbreaker imo that said, yeah, most DAWs nowadays are alright and it's really more of a question of aesthetics and workflow preferences rather than, say, sound quality (all DAWs sound the same anyway) nurmie fucked around with this message at 19:01 on Nov 7, 2021 |
# ? Nov 7, 2021 18:59 |
|
cultureulterior posted:Godot's web support is pretty good, and their DSL is pretty close to python Found something called: https://monogatari.io "Monogatari is just a webapp that uses pure HTML, CSS, and Javascript, with nothing special. The only plugns it uses are included from the get go and will require no downloads from your users. It's all self contained in the web page." Might do the trick. VideoGameVet fucked around with this message at 06:53 on Nov 8, 2021 |
# ? Nov 8, 2021 06:15 |
|
Godot is cool, but the web stuff requires the WebAssembly stuff and I don’t think it will work on Chromebooks.
|
# ? Nov 9, 2021 18:19 |
|
VideoGameVet posted:Godot is cool, but the web stuff requires the WebAssembly stuff and I don’t think it will work on Chromebooks. Godot's object model always seemed like it would make optimizing basically anything very difficult. Then again most games don't have enough things moving around where it would be a significant issue on modern hardware.
|
# ? Nov 9, 2021 18:22 |
|
VideoGameVet posted:Godot is cool, but the web stuff requires the WebAssembly stuff and I don’t think it will work on Chromebooks. I just sent https://godotengine.github.io/godot-demo-projects/2d/bullet_shower/ to my wife, and it runs on her Chromebook (though it ran kinda shittily until the screen was full of bullets, then was smooth after that, a bit weirdly - I guess something with the allocation of objects).
|
# ? Nov 10, 2021 01:24 |
|
|
# ? May 25, 2024 00:18 |
|
Spent a few hours but finally got my basic compute shader working to output 1 region: My plan basically is to use this result as a masking layer of sorts for my voronoi shader so the extents of the voronoi regions only cover "land" pixels. To simplify matters I might do this one at a time for each "region" and then overlay them to form the final image. I'm debating whether its worthwhile to try to calculate (currently on the CPU) the bounding box of each region, the centroid of each region could be useful information down the road. On the other hand, doing minimax on basically every pixel is going to slow things down significantly; unless I find a clever work around.
|
# ? Nov 10, 2021 06:18 |