Jump to content

Josh

Staff
  • Posts

    23,516
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh

    Articles
    Breaking the new engine up into sub-components and releasing them in several stages is something new. The reason for trying this was twofold:
    Steam now incentives competition for digital shelf space, unlike when Leadwerks was first released on Steam in 2014, when I was trying to build up my quality of presence and promote one app ID on Steam. I would like to get some new software out early before the full engine is finished. The beautiful thing is that Ultra App Kit all consists of things I had to get done anyways. It was not a distraction from the development of the 3D engine.  Here are some of the features I was able to finish and document. All of these will be part of the new 3D engine when it comes out:
    New documentation system using markdown pages on Github, integrated search, sitemap generation, caching, copy button in code boxes. New project creation wizard Finalize display and window classes GUI system Math Memory Process Multithreading Strings Pixmap class Icons System Dialogs In addition, this allows me to establish a lot of my plans for marketing of the new engine and perform a "dry run" before the final release:
    Community system migrated to new website License Management system collects Steam customer emails, allows subscription license model. New videos section of site with a category for official video tutorials. Affiliate / referral system Partnerships with video creators, bloggers, and advertisers. The initial release will support C++ programming, but subsequent releases for Lua and C# will allow me to judge how much interest there is in these languages relative to one another.
    Maybe we will see Ultra 2D Kit this summer?
  2. Josh
    I've been working with "Klepto2" to integrate the Scintilla text control into the new Leadwerks editor. Scintilla is very powerful and feature-rich, but is somewhat insane to work with. You've got to have a Scintilla expert onboard to integrate it successfully, which we fortunately do.
     
    Previously, I was relying on calls to a Debug:Stop() function to control breakpoints. This was hard-coded into your script program, and breakpoints could not be dynamically added or removed. Since Scintilla gives us the ability to edit breakpoints in the editor, I rewrote the debugging interface to give control to provide more communication between the application and the debugger. Breakpoints can now be added and removed as the program is running. You can also pause the program at any time from the editor and see where the code is executing.
     
    The script editor includes a great debugger that lets you view the entire contents of the Lua virtual machine. As a finishing touch, I added in some icons from Microsoft's Visual Studio icon pack. As a programmer, the result is something I really like working with:

     
    We think having a professional-grade code IDE integrated in the editor will provide a smoother and more seamless user experience, so you don't have to switch back and forth with third-party IDEs.
  3. Josh

    Articles
    I have not used the engine outside the editor in a while, but I needed to for performance testing, so now I am back to real-time rendering. During the development of the GI system I broke most of the light types, so I had to spend a couple of days getting those to work again. While doing this, I decided to resolve some longstanding issues I have put off.
    First, the PBR lighting will use a default gradient in place of the skybox, if no reflection map is set for the world. This is based off the ambient light level, so it will blend in with any scene. You can disable this by setting a black skybox, but this will give some acceptable default reflectance when an empty scene is created and it prevents unlit areas from looking completely flat:

    Shadow acne will be a thing of the past. I found that using vkCmdSetDepthBias to use the hardware depth bias feature does a great job of eliminating shadow acne. This shot shows a light that is extremely close to the floor, yet no artifacts are visible:

    Of course the new strip lights are can be used for dramatic effects:

    My new video project1.mp4 I have not yet implemented shadows for directional lights. I was hoping this whole time I would come up with a brilliant idea that would make cascaded shadow maps obsolete, but that's the one are I haven't found any great new innovative technique to use.
    Box lights are another new type of light, and can be used to simulate directional lights coming into a window, for levels that are mostly indoors.
    The realtime GI system has been very popular. I am rolling around an idea to increase the quality and performance of the system, with the flip side of that being increased latency. But looking around at the world, the general global illumination never really changes suddenly all at once, so I think it is worth trying. The whole point of Ultra Engine is that it should run very fast, so if I can make the GI system favor performance, hopefully to where it has no impact at all on framerate, I think that is more consistent with our goals.
  4. Josh
    I'm finalizing the shaders, and I was able to pack a lot of extra data into a single entity 4x4 matrix:
    Orthogonal 4x4 matrix RGBA color Per-entity texture mapping offset (U/V), scale (U/V), and rotation Bitwise entity flags for various settings Linear and rotational velocity (for motion blur) Skeleton ID All of that info can be fit into just 64 bytes. The shaders now use a lot of snazzy new function like this:
    void ExtractEntityInfo(in uint id, out mat4 mat, out vec4 color, out int skeletonID, out uint flags) mat4 ExtractCameraProjectionMatrix(in uint cameraID, in int eye) So all the storage / decompression routines are in one place instead of hard-coding a lot of matrix offset in different shaders.
    A per-entity linear and angular velocity is being calculated and sent to the rendering thread. This is not related to the entity velocity in the physics simulation, although they will most often be the same. Rather, this is just a measure of the distance the entity moved since the last world render, so it will work with any motion, physics or otherwise.
    In the video below, the linear velocity is being added to the camera position to help predict the region of the GI lighting area, so the camera stays roughly in the center as the GI updates. A single 128x128x128 volume texture is being used here, with a voxel size of 0.25 meters. In the final version, you probably want to use 3-4 stages, maybe using a 64x64x64 texture for each stage.
    Performance of our voxel cone step tracing is quite good, with FPS in the mid-hundreds on a mid-range notebook GPU. The last big question is how to handle dynamic objects, particular fast-moving dynamic objects. I have some ideas but I'm not sure how hard this is going to be. My first attempt was slow and ugly. You can probably guess which dragon is static and which is dynamic:

    It is a difficult problem. I would like the solution to be as cool as the rest of this system as I finish up this feature. Also, I think you will probably want to still use SSAO so dynamic objects blend into the GI lighting better.
    Everyone should have access to fast real-time global illumination for games.
  5. Josh

    Articles
    I'm wrapping up the terrain features now for the initial release. Here's a summary of terrain in Ultra Engine.
    Terrains are an entity, just like anything else, and can be positioned, rotated, or scaled. Non-square terrains are supported, so you can create something with a 1024x512 or whatever resolution. (Power-of-two sizes are required.)
    Editing Terrain
    Ultra Engine includes an API that lets you modify terrain in real-time. I took something very complicated and distilled it down to a very simple API for you:
    terrain->SetElevation(x, y, height); That's it! The engine will automatically update normals, physics, raycasting, rendering, and other data for you behind the scenes any time you modify the terrain, in a manner that maximizes efficiency.
    Materials
    Leadwerks supports 32 terrain texture layers. Unity supports eight. Thanks to the flexibility of shaders in Vulkan, any terrain in Ultra can have up to a whopping 256 different materials applied to it, and it will always be rendered in a single pass at maximum speed.
    To apply a material at any point on the terrain, you just call this method. The weight value lets you control how much influence the material as at that point, i.e. its alpha transparency:
    terrain->SetMaterial(x, y, material, weight) This example shows how to paint materials onto the terrain.

    I'm quite happy with how the documentation system has turned out, and I feel it is representative of the quality I want your entire user experience to be.

    All the API examples load media from the web, so there's no need to manually download any extra files. Copy and paste the code into any project, and it just works.
    //Create base material auto diffusemap = LoadTexture("https://raw.githubusercontent.com/Leadwerks/Documentation/master/Assets/Materials/Ground/river_small_rocks_diff_4k.dds"); auto normalmap = LoadTexture("https://raw.githubusercontent.com/Leadwerks/Documentation/master/Assets/Materials/Ground/river_small_rocks_nor_gl_4k.dds"); auto ground = CreateMaterial(); ground->SetTexture(diffusemap, TEXTURE_DIFFUSE); ground->SetTexture(normalmap, TEXTURE_NORMAL); Tessellation and Displacement
    Tessellation works great with terrain, which is modeled with quads. There are a lot of high-quality free PBR materials that are great for VR available on the web, so you will have no shortage of interesting materials to paint your terrains with. Here are a few sites for you to peruse:
    https://matlib.gpuopen.com/main/materials/all
    https://icons8.com/l/3d-textures
    https://ambientcg.com/
    https://polyhaven.com/textures
    https://freepbr.com/
    https://www.cgbookcase.com/textures

    Cutting Holes
    You can cut holes in the terrain by hiding any tile. This is useful for making caves, and can be used in the future for blending voxel geometry into a heightmap terrain.

    Shader Design
    Shaders in Ultra are big and quite complicated. I don't expect anyone to make 100% custom shaders like you could with the simpler shaders in Leadwerks. I've structured shaders so that the entry point shader defines a user function, then includes the base file, which calls the function:
    #version 450 #extension GL_GOOGLE_include_directive : enable #extension GL_ARB_separate_shader_objects : enable #define LIGHTING_PBR #define USERFUNCTION #include "../Base/Materials.glsl" #include "../Base/TextureArrays.glsl" void UserFragment(inout vec4 color, inout vec3 emission, inout vec3 normal, inout float metalness, inout float roughness, inout float ambientocclusion, in vec3 position, in vec2 texcoords, in vec3 tangent, in vec3 bitangent, in Material material) { // Custom code goes here... } #include "../Base/base_frag.glsl" This organizes shaders so custom behavior can be added on top of the lighting and other systems, and paves the way for a future node-based shader designer.
    Future Development
    Ideas for future development to add to this system include voxel-based terrains for caves and overhangs, roads (using the decals system), large streaming terrains, and seamless blending of models into the terrain surface.
  6. Josh
    I've received our finished "Merc" character, made exclusively for Leadwerks! Say hello:
     

     
    He still needs a simple rifle weapon and some scripting to make him actually shoot and not just punch people with the butt of his gun. When that happens, watch out, he is going to be one mean enemy (or perhaps a valuable ally against the mutant hordes?)
  7. Josh

    Articles
    While seeking a way to increase performance of octree ray traversal, I came across a lot of references to this paper:
    http://wscg.zcu.cz/wscg2000/Papers_2000/X31.pdf
    Funnily enough, the first page of the paper perfectly describes my first two attempted algorithms. I started with a nearest neighbor approach and then implemented a top-down recursive design:
    GLSL doesn't support recursive function calls, so I had to create a function that walks up and down the octree hierarchy without calling itself. This was an interesting challenge. You basically have to use a while loop and store your variables at each level in an array. Use a level integer to indicate the current level you are working at, and everything works out fine.
    while (true) { childnum = n[level]; n[level]++; childindex = svotnodes[nodeindex].child[childnum]; if (childindex != 0) { pos[level + 1] = pos[level] - qsize; pos[level + 1] += coffset[childnum] * hsize; bounds.min = pos[level + 1] - qsize; bounds.max = bounds.min + hsize; if (AABBIntersectsRay2(bounds, p0, dir)) { if (level == maxlevels - 2) { if (SVOTNodeGetDiffuse(childindex).a > 0.5f) return true; } else { parent[level] = nodeindex; nodeindex = childindex; level++; n[level] = 0; childnum = 0; size *= 0.5f; hsize = size * 0.5f; qsize = size * 0.25f; } } } while (n[level] == 8) { level--; if (level == -1) return false; nodeindex = parent[level]; childnum = n[level]; size *= 2.0f; hsize = size * 0.5f; qsize = size * 0.25f; } } I made an attempt to implement the technique described in the paper above, but something was bothering me. The octree traversal was so slow that even if I was able to speed it up four times, it would still be slower than Leadwerks with a shadow map.
    I can show you very simply why. If a shadow map is rendered with the triangle below, the GPU has to process just three vertices, but if we used voxel ray tracing, it would require about 90 octree traversals. I think we can assume the post-vertex pipeline triangle rasterization process is effectively free, because it's a fixed function feature GPUs have been doing since the dawn of time:

    The train station model uses 4 million voxels in the shot below, but it has about 40,000 vertices. In order for voxel direct lighting to be on par with shadow maps, the voxel traversal would have to be about 100 times faster then processing a single vertex. The numbers just don't make sense.

    Basically, voxel shadows are limited by the surface area, and shadow maps are limited by the number of vertices. Big flat surfaces that cover a large area use very few vertices but would require many voxels to be processed. So for the direct lighting component, I think shadow maps are still the best approach. I know Crytek is claiming to get better performance with voxels, but my experience indicates otherwise.
    Another aspect of shadow maps I did not fully appreciate before is the fact they give high resolution when an object is near the light source, and low resolution further away. This is pretty close to how real light works, and would be pretty difficult to match with voxels, since their density does not increase closer to the light source.

    There are also issues with moving objects, skinned animation, tessellation, alpha discard, and vertex shader effects (waving leaves, etc.). All of these could be tolerated, but I'm sure shadow maps are much faster, so it doesn't make sense to continue on that route.
    I feel I have investigated this pretty thoroughly and now I have a strong answer why voxels cannot replace shadow maps for the direct shadows. I also developed a few pieces of technology that will continue to be used going forward, like our own improved mesh voxelization and the sparse octree traversal routine (which will be used for reflections). And part of this forced me to implement Vulkan dynamic rendering, to get rid of render passes and simplify the code.
    Voxel GI and reflections are still in the works, and I am farther along than ever now. Direct lighting is being performed on the voxel data, but now I am using the shadow maps to light the voxels. The next step is to downsample the lit voxel texture, then perform a GI pass, downsample again, and perform the second GI pass / light bounce. Because the octree is now sparse, we will be able to use a higher resolution with faster performance than the earlier videos I showed. And I hope to finally be able to show GI with a second bounce.
  8. Josh

    Articles
    At long last, the engine that felt like it would never be done is here. This is all the result of an idea I had and wanted to put to the test. Of course I never anticipated it was possible to deliver a 10x improvement in rendering performance, but here we are with the benchmarks to prove it.
    Research & Development
    The last four years of research and development were an opportunity to rethink and redesign what a game engine should be. Along the way there were a few ideas I had that turned out to be not that great of an idea in practice:
    Variance shadow maps: Although I love the look of these under very controlled settings, the technique has extremely bad artifacts that can never be fixed. Depth shadow maps really are the best approach to texture-based shadows. They are also extremely slow to render shadow updates. I would like to see some better hardware filtering options in the future, though.
    Voxel-based indirect lighting: Compelling in theory but extremely messy in practice. I learned a lot and this prompted me to integrate compute shaders into the engine, but ultimately the results I got weren't compelling enough to turn into a finished product. Given the problems everyone else has with this approach, I think it makes sense to focus on hardware raytracing as the next step up in lighting.
    Novel entity component system: My idea was to make it so when you called a component method, all the components that had that method would get called. I had some complicated Lua code set up that handled this, and early builds of Ultra used a C++ preprocessor that analyzed header files and created some complicated wrappers to make C++ work in roughly the same way. Ultimately I decided the confusion wasn't worth the questionable benefit and I implemented a conventional multi-component system like everyone had asked for, without any preprocessor.
    Tabbed Asset Editor: Another thing that sounded good in theory but was not great in practice was to use a single asset editor window with tabs for the different opened files. All it took was a day of using this to realize how much better it was to open each item in its own window. Hunting and clicking file names in tabs is just not fun. I get claustrophobic just looking at this:

    The Results
    Besides the performance, here are the things that I think turned out better than I imagined:
    glTF Integration: Khronos glTF has proven to be a wonderful workflow, and eliminates any "black box" file formats for 3D content. Your game-ready files can always be pulled back into your modeling program, edited, and saved, with no need for secretive conversion pipelines. A wide variety of game-ready content is available for you to use with Ultra, so I am expecting to see no more programmer art!

    Physically-based Rendering: This aligns closely with glTF integration because the file format includes a well-defined PBR materials system. The secret to good PBR is to have good imagery for reflections. To achieve this, I put a lot of work into the volumetric environment probes system that first appeared in Leadwerks. Probe volumes can now be drawn like a brush object for easier creation and precise sizing in the editor. A configurable fade distance for each edge lets you control how probes blend together. Probes also incorporate the sky lighting so you can have seamless transitions between bright outdoor areas and dark enclosed spaces.

    Lua Integration: The VSCode Lua debugger turns Lua into a first-class game programming language and is a dream to work with. The editor scripting integration is in my opinion the best scripting integration of any 3D program I've ever seen. You can access the entire engine API from within editor scripts to add new functionality or modify the program. Additional documentation for the editor's innards will arrive in the coming days.
    Ultra GUI: This took a lot of time but having control over every pixel and event made it worthwhile. Taking control of the user experience by writing my own GUI was one of the best decisions I made. The interface doubles up as the editor's own UI drawn using GDI+ and the in-game UI rendered with Vulkan.

    C++ API: The most significant change is the user of shared pointers, which forever eliminate the problems with uninitialized and invalid pointers games were prone to as they grew more complex. Additionally, the API is generally better thought out and consistent than what we had in Leadwerks.
    Terrain: You wanted more terrain material layers, so you got them. Up to 256, in fact, with fast performance. You can create multiple terrains, position, rotate, and scale them, and even create non-square terrains to fill in any area.

     
    Player Physics: Yes, you can crouch now.
    Pathfinding: It's dynamic and you can create multiple navmeshes, for different areas or differently sized characters. Pathfinding and physics are now decoupled so you can have armies of characters that only use the pathfinding system for movement.
    3D Brush Editing: I was not planning on this feature until the last minute, but you can can create, move, scale, rotate, and shear brushes in any viewport, including the 3D view. the long-asked-for vertex tool is included as well as a face tool for adjusting texture mapping and geometry.
    Last but not least, the engine's multithreaded design is crazy advanced! Your game code runs on its own thread, giving you a full 16 milliseconds to operate without slowing down the renderer. Physics, pathfinding, animation, rendering, and culling all operate on separate threads. It's an amazing feat in engineering that was only possible because I had seen all the bottlenecks people could create in Leadwerks, so I could plan a way around them when designing Ultra.
    Early Access
    The 1.0 release will be marked "Early Access" because there are still a few extra features to add, and we will have a period where changes to the workflow can still be considered based on user feedback. Once decals, particle emitters, VR support, flowgraphs, and brush smooth groups are added, that will be considered version 1.1 (no "early access"). So there will still be a few months of time where I can revise any parts of the workflow you think can be improved. There are also still some compatibility issues with AMD cards that are being resolved, so please be aware of that.
    A big thanks goes out to all the testers who helped me smooth things out before the release. The good times are finally here!
  9. Josh
    I like standard interfaces. I like the consistency of having all programs look the same. That's why web browsers bug me a lot sometimes; They each have their own unique look. It's disappointing to me how Microsoft has gotten away from this idea. Why oh why can't Windows have skins? But I digress.
     
    In terms of performance, my favorite browser would probably be Opera. In terms of appearance, my favorite is Internet Explorer 6. I know, web designers hate it for its quirks. I don't use it due to security issues. But I still like it because it is the only web browser out there with what I consider a simple standard interface. So I took matters into my own hands and found a skin that makes Firefox look like IE6. Then I replaced the program icon with the IE6 icon. I also edited some configuration settings to change the name of the program. I give you Firefox Explorer!:
     

     
    In all seriousness, the reason I am getting away from Microsoft Office is the ribbon interface. I've been using it since 2007, but I still prefer the Office 2003 interface. If they still had that as an option, I would be happily buying Office 2010. Maybe I am not representative of the average customer, but I have my likes and dislikes, and consistency is a big one for me.
  10. Josh
    I got skinned animation working in the new renderer, after a few failed attempts that looked like something from John Carpenter's The Thing. I set up a timer and updated a single animation on a model 10,000 times. Animation consists of two phases. First, all animations are performed to calculate the local position and quaternion rotation. Second, 4x4 matrices are calculated for the entire hierarchy in global space and copied into an array of floats. To test this, I placed this code inside the main loop:
    float frame = Millisecs() / 10.0f; auto tm = Millisecs(); for (int n = 0; n < 10000; ++n) { monster->skeleton->SetAnimationFrame(frame, 1, 1, true); monster->UpdateSkinning(); } int elapsed = Millisecs() - tm; Print(elapsed); The result in release mode was around 60 milliseconds. When I tested each command lone, I found that UpdateSkinning() took around 30-35 milliseconds while SetAnimationFrame() hovered around 20 milliseconds.
    When I cut the number of iterations in half, the result was right around 30 milliseconds, which is within our window of time (33 ms) for games that run at 30 hz. If your game uses a 60 hz loop then you can cut that number in half. The model I am using also only has 24 bones, but models with up to 256 bones are supported (with a pretty linear performance cost).
    Now this is with a single call to SetAnimationFrame. If the animation manager is in use there could potentially be many more calculations performed as animations are smoothly blended.
    Splitting the animations up into multiple threads could be done easily, but most computers only have four CPUs, so I don't see this being useful on more than 2-3 threads. Let's say we dedicate two threads to animation. That means right now our theoretical limit is about 10,000 zombies onscreen at once. I would like to go higher, but I think this is probably our realistic limit for CPU-performed animations. The alternative would be to upload the animation sequences themselves to the GPU and perform all animation entirely on the GPU, but then we would lose all feedback on the CPU side like the current bone orientations. Perhaps a solution would be to have both a CPU and GPU animation system that produces identical results, and the CPU side stuff would only be called when needed, but that makes things pretty complicated and I am not sure I want to go down that road.
    In reality, the final results will probably be quite a lot less than this when all functionality is added, but from this data we can reasonably extrapolate that Leadwerks 5 will support thousands of animated characters onscreen. According to the developers of the Dead Rising series, a few thousand is the practical limit of how many characters you would ever want onscreen, so this is encouraging. Of course, there is no limit on the number of offscreen characters, since animation is only performed for characters that appear onscreen.

  11. Josh
    I am proud to show off our first performance demonstration which proves that my idea for the Leadwerks 5 renderer works. To test the renderer I created 100,000 instanced boxes. The demo includes both regular and a mock VR mode that simulates single-pass stereoscopic rendering with a geometry shader.
    The hardware I tested on is an Intel i7-4770R (for graphics too) which is a few years old.
    Now this is not a perfect benchmark for several reasons. There is no frustum culling being performed, the renderer just adds everything into the scene and renders it. I am not showing threaded and non-threaded performance side by side. You may also see all objects disappear for a single frame occasionally, and some triangles may be discarded prematurely in stereoscopic mode.
    However, the results are incredible and worth bragging about. In normal mode, with a polygon load of 1.2 million per frame, this little machine with integrated graphics is getting 115 FPS, and in mock VR mode (2.4 million polys) it is hovering right around 90! With 100,000 objects, on integrated graphics!
    Alpha subscribers can download the test now.

    The secret of this massive performance is an efficient architecture built to unlock the full power of your graphics hardware. Below you can see that GPU utilization is around 95%:

  12. Josh
    Using my box test of over 100,000 boxes, I can compare performance in the new engine using OpenGL and Vulkan side by side. The results are astounding.
    Our new engine uses extensive multithreading to perform culling and rendering on separate threads, bringing down the time the GPU sits around waiting for the CPU to nearly zero.
    Hardware: Nvidia GEForce GTX 1070 (notebook)
    OpenGL: ~380 FPS

    Vulkan 700+ FPS. FRAPS does not work with Vulkan, so the only FPS counter I have is the Steam one, and the text is very small.

    Vulkan clearly alleviates the data transfer bottleneck the OpenGL version experiences. I am not using a depth buffer in the Vulkan renderer yet, and I expect that will further increase the speed. I'm very happy with these results and I think exclusively relying on Vulkan in the future, together with our new engine designed for modern graphics hardware, will give us great outcomes. 
     
  13. Josh
    Leadwerks 4.x will see a few more releases, each remaining backwards compatible with previous versions.  Leadwerks 5.0 is the point where we will introduce changes that break compatibility with previous versions.  The changes will support a faster design that relies more on multi-threading, updates to take advantage of C++11 features, and better support for non-English speaking users worldwide.  Changes are limited to code; all asset files including models, maps, shaders, textures, and materials will continue to be backwards-compatible.
    Let's take a look at some of the new stuff.
    Shared Pointers
    C++11 shared pointers eliminate the need for manual reference counting.  Using the auto keyword will make it easier to update Leadwerks 4 code when version 5 arrives.  You can read more about the use of shared pointers in Leadwerks 5 here.
    Unicode Support
    To support the entire world's languages, Leadwerks 5 will make use of Unicode everywhere.  All std::string variables will be replaced by std::wstring.  Lua will be updated to the latest version 5.3.  This is not compatible with LuaJIT, but the main developer has left the LuaJIT project and it is time to move on.  Script execution time is not a bottleneck, Leadwerks 5 gains a much longer window of time for your game code to run, and I don't recommend people build complex VR games in Lua.  So I think it is time to update.
    Elimination of Bound Globals
    To assist with multithreaded programming, I am leaning towards a stateless design with all commands like World::GetCurrent() removed.  An entity needs to be explicitly told which world it belongs to upon creation, or it must be created as a child of another entity:
    auto entity = Pivot::Create(world); I am considering encapsulating all global variables into a GameEngine object:
    class GameEngine { public: std::map<std::string, std::weak_ptr<Asset> > loadedassets; shared_ptr<GraphicsEngine> graphicsengine; shared_ptr<PhysicsEngine> physicsengine; shared_ptr<NetworkEngine> networkengine; shared_ptr<SoundEngine> soundengine; shared_ptr<ScriptEngine> scriptengine;//replaces Interpreter class }; A world would need the GameEngine object supplied upon creation:
    auto gameengine = GameEngine::Create(); auto world = World::Create(gameengine); When the GameEngine object goes out of scope, the entire game gets cleaned up and everything is deleted, leaving nothing in memory.
    New SurfaceBuilder Class
    To improve efficiency in Leadwerks 5, surfaces will no longer be stored in system memory, and surfaces cannot be modified once they are created.  If you need a modifiable surface, you can create a SurfaceBuilder object.
    auto builder = SurfaceBuilder::Create(gameengine); builder->AddVertex(0,0,0); builder->AddVertex(0,0,1); builder->AddVertex(0,1,1); builder->AddTriangle(0,1,2); auto surface = model->AddSurface(builder); When a model is first loaded, before it is sent to the rendering thread for drawing, you can access the builder object that is loaded for each surface:
    auto model = Model::Load("Models\box.mdl", Asset::Unique); for (int i=0; i<model->CountSurfaces(); ++i) { auto surface = model->GetSurface(i); shared_ptr<SurfaceBuilder> builder = surface->GetBuilder(); if (builder != nullptr) { for (int v=0; v < surface->builder->CountVertices(); ++v) { Vec3 v = builder->GetVertexPosition(v); } } } 98% of the time there is no reason to keep vertex and triangle data in system memory.  For special cases, the SurfaceBuilder class does the job, and includes functions that were previously found in the Surface class like UpdateNormals().  This will prevent surfaces from being modified by the user when they are in use in the rendering thread.
    A TextureBuilder class will be used internally when loading textures and will operate in a similar manner.  Pixel data will be retained in system memory until the first render.  These classes have the effect of keeping all OpenGL (or other graphics API) code contained inside the rendering thread, which leads to our next new feature...
    Asynchronous Loading
    Because surfaces and textures defer all GPU calls to the rendering thread, there is no reason we can't safely load these assets on another thread.  The LoadASync function will simply return true or false depending on whether the file was able to be opened:
    bool result = Model::LoadASync("Models\box.mdl"); The result of the load will be given in an event:
    while (gameengine->eventqueue->Peek()) { auto event = gameengine->eventqueue->Wait(); if (event.id == Event::AsyncLoadResult) { if (event.extra->GetClass() == Object::ModelClass) { auto model = static_cast<Model>(event.source.get()); } } } Thank goodness for shared pointers, or this would be very difficult to keep track of!
    Asynchronous loading of maps is a little more complicated, but with proper encapsulation I think we can do it.  The script interpreter will get a mutex that is locked whenever a Lua script executes so scripts can be run from separate threads:
    gameengine->scriptengine->execmutex->Lock(); //Do Lua stuff gameengine->scriptengine->execmutex->Unlock(); This allows you to easily do things like make an animated loading screen.  The code for this would look something like below:
    Map::LoadASync("Maps/start.map", world); while (true) { while (EventQueue::Peek()) { auto event = EventQueue::Wait(); if (event.id == Event::AsyncLoadResult) { break; } } loadsprite->Turn(0,0,1); world->Render();// Context::Sync() might be done automatically here, not sure yet... } All of this will look pretty familiar to you, but with the features of C++11 and the new design of Leadwerks 5 it opens up a lot of exciting possibilities.
  14. Josh
    Distance fog is one of the most basic visual effects in 3D graphics, going back to the 1990s.  Here is the effect in the Quake 3 Arena map "Fatal Instinct", which was shrouded in a dense orange fog:

    Leadwerks Game Engine 2 had this available as a built-in effect, while the more flexible effects system of Leadwerks 3/4 had several Workshop shaders available to use, including one by Klepto and another one more recently added by myself.  However, this has not been part of the official SDK until version 4.4.  Why is that?
    The Problem
    When water is rendered in Leadwerks, a low-quality render is performed of the world with the camera scale inverted on the Y axis.  Because the reflection is distorted by ripples, we render to a lower-resolution buffer with all settings on low and effects disabled.  This is important because it gives a faster performance and image quality that is still acceptable.  The water plane also uses occlusion culling so that the extra pass is only rendered if part of the water plane is visible.  All post-processing effects are disabled in the reflection pass, which makes good sense, except in the case of fog.  If the world is shrouded in dense fog but the reflection in the water is clear, it creates an obvious problem.  In the screenshot below, a post-processing effect is applied to the world.  Although the water does have fog applied to it, the reflected image on the water does not have any fog, creating a stark problem, because post-processing effects are disabled in the reflection pass.

    Pre-Rendering Fog
    One option would have been to allow the user to mark some post effects as visible in reflection passes, but that seemed complicated and error-prone.  I came up with the idea build a simple fog calculation into the first ambient or directional lighting pass.  Here it is applied in the directional light pass:

    And here is what happens when the fog effect is applied in the directional light pass in the water reflection as well:

    We can modify the water shader itself to add the same fog calculation to the surface of the water.  Now our water matches the world.

    Removing Artifacts
    There was still more to do.  We are rendering fog first and other stuff later.  Anything rendered after the main lighting pass has to use the fog calculation to substract its effect from the scene.  For example SSAO will add shaded areas on top of fog, which we definitely don't want.  See the bridge and trees in the distance.

    The solution is to add the same fog calculation into the SSAO shader:
    float fogeffect = 0.0f; if (fogmode==true) { fogeffect = clamp( 1.0 - (fogrange.y - length(worldCoord - cameramatrix[3].xyz)) / (fogrange.y - fogrange.x) , 0.0, 1.0 ); fogeffect*=fogcolor.a; if (fogeffect==1.0f) { fragData0 = outputcolor; return; } } And then use the fog level to lessen the impact of the effect:
    fragData0 = outputcolor * fogeffect + outputcolor * (sumao / float(passes)) * (1.0 - fogeffect); The underwater artifacts are a separate issue that were solved by adding another calculation.  Here is the result:

    The same fog calculation had to be added to all light shaders, light volumes, and probes, to make sure lights faded into the fog.  Other effects can make use of four new built-in uniforms which will provide all the fog information the shader needs:
    uniform bool fogmode; uniform vec2 fogrange; uniform vec4 fogcolor; uniform vec2 fogangle; On the client side, eight new commands have been added to the camera class to control the fog appearance, which are also available in Lua:
    virtual void SetFogColor(const float r, const float g, const float b, const float a); virtual void SetFogAngle(const float start, const float stop); virtual void SetFogRange(const float start, const float stop); virtual void SetFogMode(const bool mode); virtual Vec4 GetFogColor(); virtual Vec2 GetFogAngle(); virtual Vec2 GetFogRange(); virtual bool GetFogMode(); This was the solution I've had in mind for some time, but I haven't had a chance to implement it until now.  It works really well and provides robust fog that looks correct under a wide variety of settings.

  15. Josh
    I'm going to focus on directing people to the Leadwerks mailing list and getting people to sign up for Leadwerks accounts. This is much more valuable than social media followers we have no data for, or even Steam users we can't contact directly.
     
    We do need something extra to get the word out to people on the web about Leadwerks, but I don't think Facebook and Twitter are it...
  16. Josh

    Articles
    Our forum software and theme have been updated. The new theme is just the default Invision Power Board skin, with our own header and footer added.
    In the past I put a lot of effort into getting the forum to look exactly the way I wanted, and I don't think that effort was a very good use of time. Each forum update requires us to redo the skin, and I just don't feel like it is that important. I can fine-tune the appearance of the user interface in the Leadwerks Editor, but this web stuff is out of my hands. The fact that Google is forcing everyone to use "responsive design" just means web design is always going to be a compromise. So I am just going with a direction that requires minimal maintenance.
    In the future, I would like to develop a dark theme and use that as the default. Again, it would just be the default theme with the colors changed, and no attempt to change the layout.
  17. Josh
    The forum software has been updated to a major new version.  This completes my effort to give the entire website responsive design, and ensures we continue to receive security updates.  The responsive design part is really for SEO, but it is kind of cool to be able to browse the entire site on your phone without zooming in.
    Documentation has been switched over to the new system here, which is independent from the forum software:
    https://www.leadwerks.com/learn
    The entire site is now using SSL on every page, again for SEO purposes.
    There are a few bits that need improvement, but overall it's a solid upgrade and I think you will find the new site to be very helpful.  I've added a new Q & A forum where you can get technical assistance and rate the answers.  Code formatting has been improved a lot, and the notifications system does a really good job of catching replies to your posts.  (If you're receiving a lot of emails you can disable this in your account settings.)
    Finally, you can now set a cover image to show at the top of your profile, which is pretty cool.
  18. Josh
    Based on the excellent sales of the SciFi Interior Model Pack, I was able to get a deal to sell a new pack of high-quality first-person weapons. The following items are included:
    Pistol
    Combat shotgun
    MP5 Machne Gun
    M4 Rifle
    Grenade
    Machete

     
    Weapons are included as animated visual weapons, and as models that can be placed throughout the map to pick up.
     

     
    Instead of just distributing raw models, I want to offer game-ready items that can just be dropped into your game. This requires me to add sounds and perform some scripting to make the FPS player handle picking weapons up and switching between weapons. It also requires some new scripting for the new weapon types, like grenades and melee weapons. It's a challenge to design the scripts in a general-purpose manner, the benefit is everyone gets game-ready weapons they can simply drop into their map for the player to find and use. Plus, I get to design some cool explosion effects.
     
    The pack will be priced at $29.99, includes sounds, scripts, and special effects, and will be available in October.
     

  19. Josh
    We're finishing up 2009 by resolving some longstanding design issues that haven't been particularly critical, but have weighted on my mind. Framework is not like the main engine. It's far more high-level, and is also the kind of code people want to customize. I don't like locking the user into my way of doing things. However, the interaction between Lua, C++, and Framework commands are a real issue, which we started to see immediately as Lua became available. This was resolved by compiling Framework into the engine DLL and providing the source code in the BMX folder. Most people will be happy with the default settings, but a few will want to write their own renderers, and fortunately they still can. Most importantly, Lua can access the Framework commands, so all the water and atmospheric effects will work the same in C++ and in the editor. In the end, we finally wound up doing something I said we never would: There are commands like SetBloom(), SetNearDOF(), etc. However, since this is open-source code built on top of the buffer and shader systems, I am happy with it. The user still has low-level power, but is supported by a lot of default code that does most of what they want. This is the design I have always tried to provide.
     
    The solution we arrived at with Framework can also be applied to other systems that are commonly needed, yet don't quite fit into the main engine. Providing open-source code, and then compiling it into the DLL and adding a Lua interface seems to be a good solution for anything like this. The next system I could see handled this way is AI. I am carefully watching the work Chris Paulson is doing with the recast library, and I think it has a very promising future.
     
    Oh, and in other news Penumbra is finally available on Steam! Penumbra is a physics-driven game that uses the same physics library we use, Newton Game Dynamics. I highly recommend this series, both for learning and for fun.
  20. Josh
    Everyone's gone for the weekend, and I am still here, so it seems like a good time to stop and say hello to the community, who I have not been communicating with much lately.
     
    We spent some time this week doing some market research, and investigating exactly why Leadwerks is different and unique. After that I feel like I have a much better picture of the game industry as a whole, and of our strategy going forward. That's the "big picture" stuff we CEO's do.
     
    Meanwhile, back on the ground, I have code to write and a few outstanding bugs to correct for Leadwerks Engine. I've made progress and have very basic CSG editing working in the editor. I ran some performance tests with my new iPad 3, and the results are looking good. More on Monday about that. We're looking to recruit a few more interns in the Sacramento area.
     
    Anyways, this is less structured than most of my blogs, but I wanted to write something. How was your week?
  21. Josh
    Dave Lee has joined the Leadwerks team. His job is to create a AAA game environment in Leadwerks Engine. Check out his work here.
     
    (Influences of Crysis and S.T.A.L.K.E.R., how could I not hire him? )
     
    Simon Benge, the lead artist from FPS Creator X, is also completing some animations for us.
  22. Josh
    My little precompiler is going well. It creates makefiles and can split a build up across multiple files. I am working out the interface with external libraries. Here's an example program:

    Print "Hello World!"
    And here's the code it outputs and compiles:

    #include "Hello World.h" using namespace codewerks; //============================================= // Main Loop //============================================= int main(int argc, char* argv[]) { Print(std::string("Hello World!")); }
     
    I'm confident this will work on both MacOS and Linux. Where things get a little foggier is on the iPhone, and especially on the Android. I'm looking for an Android and an iPhone developer to work with. It would be easiest in the long run if I can account for those platforms from the beginning.
  23. Josh
    Well, we're through the "OMG will this even work" phase. Aria got FreeType to build on all platforms, so you can load TTF files directly on Windows, Mac, Android, and iOS devices. I set up the accelerometer input on iOS today, so you can call Device::GetAcceleration() and retrieve a Vec3 telling you which way is down. Acceleration is returned relative to the screen orientation, so you don't have to worry about which way the device is rotated. This isn't my proudest screenshot, but it demonstrates that it works. Gravity is pointing in the negative Y direction, relative to the landscape screen orientation.

     
    Multitouch is working on iOS and Android. I am not 100% happy with the way events are handled at this point, but the hard parts are done.
     
    I also got cross-platform threads working. I like the Windows implementation of threads better than POSIX, but our Thread and Mutex classes work the same on everything. I use these internally to optimize routines in the engine, and you are welcome to try them, but be warned! Multithreaded programming is not for the faint of heart, and there's a lot of ways you can hurt yourself! I generally avoid use of mutexes at all, and just try to design my routines so that I send a bunch of data to get processed, then get the results. Otherwise it's just too complicated.
     
    I had an interesting discussion last week with one developer here, and it led to the decision to start using static class functions for creation and loading commands. For example, instead of CreateThread(), you will call Thread::Create() in C++, Lua, and C#. This gives us a uniform API across all three languages, and it resolves the problems that arise from C#'s lack of global functions.
     
    The goal right now is to get all the platform-specific stuff totally resolved and 100% tested so that we can move on and be totally platform-agnostic. That means from now on I can just write code without worrying about whether it's running on Android, Mac, Windows, or whatever. Not much else to say at the moment. Here's a screenshot of the code log to show what we've been working on:

  24. Josh
    This is just a little walk down memory lane that pleasantly shows what has led to where we are today. Some of this predates the name "Leadwerks" entirely.
     
    Cartography Shop (2003)

     
    3D World Studio (2004)

     
    Leadwerks Game Engine 2 (2008)

     
    Leadwerks Game Engine 3 (2013)

×
×
  • Create New...