Jump to content

Josh

Staff
  • Posts

    23,313
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh
    The beta branch now contains an update that adds C++11 support for GCC on Linux. To use this you must enable C++11 support in the compiler settings in Code::Blocks. Select the Settings > Compiler and Debugger... menu item and then check the box indicated below.
     

     
    All new projects created from the Leadwerks templates will work correctly out-of-the-box.
     
    Your existing projects need a couple of new libraries added to them. The easiest way to do this is to open the CBP project file in a text editor. Find two chunks of text that look like this:

    <Linker> <Add library="$(LeadwerksPath)/Library/Linux/Debug/Leadwerks.a" /> <Add library="dl" /> <Add library="openal" /> <Add library="GL" /> <Add library="GLU" /> <Add library="$(LeadwerksPath)/Library/Linux/libluajit.a" /> <Add library="../../libsteam_api.so" /> <Add library="X11" /> <Add library="Xext" /> <Add library="pthread" /> </Linker>
     
    Add these two libraries to the list. Remember, this will occur twice in the file.

    <Add library="Xrender" /> <Add library="Xft" />
     
    Save the project file and you're ready to use C++11 features with Leadwerks on Linux.
  2. Josh
    This shows the fundamental difference between shared pointers and manual reference counting.
    Leadwerks 4:
    void Material::SetTexture(Texture* texture, const int index) { if (this->texture[index] != texture) { if (this->texture[index]) this->texture[index]->Release(); this->texture[index] = texture; if (this->texture[index]) this->texture[index]->AddRef(); } } Leadwerks 5:
    void Material::SetTexture(shared_ptr<Texture> texture, const int index) { this->texture[index] = texture; } The second example automatically does the same thing as the first (basically) but you don't have to worry about making mistakes.  When the texture is no longer referred to by any variable, it will be automatically deleted from system and video memory.
  3. Josh
    Christmas is the season for giving, and it also happens to be my biggest sales time of the year. The Steam Winter Sale just kicked off and I need help getting us up on the first page of top sellers:
    http://store.steampowered.com/tag/en/Game%20Development/#p=0&tab=TopSellers
     
    How do we do that? We drive web traffic to the Leadwerks Steam Store page. Here's a simple way to do it. If you could "Share" this Facebook post with your Facebook account, I would appreciate it:
    https://www.facebook.com/Leadwerks/photos/a.485763276182.322419.352779906182/10153713393416183/?type=1&theater
     
    That should push us up to the first page.
     
    Thanks for your help. Hope you're enjoying the new vegetation system!
  4. Josh
    CSG carving now works very nicely. The hardest part was making it work with the undo system, which was a fairly complicated problem. It gets particularly difficult when brushes are in the scene hierarchy as a parent of something or a child of something else. Carving involves the deletion of the original object and creation of new ones, so it is very hard to describe in a step-wise process for the undo system, especially when all manner of objects can be intermixed with the brush hierarchy.
     

     
    Eliminating the ability for brushes to be parented to another object, or another object to be parented to them, would solve this problem but create a new one. Compound brushes such as arches and tubes are created as children of a pivot so that when you select one part, the entire assembly gets selected. Rather than a hierarchy, the old "groups" method from 3D World Studio would be much better here. It becomes a problem when you carve a cylinder out of a brush and are left with a lot of fragments that must be individually selected.
     
    At the same time, the scene tree needs some love. There's too many objects in it. The primary offenders are brushes, which maps just tend to have a lot of, and limbs in character models.
     

     
    Filters like in Visual Studio could help to eliminate some of the noise here. I would set it up to automatically add new brushes into a "Brushes" folder in the scene tree. What would be really nice is to eliminate model subhierarchies from the scene tree. This means the limbs of a model would be effectively invisible to the editor, but would still allow parenting of different objects to one another. In the screenshot below, the crawler skeletal hierarchy is not shown in the editor, but he has a particle emitter parented to him Opening the model in the model editor will still show the entire sub-hierarchy of bones.
     
    Notice the character has a point light as a child, but its own limb hierarchy is tucked away out of sight.
     

     
    If the model sub-hierarchy were not shown in the scene tree, this would free me from having to treat hierarchies as groups, and implement a grouping feature like 3D World Studio had. Filters could be added as well, instead of relying on a pivot to organize the scene hierarchy.
     

     

     
    To sum up, this change would cause group selection to be based on user-defined groups rather than limb hierarchy. The sub-hierarchy of model limbs would no longer be visible in the editor. Objects could still be parented to one another, and they would be parented to the base model rather than a specific limb.
     
    What changes:
    Ability to adjust individual limbs in model hierarchy. For example, if you wanted to add a script to a tank's turret, the turret should be a separate model file you parent to the tank body in the editor. It would not be possible to set the color of one individual limb in a model file, unless you had a script that found the child and did this. Setting a color of the model would affect the entire model, including all limbs.
    Ability to parent a weapon to one specific bone in the editor. Scripts cam still call FindChild() to do this in code. Which is what I suspect most people do anyways, because diving into the mesh limbs to find one specific bone is pretty difficult.

     
    What we gain:
    One button to group / ungroup objects.
    No more confusing multi-selection of entire limb hierarchies.
    Compound brushes no longer need a pivot to hold them together, can be created as a new group.
    Carved brush fragments can be automatically grouped for easy selection.
    If model hierarchy changes, reloaded maps match the model file more accurately; no orientation of limbs in unexpected places.
    Faster, less bloated scene tree without thousands of unwanted objects.
    Better entity selection method to replace drag and drop.
    The scene tree in general feels a lot less weighted down and a lot more manageable.

     
    It is possible this may modify the way some maps appear in the editor, but it would be an "edge case". Improvements are needed to accommodate brush carving and address the present limitations of the scene tree. This does not involve any changes to the engine itself, except updating the map load routine to read the additional data.
  5. Josh
    A new map called "09-Change Map.map" has been added to the example game. This demonstrates how to use the new TriggerChangeMap.lua script to make your player progress from one level to the next.
     
    In order to use this script, you must update your project with the new executables. Select the File > Project Manager menu to open the Project Manager, then press the "Update" button to update your project.
     
    A new chunk of code has been added to App.lua to handle map changes. This code will be found in the main loop of the new App.lua script:

    --Handle map change if changemapname~=nil then
     
    --Clear all entities
    self.world:Clear()
     
    --Load the next map
    Time:Pause()
    if Map:Load("Maps/"..changemapname..".map")==false then return false end
    collectgarbage()
    Time:Resume()
     
    changemapname = nil
    end
     
    Using the TriggerChangeMap script is easy. Just attach it to a CSG brush and set the name of the next map you want to load, without the path or file extension. For example, to load the map "Maps/09-Change Map.map" you just type in "09-Change Map" in the "Map Name" field. When the player collides with the brush, the new map will be loaded. You can make the brush a panel on the floor, or an invisible trigger field.
     
    You must opt into the beta branch on Steam to get these changes.
  6. Josh
    I'm pleased to say our very first character pack DLC is now available on Steam.
     

     
    Originally, my plan was to just license third-party model packs and sell them on Steam, ready-to-use with Leadwerks. However, once I started acquiring content I ran into some problems.
    The selection of usable character packs out there are pretty lacking, when you start examining them closely.
    Artists often just wanted to sell "raw models" and were not interested in the final steps to make an item truly game-ready, like physics and scripting.
    Models sourced from different artists lacked cohesion in detail, quality, and art direction.
    Artists wanted to charge much higher prices than I thought was optimal.

     
    However, Leadwerks DLC sales are now high enough that we can produce our own exclusive content for you. The cost of producing the zombie models and animations was $3500. At a price of $29.99, and after Steam's 30% of sales, we need to sell just 166 copies of this pack to break even and start making a profit. If we can break even, that means I can effectively "turn on" content production and start bringing lots more model packs to you for use with Leadwerks.
     
    Because our content comes from only a few artists, with each artist working on one area (characters, animation, and environment) that means Leadwerks original content will have a visual consistency you can't get by buying models from different sources.
     
    I do have plans for selling third-party content in the Leadwerks Workshop, but game characters are the hardest item to produce, and I think we need to take responsibility for making sure these are done right.
     
    I hope you enjoy the pack, and I am looking forward to bringing you more.
  7. Josh
    I update to latest version of Newton and did a lot of work on character physics.
    All collisions below the step height will now be ignored, regardless of incline.
    Character collision in general is much more stable and accurate.
    Terrain collisions now work properly.
    Character collisions using an adaptive method that will be much faster overall.

     
    Opt into the beta branch on Steam to get the update. If you're using Lua, be sure to update your project to get the latest EXEs.
  8. Josh
    The first step to building a character model is to establish the concept. Here are the images I have received. I have my favorite in mind, but what do you think? The purpose of this character is to serve as an enemy for a wide range of games. It could also be used as a main character with a third-person camera.
     
    Which one do you like best?
     

  9. Josh
    Before Leadwerks 3 existed, Leadwerks 2 used a little tool called "Phygen" to generate collision shape files for 3D models:
     

     
    The user would input the parameters and then save that file with the same name as the model it was to be associated with, with the PHY file extension. This was not a very good system, but the idea of storing a physics shape in a PHY file that was automatically loaded along with the model was a good one.
     
    In Leadwerks 3 we implemented prefabs to make it easier to have a ready-to-use game model. However, after using the system for a while it became obvious that 90% of your models just need a simple collision shape and no other special settings. The prefab system was overkill for a simple static model.
     
    I've simplified physics shapes by adding physics shape generation in the model editor, for convex decomposition, boxes, spheres, cones, and cylinders. When you generate a physics shape it is created automatically from the model's bounds and saved as a PHY file alongside the model. Whenever that model is loaded, the engine will look for an associated physics shape file and load it at the same time.
     

     
    The physics tab has been simplified with no more confusing physics shape fields to be adjusted:
     

     
    However, under the hood the ability to assign an arbitrary physics shape to any entity is still there. If your map depends on this feature there is a hidden setting in the config file you can use to retain this feature in the editor. Just open your Leadwerks.cfg file and set the "EnableLegacyFeatures" value to 1 and it will appear. Existing maps will be unaffected, even if you don't enable this feature.
     
    These changes improve the workflow because now you just open up a model, generate a shape of any type, save it, and you have a model with physics ready to go. It does mean physics shapes are more strongly associated with models, and I originally intended them to be assigned to any old entity. However, in practice the ability to set a physics shape to a light or camera or something in the editor is pretty useless, and it's better to focus on the way it's used 99% of the time instead of designing for edge cases.
  10. Josh
    In this non-technical blog I will give you more of Josh's useful tips on how to live. In this blog I am talking about baggage, in the form of data physical possessions.
     
    Archive and Delete
    The first thing you need to do is organize. If you have all your files in dozens of different folders all over your computer, it will be very difficult to track them all down. This is why Leadwerks and most other programs store files in your Documents folder on your computer. Leadwerks projects, along with images, records, schools papers, and anything else you are working on should all be stored here. Your music is ideally stored in the cloud with iTunes, Steam, or another service.
     
    Next, take the entire contents of your documents folder and burn it onto a Blu-Ray disk. Put this disk in a nice CD case like this, and put it in your closet somewhere.
     

     
    Now, delete everything in your Documents folder you are not using right now on a daily basis. You have a copy of everything, and you can always go back and get whatever you need. All your tax records, old school papers, PDFs you never read, and everything else is all safely locked away.
     
    Do this and your computer and mind will feel free, clear, and refreshed. Nowadays I am thinking of the hard drive less as storage for files and more as a temporary cache to place program files that get installed from Steam, the Mac App Store, etc. Not only am I immune from hard drive failures and can easily migrate to a new machine at a moment's notice, but my computers always feel new and uncluttered. Here's my very Zen desktop:
     

     
    Prune Your Bookmarks
    How often do you visit all those hundreds of bookmarks in your web browser? Go through and visit each one. if it's not worth coming back to, delete it. If it's just a random idea you might someday want to look at, archive it. If it's an article you might someday read, read it today. If it's not worth reading today, delete it.
     
    There is presently no way I know of to sync bookmarks between browsers on Windows, Linux, and Mac, unfortunately. This is probably by design or at least by lack of motivation to be cross-platform.
     
    Minimize the Number of Programs You Have Installed
    Unless you are developing a web page, don't install more than one web browser. Don't horde programs to make your computer feel more capable. Keep the bare number of programs you need right now installed on your computer. If you're using an app store of some kind then it's easy to install and uninstall programs at a moment's notice, so don't be afraid to remove them. Having fewer programs will make you more focused when you sit down to work.
     
    Minimize the Number of Machines You Own
    For cross-platform development, I recommend owning two computers, a Mac and a PC with dual boot Windows / Linux. I am not presently following this advice because I also own an Alienware Steam Machine and a Gigabyte Brix Mini PC I take to the office with me. However, I feel better the fewer CPUs I have in my life. For this reason, I favor the Steam Link, as it only requires you to have games installed on one single PC. I am waiting for the day the DAN A4-SFX case becomes available so I can get my PC into an even smaller footprint:
     

     
    Compress, Compress, Compress
    Below is the smallest possible way you can get an entire home entertainment system. A Steam Link acts as a very capable console and Netflix player. A mini projector provides a ten foot tall screen that fits in your hand. Sound is provided by a Bose music player that can be streamed to from your phone or have an audio cable plugged in from the projector. And it all fits in a shoe box.
     

     
    Fix it or Lose it
    Do you have any broken electronics or other equipment lying around you might someday use? Maybe a bicycle with a flat tire? If you can't fix it today you never will be able to, and it's worthless. Fix it and start using it or throw it out. Unused equipment = mental baggage.
     
    Conclusion
    It has been said that "Things you own, end up owning you". This really is true. That nice expensive sofa you bought will have to be carefully transported across the country if you decide you want to live somewhere else. You'll always have to pay rent in an apartment with a living room or buy a house to provide storage for that object. One way or another, you're paying rent for an inanimate object that reduces your options.
     

     
    Follow my useful tips and you will feel more focused, alert, and less stressed. Although my work requires me to keep a hefty amount of electronic equipment, I hope to live semi-nomadically in the near future. The old-style life goals of collecting a lot of stuff in a house in the suburbs need to be updated. I'd rather collect stickers on my laptop from different cities I've lived in. The internet and remote working have given us new options in life, and we need to find new perspectives to define our happiness and goals.
  11. Josh
    In Leadwerks GUI, any widget can be the child of another widget. If the child goes outside of the parent widget's area it will be clipped for both rendering and mouse events. Below you can see the button in the upper-left corner and the progress bar and slider on the right are clipped by the parent tabber.
     

     
    A parent widget can also have a padding value which indents the area. The tabber uses padding on the top to display the tabs and make sure children don't appear on top of the tabs.
     
    Leadwerks also allows you to set an edge mode for each each of each widget (left, right, top, and bottom). This controls how the widgets scale when the window is resized. Here you can see a slider and a listbox have been locked to the right and bottom edges, respectively, and are being stretched out when the window is made larger.
     

     
    I am also interested in bringing LeadwerksGUI to Linux as a standalone library to replace GTK, QT, etc. It's MUCH easier to skin and add new widgets to this system, and it provides resolution independence for any DPI display. Here it is at 75% scaling:
     

     
    And at 400%:
     

  12. Josh
    I decided I want the voxel GI system to render direct lighting on the graphics card, so in order to make that happen I need working lights and shadows in the new renderer. Tomorrow I am going to start my implementation of clustered forward rendering to replace the deferred renderer in the next game engine. This works by dividing the camera frustum up into sectors, as shown below.

    A list of visible lights for each cell is sent to the GPU. If you think about it, this is really another voxel algorithm. The whole idea of voxels is that it costs too much processing power to calculate something expensive for each pixel, so lets calculate it for a 3D grid of volumes and then grab those settings for each pixel inside the volume. In the case of real-time global illumination, we also do a linear blend between the values based on the pixel position.
    Here's a diagram of a spherical point light lying on the frustum.

    But if we skew the frustum so that the lines are all perpendicular, we can see this is actually a voxel problem, and it's the light that is warped in a funny way, not the frustum. I couldn't figure out how to warp the sphere exactly right, but it's something like this.

    For each pixel that is rendered, you transform it to the perpendicular grid above and perform lighting using only the lights that are present in that cell. This tecnnique seems like a no-brainer, but it would not have been possible to do this when our deferred renderer first came to be. GPUs were not nearly as flexible back then as they are now, and things like a variable-length for loop would be a big no-no.

    Well, something else interesting occurred to me while I was going over this. The new engine is an ambitious project, with a brand new editor to be built from scratch. That's going to take a lot of time. There's a lot of interest in the features I am working on now, and I would like to get them out sooner rather than later. It might be possible to incorporate the clustered forward renderer and voxel GI into Leadwerks Game Engine 4 (at which point I would probably call it 5) but keep the old engine architecture. This would give Leadwerks a big performance boost (not as big as the new architecture, but still probably 2-3x in some situations). The visuals would also make a giant leap forward into the future. And it might even be possible to release in time for Christmas. All the shaders would have to be modified, but if you just updated your project everything would run in the new Leadwerks Game Engine 5 without any problem. This would need to be a paid update, probably with a new app ID on Steam. The current Workshop contents would not be accessible from the new app ID, but we have the Marketplace for that.
    This would also have the benefit of bringing the editor up to date with the new rendering methods, which would mean the existing editor could be used seamlessly with the new engine. We presently can't do this because the new engine and Leadwerks 4 use completely different shaders.
    This could solve a lot of problems and give us a much smoother transition from here to where we want to go in the future:
    Leadwerks Game Engine 4 (deferred rendering, existing editor) [Now] Leadwerks Game Engine 5 (clustered forward rendering, real-time GI, PBR materials, existing architecture, existing editor) [Christmas 2018] Turbo Game Engine (clustered forward rendering, new architecture,  new editor) [April 2020] I just thought of this a couple hours ago, so I can't say right now for sure if we will go this route, but we will see. No matter what, I want to get a version 4.6 out first with a few features and fixes.
    You can read more about clustered forward rendering in this article
  13. Josh
    I was able to partially implement clustered forward rendering. At this time, I have not divided the camera frustum up into cells and I am just handing a single point light to the fragment shader, but instead of a naive implementation that would just upload the values in a shader uniform, I am going through the route of sending light IDs in a buffer. I first tried texture buffers because they have a large maximum size and I already have a GPUMemBlock class that makes them easy to work with. Because the GPU likes things to be aligned to 16 bytes, I am treating the buffer as an array of ivec4s, which makes the code a little trickier, thus we have a loop within a loop with some conditional breaks:
    vec4 CalculateLighting(in vec3 position, in vec3 normal) { vec4 lighting = vec4(0.0f); int n,i,lightindex,countlights[3]; vec4 lightcolor; ivec4 lightindices; mat4 lightmatrix; vec2 lightrange; vec3 lightdir; float l,falloff; //Get light list offset int lightlistpos = 0;//texelFetch(texture12, sampleCoord, 0).x; //Point Lights countlights[0] = texelFetch(texture11, lightlistpos).x; for (n = 0; n <= countlights[0] / 4; ++n) { lightindices = texelFetch(texture11, lightlistpos + n); for (i = 0; i < 4; ++i) { if (n == 0 && i == 0) continue; //skip first slot since that contains the light count if (n * 4 + i > countlights[0]) break; //break if we go out of bounds of the light list lightindex = lightindices[1]; lightmatrix[3] = texelFetch(texture15, lightindex * 4 + 3); vec3 lightdir = position - lightmatrix[3].xyz; float l = length(lightdir); falloff = max(0.0f,-dot(normal,lightdir/l)); if (falloff <= 0.0f) continue; lightrange = texelFetch(texture15, lightindex * 4 + 4).xy; falloff *= max(0.0f, 1.0f - l / lightrange.y); if (falloff <= 0.0f) continue; lightmatrix[0] = texelFetch(texture15, lightindex * 4); lightmatrix[1] = texelFetch(texture15, lightindex * 4 + 1); lightmatrix[2] = texelFetch(texture15, lightindex * 4 + 2); lightcolor = vec4(lightmatrix[0].w,lightmatrix[1].w,lightmatrix[2].w,1.0f); lighting += lightcolor * falloff; } } return lighting; } I am testing with Intel graphics in order to get a better idea of where the bottlenecks are. My GEForce 1080 just chews through this without blinking an eye, so the slower hardware is actually helpful in tuning performance. I was dismayed at first when I saw my framerate drop from 700 to 200+. I created a simple scene in Leadwerks 4 with one point light and no shadows, and the performance was quite a bit worse on this hardware, so it looks like I am actually doing well. Here are the numbers:
    Turbo (uniform buffer): 220 FPS Turbo (texture buffer): 290 FPS Leadwerks 4: 90 FPS Of course a discrete card will run much better. The depth pre-pass has a very slight beneficial effect in this scene, and as more lights and geometry are added, I expect the performance savings will become much greater.
    Post-processing effects like bloom require a texture with the scene rendered to it, so this system will still need to render to a single color texture when these effects are in use. The low quality settings, however, will render straight to the back buffer and thus provide a much better fallback for low-end hardware.

    Here we can see the same shader working with lots of lights. To get good performance out of this, the camera frustum needs to be divided up into cells with a list of relevant lights for each cell.

    There are two more benefits to this approach. Context multisample antialiasing can be used when rendering straight to the back buffer. Of course, we can do the same with deferred rendering and multisample textures now, so that is not that big of a deal.

    What IS a big deal is the fact that transparency with shadows will work 100%, no problems. All the weird tricks and hacks we have tried to use to achieve this all go away. (The below image is one such hack that uses dithering combined with MSAA to provide 50% transparency...sort of.)

    Everything else aside, our first tests reveal more than a 3X increase in performance over the lighting approach that Leadwerks 4 uses. Things look fantastic!
  14. Josh
    By modifying the spotlight cone attenuation equation I created an area light, with shadow.

    And here is a working box light The difference here is the box light uses orthographic projection and doesn't have any fading on the edges, since these are only meant to shine into windows.

    If I scale the box light up and place it up in the sky, it kind of looks like a directional light. And it kind of is, expect a directional light would either use 3-4 different box lights set at radiating distances from the camera position (cascaded shadow maps) or maybe something different. We have a system now that can handle a large number of different lights so I can really arrange a bunch of box lights in any way I want to cover the ground and give good usage of the available texels.

    Here I have created three box lights which are lighting the entire courtyard with good resolution.

    My idea is to create something like the image on the right. It may not look more efficient, but in reality the majority of pixels in cascaded shadow maps are wasted space because the FOV is typically between 70-90 degrees and the stages have to be square. This would also allow the directional light to act more like a point or spot light. Only areas of the scene that move have to be updated instead of drawing the whole scene three extra times every frame. This would also allow the engine to skip areas that don't have any shadow casters in them, like a big empty terrain (when terrain shadows are disabled at least).

    Spot, and area lights are just the same basic formula of a 2D shadowmap rendered from a point in space with some direction. I am trying to make a generic texture coordinate calculation by multiplying the global pixel position by the shadow map projection matrix times the inverse light matrix, but so far everything I have tried is failing. If I can get that working, then the light calculation in the shader will only have two possible light types, one for pointlights which use a cube shadowmap lookup, and another branch for lights that use a 2D shadowmap.
  15. Josh
    I added spotlights to the forward clustered renderer. It's nothing too special, but it does demonstrate multiple light types working within a single pass.

    I've got all the cluster data and the light index list packed into one texture buffer now. GPU data needs to be aligned to 16 bytes because everything is built around vec4 data. Consequently, some of the code that handles this stuff is really complicated. Here's a sample of some of the code that packs all this data into an array.
    for (auto it = occupiedcells.begin(); it != occupiedcells.end(); it++) { pos = it->first; visibilityset->lightgrid[pos.z + pos.y * visibilityset->lightgridsize.x + pos.x * visibilityset->lightgridsize.y * visibilityset->lightgridsize.x] = visibilityset->lightgrid.size() / 4 + 1; Assert((visibilityset->lightgrid.size() % 4) == 0); for (int n = 0; n < 4; ++n) { visibilityset->lightgrid.push_back(it->second.lights[n].size()); } for (int n = 0; n < 4; ++n) { if (!it->second.lights[n].empty()) { visibilityset->lightgrid.insert(visibilityset->lightgrid.end(), it->second.lights[n].begin(), it->second.lights[n].end()); //Add padding to make data aligned to 16 bytes int remainder = 4 - (it->second.lights[n].size() % 4); for (int i = 0; i < remainder; ++i) { visibilityset->lightgrid.push_back(0); } Assert((visibilityset->lightgrid.size() % 4) == 0); } } } And the shader is just as tricky:
    //------------------------------------------------------------------------------------------ // Point Lights //------------------------------------------------------------------------------------------ countlights = lightcount[0]; int lightgroups = countlights / 4; if (lightgroups * 4 < countlights) lightgroups++; int renderedlights = 0; for (n = 0; n < lightgroups; ++n) { lightindices = texelFetch(texture11, lightlistpos + n); for (i = 0; i < 4; ++i) { if (renderedlights == countlights) break; renderedlights++; lightindex = lightindices[n]; ... I plan to add boxlights next. These use orthographic projection (unlike spotlights, which us perspective) and they have a boundary defined by a bounding box, with no edge softening. They have one purpose, and one purpose only. You can place them over windows for indoor scenes, so you can have light coming in a straight line, without using an expensive directional light. (The developer who made the screenshot below used spotlights, which is why the sunlight is spreading out slightly.)

    I am considering doing away with cascaded shadow maps entirely and using an array of box lights that automatically rearrange around the camera, or a combination of static and per-object shadows. I hope to find another breakthrough with the directional lights and do something really special. For some reason I keep thinking about the outdoor scenery in the game RAGE and while I don't think id's M-M-MEGATEXTURES!!! are the answer, CSM seem like an incredibly inefficient way to distribute texels and I hope to come up with something better.

    Other stuff I am considering
    Colored shadows (that are easy to use). Volumetric lights either using a light mesh, similar to the way lights work in the deferred renderer, or maybe a full-screen post-processing effect that traces a ray out per pixel and calculates lighting at each step. Area lights (easy to add, but there are a lot of possibilities to decide on). These might be totally unnecessary if the GI system is able to do this, so I'm not sure. IES lighting profiles. I really want to find a way to render realistic light refraction, but I can't think of any way to do it other than ray-tracing:

    It is possible the voxel GI system might be able to handle something of this nature, but I think the resolution will be pretty low. We'll see.
    So I think what I will do is add the boxlights, shader includes, diffuse and normal maps, bug test everything, make sure map loading works, and then upload a new build so that subscribers can try out their own maps in the beta and see what the speed difference is.
  16. Josh
    In order to get the camera frustum space dividing up correctly, I first implemented a tiled forward renderer, which just divides the screen up into a 2D grid. After working out the math with this, I was then able to add the third dimension and make an actual volumetric data structure to hold the lighting information. It took a lot of trial and error, but I finally got it working.

    This screenshot shows the way the camera frustum is divided up into a cubic grid of 16x16x16 cells. Red and green show the XY position, while the blue component displays the depth:

    And here you can see the depth by itself, enhanced for visibility:

    I also added dithering to help hide light banding that can appear in gradients. Click on the image below to view it properly:

    I still have some bugs to resolve, but the technique basically works. I have no complete performance benchmarks yet to share but I think this approach is a lot faster than deferred rendering. It also allows much more flexible lighting, so it will work well with the advanced lighting system I have planned.
  17. Josh
    I got the remaining glitches worked out, and the deal is that clustered forward rendering works great. It has more flexibility than deferred rendering and it performs a lot faster. This means we can use a better materials and lighting system, and at the same time have faster performance, which is great for VR especially. The video below shows a scene with 50 lights working with fast forward rendering
    One of the last things I added was switching from a fixed grid size of 16x16x16 to an arbitrary layout that can be set at any time. Right now I have it set to 16x8x64, but I will have to experiment to see what the optimum dimensions are.
    There are a lot of things to add (like shadows!) but I have zero concern about everything else working. The hard part is done, and I can see that this technique works great.
  18. Josh
    I've been following Eric's progress with this idea since last spring, and it's really great to see what started as a fuzzy concept turn into reality.
     

    http://www.youtube.com/watch?v=pK_yjZpOs6w
     
    About Hacker Lab
    We believe that technology can change the world and the starting point is education. Hacker Lab aims to educate folks and seed startups with community driven resources. Collectively we can build a brighter future using lean methods in both education and business.
     
    We Provide
    Community Mentorship For Startups
    Educational Courses For Both Adults & Youth
    Networking Events
    Industry Events
    Workspace for Students and Professionals in the Software and Hardware space including Design & Business Development.

     
    Here's the local media coverage of the event:
    http://gooddaysacram...740-hacker-lab/
     
    I'll be teaching a class on OpenGL on October 24th. Check the site for details.
     
    www.hackerlab.org
     

     

  19. Josh
    Lately I've been talking a lot about making non-programmers happy, so here's something for the coders. B)
     
    For Leadwerks3D documentation, I considered three possibilities:
    -IPB-based docs
    -Wiki
    -Offline CHM files
     
    Each has their own strengths and weaknesses, as always seems to be the case.
     
    IPB
    A bit slower, harder to organize, harder to edit, looks really good and consistent with the site, search requires quite a few clicks to get where you want to go, missing table of contents is a bummer for long pages.
     
    Wiki
    A target for spam, doesn't match the main website, user-written docs cause fragmention and a mix of official and unnofficlal information, nice table of contents, good searchability.
     
    Offline CHM
    Fast, doesn't require internet connection, easy to edit, Windows-only.
     
    I dismissed offline docs simply because we wouldn't be able to post a link to refer people to a certain page. I decided on a wiki because of the better search functionality, table of contents, and ease of editing.
     
    Here's what I have in mind for the docs. Because Leadwerks3D is written in C++, we're able to document members, constructors, operators, and other stuff we haven't had access to in the past. Best of all, almost everything works exactly the same in Lua, including function and operator overloading.
    http://www.leadwerks.com/newwiki/index.php?title=Vec3
     
    I'm also a big fan of the ease with which we can add internal links. For example, the Vec3 members in the AABB class documentation link straight to the Vec3 class page:
    http://www.leadwerks.com/newwiki/index.php?title=AABB#Members
     
    To avoid spam, and to make sure I can answer any questions about the contents of the wiki, it's going to be read-only. Community tutorials have been very useful in the past, and we're going to continue that going forward, either through a subforum or database for Leadwerks3D tutorials.
     
    I think having one page per command and an example for every single command has been more redundant and time-consuming that we have needed. I want to list the syntax for each command only once, like this:
    http://www.leadwerks.com/newwiki/index.php?title=Entity#SetPosition
     
    Instead of making a lot of redundant examples (Do we really need a page of code for Entity::SetPosition() AND Entity::SetRotation()?) I hope to provide more comprehensive examples showing how to actually do something, and how the functions can be used together to do interesting things.
     
    In general, I want to go into much more depth with the Leadwerks3D documentation, on all aspects of using the program, because I plan for this iteration of our technology to have a pretty long life. If you have any suggestions, just let me know.
  20. Josh
    I frequently come across models that have an excessive hierarchy of unnecessary limbs. This causes rendering to be slower and memory usage to be higher than it needs to be. If great numbers of the model are used in the scene, these problems can be significant. The windmill model below contains a pretty complex hierarchy.
     

     
    A new tool is being added in the model editor to collapse all limbs of a model into a single object. Select the Tools > Collapse menu item and your model will be optimized:
     

     
    This model needs a little more work so we're going to calculate some new normals for it:
     

     
    And then we'll add an automatically generated physics shape to it:
     

     
    This feature will be included in the next build.
  21. Josh

    Articles
    I haven't been blogging much because I am making so much progress that there would be too much to cover. In this article I will talk about one little system I spent the last week on and show the improvements I have made to the workflow over Leadwerks.
    In the asset editor, when the root of a model is selected, a "Collider" field appears in the physics properties. You can use this to quickly calculate and apply a collider to the model.

    The convex hull collider includes an option for tolerance. You can adjust this to get a more or less precise convex hull around the model:

    There is also an "optimize" option for the mesh collider. When this is activated it will attempt to merge adjacent coplanar polygons into a single face, and can result in fewer seams on colliding faces.
    Two new shapes are included, the capsule and the chamfer cylinder, so now all the shapes supported by Newton Dynamics are available. (The chamfer cylinder is good for vehicle tires.)
     
    Unlike Leadwerks, you no longer need to specify the axis cylindrical shapes are oriented around. The editor will calculate which bounding box axes are most like each other, and use the third axis to orient the shape. This works for long skinny objects:

    And it also works for short fat objects:

    It will even detect which direction a cone should be facing, by calculating the total distance from the shape the model vertices are with each direction, and selecting the orientation with the smallest error value. (A single cone is probably not the best choice of shape for this model, but the point is that it correctly guesses which direction the cone should point based on the model vertices.)

    For more advanced geometry, the convex decomposition tool is available in the Utilities panel. This exposes all the parameters available in V-HACD 4.0 and processes the task on a separate thread so you can continue to use the editor as the task runs in the background. It usually only takes a few seconds to compete, but it is nice to not have your workflow interrupted:

    You can export colliders as model files, so it's also possible to just use this to generate convex hulls and export them to .obj. (I could get a better fitting shape if I spent more time adjusting the settings, but I just quickly made this shape with very low settings in order to get this screenshot.)

    The new .collider file format, like everything else in Ultra, is JSON-based. Simple shapes can be stored in pure ASCII text, so they can be edited by hand if needed:
    { "collider": { "parts": [ { "offset": [ 0.0024815797805786133, -0.18715500831604004, -1.055002212524414e-05 ], "rotation": [ 0.0, 0.0, 0.0 ], "shape": "BOX", "size": [ 1.8899539709091187, 2.0, 1.8019688129425049 ] } ] } } More complex shapes like convex hulls and meshes use binary data appended to the end of the file to store their contents, so that they load quickly in the engine:
    { "collider": { "parts": [ { "data": 0, "shape": "CONVEXHULL", "vertices": 61 } ] } }�n�2��<�5�j�k��#�I3��ch�������=b[��I<��~d�I�D�` �[�\{4���A���?XO3���>��վ�v!���f��� ?]����I�!�����V� >�?���mdG�t9�a��@���X?W��0o��e�-�D��h�P?>����>��׾���@��=T�U?��ž�{����w�� ���G��3��ޑ?>V?c�����;���6�s�/?&�=����?q�e?j��N���[#b��bݽ(��>��Ǿ�ڽ�E��MV�ַؽ��8<�G������D?BYT?I���@"N?6?�";-�$?��콜�";��t>8�"�t�";�z��3�0���";����ݐ�)�%=}P?��0?���=/�E?BYT?'>�=�E��MV����={; ?"����>�־��c� �>��?q�e?�$>�ӽ��P��@>��,?�j|=�2�>[o/���P�C��>��?>V?Z�>�������Қ�>��h���@�>��E�CO2��.�>T��[A�y]�>L��=T�U?w4�>���>�쾛?#o��e�-�r?�����U?�"?.�v>��!?�R?�zv����>�@?(�0�S �>.(?�n_�C�?�|-?d�[��}?��4?��>��վ��6?2M4��*?�>?P��=_�s��F?V ���ྲAm?�#�I3�Lr?����� Leadwerks .phy collider files can also be loaded.
    Notice in the shots above, in the drop-down menu there is also a "Browse" option, so you can create a collider file with a low-resolution model and then load the resulting collider to use with a high-resolution model.
    I think this design strikes the right balance to let you do simple things quickly, but still allow for more advanced options when you need them. In the future I would like to add an additional in-depth collider editing utility that would allow you to select each sub-object, select model polygons and generate shapes just from those polys, and other advanced features.
    The pick mode feature has been revised. The original design was based on Blitz3D, which did not support collision primitives at all. Instead of specifying a sphere or other shape for picking, you can now just tell the entity to use the collider for picking. (PICK_SPHERE is removed.)
    On an unrelated note, I had to adjust the camera range based on the distance from the model being viewed, in order to make very small objects visible. This allows extreme close-up shots like in the blog header image that you probably aren't used to seeing except in VR. It's kind of interesting.
  22. Josh
    As I was implementing the collision commands for Leadwerks3D, I noticed a few things that illustrate the differences between the design philosophies of Leadwerks Engine and Leadwerks3D.
     
    You'll easily recognize the new collision commands, although they have been named in a more verbose but logical manner:

    void ClearCollisionResponses(); void SetCollisionResponse(const int& collisiontype0, const int& collisiontype1, const int& response); int GetCollisionResponse(const int& collisiontype0, const int& collisiontype1);
    In Leadwerks Engine, the collisions were left to the end user to define however they wished. In Leadwerks3D, we have some built-in collision types that are declared in the engine source code:

    const int COLLISION_SCENE = 1; const int COLLISION_CHARACTER = 2; const int COLLISION_PROP = 3; const int COLLISION_DEBRIS = 4;
    By default, the following collision responses are created automatically:

    SetCollisionResponse(COLLISION_SCENE,COLLISION_CHARACTER,COLLISION_COLLIDE); SetCollisionResponse(COLLISION_CHARACTER,COLLISION_CHARACTER,COLLISION_COLLIDE); SetCollisionResponse(COLLISION_PROP,COLLISION_CHARACTER,COLLISION_COLLIDE); SetCollisionResponse(COLLISION_DEBRIS,COLLISION_SCENE,COLLISION_COLLIDE); SetCollisionResponse(COLLISION_PROP,COLLISION_PROP,COLLISION_COLLIDE); SetCollisionResponse(COLLISION_DEBRIS,COLLISION_PROP,COLLISION_COLLIDE);
    Each entity's default collision type is COLLISION_PROP, which means that without specifying any collision responses, all entities collide with one another.
     
    Of course if you want to scrap all my suggested collision responses and define your own, you can just call ClearCollisionResponses() at the start of your program. The main difference in design is that Leadwerks3D assumes the user wants some default behavior already specified, instead of being a completely blank slate. That's a design decision that is being implemented across all aspects of the engine to make it easier to get started with.
  23. Josh
    The Vulkan graphics API is unbelievably complex. To create a render context, you must create a series of images for the front and back buffers (you can create three for triple-buffering). This is called a swap chain. Now, Vulkan operates on the principle of command buffers, which are a list of commands that get sent to the GPU. Guess what? The target image is part of the command buffer! So for each image in your swap chain, you need to maintain a separate command buffer  If anything changes in your program like the camera clearscreen color, you have to recreate the command buffers...all of them! But some of them will still be in use at the time your frame begins, so you need to store a flag that says "recreate this command buffer when it is time to start rendering with this image / command buffer".
    The whole thing is really bad, but admitting that there is any practical limit to the how complex an APi should be opens a developer to ridicule. I make complex technologies easy to use for a living, so I'm just calling it out, this is garbage design. Vulkan is actually good for me because it means fewer people can figure out how to make a game engine, but it's really ridiculous. Khronos has stated that they expect semi-standard open-source code to arise to address these complexities, but I don't see that happening. I'm not going to touch something like AMD's V-EZ because it's just another layer of code that might stop being supported at any time. As a result of the terrible design, Vulkan is going to continue to struggle to gain adoption, and we are now entering an era where the platform holders are in a fight with the application developers about who is responsible for writing graphics drivers.
    I really like some aspects of Vulkan. SPIR-V shaders are great, and I am very glad to be rid of OpenGL's implicit global states, FBO creation, strange resource sharing, and so on. But nobody needs detailed access to the swap chain. Nobody needs to manage their own synchronization. That's what we have graphics drivers for.
    Anyways, here is my test application. The screen will change color when you press the space key, which involves re-creation of the command buffers. The Vulkan stuff is 1300 lines of code.
    vktest3.zip
    The good thing is that although the initial setup is prohibitive, this stuff tends to get compartmentalized away as I add more capabilities, so it gets easier as time goes on. This is very difficult stuff but we will be better off once I get through this.
  24. Josh
    Leadwerks 4.3 brings a big performance boost to your games. In this blog I am going to talk about some of the common problems you can eliminate to make your games run faster.
    When slow performance is encountered, it is typically one really bad mistake that is slowing everything down. Here's a few common bottlenecks for performance you can create in your games, how to identify them, and how to fix them.
    Shadow Updates
    Shadow rendering is cheaper than regular renders because no textures have to be used, but extra rendering passes to update shadows can add up.
    How to identify: The game stats will display the number of shadows updated. If this is more than a few, you might have a problem. Remember that point lights require six extra passes, and directional lights three, but both only count as one shadow. You also want your rendered shadow polys to be as low as possible.
    How to fix: Figure out what objects are triggering the redraw and whether it is necessary. Non-moving high-polygon models should use the static shadow mode so they don't have to be redrawn during a render. In version 4.3, low and medium light quality settings will also stagger shadow updates so that fewer are rendered each frame. (This can also make it harder to detect a problem, so maybe test on high quality settings when you are examining this.)
    GPU Pixel Pipeline
    The GPU has a limited number of stream processors it can split up the task of rendering an image with. When you overload the GPU pixel pipeline it slows down your program.
    How to identify: If you have a much higher framerate at a lower screen resolution, this is probably the cause.
    How to fix: Lower light quality settings, remove post-processing effects, or run at a lower screen resolution.
    GPU Vertex Pipeline
    This is pretty rare because the number of vertices the GPU has to process are tiny compared to the number of pixels, but it is possible.
    How to identify: Slow speed regardless of screen resolution, slow even when rendering the scene with no gameplay, extremely high-polygon counts in the game stats (like 2,000,000+). There are some applications where extremely high polygon counts are acceptable, but unless you are specifically making such an application and are aware of this, it probably means you should use models designed for real-time games.
    How to fix: Use lower-resolution models or lighten up on the vegetation.
    Too Many Objects
    The renderer itself has a cost of computation on the CPU. The more separate objects there are, the more the CPU has to work to determine what objects are visible. On the other hand, discarding large numbers of objects can give a big speed boost, so it's always a balance.
    How to identify: The render time shown in your game stats will be more than a few milliseconds, and the number of batches, displayed in the game stats, will be very high. It's all relative but if you have a simple scene and 500 batches are being drawn, there is probably a problem. Large spread out maps with dense distribution of objects can often have this problem. This will happen on all machines, regardless of how good the GPU is. The most complex maps I've ever made had about 700 batches rendered. There is no need to go above that no matter how big the map is, because objects in the distance will be culled. The vegetation system does not cost much on a per object basis, so it is an extremely efficient way to lay down a lot of dense objects.
    How to fix: Use the model editor Collapse feature to collapse models into a single object and resave them. Also set the view range of smaller objects to a closer distance so there are fewer of them visible in the distance.
    Slow Collision
    If your game slows down when you get close to an object, you might have a high-poly collision mesh.
    How to identify: The physics update time in the game stats will be more than a few milliseconds. Enable "View Physics" in the editor and check to make sure all physics shapes are low-poly.
    How to fix: Use the model editor to generate a low-poly physics shape with the best available option.
    Code Errors
    Is your game constantly reloading files from the hard drive? Are you performing lots of pick operations each frame? Did you create a runaway loop of new objects to process?
    How to identify: Comment out sections of your code and test the framerate.
    How to fix: Figure out the main section that is causing the slowdown, then keep commenting out smaller and smaller parts until you narrow down the problem. Post on the forum if you don't know why something is causing a performance drop.
×
×
  • Create New...