ASCII Renderer | Useless Game Dev

Поділитися
Вставка
  • Опубліковано 21 лис 2024

КОМЕНТАРІ • 216

  • @uselessgamedev
    @uselessgamedev  Рік тому +8

    Hey y'all, I now have a Patreon where I share the source code for every project, as well as bonus video content!
    Check it out if you want, there's a bonus video where I try out your suggestions for optimizing the ASCII Renderer
    www.patreon.com/UselessGameDev

    • @walmarp
      @walmarp 8 місяців тому

      I asked ChatGPT to code me an ascii game and the results are in a playlist on my channel/my most recent video should be the latest progress

  • @TheKingOfApples100
    @TheKingOfApples100 Рік тому +582

    this made me think of the viability of a 3d horror ascii game because of the time it takes to brain to process images and the effect of imaging things that aren't there because of the noise.

    • @jumbledfox2098
      @jumbledfox2098 Рік тому +18

      oh that would be so cool!

    • @bobbywatson942
      @bobbywatson942 Рік тому

      Check out Scanner Sombre

    • @cingiler3105
      @cingiler3105 Рік тому +14

      A very good idea to steal!❤

    • @ThePixelatedCoder
      @ThePixelatedCoder Рік тому +14

      Actually that’s something I’ve been planning for quite a while now is that something you would like me to update you on if I see through with it

    • @theworm7156
      @theworm7156 Рік тому +6

      And it would have custom characters that kinda look like the glitch text ones

  • @pauldaulby260
    @pauldaulby260 2 роки тому +195

    I wonder if you add a darkening 3d fog effect it would help visibility in the detailed 3d scenes

    • @uselessgamedev
      @uselessgamedev  2 роки тому +74

      That's a good solution. I tried that and I actually cheated during the 3D Game Kit part, the ASCII side is actually running a version with a heavily modified post processing profile, including a depth fog. I thought it wasn't interesting enough to talk about it in the video, but good catch!

    • @thelaiq
      @thelaiq Рік тому +2

      Thought the same

    • @ChickentNug
      @ChickentNug Рік тому +11

      @@uselessgamedev It's worth talking about literally anything imo. People like me know almost nothing about how this stuff works and videos like this are super educational. Maybe not everyone would like to know how everything works but it's really interesting to me

  • @nomadiccode6543
    @nomadiccode6543 Рік тому +109

    After watching your moebius-style 3D rendering video, and THIS, holy moly, you're great, thanks for these videos, they're so well produced

  • @lucbloom
    @lucbloom Рік тому +53

    Another way to improve would be to use a lot more ASCII or unicode characters and do a patch-matching lookup. Pre-compute what patch of e.g. 8x8 pixels matches best to which character. Then put it in a hash table and draw it. Preferably in a shader.

    • @uselessgamedev
      @uselessgamedev  Рік тому +34

      Yes! I found a paper describing how to do this while researching this video. I was less skilled at the time and wanted to get this channel going (I had been procrastinating on the idea for litteral years) so I kept it simple but I think I'll revisit it some day

    • @savagesarethebest7251
      @savagesarethebest7251 Рік тому +7

      This is what I did on my graphic calculator in school before I learnt the way to program it in assembler. It was some kind of trick, the display is black and white but if you updated it quickly enough you could have many levels of grayscale. I still can't understand that I out of 9k students was the only one that even made basic programs on the calculator. Or the only one who got it right on a few questions that were made to overflow the calculators.
      All you had to do was to count all zeros, remove them, make the calculations and then add all zeroes back. Supereasy. No need to think...

  • @leahwaymire2715
    @leahwaymire2715 Рік тому +19

    You could divide the RGB value by the brightest of the 3 to give it full brightness without the need for HSB conversion

  • @MechanizationStudio
    @MechanizationStudio Рік тому +6

    A few years ago, I couldn't even imagine how I could do something like this, but now I actually know how it can be done. I guess I did make some progress

  • @AmaroqStarwind
    @AmaroqStarwind Рік тому +25

    I like ASCII art that uses the full Unicode character set to represent different shapes and outlines.
    By cross-referencing the Depth Buffer and Normal Buffer, you could probably do this pretty wel.

  • @theseatoad
    @theseatoad 2 роки тому +63

    It would be interesting to see this run on an actual shell

    • @uselessgamedev
      @uselessgamedev  2 роки тому +21

      Oh there's plenty of videos about that around here.
      I think there's one in the description.
      But usually they involve actually making a valid renderer / raycaster and I certainly couldn't do that

    • @le9038
      @le9038 Рік тому +1

      NEED FOR VT100

    • @w花b
      @w花b Рік тому +2

      ​@jimmified you might wanna hold your horses Sir, they're escaping

    • @king_james_official
      @king_james_official Рік тому +1

      @jimmified you still need to render the game in a pretty high resolution. also i have no clue what "doing rtx" is, rtx is nvidia's gpu feature

  • @2001herne
    @2001herne Рік тому +3

    This is really cool. If there's one issue I have with this it's that it's run as a post-processing effect. In theory, rendering directly to ASCII would give you better results, as you could use the depth buffer to filter/hide detailed background elements.

  • @claytonrumley
    @claytonrumley Рік тому +5

    I like you you come up with ideas outside the box and then make them happen. Someday I will learn shaders, but in the meantime videos like yours are great inspirations! Keep up the amazing work!

  • @HugoBDesigner
    @HugoBDesigner Рік тому +1

    What I did when I wrote an ASCII renderer was to first render a list of characters I selected, pixelate that, then find the brightness value of each character. That skipped the manual fiddling part and allowed for a lot more variety of characters. Anyways, great video!

  • @Shack263
    @Shack263 Рік тому +2

    A very quick way to convey rgb values to an equivalent with maximum brightness is simple. Find the largest value (r, g, b) and divide every value by this amount. This will work assuming the values are represented by floats 1-0. This will raise every channel up so that one channel has maximum value but the proportion is kept the same.

  • @martijnvanderlee
    @martijnvanderlee Рік тому +11

    You could use the shape of ASCII characters to roughly match to a 2x2 (or even 3x3) density grid. Won't work for all cases, but might improve some.

    • @BaronVonScrub
      @BaronVonScrub Рік тому

      Considering the extra processing power it would take, you'd almost be forced to write this into a compute shader that uses a lookup map.
      Doable, but definitely messier. :)

    • @morgan0
      @morgan0 Рік тому +2

      honestly probably worth doing it all as a shader. all the effects are local and seem like a good fit for a gpu. and then it outputs a texture instead of text. just prerender the glyphs to a texture, which could be redone as needed based on the character size

  • @arkel_77
    @arkel_77 Рік тому +2

    as far as the more detailed scenes go, I would like to see what this effect looks like if the ascii grid is offset randomly - just a little jitter in how the camera is positioned relative to the character grid (maybe move the grid to match?) would create the same effect as having the 3d camera moving around. Also, it would give a similar effect to film jitter.
    Additionally, a method I once attempted was to take one character grid square of the original image, subtract it from each rendered character, and then choose the character with the least total error (in the value space). This provides better contours on the edges of objects, and if you include color in the error calculation you can also get better contours between objects that are similar in brightness instead of just being a blob. The approach would be something like this:
    1. For each character you plan on using (probably the 127 visible ASCII characters), run a shader on the input image (output image: text grid size, 256x144 or so) that calculates the error in each grid space of tiling the character across the image.
    2. Use another shader with all of the character buffers and rendered characters as input textures to choose and render the character with the lowest error in each grid space in the right color.
    I'd love to see what happens when if use this method or a similar one, which Luc Bloom called "patch matching," on the output of an edge detection shader - will we get good ASCII line art? If we combine the edge detection with the original image to increase the brightness of the lines, would we get the ASCII shading but also with good line art?
    I've been meaning to dive back into this one because I think it'd be a really cool render pipeline for an analog horror kind of aesthetic, loved the video!

  • @andrewdunbar828
    @andrewdunbar828 Рік тому

    One way to choose the characters is programatically, in face you can also choose the best monospace font to use the same way. Render out all the characters in the font, or just the ASCII range, into a square of the number of pixels you want and count the pixels or set vs unset, or sum their brightness if they render greyscale. Anyway this kind of thing is always fun!

  • @pafnutiytheartist
    @pafnutiytheartist Рік тому +10

    Would be Interesting to do it fuly as a GPU shader. Have a texture with all the ascci symbols in memory and switch between the characters based on luminence. Should be blazing fast compared to cpu.

    • @uselessgamedev
      @uselessgamedev  Рік тому +4

      Yes! I tried that back then but wasn't good enough at shaders haha. I may come back to it though

  • @shortguy436
    @shortguy436 Рік тому +3

    This could be made faster by pre-allocating space for the string. You are able to know precisely how large it needs to be.

  • @tymekgowacki4280
    @tymekgowacki4280 Рік тому

    hey, cool video, i like how you experiment with different stuff in your videos :) . a few ideas to consider:
    - processing this on CPU creates unnecessary overhead, and will cause slowdowns. it would be easier to just create a texture with all the characters and use it as a lookup. this way you can just create a simple postprocess shader that does the whole job, and it's cost should be negligible. And the color conversions wouldn't be a problem as well since it would be parallelized on gpu
    - right now you're mapping one brightness value to one character which is a bit limiting. different characters have different brightness in different places. if you split each character into, let's say 9 regions, and in the shader sample blocks of 9 pixels, you could have static 512 (2^9) elements array with mappings. it could create a more varied image
    - to avoid banding you could experiment with dithering. blue noise for a more organic look or indexed for an old school feel.
    - another intresting experiment would be to run edge detection first to actually use directional characters like / \ | L _ - etc
    - if you want to get the hue without saturation and value, and are really desperate with performance, my hackiest, cheapest way to get it is to just normalize the color vector. is it perfect? definietly no. is it dirt cheap and gets the work done in most cases. yes.

  • @sagielevy
    @sagielevy Рік тому

    This is awesome! Btw if I recall correctly TMP has some API where you pass it a char[] instead of a string to save on memory allocation performance. I used it once on mobile and it worked well. I don't know how it compares to Unity imGUI though.
    Edit: The api is `text.SetCharArray(textInCharArr)` where text is `TextMeshProUGUI`

  • @theisegeberg
    @theisegeberg Рік тому

    Clear and watchable! I love that you put the time in to do this!

  • @simtrip6452
    @simtrip6452 Рік тому

    I'd be interested to see if you'd get much of a benefit by parallelising this Jobs and Burst. It does seem like an "embarrassingly parallel" kind of task. You would need a very large NativeArray instead of a string, where the array has space for each ascii character surrounded by the tag. Maybe NativeArray would work since you're using ASCII, you just need to convert it to a string at the end with System.Text.Encoding.ASCII (which might end up being pretty expensive.) Secondly I don't know how well Color works in burst code, so you might need to make your own burstable version, which also means making your own RGBToHSV implementation for it. It's still probably more the kind of thing you'd use a compute shader for, but that's probably even harder and more error prone. Looks sweet though.

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Maybe! It does seem like a single letter is too small a task to warrant a job. Maybe launching like... 10 jobs that each take care of a batch of pixels. Thanks for the suggestion!

  • @Melds
    @Melds Рік тому

    Nice job. Reminds me of the AAlib demos. I those you could get higher resolution by increasing the number of characters. There was a patch for Doom, too,

  • @ZeDlinG67
    @ZeDlinG67 Рік тому

    You know what would be cool? To have multiple resolutions versions tagged to different entities at different range,
    could be it's own aesthetic on its own :D

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Yeah why not! The character could be more detailed than the background, that may even increase readability

  • @ihsankurniawan3591
    @ihsankurniawan3591 Рік тому +1

    hey! great video there! i have a question. since this renderer is actually render the actual scene first, then converting it to ASCII isn't it better to just render the scene directly to ASCII? sorry if it sounds like stupid question 🙏😁

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Yes it would certainly be better/faster.
      However that would require writing a renderer from scratch, for instance with raytracing, and that's above my level for now. Also having my "filter" working in unity means I can theoretically apply it on top of any unity project which is nice

    • @ihsankurniawan3591
      @ihsankurniawan3591 Рік тому

      @@uselessgamedev ah i see. seeing the trends using old school graphics makes me really excited to do game dev too. this video makes me really want to build the actual ASCII renderer!

  • @dghfgdhfdfghdhfg
    @dghfgdhfdfghdhfg Рік тому

    Change your name. RIGHT. THIS. MINUTE, Amazing Game Dev.

  • @Nilloc777
    @Nilloc777 Рік тому

    Awesome video I did a very similar project with one small difference I started from scratch and using ray marching. I actually prefer your approach of leveraging unity though! very cool

  • @coolbrotherf127
    @coolbrotherf127 Рік тому

    I feel like just building a shader that uses the ASCII text like editable bitmap textures directly within Unity would make this a lot easier to work with. Rasterizing the text after calculating what it should look like takes a bit of time that could be saved by precalculation. Then all you would need to do is calculate a single offset value per character and let the GPU handle the scaling and RGB values.

  • @szabib8048
    @szabib8048 Рік тому +1

    First of all, great video! I was always fascinated by renderers, never got to play with them as I'm too lazy / bad at creating meaningful 3D spaces to try them on...
    Question: Do you try and optimalize the color text generating, e.g.trying to write PPP instead of PPP ? All it would take is caching the current color in a single variable as I you go line-by-line, pixel-by-pixel anyway. Not sure if it would save much time, especially on "noisy" screens, or if you do it already just omitted mentioning it for the sake of video brevity (I did not see a check in the video at around 4:11 where the stringbuilder code is).

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Hmmm that's a great idea I think it could give a significant performance boost!
      I did think about it but I thought it would be too hard to do so I didn't even try, but now reading your suggestion it seems really simple, I'll have to give it a go! Thanks

    • @szabib8048
      @szabib8048 Рік тому

      @@uselessgamedev Well, there have been some great suggestions in the comment section, so I'm really curious that if/when you have worked all of them into the code, how would the performance change. It would be nice to have a 2.0 version, along with a before - after comparison, with different scenes.
      Regarding the text colorization:
      A further optimalization could be realizing that "black pixels", i.e. the space character can be ANY color, as it will not show up anyway. This shortens the string in 2 cases:
      - If the image starts out as black, there is no need for a color tag (for example your maze scene has a black skyline, so you don't actually need colors until the walls start to render)
      - If a colored area is followed by a black pixel there is no need to close the tag just yet, saving you at least 1 tag, more if the next pixels will be the previous color...
      Implementing all this would not take much, here is some pseudo logic:
      1. starting color = null, "SC"
      -- for y and for x cycle starts here ---
      2. calculate the ASCII of the next character, "NC"
      3. if we use color and NC is not a space:
      3-1 get the base color, "BC"
      3-2a if SC is null, append the open color tag of BC (this means we have no colors yet)
      3-2b else if SC not equals BC (there was a previous color that does not match) append close color tag, and an open tag of BC
      3-3 make SC the same color as BC
      4. append NC (out of the "if using color" structure, just like in your code)
      -- for loop ends here, of course add line breaks to the inner loop when x is finished --
      5. if we use colors and SC is not null (there has been at least 1 color on the screen and not only blackness) append a close color tag.
      (Regarding 5: Note that we only write closing tags so far if there is a color change, so the last used color will always be open at/before this point. Well, except - as stated - if the whole screen is black and we never opened a color tag anyway.)
      The above code might not be perfect, but you get the idea. I think it would be a nice boost for screens that have large areas of horizontally similar color, and hopefully not too much overhead for very "colorful" images that do not.
      Cheers, and good luck!

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      @@szabib8048 yeah at this point there have been enough suggestions that I might make a "trying out your ideas" video where I implement and profile the suggestions and compare them to the original. In any way your feedback is much appreciated ☺️

  • @CrownRock1
    @CrownRock1 Рік тому

    I actually really like the idea of a game where you can only clearly see movement. You could make it a horror game, or it could be used to simulate echolocation for a blind character.

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      Interesting. Like a game where every pixel fades progressively unless it's refreshed, forcing you to move constantly if you want to see around you, and rely on your memory

    • @CrownRock1
      @CrownRock1 Рік тому

      @@uselessgamedev That's one take on the idea, and I like that too.
      I was thinking of just using an extremely low-res monotone filter like at 6:39. The player is chased by a monster that can hear, so the player is forced to hold still and hide, but needs to move to see clearly. Maybe there could also be a button to make a clicking sound that would reveal your position, but temporarily increase the resolution.
      Or instead of a horror game, your main character could have a pet that you occasionally take control of, and the motion-based sight (however you implement it) could be used to simulate the pet's different perception of the world.

  • @Mooingpsychoduck
    @Mooingpsychoduck 8 місяців тому

    I was really expecting this to render the original graph at a highest resolution, and then render each 8x8, or 10x10 set of pixels as a single character. then you could make a map of cluster shapes to ASCiI characters, making use of the full ASCII set, not just five characters. effectively using the characters as rendering edges rather than brightness.
    this separation of lines/ascii from brightness, thus allowing you to make full use of the colors for brightness. this would allow you to render far more detail, with fewer characters, thus greatly improving visibility in low contrast/ static imagery. as a bonus, since the colors are independent from shapes, you can make use of foreground and background colors separately, to add additional color without increasing text resolution

    • @uselessgamedev
      @uselessgamedev  8 місяців тому

      Yes that's a good plan. I've been actually planning to revisit this topic to 1. do what you describe, and 2. port it to the GPU

  • @krovlood
    @krovlood Рік тому

    This is how the characters of Dwarf Fortress see the world

  • @SanyaBane
    @SanyaBane Рік тому

    It looks awesome! Great video!

  • @agsystems8220
    @agsystems8220 Рік тому

    Super cool! I think there is some low hanging fruit in terms of improvement available though.
    The linear brightness 'pixel' values are causing issues, and a curve cannot fully fix that. Compare a stop to a colon. The colon is twice as bright. A # compared to an @ is only maybe 10% dimmer, despite being two stops in your brightness scale. You probably want your pixel brightness values to be close to exponential instead, because we perceive relative brightness rather than absolute. Secondly, have you tried dithering it at all? Multiply each pixel by a random number between maybe 0.7 and 1.4 (if you switch to using exponential pixel brightness). The idea is that brightness differences that are smaller than one stop still show up as an increased probability of making the pixel brighter.
    The dragon crusher demo was a bit unfair on it. I don't think it would do particularly well even in grayscale, so grayscale low res was never going to work well.

  • @keineahnung1919
    @keineahnung1919 Рік тому

    I would recommend doing some floyd Steinberg or Bayee dithering in addition

  • @sdsdfdu4437
    @sdsdfdu4437 Рік тому

    Using more ASCII characters and also using a depth buffer to darken distant points would make the games clearer imo

    • @uselessgamedev
      @uselessgamedev  Рік тому

      i do this already with Unity's fog (which I guess uses the depth buffer). I don't show this in the video but there is a thick black fog, as you're 5 meters out it's completely black. From your suggestion I could make it even darker I guess

  • @storingjazzinmycheeksforth5319

    ASCII is at its best when its at a lowish resolution imo. I love being able to see that its a literal string of characters but somehow it still registers as a 3d space. shits cool as fuck

  • @LandmineSoldier
    @LandmineSoldier Рік тому

    This is very cool! Thank you Unuseless Game Dev

  • @havenbastion
    @havenbastion Рік тому

    making the default/background colour light grey instead of black would help your brightness.

  • @frogonlilypad
    @frogonlilypad Рік тому +1

    i'm wondering how hard it would be to speed up the color processing if you limit it to the traditional 16 color palette

  • @BlameTaw
    @BlameTaw Рік тому

    I would love to see a version of this using all 128 standard ASCII values, but not just using their pixel density but also the position of the pixels themselves. For example, L and T have similar pixel density, but T has it at the top and down the center, but L has it along the left and bottom. I'm not sure there's a good way to determine the best character for any given region very quickly though, and as you mentioned this already has speed issues. Still an interesting idea I think.

    • @uselessgamedev
      @uselessgamedev  Рік тому

      There is a paper linked in a description that utilizes the shape of the characters like you describe, if you want to see some interesting results. I may try and revisit this myself in the future too!

    • @BlameTaw
      @BlameTaw Рік тому +1

      @@uselessgamedev yeah I just saw another comment mentioning that paper, too. Certainly would be interesting to see!

  • @mikaelfoster9726
    @mikaelfoster9726 Рік тому +1

    Rip compression algorithm

  • @anfraylapeyre5294
    @anfraylapeyre5294 Рік тому

    You could reduce brightness based on distance to fade the background automatically :)

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      I do. Using the built in Unity fog, this way I can get colored fog if needed. But I ended up using black fog so the result is similar to what you're suggesting

  • @the_game1259
    @the_game1259 Рік тому

    You could use this if your game is like in a computer, and use it as a transition or something, overall very cool!

  • @SolarTara
    @SolarTara Рік тому

    You could use scene depth to render opacity as well, effectively making distant objects not clash with the foreground as much? idk

    • @uselessgamedev
      @uselessgamedev  Рік тому

      I already do actually. There's a thick black fog in the maze scene to avoid drawing objects that are too far away. Unfortunately there's no scene depth for 2D scenes in Unity

  • @ricdinchirock3625
    @ricdinchirock3625 Рік тому

    Idea: Use this to render a game at a very high resolution, but hide actual text in certain places.

  • @OctoBrains
    @OctoBrains Рік тому

    Reminds me of Faceball 2000 for the gameboy.

  • @bortsimons7457
    @bortsimons7457 Рік тому

    I remember OpenGL had this feature build in from scratch. I played quite some games that way

  • @Hyperboid
    @Hyperboid Рік тому

    Make sure the font of the terminal emulator is the same as the one you use for deciding which characters correspond to each brightness value.

  • @baptisteg4728
    @baptisteg4728 Рік тому

    Considering you want to emulate the look and feel of a terminal cant you restrict the color palette to a few pre-selected color to save on computing time ?
    although modern terminal offer 'any' color you want old terminal didn't and it would make sense both as a first iteration of your shader and for optimisation.

  • @davids91nk
    @davids91nk Рік тому

    you can directly modify the rgb values to maximize the (hs)value component!
    correction = 1.0 - max(r,g,b); // If the color range is 0..1
    corrected_color = Color( r + correction, g + correction, b + correction )
    I may be wrong tho

  • @tiagotiagot
    @tiagotiagot Рік тому

    Hm, I wonder if it would be possible to use something like a perceptual hash where strong contrast is detected, to get characters that more closely resemble the borders between smooth regions of different colors...

  • @ThePixelatedCoder
    @ThePixelatedCoder Рік тому +1

    Quick question is there any more ways to optimise this I swear you left a link to a document about optimisation or am I imaging stuff I cant remember. Edit - found it I was just being blind

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      For optimizing the *performance* , the comment section has had various very interesting suggestions.
      The linked paper aims at optimizing *looks* by picking characters that match the underlying lines and shapes
      (I might revisit both one day)

    • @ThePixelatedCoder
      @ThePixelatedCoder Рік тому

      @@uselessgamedev sorry its me again when im using a gui.label with the imgui how do i control padding between letters to make it fit with the screen size and also make it scale with screen size right now im storing the ascii chartcers in a string moving then render that with GUI.Label(new Rect(0, 0, Screen.width, Screen.height), ASCIIString, font); in the void OnGUI() and font is a guiStyle so i can controll the font so it is a mono space font ​

  • @GeoRoze
    @GeoRoze Рік тому

    A good game (and I know this meme is old now) to try this renderer on is… doom. No, seriously. I’d love to see how doom looks in this!

  • @ThibsWorkshop
    @ThibsWorkshop Рік тому

    Very underrated channel

  • @ThePixelatedCoder
    @ThePixelatedCoder Рік тому +1

    One idea im exploring that actually might work if you revist it is compute shaders

  • @mmheti
    @mmheti Рік тому

    If you want this to run faster dont get pixel inside the loop. Get all the pixels and loop through the array.

  • @artemisDev
    @artemisDev Рік тому

    i think it's possible to get huge speedup by using a fragment shader with a tileset bitmap font as the pallette

  • @while_1_action
    @while_1_action Рік тому

    I tryed to make a big open space location with 3d array of characters. But i didnt use colors, only symbols. C++ console is too slow when i use colors in it.

  • @timurryssuly305
    @timurryssuly305 10 місяців тому +1

    Hello! I know I'm late to the party, but how did you add the curve from 2:16?

    • @uselessgamedev
      @uselessgamedev  10 місяців тому +2

      Hi! The party never stops
      Lookup Unity's AnimationCurve.
      If you have a AnimationCurve field, the inspector will show this widget that allows you to set your curve.
      Then you just have to call curve.Evaluate(anyFloat);
      It's useful for creating easing functions that map a [0;1] float to another [0;1] float but there are other uses

  • @AlejandroArch22
    @AlejandroArch22 2 роки тому +2

    How do you do this? Is there a tutorial on this?

    • @uselessgamedev
      @uselessgamedev  2 роки тому +2

      I haven't seen tutorials specifically on this, however most of the relevant code is in the video.
      You might want to check out tutorials on manipulating render textures, and also on scriptable render features but this part is not strictly necessary. Displaying text is pretty straightforward, but the camera setup is a bit tricky.
      I do plan to share source code and more in-depth write-ups in the future, but I'm still in the process of setting everything up.

  • @kurtle2822
    @kurtle2822 Рік тому

    instead of converting to and from hsv you can take the greatest rgb value and divide it by 255, then multiply all values by that new number

  • @ThePixelatedCoder
    @ThePixelatedCoder Рік тому +1

    Sorry i am back how can i make all the characters fit like that ? Mine just won't fit or have funny spacing

    • @uselessgamedev
      @uselessgamedev  Рік тому +2

      If you're using ImGUI the GUI skin should have everything you need, if not change the GUIStyle of your text directly from code

    • @ThePixelatedCoder
      @ThePixelatedCoder Рік тому +1

      @@uselessgamedev yeah I don’t know how to get imGUI working I can’t make text field I tried but I can’t seem to find any

  • @nigeladams8321
    @nigeladams8321 Рік тому

    there's actually a full brightness character "█"
    I used it in an awful python script i wrote called DotGL. It turns your terminal into a pixel display by printing characters to the output. Its really flicker-y, but it draws lines

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      Yes, I looked at the entire character table when researching this video, and saw there were actually dithering characters ▌▐░▒▓ but I thought it would be kind of cheating to use them and would lose the "command line" feel. But maybe they could be used for an Obra Dinn effect

    • @nigeladams8321
      @nigeladams8321 Рік тому

      @@uselessgamedev that's fair, I was definitely going for a pixel look

  • @KucheKlizma
    @KucheKlizma 5 місяців тому

    Since you're working with a small number of symbols, perhaps instancing the symbols could be one possible strategy to improve performance among others? I don't want to be a downer, but 20fps isn't viable for a realtime videogame, so this definitely falls in needs performance optimization category.

  • @lincolngrisso7196
    @lincolngrisso7196 Рік тому

    what if you doubled the pixelated resolution, and then assigned characters to different combinations of light and dark 2x2s.

  • @domski196
    @domski196 Рік тому

    (I know nothing about Unity, but felt like asking this question lol) Am I getting this right? You're caching the results of that ToHtmlStringRGB for every primaryColor? Isn't that going to be thousands of values. While maybe not a massive deal actually, couldn't you narrow the colours so you only use like 16 or 32 or whatever, seems like with this rendering you can't tell the colour that accurately anyway.

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Yeah you're right this wouldn't scale in a real life scenario.
      Reducing the number of colours is a good idea!
      I think porting this on the GPU eventually will solve all the problems (framerate, memory issues, ...)

  • @yifengchen5274
    @yifengchen5274 Рік тому

    very nice and very on point

  • @gobble_gang
    @gobble_gang Рік тому

    Working on something like this myself the only difference is that I am using the actual windows command prompt for my rendering so my color options are HEAVILY limited. It brings about the issue of matching colors on an input frame to each nearest color option I have in console. I can't think of a way to do this without a data structure to use a nearest neighbor algorithm.

  • @lazergenix
    @lazergenix Рік тому

    Would it not be much easier to just render a scene at a lower resolution, then upscale it replacing the texture colors with ascii characters with a shader?

  • @dIancaster
    @dIancaster Рік тому

    Dwarf Fortress, into 2D, into 3D, into original rendering style of ASCII.

  • @forsomereason3713
    @forsomereason3713 Рік тому

    You have a very cool youtube channel.

  • @FurryEskimo
    @FurryEskimo Рік тому

    Brightness is one thing, but I’ve always wanted to find one that could also account for shapes if possible, but I’ve never found a program that attempts to do it.

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      There's a paper linked in the description, that does that, with some cool examples. Might revisit this topic myself some day

    • @FurryEskimo
      @FurryEskimo Рік тому

      @@uselessgamedev Cool, good to know, thanks!

  • @theworm7156
    @theworm7156 Рік тому +1

    This is literally the bloody matrix, just make everything green

  • @vaqquixx8620
    @vaqquixx8620 Рік тому

    How did you get the characters to overlap?

    • @uselessgamedev
      @uselessgamedev  Рік тому

      In the ImGUI GUISkin you can set the spacing between lines/chatacters

  • @candybluebird
    @candybluebird Рік тому

    If I was making this for a serious project, I'd make a text renderer that uses rgb values so you don't have to convert colors to hex

  • @thatoneguy2394
    @thatoneguy2394 Рік тому

    What IMGui settings did you use? I feel like my image keeps getting compressed or elongated and doesn't seem to scale with screen size once I switch to IMGui.

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Yes. Characters aren't 16:9 so it's expected. Also the space between lines is by default not what it should be. Also also, font.
      Luckily you can create a "GUI Skin" from the project Create menu, where all of this is configurable. You then need to reference it in your script (via a serialized field would be the best option) and at the start of OnGUI, use GUI.skin = your skin

  • @official-obama
    @official-obama Рік тому

    maybe to cut down the speed of converting to hsv you could divide by the max rgb value of the three, and maybe multiply by 256 if you had it from 0-255
    here it is but in javascript for clarity, in case you didn't get that:
    function brighten(r, g, b) {
    var max = Math.max(r, g, b);
    //max /= 256 //if rgb ranges from 0-255
    r /= max;
    g /= max;
    b /= max;
    return [r, g, b];
    }

  • @krystiano.610
    @krystiano.610 Рік тому

    Hmm, reading pixel values from the GPU is usually slow - you could improve the performance (and so skip some pixel calculations on the CPU) by blitting active render target to a render texture (with lower ascii resolution) with a custom shader, which converts RGB values to HSV, so then, when you read your pixels from the render texture, you would already have HSV values. You could also improve the speed of reading pixels by using GetPixelData method.

    • @krystiano.610
      @krystiano.610 Рік тому

      As for output ascii text component - this would probably need profiling, but I think it would be more performant to create 2D Array of imgui text components (1:1 pixel - ascii) and completely ditch the rich text approach, with GPU instanced material (or probably even with the built-in component color) it should perform better than parsing a color to and from a html color string

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Lots to unpack here, thanks for your suggestions!
      Blitting directly to HSV space is a good idea. That would offset that computation to the GPU, good catch! Might try it some time.
      GetPixel is not "reading pixel values from the GPU" as far as I know, Texture2D are in CPU memory.
      I don't know what you mean by "ImGUI text components", I'll assume it's a typo and you mean text mesh pro, you'd still be generating 10000+ meshes, albeit smaller ones, every frame, so I'm not sure this would work better. But you would indeed skip the rich text and HTML part, so maybe it evens out!

    • @krystiano.610
      @krystiano.610 Рік тому

      @@uselessgamedev Oh, my bad - looks like I missed the part where you were explaining that you are rendering the camera view to a low res render texture, I thought you were grabbing entire screen content - which you probably know - is slow - while Texture2D GetPixel is indeed on the CPU side, we still have to get the data from the GPU first (from the render texture) - but since you are already using lower res render target that's not an problem.
      As for why I personally advise to not use GetPixel / GetPixels is because there is a conversion happening for each method call. GetPixelData skips that conversion, but now its on the programmers side to correctly interpret the data.
      Now ImGUI - so it came to the light that I've never used it in Unity :D I assumed it's similar to the UGUI (component based). Not sure how ImGUI internally renders text, but in the end there will always be a plane, which needs to be generated. Depending how often it's updated - that's where we get the performance gains.
      TMP generates unique plane for every character, so the amount of generated planes doesn't change - no matter if it's single component or multiple ones. Ofc there will be an additional overhead for multiple components. Additionally draw calls count would increase (separate renderers), so without profiling I'm not sure which one approach would be faster.

  • @ellasorellabrella
    @ellasorellabrella Рік тому

    i want to see the steam version of dwarf fortress run thru this renderer :D

  • @ThePixelatedCoder
    @ThePixelatedCoder Рік тому +3

    Hello absolutely incredible video very underrated UA-camr the amount of polish in your videos I could easily think you have 5K + subscribers. Also is there any way I can have the code for the urn pipeline I am trying to make a small horror game using ascii and this is exactly what I am looking for is it possible for the code without any Color conversion (if you can’t do that I can change it myself) thx GC edit - just Like a Google drive or you could discord it to me (also do you have a discord server or anything) and how is the project setup is there like 2 cameras 1 for getting the render texture and 1 for displaying it and how would you set that up (at this you could just send me the project and I will look through it and change it to my liking) have a good day
    Sry for the rly long message

    • @uselessgamedev
      @uselessgamedev  Рік тому +1

      Hi, I'm glad you like the channel!
      I'm still in the process of figuring out a way to share source code for the projects (blog? Patreon? GitHub?) So for now I don't have a way to share it easily.
      However for this project all of the relevant code is shown in the video which is handy.
      You do indeed need a two camera setup, one which outputs to a render texture, and one to display the imgui text (while culling everything else)

    • @ThePixelatedCoder
      @ThePixelatedCoder Рік тому

      @@uselessgamedev 1. i would personally recommend github 2. with the character to grayscale i cant find a function for that and also how do you set it up and how do i turn the manipulated string into characters becuase i dont know how to do that

    • @uselessgamedev
      @uselessgamedev  Рік тому

      @@ThePixelatedCoder you have your sorted array of characters so a grayscale value from 0 to 1 maps the array from 0 to array.length.
      Repeat this for every pixel and you have your ASCII text

  • @nero5052
    @nero5052 Рік тому

    are voulmes possible in ascii

  • @ThePixelatedCoder
    @ThePixelatedCoder 10 місяців тому

    I know you probably won’t see this but I have finished off my compute shader for ascii (and colour compression for that retro style) and it defiantly gets much better performance (1000fps rn) if you were ever to touch this topic again I would defiantly recommend shaders (I used compute as I said earlier) still a great video

    • @uselessgamedev
      @uselessgamedev  10 місяців тому

      Hey I still read all comments ;) Congrats on getting this done. I agree using a compute (or any kind of) shader is certainly a better approach, if not the best. I may revisit this topic in the future though

    • @ThePixelatedCoder
      @ThePixelatedCoder 10 місяців тому

      @@uselessgamedev nice to hear honestly shocked you still read the comments still just as great a channel as ever

  • @lucbloom
    @lucbloom Рік тому

    Damn sun, how bout a few bitmaps of characters instead of using the text components?
    You can color it by setting the color on the mesh.

  • @ShadowDrakken
    @ShadowDrakken Рік тому

    don't most terminals only support 16 discreet colors though? :)

  • @dragoncosmico
    @dragoncosmico Рік тому

    with colors is called ANSI

  • @celebalert5616
    @celebalert5616 Рік тому

    this is what that guy was seeing in da matrix

  • @AustenSolvie
    @AustenSolvie Рік тому

    How do you figure out the bottle necks of a game?

    • @uselessgamedev
      @uselessgamedev  Рік тому

      Mostly with profiling. In Unity, the profiler tells you pretty much instantly what function is to blame for poor performance

  • @marcelofrau8818
    @marcelofrau8818 Рік тому

    I wonder if he used libcaca it could perform better.

  • @graydhd8688
    @graydhd8688 2 місяці тому

    Okay I had an idea that broughte right back to this video. I am building a custom ascii font made up of 3x3 characters- why three by three? Because every possible combination of pixels comes to only 512 characters- two ASCII tables. I could cut down by but id have to be careful here. I think if done right it has potential to create some😮 impressive terminal/ascii graphics combined with the techniques you are doing here.
    This all said this is quite ambitious and im not comfortable enough to attempt this, so to test the waters I'm creating a font designed to run Pac-Man in the terminal- where individual characters are sprites essentially, with separate characters in the font being able to contain actual animation frames. This obviously is limited as each "sprite" must only contain one color - though this will work fine for pac man. This will have me feeling more ready for a bridge project before attempting the big thing, but I'm hoping i reach a point where i feel ready to come back to this video to begin understanding how to integrate these concepts

    • @graydhd8688
      @graydhd8688 2 місяці тому

      Oh I think I'll create two fonts for the 3x3 ones- one for curved shapes one for angular ones!

    • @uselessgamedev
      @uselessgamedev  2 місяці тому

      Hi! Thanks for your comment. Having a smooth and an angular fonts sounds like a neat idea.
      Check out the link to the paper in the description regarding 3x3 rendering if you haven't already. I do plan to revisit this at some point and integrate 3x3 mapping for more accurate shape rendering.
      Good luck on your project!

    • @graydhd8688
      @graydhd8688 2 місяці тому

      ​@@uselessgamedev oh interesting, I'll give it a look! Looks a bit different from the implementation I'm aiming for, but I came up with a way of representing all 512 pixel combinations possible in a single extended ascii table- I drew out every single possible combination of 0 pixels (1 variant only), 1 pixel (9 possible variants), 2 pixels (36 variants), 3 pixels (84 unique variants), and finally 4 pixels (with 126 variants). Here's where my trick comes into play, as the above will fill an entire extended ascii table: to represent all the remaining variants, just invert the foreground/background of every existing character. I want to play around with this, scaling character larger to a lower resolution for a more pixelated aesthetic, or smaller characters to attempt more hi-resolution imagery. Really curious to see what comes of this experiment, I'll probably put the font up on github once I make it if you want to play with it, you could probably do a whole heck of a lot more than I could with it right now lol.

  • @thinker2273
    @thinker2273 Рік тому

    Couldn't this just be made into a fragment shader through which the entire screen is rendered? Would completely avoid having to do any computations on the CPU, thus significantly improving performance.

  • @blackfire2694
    @blackfire2694 Рік тому

    Can someone help me with figuring out what scripts and assets he used to make this work?

    • @uselessgamedev
      @uselessgamedev  Рік тому

      In terms of assets there's just the maze textures.
      In terms of scripts it's all native Unity stuff, using the ImGUI library, and the URP's scriptable renderer features

  • @notquitehim
    @notquitehim 5 місяців тому

    3:45 Gee I wonder why that is 😆
    *stares at 3 nested for loops to parse each frame*

  • @stephendallas9709
    @stephendallas9709 Рік тому

    could be cool for special items or view-finder in-game

  • @notnullnotvoid
    @notnullnotvoid Рік тому +1

    The fact that you didn't just do this in a shader is baffling to me.

    • @uselessgamedev
      @uselessgamedev  Рік тому

      I don't know how 🤫 or at least I didn't back then, maybe I could manage it now

  • @QUASAR098
    @QUASAR098 Рік тому

    very well made video!

  • @gloop3621
    @gloop3621 Рік тому

    How is converting rgb to hex expensive? All you need is to floor the components and cast them to a hex number, then it’s just a bit of string manipulation to cut off the ‘0x’
    HSV isn’t that expensive either afaik

  • @MRGCProductions20996
    @MRGCProductions20996 Рік тому

    you could implement a small constant camera twitch so its constantly slightly shifting perspectives. combine that with adding a slight dynamic wobble to the grayscale curve sort of to "add animation" to the textures

    • @uselessgamedev
      @uselessgamedev  Рік тому

      That's an interesting idea, I specifically tried to reduce movement as much as possible to try and keep the image as stable as possible. My hypothesis was that having every pixel/character blinking constantly would be a bit nauseating, but maybe I'm mistaken

  • @yokmp1
    @yokmp1 9 місяців тому

    YT compression seems to hate this ^^

  • @GreenFox1505
    @GreenFox1505 Рік тому

    A post processing shader could move your RGB to HSV way faster than your CPU can.