Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Sep 14 22:52

    turanszkij on master

    updated third person controller… (compare)

  • Sep 14 18:20

    turanszkij on master

    camera constant buffer refactor (compare)

  • Sep 14 16:22

    turanszkij on master

    added chromatic aberration post… (compare)

  • Sep 14 14:53

    turanszkij on master

    sky + readme update (compare)

  • Sep 11 22:53

    turanszkij on master

    new-sky dynamic sky atmosphere updates (compare)

  • Sep 11 22:48

    turanszkij on new-sky

    dynamic sky atmosphere updates (compare)

  • Sep 08 21:55

    turanszkij on new-sky

    new-sky (compare)

  • Sep 04 20:42

    turanszkij on master

    cloud update (compare)

  • Sep 04 19:08

    turanszkij on master

    updated clouds and shadercompil… (compare)

  • Sep 03 20:02

    turanszkij on master

    small refactor (compare)

  • Sep 02 10:59
    turanszkij commented #28
  • Aug 31 19:29

    turanszkij on appveyor

    removed uwp (compare)

  • Aug 31 19:00

    turanszkij on appveyor

    block rdp (compare)

  • Aug 31 18:51

    turanszkij on appveyor

    rdp no password (compare)

  • Aug 31 18:46

    turanszkij on appveyor

    rdp (compare)

  • Aug 31 18:39

    turanszkij on appveyor

    try (compare)

  • Aug 31 18:28

    turanszkij on appveyor

    updated to vs 2019 (compare)

  • Aug 31 18:26

    turanszkij on appveyor

    updated to vs 2019 (compare)

  • Aug 29 19:20

    turanszkij on master

    lightmap fix (compare)

  • Aug 28 21:46

    turanszkij on master

    updated hello world sample (compare)

Kenji245
@Kenji245
@turanszkij any plan to create Lua scripting tutorial videos?
Turánszki János
@turanszkij
@Kenji245 Hi, no plans I'm afraid, but good idea, I'll think about it. I want to at least include a bigger lua script demo than the current one. I have made a basic third person character controller/dungeon generator in lua previously, but needs to be updated before I include it. Thanks for feedback!
Kenji245
@Kenji245
well, at least please describe how to link a single Lua Script(lets say a base script) to the main.cpp. i saw it from the tests project but i'm not sure if i'll do the right thing.
Turánszki János
@turanszkij
@Kenji245 I'm afraid there is nothing of a more advanced system in place yet, this is it, you can load text files with wiLua::RunFile("myFile.lua"). You can also run a file from a lua script by calling doFile("myFile.lua") from a lua script. You can also load a string from a C++ file by wiLua::RunText("myLoaCommands as text")
Kenji245
@Kenji245
alright basically thats the info i need :smile: i will try it out, thanks by the way
Turánszki János
@turanszkij
@Kenji245 Also, on application load, startup.lua file is called as a script if the file itself is found in the app working directory. And from a lua script you can immediately access the "main component" as main which has a few functions to control application state. Application state change could be something like calling main.SetActiveComponent(myGameComponent). The idea is that for example a main menu could be a game component like a Renderable2DComponent, and game could be DeferredRenderableComponent for instance and the MainComponent can switch between them. Sorry that it is not well documented yet...
Turánszki János
@turanszkij
@Kenji245 Oh and you can also press "Home" button in the application like Editor which will bring down a blue screen and you can write lua script, but very bare bones still, you can only input with keyboard
Matthias Moulin
@matt77hias
Was looking for something in "Interactive Indirect Illumination Using Voxel Cone Tracing" and noticed the color blend formula c :=
αc + (1 − α)α2c2. Isn't the α2 missing from your blend formula https://turanszkij.wordpress.com/2017/08/30/voxel-based-global-illumination/? For example an initial sample of [1,1,1,Ɛ], while marching, currently contributes [1,1,1] as opposed to [Ɛ,Ɛ,Ɛ]? Though, I assume the effect is small in typical scenes, since the low alpha values are contained in the coarse mip levels and the fully transparent cells which already have a color of [0,0,0].
Turánszki János
@turanszkij
Ahh, I don't have the time to look into this now, sorry. Have to finish the cpu-side rewrite, it is already taking too long. The current state of Voxel GI definitely can be improved and I am still slightly interested, and there are even more interesting things such as solid voxelization, anisotropic voxelization, voxel cascades. Though pure raytracing is much more satisfying and interesting these days, in my opinion. :)
Matthias Moulin
@matt77hias
wiECS.h's ComponentManager uses a separate collection of entities (32 bit values) and components. Sorting the latter requires sorting the former and updating the lookup table as well. I wonder if the gain of decoupling the entities from the components for processing outweighs the bookkeeping? I mean if you add the entity to each component, what would the performance drop be? Or is there another reason?
*Other reason for the decoupling
Was working on something similar to allow reordering the components. If a multi iterator which wraps multiple iterators would be compliant with the std, all the std algorithms could be used and everything would be transparent (ComponentManager could be implemented as a separable map for instance). Unfortunately, pairing iterators is not supported for operator*, operator->, operator[] :-( )
Turánszki János
@turanszkij
Good insight! That was the first way I did it, to include the entity ID in components (as component being a "base class" of sort that must always include entity ID). But I don't like that way because most of the time ideally I only want to access a component. I want a component to be as light weight as possible, what if I really just need a component which is just 8 bits? Then having an extra 32 bits always loaded would be very heavy. Sorting is not something that is done very frequently (really right now I only do sorting on the hierarchy components whenever I attach or detach), so I don't think it's important to optimize for that instead and lose flexibility. Also, when I only want to look up an entity ID, it's also more light weight. I sometimes do this just to see if an entity contains a specific component or not.
As for the other part, most of the time I'd like to avoid overloading operators and doing fully std compliant solution. Even though I slipped in a operator[] anyway to access components…
Matthias Moulin
@matt77hias
Thanks for the answer, János! I think it is also cleaner since you can treat components as values in comparisons and copies without having to handle the entity member variable.
I also assume that the transformation is retrieved the most some_component --> entity --> transform_component (e.g., for populating some model buffer).
I also have some slight incoherent questions about different aspects, if you don't mind me asking all of them :-)
1) If you kill an entity, you need to access all component managers (engine-defined and user-defined), right?
Matthias Moulin
@matt77hias
2) One aspect which keeps me puzzling is enabling/disabling an entity/component. You don't want to destroy and re-create these, but still want to keep them around, but that also means that each entity and component can be possibly disabled during some update cycle. A separate component for such state creates too many indirections since every component operation needs to check. Any thoughts on enabling/disabling?
3) Is it still beneficial to do skinning only once per frame? As far as I understand, skinning only differs with regard to the VS. Pre-computing the skinning once per frame consumes memory while still requiring some basic VS for shadowing, lighting, etc. (memory consumption vs memory accesses)?
Turánszki János
@turanszkij
Yes, for example if you see the serialization, you have to do special consideration for entities for several reasons, so it is also better to keep them separated, so if you would have custom constructors for components, they wouldn't interfere and less error prone.
Transform component can be retrieved as you said, however it is generally better to avoid the map lookup when querying a component manager by entity. Usually I aim to do it once per frame, so mesh instances would receive an index for their transform component, or just copy the transform component into them in some other cases. Then I can do several render passes, and no need for map lookups any more, only direct indexing.
1) Yes, you have to do it, but you can make a system that takes care of that. A system in my opinion is just a function that takes the ComponentManagers that it operates on as arguments.
2) What about having a boolean in the component indicating if it is enabled/disabled? It seems like it is just a specialized behaviour, not needed for every type of component. Better yet, to avoid booleans in structs (because of alignment issues), and have bitfields with packed booleans in them. It even makes it easier to serialize and keep backwards and forward compatibility
Turánszki János
@turanszkij
3) I still prefer skinning in compute shader. Sure you have increased memory requirements, but several benefits too:
  • vertex shader permutations vastly simplified
  • Also use skinned meshes to spawn particles from
  • reuse skinned meshes across several render passes or even frames
  • use async compute
Matthias Moulin
@matt77hias
So with regard to the meshes, you have some extra intermediate set of components which more directly map to GPU buffers? E.g., transform, mesh, material are separate components which are merged in some fourth component per frame that can be directly mapped to a constant buffer (or just populate the buffers directly without storing these intermediates)?
You're right about the boolean, it should indeed be some elementary operation that should be part of specific component interfaces.
Matthias Moulin
@matt77hias
For the skinning, you'll indeed have some extra VS but are the permutations that large for VSs (not sure, though, how many different vertex layouts you handle)? You can indeed reuse the data, but these data is passed to the regular VS which still requires a certain number of cycles for each render pass? The particle benefit is a nice feature, but I guess SO can handle that as well? Anyway thanks for the feedback, animation stuff is not for very soon yet :D
Turánszki János
@turanszkij
Right now, I have the GPUBuffers as part of the MeshComponent and MaterialComponent which are used when rendering the scene. Then the renderer assembles a render queue which is just direct indices to ObjectComponents (which are the mesh instances, kind of a stupid name, but I got used to it) and MeshComponents. Then the renderqueue gets sorted by meshIndex and distance to camera, and the nice thing is that it only sorts indices which directly index into ComponentManagers (these not change after the Scene::Update has been called, so indexing directly is safe for one frame).
For skinning, permutations might not be huge, but still very much easier to manage without a complicated shader build system and one person only. Kind of why I don't have tangent vertex buffers too. The skinning data is not passed to any vertex shader, they just swap the unskinned vertex buffers with the animated ones. Streamout can handle skinning, but the API is clunky and inefficient as it is a geometry shader extension (even if you have it as part of vertex shader, you still compile it as GS as far as I can remember). Then StreamOut stage has ordering requirements which make it less efficient than Compute Shaders. Also, you can use groupshared memory in CS which I also use for skinning.
Matthias Moulin
@matt77hias
So a MeshComponent contains things like VertexBuffer and IndexBuffer. MaterialComponent a material buffer. But what about transform data? I presume you could combine transform and material data (all model data) in one buffer for each instance?
Turánszki János
@turanszkij
You can take a look at wiRenderer::RenderMeshes() in wiRenderer.cpp if you are interested. This function is doing instanced draw calls. The renderqueue is a list of (meshindex, instanceindex) sorted by meshindex. It maps a big gpu buffer, then copies the instance matrices (by indexing into transform component manager) into it. After that it loops through the meshes and calls DrawIndexedInstanced for each and offsetting into the instance buffer.
Matthias Moulin
@matt77hias
What are the invalid entities for?
Turánszki János
@turanszkij
Not sure which particular one you mean, but usually it just means "nullptr" in the ecs world. It is the 0 value. It is a value that can never be a valid entity, and the ComponentManager is unable to contain it. There is a nice feature to this: there is a hashmap optimization that can be done, if there is a designated special value that can never be a key (the hashmap can be flattened into a simple array, and this specific key will be responsible of separating hash buckets). Although I am still using std::unordered_map, hopefully replacing it with yield a big performance increase with minimal code change. I am still contemplating whether to start writing my own, or include a third party fast hash map.
Matthias Moulin
@matt77hias
But without the optimization you mention, you do not use invalid entities?
Isn't the flattening of the hashmap prone to lots of overhead if the the first buckets are too small?
Alternatively, you can assume that all hashed keys are equally likely so that all buckets can reserve the same number of elements.
Then you can use a special value to tag empty slots, or just use a separate array on the stack containing the size (!= capacity) of all the buckets.
Matthias Moulin
@matt77hias
And the capacity of a single bucket is just allocated (size / (sizeof key-value pair) * (number of buckets))
Correction: no size array, since the number of buckets may grow (or shrink) dynamically.
Turánszki János
@turanszkij
I still use invalid entities. When declaring an entity somewhere, I always initialize to invalid entity. The ComponentManager always asserts if it finds an invalid entity. It is generally used when entity is a member of something, it can be checked for invalid entity and I know that it references nothing if it is invalid. Like MeshComponent for example has an armatureID entity as its member. If that is INVALID_ENTITY, that means the mesh is not deformed by armature.
For the hashmap, I haven't tried writing it yet, so I can't really comment. But in this video the guy speaks of the expected speedups of a fast hashmap implementation and comparing it to std::unordered_map: https://youtu.be/M2fKMP47slQ
Turánszki János
@turanszkij
I said that I use invalid entities for specifying unused entities, so that would also mean I am actually not using invalid entities for anything. So clarification: INVALID_ENTITY means that it should not be used because it doesn't point to any components
nemesis567
@nemesis567
Hello
Turánszki János
@turanszkij
@nemesis567 Hi, if you have a question, ask away or just chat. :)
nemesis567
@nemesis567
Thanks
What's the current workflow for creating a new compute shader?
Turánszki János
@turanszkij

@nemesis567 You can just create a new compute shader in the WickedEngine_SHADERS project. When it's compiled, it will be output to WickedEngine/shaders folder by default. Then the simplest way is to load it via the resource manager:

ComputeShader* mycomputeshader = (ComputeShader*)wiResourceManager::GetShaderManager().add("mycomputeshader.cso", wiResourceManager::COMPUTESHADER);

(The wiResourceManager::GetShaderManager() is not necessary, you can use any resource manager object, but this one will be cleared when wiRenderer::ReloadShaders() is called)

You don't have to create the shader in that project though, it can be anywhere, you just have to load the compiled shader object (.cso) file
Furthermore, there are lots of examples how to create shaders in wiRenderer.cpp LoadShaders() function, good luck!