Wicked Engine - Voxel GI [C++][DX11]

Поделиться
HTML-код
  • Опубликовано: 23 янв 2025

Комментарии • 127

  • @agnel47
    @agnel47 7 лет назад +35

    wow remember when big guys like Epic came out with tech demos, this is quality.

    • @CapnSlipp
      @CapnSlipp 4 года назад +7

      And then there was Unreal V with Lumen.

    • @agnel47
      @agnel47 4 года назад +1

      @@CapnSlipp yeah youre right

    • @hi_its_jerry
      @hi_its_jerry 4 года назад

      @@CapnSlipp beat me to it

  • @okaybutwhythough7456
    @okaybutwhythough7456 5 лет назад +5

    So you already have one of the best SSR implementations I've seen, combined with Voxel Ray Traced Reflections at a pretty high resolution even compared to too tier AAA games, and the least buggy Parallax Corrected Cubemap Reflections I've seen yet. Honestly your engine changed my mind about computer graphics in general.

  • @theottergames1969
    @theottergames1969 5 лет назад +6

    we should see more of this in video games. results are pretty damn good and this technic is probably much cheaper than full path tracing. so awesome :D

  • @unfa00
    @unfa00 4 года назад +7

    I gotta love that you're making this open-source!

  • @Gersberms
    @Gersberms 7 лет назад +50

    Nobody commenting on the Deus Ex music? Automatic upvote from me! Beautiful work.

  • @casvanmarcel
    @casvanmarcel 7 лет назад +14

    fantastic work!!!! very impressed

  • @oby1
    @oby1 7 лет назад +1

    I would love to push this engine to it's limits :)

  • @magyarfiu
    @magyarfiu 3 года назад

    Örülök, hogy magyar is foglalkozik ilyen munkákkal, egy nagy pacsi neked! :D

  • @Yetipfote
    @Yetipfote 5 лет назад +3

    "Meet with Manderley on level 2!"

  • @saltyyolk9934
    @saltyyolk9934 5 лет назад

    5:01 why the smooth mirror reflection leaking cube like voxel shape?

    • @GuilhermeMaia100
      @GuilhermeMaia100 5 лет назад +2

      Are you talking about the moving curtain? If yes, the reflection are based on the voxels itself, so real time reflection based on voxel are bad for mirror like surfaces, but are very good for rough materials.

  • @almighty151986
    @almighty151986 5 лет назад

    Using Voxels for reflection data also enabled reflection of objects not in screen space similar to ray tracing?

  • @maanastaneja5724
    @maanastaneja5724 7 лет назад +2

    Stunning Graphics!!

  • @dzima-create
    @dzima-create Год назад

    Wooow. Looks great!
    Can you please tell how does this voxelization into texture happens. I'm not using DX, I'm using OpenGL. And I have no idea how to convert the scene into voxels in realtime. Do you have any resource recommendations for implementing Voxel Cone Tracing?
    Thanks

    • @specialisthun
      @specialisthun  Год назад +1

      Just search for voxel cone tracing, I did the same.

  • @alexfuntico
    @alexfuntico 3 года назад

    can you do stylized worlds in your wicked engine?

  • @henryso4
    @henryso4 4 года назад

    Hey I was wondering if you'd ever ran into the issue of your voxels flickering when rendering the voxel texture per-frame? I have a somewhat working implementation - and the scene does render fine with me able to raymarch through it to produce stuff like reflections, however if I render to it every frame I start to get a weird flickering issue that is obviously not pleasing to the eye. If I render to the 3d texture maybe once, and just update it when something such as light moves for instance, it works fine - but then again having a static SVO isn't the best thing in the world

    • @specialisthun
      @specialisthun  4 года назад

      No, sounds like you either have a race condition or not moving the voxel grid in voxel size increments.

    • @henryso4
      @henryso4 4 года назад

      @@specialisthun Could be something along those lines - I might rule out race conditions though because this is still on D3D11 and my state seems to be setup correctly. I just use an orthographic matrix to transform everything into voxel space, then in my geometry shader do the conservative rasterization and stuff - cause I'm on a polaris GPU with no hardware conservative rasterization - and then discard any fragments that aren't seen to be inside the voxel grid with a basic test in the pixel shader. Horizontal surfaces like the floor in the sponza atrium render fine and don't seem to flicker at all, but vertical stuff like the draped cloth and pillars seem to like to flicker quite a bit. I'd probably assume it's something to do with how I'm binning voxels though, might check out what's going on there

    • @specialisthun
      @specialisthun  4 года назад

      @@henryso4 I also blend the voxel texture with the previous frame, to not let dynamic objects pop up hard.

    • @henryso4
      @henryso4 4 года назад

      @@specialisthun That could actually be quite useful, I'll take that into account. Thank you very much!

  • @StanislawFortonski
    @StanislawFortonski 4 года назад

    Breathtaking. Great project! :D

  • @Rhys510
    @Rhys510 6 лет назад +1

    This could change the way we do LOD in games if i am not mistaken, i mean making a point beyond rather within the players position to lower the poly count and texture quality. But i am not sure if the models are lower in memory by them self or voxelised. Either way, great stuff. Looks pretty :D

    • @specialisthun
      @specialisthun  6 лет назад

      Your idea is not far off. You can make voxel based impostors, or "3D texture impostors". The problem is, as you already said, that memory requirements can actually be higher than a mesh + 2D textures, and also, rendering them would involve rendering multiple slices of 2D textures or doing ray marching which can even be a larger cost than that. And if that's not enough, you have to find a way to compute lighting on them for multiple slices of the 3D texture. But it is definitely well worth to consider and try! Maybe switch to low res 3D texture impostors when really far away, and small screen coverage. Thanks for watching :)

  • @MariomasterNSMBHD
    @MariomasterNSMBHD 4 года назад

    Didn't they use exactly this for the Crysis remake?

  • @OBryanAguiar
    @OBryanAguiar 5 лет назад +1

    Very impressive, I read a paper about that last week... But won't anybody ask what minecraft texture pack is that?

  • @LogicEu
    @LogicEu 2 года назад

    This is amazing

  • @bluea75
    @bluea75 7 лет назад +1

    i got an error "WickedEngine_Windows.lib is not valid "

    • @specialisthun
      @specialisthun  7 лет назад +1

      Hugo Monge Hi, there are multiple projects, some build the static library of the engine, others build a runnable executable linking against the library. You pobably want to build and run the "Editor" project. :)

    • @bluea75
      @bluea75 7 лет назад +1

      hey thanks it worked nice job

  • @donglers
    @donglers 2 года назад

    would this be possible in godot?

  • @jovlem
    @jovlem 7 лет назад +13

    Really awesome work!
    I believe I read somewhere you use a GTX 1070, is that true?
    You might want to take a look at Godot's 3.0 implentation.
    They also have voxel cone tracing BUT it runs on very low hardware. It even runs on mid to high end mobile devices.
    I don't know exactly how they did it. I believe they use a probe and pre-bake the static meshes. The dynamic meshes are not baked so everything updates in realtime and runs blazing fast.
    Godot is open source so you can take a look at it!

    • @specialisthun
      @specialisthun  7 лет назад +4

      Hey thanks!
      Yeah in my engine everything is dynamic, even when capturing voxels, everything is re-rendered into the voxels (in a certain range around the camera). It will obviously be optimized. I will also check out Godot engine's implementation. :)

    • @jovlem
      @jovlem 7 лет назад +4

      The best scenario would to have both methods integrated in your engine:
      The pre-baking is great as it runs really fast. But it takes a bit longer for creating levels. Because each time you want to add or change a static mesh, you need to re-bake to see the result.
      So your "everything-runs-realtime" comes in handy for that as you can add stuff and it wil update immediately. So it's very usefull for quick testing and making adjustments.
      Add the moment you are ready with your level / game, there should some be a "bake-and-optimize-performens" button. So you get the best results.

    • @specialisthun
      @specialisthun  7 лет назад +5

      You are right. But pre-baked lighting also complicates the whole lighting pipeline though, that's the other reason I've been avoiding it.
      Take the light mapping technique for example; First your shaders explode combinatorically: everything now needs a shader with lightmaps and without. Also how do you properly combine lightmaps and dynamic lighting coming from the same light. The new Doom has a really nice tech which keeps two shadow maps for example: one for the statics and one dynamic part, so you can always combine to a correct result. I want something like that but it is not quite so efficient as light maps I think. I will probably not implement light maps in the near future, I don't think it would be interesting from a development perspective, just tedious to manage. If I'd be thinking of a concrete game, I would consider it at that point.
      I already have static reflections though, that is something that is more easily managable.

    • @jovlem
      @jovlem 7 лет назад +2

      Well, Godot is open source so just take a look at it. Maybe it gives you some new idea's!

    • @specialisthun
      @specialisthun  7 лет назад +2

      Will do!

  • @leroywalton4348
    @leroywalton4348 3 года назад

    superb !

  • @eborge9711
    @eborge9711 7 лет назад +1

    Can you optimize it well? Could the voxel scale have a relation to zdepth or player distance? Also, can occlusion culling force it not to waste resources on voxels behind you?

    • @specialisthun
      @specialisthun  7 лет назад

      I have some ideas how it could be further optimized, but I need more time. :) The voxel scale is adjustable in real time, but here it is not in relation with those values, but set by me explicitly. I have a system to easily query objects which are visible, so you could avoid voxelizing objects outside the view frustum / occluded but the simulation will be less accurate, because then light can not bounce from behind you for example. Now I am voxelizing every object in a box area around the main camera.

    • @eborge9711
      @eborge9711 7 лет назад

      Ah, very cool. I beleive voxel lighting is the future of lighting in games. Could you use it as a diffuse? Does it follow lambert's rules?

    • @specialisthun
      @specialisthun  7 лет назад

      This implementation only targets the indirect part of the diffuse lighting. You could do the direct illumination part with voxels too but I imagine it would be slower and more imprecise than just calculating it up front with forward/deferred lighting.

  • @championazhan2180
    @championazhan2180 4 года назад

    Now that's some sexy lighting

  • @Xardas105
    @Xardas105 5 лет назад

    Good work, is there any way to read the 3dtexture from the main loop? Could you provide example code for that? I have stored some information inside the 3d texture too, but I want to debug thje texture just in case i did something wrong.

  • @avada0
    @avada0 7 лет назад

    I wonder if GI (cone tracing or not) will be standard in the next generation of consoles.
    I hope they'll finally make the leap.

  • @almighty151986
    @almighty151986 6 лет назад

    I expect to see voxel based lighting and reflections become standard next console generation. The voxel based reflections are especially interesting as with Ray Tracing now coming on to the scene and having correct off screen reflections but abysmal performance maybe voxels can be a nice middle ground. Do you have any more information in regards to the limitations of using voxels to handle reflections? Can they reflect objects not in screen space? What's the performance hit? Are reflection resolution restricted in anyway?

  • @CGFUN829
    @CGFUN829 7 лет назад

    pllllllllllllllllllz what is source could and how to use it plz man ?

    • @specialisthun
      @specialisthun  7 лет назад

      Hi, you can download the program source code and compile it yourself, or download a built executable version, there is a link for it on my GitHub! :)

  • @mpetyahun2
    @mpetyahun2 7 лет назад

    Tudsz adni egy elérhetőséget kérlek?

  • @oby1
    @oby1 7 лет назад

    I'm no programmer, just the Asset guy. I'd seriously love to have this engine as an executable

    • @specialisthun
      @specialisthun  7 лет назад +3

      I'm thinking of doing a binary release in some form. But first I must do a cleanup, improve stability and user interface and also add support for more common model formats. I am working hard on it. Thank you for watching!

  • @remydubois922
    @remydubois922 7 лет назад +1

    dude i wanna lick the map i really hope one day we play games with really good graphics !

  • @MustafaYayaRonNi3
    @MustafaYayaRonNi3 6 лет назад +1

    That's amazing man...

  • @eborge9711
    @eborge9711 7 лет назад

    why does it render it as voxels? Wouldn't it be way more optimized to render it as a singular point?

    • @specialisthun
      @specialisthun  7 лет назад

      You mean the debug view? I just found it nice this way.

    • @eborge9711
      @eborge9711 7 лет назад

      So does it not actually render it as voxels? The voxels are just there as a representation?

    • @specialisthun
      @specialisthun  7 лет назад

      The voxel data structure stores lighting information for the scene and it is only used for querying nearby lighting for a pixel (with ray marching). The rendered cubes are just a means of debugging the voxel data.

    • @eborge9711
      @eborge9711 7 лет назад

      Ah okay.I was confused with all of the tech demos showing the voxels.

  • @matheusw931
    @matheusw931 6 лет назад +1

    Its amazing! I would like to ask a few questions:
    1- Among the various render techniques in real time, do you think that Voxel Cone Tracing is closer to realism? I see that he is not much mentioned.
    2- For someone who never code a render engine in life, where do you advise to start? I saw one guy say that the first step is to choose a language and then an api. I live in Brazil and here it is not very well documented, unfortunately. if it can indicate good books in English, it would help lot. Thank you!!

    • @specialisthun
      @specialisthun  6 лет назад +1

      Hi, thanks for watching. It's not like voxel cone tracing is closest to realism, that would be path tracing. But voxel GI can be run real time and get a cheaper kind of dynamic global illumination. You can start coding a rendering engine wherever you are. You don't need books, just look up tutorials on the internet, that's how I started. I don't know which is the best nowadays though... :)

    • @matheusw931
      @matheusw931 6 лет назад +1

      János Turánszki Thanks for reply. would you advise starting with rendering "easier" engines? if so, which ones? can you indicate good chanels on youtube? thank you so much, you are helping me a lot !!

    • @specialisthun
      @specialisthun  6 лет назад

      I'm not really familiar with any youtube content to get you started, though I am sure there are a lot. If you are starting out with graphics, I recommend learning C++ and DirectX 11. The process is usually like:
      1) render your first triangle
      2) textured triangle
      3) render a model
      4) learn shaders
      .... and a lot more.
      Once you are familiar with it, you will start to do your own thing. Also, you will be easily hired at a game studio (or other) as graphics programmer. :)

    • @matheusw931
      @matheusw931 6 лет назад

      János Turánszki thanks a lot my friend. I'll keep an eye on it!! :D

  • @wolflow94
    @wolflow94 7 лет назад +1

    Amazing !

    • @specialisthun
      @specialisthun  7 лет назад

      Thank you!

    • @wolflow94
      @wolflow94 7 лет назад

      I would say that voxels are like 3D pixels. You can think about minecraft like a game with big voxels. few engines use only voxels to modelize the environment, sometimes with the marching cube algorithm.
      But most of the engines deals with polygones i.e geometries rendered with triangles. Janos' engine uses polygones. Here the "voxel" part is just a post processing effect.
      If you are making a game engine with opengl from scratch i recomend you learnopengl.com for good tutorials about opengl.

    • @specialisthun
      @specialisthun  7 лет назад

      Hey, you can think of voxels as a logical representation of 3D space where every unit of the space is a "voxel". But if we are talking about hardware accelerated rendering it is always polygon based even if the underlying representation of the scene is "voxels". The simplest way of rendering voxels is that you render a cube in place of each voxel but there are much more sophisticated algorithms out there.
      In my demo I don't use voxels to represent my renderable scene, I use them to simplify my scene to more easily retrieve spatial information, in this case to calculate a simplistic "global illumination".
      Thanks for watching! :)

  • @joshklint881
    @joshklint881 6 лет назад

    How do you "render the scene into a 3D texture"? Do you render 256 cross-sections with an orthogonal projection?

    • @specialisthun
      @specialisthun  6 лет назад

      That is one way to do it. However, I am using an other method, which requires only one geometry pass for voxelization. From the pixel shader, I am writing to UAV instead of render target. The fragment world position can be used to index into the 3D texture when writing. You have to use atomic instructions to write. Also, there are other details to this, such as getting the best-fit projection axis for the triangle in geometry shader.

    • @joshklint881
      @joshklint881 6 лет назад

      Is best-fit projection necessary if you use conservative bias for the pixel coverage?

    • @specialisthun
      @specialisthun  6 лет назад

      Absolutely. otherwise you could get zero area triangle if it is projected sideways by accident. Selecting the best fit axis is just selecting the greatest component of the face normal (x/y/z) and swizzling the position components accordingly.

  • @base41studios72
    @base41studios72 3 года назад

    Goood Work!!! nice engine

  • @NathanFranckGameDev
    @NathanFranckGameDev 7 лет назад

    WICKED SICK

  • @NollywoodStudio
    @NollywoodStudio 4 года назад

    Incredible images, and magnificent pictures ... Does it work on Windows 8.1? ... Thank you very much

  • @IgorAherne
    @IgorAherne 7 лет назад +2

    Really good work!
    I couldn't get mine to work above 128^3 because I didn't use octree, just 3D textures. Are you using it?
    Also, even with 3D texture which is significantly easier to mipmap than octree, I couldn't get above 50 fps on 1920-1080 pixels on GTX 980, with the double-bounce GI.
    I Was mipmapping through a "mip-map-generating compute shader", with manual integer-coordinate sampling of texels. For some reason I couldn't get OpenGL to sample in-between 8 texels and use hardware's linear interpolation to produce the higher-level pixel. I was getting weird bugs with color (something to do with alpha)
    How come are you getting such speeds and are you using anisotropic voxels?

    • @IgorAherne
      @IgorAherne 7 лет назад

      Janos, how do you compute increasing intervals at which you are sampling the voxels with the cones? is it a simple tan formula with the radius of the cone at current advance? In that case, how do you prevent sampling the same voxel twice? If-else checks are very expensive, and so are "step + mix" combinations (3 times cheaper than if, but still).
      I tried using "A Fast Voxel Traversal Algorithm" by John Amanatides, but it was too slow, so I only used it in debugging the voxels, to visualize them.
      And did you encounter any banding issues? Because reflections look so perfect
      Excellent grafics, man

    • @specialisthun
      @specialisthun  7 лет назад +1

      Hey Igor, I use a GTX 1070 which is a very good gpu and can handle the 256^3 3d texture easily. My FPS also drops though below 50 if there are some more lights in the scene. I have yet to implement a light culling for the voxelizer, like a clustered light culling approach. When rendering the voxels, I already apply the lighting to the scene so I don't save albedo color like you (considering one of your comments on your vid). I pack the hdr color into an uint and write it out alongside the packed normals (also uint) into a single buffer and this is the fastest part in the whole voxelGI for me, the ray marching is a lot heavier. I don't use anisotropic voxels, I want to optimize the speed first, maybe after that I will try that.
      Sparse voxel octree is on my list, too. I also use a compute shader for generating the mips because I want a custom sampling which doesn't darken the texture so much. I could easily use the bilinear sampling but I use DirectX11.
      I have yet to implement a physically more correct sampling of the cones and the hemisphere, I just use some values now with trial and error. I avoid sampling the same voxel twice by keeping the raystep the at the minimum of 1 pixel length. But this unfortunately can miss a pixel if the ray travels diagonally.
      My reflections are actually really banding because of the crude ray-marching, but the normal map on the floor helps with that a LOT. :)
      Thanks for watching, your video was an inspiration and I think much better than mine. :)

    • @IgorAherne
      @IgorAherne 7 лет назад

      Hm, that's interesting. So by keeping raystep at minimum 1 pixel length, - do you mean restoring the world-space distance between two screen-space fragments and using it as a minumum of the ray steps? But it seems this might still cause sampling the same voxel if you look very close at some voxel with the main camera.
      Or you mean texture pixel (which are our voxels)? I also used 1 voxel *diagonal* length, which missed voxels a lot. But I think using the ray marching article, although making it precise, it would be way too expensive.
      Also, I remember attempting to pack my 'albedo + opacity' and 'normal + brightness' into 4 floats, but, as it always happens with me, I got some silly errors out of nowhere and eventialy diched the idea after several days. GJ for making it :D
      thanks, looking forward for more work by you!

    • @IgorAherne
      @IgorAherne 7 лет назад

      Also Janos, you probably are using it, but I managed to sqeeze-out extra 7-10 FPS with double bounce by using the x4 up-sampling interpolation technique from RSM www.klayge.org/material/3_12/GI/rsm.pdf

    • @specialisthun
      @specialisthun  7 лет назад

      Yeah I meant voxel pixel :)

  • @Hugobros3
    @Hugobros3 7 лет назад

    Awesome stuff

  • @M4nu3l90F
    @M4nu3l90F 7 лет назад

    Do you voxelize the whole map every frame or only the objects that moved in that frame?

    • @specialisthun
      @specialisthun  7 лет назад +1

      In this video, everything is re-voxelized each frame. An extension which would only voxelize the dynamic objects would be easy but would require more memory because static voxel information should be stored separately.

    • @M4nu3l90F
      @M4nu3l90F 7 лет назад

      Thanks! I've got another question. Is voxelization done entirely on the CPU? Do you exploit multithreading to speed up the voxelization process?

    • @specialisthun
      @specialisthun  7 лет назад

      The voxelization is performed entirely on the GPU, exploiting the rasterization unit. A very high level overview is available at Nvidia: developer.nvidia.com/content/basics-gpu-voxelization
      Which also means that it is highly multi threaded by the way. :)

    • @M4nu3l90F
      @M4nu3l90F 7 лет назад

      Great, thanks again!

    • @M4nu3l90F
      @M4nu3l90F 7 лет назад

      What I don't get from the paper is how you get from a UAV buffer in the GPU to a 3D texture. Do you transfer the buffer back to the CPU and then upload it as a texture or is there a way in DirectX to do that? Or you don't use 3D textures at all? I only know something about Open GL, no DirectX... and I was thinking on how this could be implemented in it.

  • @mpetyahun2
    @mpetyahun2 7 лет назад

    Szia!
    Ez egy stand alone progi? Vagy meg tudod csinálni Unity-hez is?
    Üdv
    Péter

  • @Mike.Garcia
    @Mike.Garcia 7 лет назад

    very impressive :D

  • @gaving.griffon2703
    @gaving.griffon2703 6 лет назад

    The engine you made here looks amazing! What's the framerate when MSAA is disabled?

    • @specialisthun
      @specialisthun  6 лет назад

      Thanks! Well, it's only much faster because MSAA is a performance hog. Btw, this video doesn't reflect current performance, it has been updated since :)

    • @gaving.griffon2703
      @gaving.griffon2703 6 лет назад

      János Turánszki
      Awesome, so how does the wicked engine stack up against unity or unreal in terms of performance?

    • @specialisthun
      @specialisthun  6 лет назад

      Obviously, as a single developer, I have no chance to keep up with those engines. I am however always trying to update the engine to use the latest and greatest rendering tech. I also intend to keep everything as light weight and dependency free as possible and because of this, new features are faster to implement here than a big bloated engine.

    • @gaving.griffon2703
      @gaving.griffon2703 6 лет назад +1

      János Turánszki still, the wicked engine is one of the most beautiful game engines I've seen to date.

    • @specialisthun
      @specialisthun  6 лет назад

      Thanks! I'm trying to work on it every day! :)

  • @gaving.griffon2703
    @gaving.griffon2703 6 лет назад

    So... how do you run this demo?

    • @specialisthun
      @specialisthun  6 лет назад

      This is released as source code only so far. You can find a link to it in the description, but you have to build it yourself. If you have Visual Studio 2017, this is straight forward, just press F5 after you opened the project.

    • @gaving.griffon2703
      @gaving.griffon2703 6 лет назад

      János Turánszki I tried it and it keeps saying it failed to biuld.

    • @specialisthun
      @specialisthun  6 лет назад

      I am sorry to hear. If you open an issue on GitHub and tell me some details what failed, then I can help you there.

    • @gaving.griffon2703
      @gaving.griffon2703 6 лет назад

      János Turánszki i was able to fix it (forgot to install the windows sdk), but now it's saying that "WickedEngine_Windows.lib is not a valid win32 application"

    • @specialisthun
      @specialisthun  6 лет назад

      Oh, that's good, you just have to select which project to run, for example right click on "Editor" project and build+run that.

  • @kingburrito7773
    @kingburrito7773 7 лет назад +1

    fucking brilliant

    • @specialisthun
      @specialisthun  7 лет назад

      Thanks! Also for starring my repos! :)

    • @mpetyahun2
      @mpetyahun2 7 лет назад

      Hogy állsz vele? :)

    • @specialisthun
      @specialisthun  7 лет назад

      Most nyáron kicsit belassult a fejlesztés.. :D

    • @mpetyahun2
      @mpetyahun2 7 лет назад

      Hát igen, Sziget :D :P
      Tervezed hogy mobile-ra is menjen (crossplatform) illetve VR támogatást?

    • @specialisthun
      @specialisthun  7 лет назад

      Van UWP support és Windows Phoneon szoktam tesztelni (persze nem a Voxeles részt, az eléggé high-end), de más platformokon még nem működik. Főképp grafikus API-t lenne nagy meló portolni. (Vulkan-t tervezek)

  • @Rene-uz3eb
    @Rene-uz3eb 2 года назад

    That Nvidia paper is the worst I've ever read I'm still not getting it, which is a pity cause I want this, but I guess I'll read all the references first

  • @EndsGamesStudio
    @EndsGamesStudio 6 лет назад

    wow!
    Fantastic!