Jump to content

Josh

Staff
  • Posts

    22,895
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh
    Ladies and gentlemen, come one, come all, to feast your eyes on wondrous sights and behold amazing feats! It's "Cirque des Jeux", the next Leadwerks Game Tournament!

    How does it work?  For one month, the Leadwerks community builds small playable games.  Some people work alone and some team up with others.  At the end of the month we release our projects to the public and play each other's games.  The point is to release something short and sweet with a constrained timeline, which has resulted in many odd and wonderful mini games for the community to play.
    WHEN: The tournament begins Thursday, February 1, and ends on Wednesday, February 28th at the stroke of midnight.
    HOW TO PARTICIPATE: Publish your Circus-or-other-themed game to the Games Showcase before the deadline. You can work as a team or individually. Use blogs to share your work and get feedback as you build your game.
    Games must have a preview image, title, and contain some minimal amount of gameplay (there has to be some way to win the game) to be considered entries. It is expected that most entries will be simple, given the time constraints.
    This is the perfect time to try making a VR game or finish that idea you've been waiting to make!
    PRIZES: All participants will receive a limited-edition 11x17" poster commemorating the event. To receive your prize you need to fill in your name, mailing address, and phone number (for customs) in your account info.
    At the beginning of March we will post a roundup blog featuring your entries. Let the show begin!
  2. Josh
    So after about three weeks of pain and frustration, I have successfully calculated my first path using Recast navigation. This has been a new experience for me. I've implemented half a dozen low-level C++ libraries, and never had any serious trouble, but Recast Navigation is something else.
     
    The technology underlying Recast is impressive. First they take triangle geometry, convert it to voxels, then calculate navigation, and convert it back into rough polygons. You can read about the process in more detail here:
    https://sites.google.com/site/recastnavigation/MikkoMononen_RecastSlides.pdf
     
    The results seem pretty reliable, and although the speed of regenerating a tile is slow, it can be done on a separate thread and doesn't have to be updated all that often. I have two criticisms of the library.
     
    First, the code is a total mess. I can't complain too much since it's a free library, and I definitely appreciate Mikko putting it out there, but integrating it into the engine was a hellish process. I wouldn't even call Recast a code library so much as it is an open-source program. The amount of work it took to figure out what was going on was far beyond any library I have worked with, and it could have been wrapped up into a set of much simpler commands (which is what my end result was).
     
    Second, I believe converting polygons to voxels and back is the technically wrong way to go about this. Constructive solid geometry is perfect for navmeshes, autogenerated or otherwise. It would be very fast to generate. It could be dynamically updated quickly. The results would also be 100% accurate virtually all the time. However, it would require all navigation geometry to be modeled with CSG, and although I would be fine with that, I know others will want to use arbitrary polygonal geometry. So that's one thing I would do different if I were making an engine for just myself. There's an example of why you need to be flexible with your goals sometimes.
     
    Still, it's great to be able to build navigation data for any scene and make a character walk around in it without any waypoints or ray casts. Below is my very first result with Recast. There's some obvious strange results with the path, but the point is that it's working, to some extent. It's a minor miracle I am able to plot any kind of path at all. The hard part is done, and I'm sure I'll get any remaining issues ironed out pretty quickly:

     
    Building AI features right into the engine will give us better integration than using a third-party add-on, or trying to build it on top of the engine. First example, we can use physics geometry instead of visual polygons, and make the engine automatically invalidate and update sections of a map when objects move. This will give you powerful AI features that work perfectly with the rest of the engine, so you can control characters with just a few lines of script code. When this is done, it's reasonable to expect to be able to program something like Left 4 Dead in just a couple hundred lines of script (or less, if you just feel dragging some premade scripts around and attaching them to entities).
     
    Once the pathfinding is all tidied up, it will be a big moment, because it means at that point I will know everything I need to finish Leadwerks3D! When setting out with Leadwerks3D, the things I hadn't done before were what I was most worried about. I attacked the unknown issues first. Now that we are coming to the end of this long research and development phase, all that remains is a lot of hard work. It's all stuff I have done before, so I expect the remaining tasks to go pretty quickly. It's also pretty awesome to have a clear picture of how this massive piece of technology all works...four platforms, with rendering technology stretching from fixed-function graphics all the way to Shader Model 5 hardware tessellation...plus the easiest art pipeline ever and a script and flowgraph system that no one has ever done. The scope of this engine is just so much bigger than anything I have ever done, and it actually works! B)
  3. Josh
    I've got my models and a little time to put this together, so I am starting on my Halloween Game Tournament entry now. This will be an exercise in speed-developing!
     
    Basically, I just want to make a game where you fly a ship through an asteroid field shooting meteors. To spice things up, I'm going to add pumpkins that appear after the first level, and are attracted to your ship:


     
    The game asset requirements are very simple. Here are my main models:

     

     
    So now I'm going to add ship controls and meteor spawning.
     
    --EDIT--
    And it's done:


     
    Play it on Steam:
    http://steamcommunity.com/sharedfiles/filedetails/?id=333829569
     

  4. Josh
    Explore our reimagining of the Chernobyl nuclear exclusion zone with The Zone asset pack.  This package contains over three gigabytes of high-quality game assets prepared to take advantage of the latest Leadwerks features.  Use our ready-made map (included) to start your game or create your own post-apocalyptic environment.
    Get it now on Steam with a discount during launch week.


    "The Zone" DLC includes the following assets:
    24 terrain textures 11 buildings (plus 2 background buildings) 4 types of bridges 2 types of fences 6 crates 3 cargo containers 12 signs 13 rocks 7 gravestones 8 plants 39 junk and debris models 20 furniture models Barriers Railway tracks Diesel locomotive and boxcar 2 skyboxes And much more... TECHNICAL SPECIFICATIONS
    Polygon Count: 30-46985
    Textures: Diffuse, Normal, Specular
    Texture Resolution: 64x64, 128x128, 256x256, 512x512, 1024x1024, 2048x2048
    Collision Shapes: Yes
    Source Files: FBX, MAX, PSD, JPG, PNG, BMP



     
  5. Josh
    I like how a sequence of decisions can lead in one overriding direction. It's very fun.
    The FPS weapons and zombie packs were released because I felt there needed to be a little more built-in gameplay available to users.
     
    The Steam Community Choice sale resulted in a large number of new users, most of whom are completely new to game development.
     
    The Winter Games tournament resulted in ten new games that were fun and very creative.
     
    This finally gave me the ammo I needed to launch the standalone game player on Steam. All the videos and screenshots look great, so for Steam users it's a no-brainer to vote yes. This will be awesome because you'll be able to get thousands of players very easily who will give you feedback on your game and become your fan base, when you're ready to move on to Kickstarter or Greenlight.

     
    This came about because it was decided that "gameplay" was the most important factor we needed to focus on. And now we are seeing the result of that, and it is very good. I'm pretty darn proud of what you guys have made, and I am very happy with the direction we're going in.
  6. Josh
    Well, the single-state lua update is out and I am ready to start making tutorials again.
     
    Someone in the forum pointed out the game Fuel to me. This is an offroad racing game with a nearly infinite world. The data is streamed off the hard drive, basically like its treating the drive as if it were extended RAM. The game got bad reviews, but I think it's great. I went driving for at least 30 minutes and covered mountains, desert, redwood forests, and ravines. I'm in love with the terrain engine. If only they had used that to make S.T.A.L.K.E.R...
     
    There's much to do with our existing technology before I start inventing new technology again, but the possibilities are intriguing.
  7. Josh
    This is a good idea to keep in mind, especially with something like software development:
     
    "Don't judge each day by the harvest you reap but by the seeds that you plant."
    -Robert Louis Stevenson
  8. Josh
    Working to improve the implementation of the code known as framework. It needs to be able to talk to Lua, with all programming languages. I can't really go on documenting the script until this is finalized, so the time to do it is now.
  9. Josh
    I dabbled in a lot of little things recently, like GUI code and networking, just to make sure things would work the way I want in the long run. The lighting optimizations weren't planned to come out yet, but were moved to the front due to one user who is finishing up a commercial game. I've also been helping Pure3D a little bit, but I can't say anything about that right now. Of course, our website is still in progress, and that will hopefully come together by the end of the month.
     
    We'll have some cool stuff for you guys at the GDC. If you happen to be going, speak up now!
     
    There are two big things I want to complete in the next two months. They are:
     

    Art pipeline enhancements. The plan is to have a model viewer and editor integrated into the main editor. There's lots of little things like normals, binormal/tangents, physics, and the mesh hierarchy that can be difficult to export properly. This tool will give the user more control over their assets, and make it easier to import content from a variety of sources.
     
    Vegetation system improvements. Some parts of the vegetation rendering routines will be rewritten for better speed with large numbers of layers. I'll also add collision, while I am in there.
  10. Josh
    Leadwerks is about making games, first and foremost. Therefore, you can expect me to focus on the following in the next year:
    More and better AAA first-party content. We're working out the process right now. It's a lot harder to produce top-quality content, but the results are worth it. I figure once we get the process down it will be easier to go back and produce more.
    Easy to use networking will open up a lot more gameplay possibilities and give us some fun games we can jump in and out of. I want to shoot it out with you guys in a variety of games with different objectives.
    Paid Workshop items are something I am very interested in.

     
    These are the main ideas that I feel will move Leadwerks in the direction we want to go. There will be undoubtedly other features and improvements added, but these are the things that really move us forward. Overall, I want Leadwerks to become more like a moddable game, without losing the simplicity and flexibility we have to make anything.
  11. Josh

    Articles
    2020 was the most intellectually challenging year in my career. Many major advancements were invented, and 2021 will see those items refined, polished, and turned into a usable software product. Here is a partial list of things I created:
    Streaming hierarchal planet-scale terrain system with user-defined deformation and texture projection. Vulkan post-processing stack and transparency with refraction. Vulkan render-to-texture. Major progress on voxel ray tracing. Porting/rewrite of Leadwerks GUI with Implementation in 3D, rendered to texture, and using system drawing. Plugin system for loading and saving textures, models, packages, and processing image and mesh data. Lua debugger with integration in Visual Studio Code. Pixmap class for loading, modifying, compressing, and saving texture data. Vulkan particle system with physics. Implemented new documentation system. Lua and C++ state serialization system with JSON. C++ entity component system and preprocessor. (You don't know anything about this yet.) Not only was this a year of massive technical innovation, but it was also the year when my efforts were put to the test to see if my idea of delivering a massive performance increase for VR was actually possible, or if I was in fact, as some people from the Linux community have called me, "unbelievably delusional". Fortunately, it turned out that I was right, and an as-of-yet-unreleased side-by-side benchmark showing our performance against another major engine proves we offer significantly better performance for VR and general 3D graphics. More on this later...
    Additionally, I authored a paper on VR graphics optimization for a major modeling and simulation conference (which was unfortunately canceled but the paper will be published at a later time). This was another major test because I had to put my beliefs, which I mostly gain from personal experience, into a more quantifiable defensible scientific format. Writing this paper was actually one of the hardest things I have ever done in my life. (I would like to thank Eric Lengyel of Terathon Software for providing feedback on the final paper, as well as my colleagues in other interesting industries.)
    I'm actually kind of floored looking at this list. That is a massive block of work, and there's a lot of really heavy-hitting items. I've never produced such a big volume of output before. I'm expecting 2021 to be less about groundbreaking research and more about turning these technologies into usable polished products, to bring you the benefits all these inventions offer.
  12. Josh
    I ordered my Oculus Rift DK2 in the middle of August and it finally arrived two days ago. Here are my quick impressions.

    Unboxing and Setup
    The box comes with a convenient carrying handle, so it makes a nice case. Upon opening it, the parts were pretty straightforward with no assembly required. There's an extra pair of lenses to extend the focal length or something like that, but I didn't use them. 
    Setup was pretty difficult. There's an excessive number of cords. A USB and HDMI cable plug into the headset. These plug into a four-way junction that has two cords going to the PC and two going to the camera...actually, I'm not even sure how they are connected, and it's right in front of me. There's also an optional power cord coming off this hub because I guess sometimes the USB power isn't enough. So it's a pretty bad mess of wires.
     
    Once you have it running, a systray icon allows you to open a dialog and adjust settings. The DK2 has two display modes, one for "direct" rendering and one to display the desktop, which I think is the legacy mode the DK1 used. It's confusing because some games will crash if you have one enabled, and some will crash if the other is enabled. I found the new direct mode to be more reliable, but it only works with Windows for now.

    Initial Impressions
    Having tried Valve's virtual reality room last summer, I was eager to see how the new Rift compares. The latency when you turn your head and when the image responds is much better than the DK1, but is still in the "nausea-inducing" range. If you don't turn your head quickly it's not bad. The motion tracking helps with the rotation accuracy, and it also helps a lot with the sense of presence. Games that only support the DK1 (and thus no motion tracking) were really difficult to handle. When you move your head to the right and the scene doesn't respond, it feels like the whole world is shifting with you. The motion tracking is quite good even when rotating with my back to the camera. There are no markers on the headset, so I have no idea how it works, but it's pretty accurate. 
    Overall, the motion tracking in the DK2 makes it much better than the DK1, but I didn't get the feeling of presence I had with Valve's VR room. Everything still felt like a screen on my face, but it's getting close.

    Games and Demos
    About 80% of the user-made demos on OculusVR's website do not work. There's a large number of demos available for the DK1, and I think the changes in the newer SDKs cause these to no longer work. Many will display a message saying no device is detected, or they will open a 1920x1080 screen in a weird position on the desktop and lock your mouse so you can't move it. The demos were a little underwhelming, perhaps because so many are designed for the DK1 and no longer work. I was looking forward to trying "The Affected" but it just doesn't run. I recommend From Ashes and Don't Let Go. The roller coasters were also fun. They didn't make me sick, but there was a disconnect between what I was seeing and sitting stationary in a chair. 
    Commercial games weren't any better. Alien Isolation has an unofficial hack to enable VR mode but my camera angle got messed up and I couldn't reset it. Half-Life 2 appears to not use motion tracking, so it's not as good as it could be. I played the airboat level for a while, which I don't recommend if you get carsick. I was disappointed I could not get Doom 3 BFG Edition to work.
     
    While playing Half-Life 2 I did notice that my aim and responsiveness were superhuman. Being inside the Half-Life world allowed me to take aim with incredible ease and accuracy. I am much better at FPS games in VR mode, which I did not expect at all. However, the bounciness and rapid movement of Gordon Freeman were very apparent and it was a little difficult to stomach, especially when combined with the lack of motion tracking. It was also strange that the characters all looked like 2D cardboard cutouts in an otherwise convincing world.

    Conclusions
    Motion tracking is a critical component of VR. It reduces nausea and greatly increases the believability of a scene. Although the Oculus Rift DK2 is not as good as Valve's VR room, it's getting close and I expect the final consumer product will be better. Without motion tracking, the Oculus Rift is just a nausea mask. 
    There's a big demand for new VR games and experiences, and a very limited supply. Most of the existing demos were made for the DK1, and do not support motion tracking. The majority of user-made demos will not even run, or won't detect the DK2 headset. So I hope to see more good applications in the future made for with the current Oculus SDK.
     
    The Oculus Rift has problems with the complexity of the setup, software incompatibility, and physiological input. In spite of these issues, it allows you to have some amazing experiences that are otherwise impossible. Walking around a game level and looking at things suddenly becomes an overwhelming experience. A monster roaring in your face or a spider crawling up your arm almost feels like it's really there. If you can get through the hardware setup, and if you can find a game that works, the experience in VR is the most interesting thing I've seen since the advent of real-time 3D graphics.
  13. Josh
    Previously I described how multiple cameras can be combined in the new renderer to create an unlimited depth buffer. That discussion lead into multi-world rendering and 2D drawing. Surprisingly, there is a lot of overlap in these features, and it makes sense to solve all of it at one time.
    Old 2D rendering systems are designed around the idea of storing a hierarchy of state changes. The renderer would crawl through the hierarchy and perform commands as it went along, rendering all 2D elements in the order they should appear. It made sense for the design of the first graphics cards, but this style of rendering is really inefficient on modern graphics hardware. Today's hardware works best with batches of objects, using the depth buffer to handle which object appears on top. We don't sort 3D objects back-to-front because it would be monstrously inefficient, so why should 2D graphics be any different?
    We can get much better results if we use the same fast rendering techniques we use for 3D graphics and apply it to 2D shapes. After all, the only difference between 3D and 2D rendering is the shape of the camera projection matrix. For this reason, Turbo Engine will use 2D-in-3D rendering for all 2D drawing. You can render a pure 2D scene by setting the camera projection mode to orthographic, or you can create a second orthographic camera and render it on top of your 3D scene. This has two big implications:
    Performance will be incredibly fast. I predict 100,000 uniquely textured sprites will render pretty much instantaneously. In fact anyone making a 2D PC game who is having trouble with performance will be interested in using Turbo Engine. Advanced 3D effects will be possible that we aren't used to seeing in 2D. For example, lighting works with 2D rendering with no problems, as you can see below. Mixing of 3D and 2D elements will be possible to make inventory systems and other UI items. Particles and other objects can be incorporated into the 2D display.
    The big difference you will need to adjust to is there are no 2D drawing commands. Instead you have persistent objects that use the same system as the 3D rendering.
    Sprites
    The primary 2D element you will work with is the Sprite entity, which works the same as the 3D sprites in Leadwerks 4. Instead of drawing rectangles in the order you want them to appear, you will use the Z position of each entity and let the depth buffer take care of the rest, just like we do with 3D rendering. I also am adding support for animation frames and other features, and these can be used with 2D or 3D rendering.

    Rotation and scaling of sprites is of course trivial. You could even use effects like distance fog! Add a vector joint to each entity to lock the Z axis in the same direction and Newton will transform into a nice 2D physics system.
    Camera Setup
    By default, with a zoom value of 1.0 an orthographic camera maps so that one meter in the world equals one screen pixel. We can position the camera so that world coordinates match screen coordinates, as shown in the image below.
    auto camera = CreateCamera(world); camera->SetProjectionMode(PROJECTION_ORTHOGRAPHIC); camera->SetRange(-1,1); iVec2 screensize = framebuffer->GetSize(); camera->SetPosition(screensize.x * 0.5, -screensize.y * 0.5); Note that unlike screen coordinates in Leadwerks 4, world coordinates point up in the positive direction.

    We can create a sprite and reset its center point to the upper left hand corner of the square like so:
    auto sprite = CreateSprite(world); sprite->mesh->Translate(0.5,-0.5,0); sprite->mesh->Finalize(); sprite->UpdateBounds(); And then we can position the sprite in the upper left-hand corner of the screen and scale it:
    sprite->SetColor(1,0,0); sprite->SetScale(200,50); sprite->SetPosition(10,-10,0);
    This would result in an image something like this, with precise alignment of screen pixels:

    Here's an idea: Remember the opening sequence in Super Metroid on SNES, when the entire world starts tilting back and forth? You could easily do that just by rotating the camera a bit.
    Displaying Text
    Instead of drawing text with a command, you will create a text model. This is a series of rectangles of the correct size with their texture coordinates set to display a letter for each rectangle. You can include a line return character in the text, and it will create a block of multiple lines of text in one object. (I may add support for text made out of polygons at a later time, but it's not a priority right now.)
    shared_ptr<Model> CreateText(shared_ptr<World> world, shared_ptr<Font> font, const std::wstring& text, const int size) The resulting model will have a material with the rasterized text applied to it, shown below with alpha blending disabled so you can see the mesh background. Texture coordinates are used to select each letter, so the font only has to be rasterized once for each size it is used at:

    Every piece of text you display needs to have a model created for it. If you are displaying the framerate or something else that changes frequently, then it makes sense to create a cache of models you use so your game isn't constantly creating new objects. If you wanted, you could modify the vertex colors of a text model to highlight a single word.

    And of course all kinds of spatial transformations are easily achieved.

    Because the text is just a single textured mesh, it will render very fast. This is a big improvement over the DrawText() command in Leadwerks 4, which performs one draw call for each character.
    The font loading command no longer accepts a size. You load the font once and a new image will be rasterized for each text size the engine requests internally:
    auto font = LoadFont("arial.ttf"); auto text = CreateText(foreground, font, "Hello, how are you today?", 18); Combining 2D and 3D
    By using two separate worlds we can control which items the 3D camera draws and which item 2D camera draws: (The foreground camera will be rendered on top of the perspective camera, since it is created after it.) We need to use a second camera so that 2D elements are rendered in a second pass with a fresh new depth buffer.
    //Create main world and camera auto world = CreateWorld(); auto camera = CreateCamera(world); auto scene = LoadScene(world,"start.map"); //Create world for 2D rendering auto foreground = CreateWorld() auto fgcam = CreateCamera(foreground); fgcam->SetProjection(PROJECTION_ORTHOGRAPHIC); fgcam->SetClearMode(CLEAR_DEPTH); fgcam->SetRange(-1,1); auto UI = LoadScene(foreground,"UI.map"); //Combine rendering world->Combine(foreground); while (true) { world->Update(); world->Render(framebuffer); } Overall, this will take more work to set up and get started with than the simple 2D drawing in Leadwerks 4, but the performance and additional control you get are well worth it. This whole approach makes so much sense to me, and I think it will lead to some really cool possibilities.
    As I have explained elsewhere, performance has replaced ease of use as my primary design goal. I like the results I get with this approach because I feel the design decisions are less subjective.
  14. Josh
    I have been working on 2D rendering off and on since October. Why am I putting so much effort into something that was fairly simple in Leadwerks 4? I have been designing a system in anticipation of some features I want to see in the GUI, namely VR support and in-game 3D user interfaces. These are both accomplished with 2D drawing performed on a texture. Our system of sprite layers, cameras, and sprites was necessary in order to provide enough control to accomplish this.
    I now have 2D drawing to a texture working, this time as an official supported feature. In Leadwerks 4, some draw-to-texture features were supported, but it was through undocumented commands due to the complex design of shared resources between OpenGL contexts. Vulkan does not have this problem because everything, including contexts (or rather, the VK equivalent) is bound to an abstract VkInstance object.

    Here is the Lua code that makes this program:
    --Get the primary display local displaylist = ListDisplays() local display = displaylist[1]; if display == nil then DebugError("Primary display not found.") end local displayscale = display:GetScale() --Create a window local window = CreateWindow(display, "2D Drawing to Texture", 0, 0, math.min(1280 * displayscale.x, display.size.x), math.min(720 * displayscale.y, display.size.y), WINDOW_TITLEBAR) --Create a rendering framebuffer local framebuffer = CreateFramebuffer(window); --Create a world local world = CreateWorld() --Create second camera local texcam = CreateCamera(world) --Create a camera local camera = CreateCamera(world) camera:Turn(45,-45,0) camera:Move(0,0,-2) camera:SetClearColor(0,0,1,1) --Create a texture buffer local texbuffer = CreateTextureBuffer(512,512,1,true) texcam:SetRenderTarget(texbuffer) --Create scene local box = CreateBox(world) --Create render-to-texture material local material = CreateMaterial() local tex = texbuffer:GetColorBuffer() material:SetTexture(tex, TEXTURE_BASE) box:SetMaterial(material) --Create a light local light = CreateLight(world,LIGHT_DIRECTIONAL) light:SetRotation(55,-55,0) light:SetColor(2,2,2,1) --Create a sprite layer. This can be shared across different cameras for control over which cameras display the 2D elements local layer = CreateSpriteLayer(world) texcam:AddSpriteLayer(layer) texcam:SetPosition(0,1000,0)--put the camera really far away --Load a sprite to display local sprite = LoadSprite(layer, "Materials/Sprites/23.svg", 0, 0.5) sprite:MidHandle(true,true) sprite:SetPosition(texbuffer.size.x * 0.5, texbuffer.size.y * 0.5) --Load font local font = LoadFont("Fonts/arial.ttf", 0) --Text shadow local textshadow = CreateText(layer, font, "Hello!", 36 * displayscale.y, TEXT_LEFT, 1) textshadow:SetColor(0,0,0,1) textshadow:SetPosition(50,30) textshadow:SetRotation(90) --Create text text = textshadow:Instantiate(layer) text:SetColor(1,1,1,1) text:SetPosition(52,32) text:SetRotation(90) --Main loop while window:Closed() == false do sprite:SetRotation(CurrentTime() / 30) world:Update() world:Render(framebuffer) end I have also added a GetTexCoords() command to the PickInfo structure. This will calculate the tangent and bitangent for the picked triangle and then calculate the UV coordinate at the picked position. It is necessary to calculate the non-normalized tangent and bitangent to get the texture coordinate, because the values that are stored in the vertex array are normalized and do not include the length of the vectors.
    local pick = camera:Pick(framebuffer, mousepos.x, mousepos.y, 0, true, 0) if pick ~= nil then local texcoords = pick:GetTexCoords() Print(texcoords) end Maybe I will make this into a Mesh method like GetPolygonTexCoord(), which would work just as well but could potentially be useful for other things. I have not decided yet.
    Now that we have 2D drawing to a texture, and the ability to calculate texture coordinates at a position on a mesh, the next step will be to set up a GUI displayed on a 3D surface, and to send input events to the GUI based on the user interactions in 3D space. The texture could be applied to a computer panel, like many of the interfaces in the newer DOOM games, or it could be used as a panel floating in the air that can be interacted with VR controllers.
  15. Josh
    Leadwerks Game Engine 5 is being designed to make use of shared pointers.  This eliminates manual reference counting, which has probably been the most difficult part of programming games with Leadwerks.  Here are three concepts you must understand before you start using smart pointers in Leadwerks 5,
    Don't Create Multiple Shared Pointers from One Object
    When a shared pointer goes out of scope, it deletes the object it references.  If another smart pointer was created separately that references that object, the other smart pointer will now point to an object that has been deleted!  Set breakpoints in the example below and you will see the problem.  The object is deleted while the second smart pointer still references it.  Any attempt to use the second smart pointer will cause an error:
    class Thing { public: ~Thing(); }; Thing::~Thing() {}// <--------- set a breakpoint here int main(int argc, const char *argv[]) { Thing* thing = new Thing; shared_ptr<Thing> p1 = shared_ptr<Thing>(thing); shared_ptr<Thing> p2 = shared_ptr<Thing>(thing); p1 = nullptr; int k = 0;// <--------- set a breakpoint here } Instead, initialize a smart pointer once and copy it.  Here is the correct way:
    class Thing { public: ~Thing(); }; Thing::~Thing() {}// <--------- set a breakpoint here int main(int argc, const char *argv[]) { Thing* thing = new Thing; shared_ptr<Thing> p1 = shared_ptr<Thing>(thing); shared_ptr<Thing> p2 = p1; p1 = nullptr; int k = 0;// <--------- set a breakpoint here } It's even better to eliminate the new keyword entirely and create object and smart pointer in one step:
    class Thing { public: ~Thing(); }; Thing::~Thing() {}// <--------- set a breakpoint here int main(int argc, const char *argv[]) { shared_ptr<Thing> p1 = make_shared<Thing>(); shared_ptr<Thing> p2 = p1; p1 = nullptr; int k = 0;// <--------- set a breakpoint here } The point is, you create the first smart pointer and thereafter all code should pass that around.  You never need to access the pointer directly.
    Of course the use of auto makes everything a lot simpler:
    auto p1 = make_shared<Thing>(); auto p2 = p1; Parent / Child Relationships
    If you have an object that is some kind of "child" of a parent object, you probably want that parent to keep a smart pointer to the child that keeps the child from being deleted.  However, if the child has a smart pointer to the parent you are creating a circular reference that will never be deleted from memory.  Think of the parent as the owner of the child.  Something other than the child must keep the parent in memory, but sometimes the child wants to retrieve the parent object in a bit of code.  Therefore, for the child member we will use a shared pointer, and for the parent member we will use a weak pointer:
    class Thing { public: shared_ptr<Thing> child; weak_ptr<Thing> parent; ~Thing(); shared_ptr<Thing> GetParent(); }; The GetParent() function would look like this:
    shared_ptr<Thing> Thing::GetParent() { return parent.lock(); } You can modify existing functions that access a parent by adding one line of code.  Here is one such function as it would appear in Leadwerks 4, where the parent member is just a regular old stupid pointer:
    void Thing::AccessParent() { if (parent != NULL) { //do some stuff to parent here } } The updated version for Leadwerks 4 creates a new shared_ptr<Thing> variable (with auto) and locks the weak pointer to make a shared pointer.  The rest of the code works seamlessly:
    void Thing::AccessParent() { auto parent = this->parent.lock(); if (parent != NULL) { //do some stuff to parent here } } Class Functions Should Never Returns Themselves
    The following code illustrates a problematic issue:
    class Thing { public: shared_ptr<Thing> GetSelf() }; shared_ptr<Thing> Thing::GetSelf() { return shared_ptr<Thing>(this); } int main(int argc, const char *argv[]) { shared_ptr<Thing> p1 = make_shared<Thing>(); shared_ptr<Thing> p2 = p1->GetSelf(); } The GetSelf() function creates a new shared pointer that has no relation to the first one.  Both of these shared pointers will attempt to delete the object when they go out scope.  Only one will win.
    I did a search throughout the entire Leadwerks Engine project and found only three instances of the phrase "return this;".  The easiest way to fix this problem would be to eliminate this type of behavior altogether by having a parent get the object instead of the object returning itself.  For example if you have a recursive function that is structured like this:
    Thing* Thing::FindChild(const std::string& name) { if (name == this->name) return this; for (auto it = kids.begin(); it != kids.end(); it++) { auto child = (*it)->FindChild(name); if (child) return child; } return NULL; } You can restructure it like this:
    shared_ptr<Thing> Thing::FindChild(const std::string& name) { for (auto it = kids.begin(); it != kids.end(); it++) { if (name == (*it)->name) return this; auto child = (*it)->FindChild(name); if (child) return child; } return NULL; } I considered deriving all complex objects from a "SharedObject" class with a weak pointer that referenced itself:
    class SharedObject { weak_ptr<SharedObject> self; }; However, this requires the "self" member to be set when the object is created and is tedious to use.  I think it's easier to just eliminate functions that return the object itself.
  16. Josh
    Leadwerks Game Engine 5 moves Leadwerks forward into the future with massive performance increases and more advanced features, it also makes game development easier than ever before with three great new programming features.
    Shared Pointers
    I could write a whole article about the benefits of shared pointers.  Shared pointers are basically a simple form of garbage collection that relieves you from the need to manually delete objects, but doesn't suffer from the slow speed of full garbage collection.like C# uses.
    In Leadwerks 4 we need to keep track of object reference counts by using the Release command when we are done with them:
    Texture *texture = Texture::Load("Materials/Bricks/brick01.tex"); Material *material = Material::Create() material->SetTexture(texture); Model *model = Model::Box(); box->SetMaterial(material); material->Release(); if (texture) texture->Release(); In Leadwerks 5 we never have to worry about calling Release() or (less commonly used) AddRef() because reference counts of shared pointers are tracked automatically.  The code below would cause a memory leak in Leadwerks 4 but is perfectly fine to use in Leadwerks 5:
    auto material = Material::Create() material->SetTexture(Texture::Load("Materials/Bricks/brick01.tex")); auto model = Model::Box(); box->SetMaterial(material); This even works with entities.  As soon as a variable goes out of scope the object is deleted:
    if (true) { auto model = Model::Box(); }// automatic deletion occurs here
    We can prevent deletion of an object by either keeping the variable in our code, or keeping a container that holds it.  In the case of map loading, the Map:Load() will return a structure that contains all the entity handles so they stay in memory.  Want to delete a camera?  It's easy:
    camera = NULL;// poof! There are still some details to work out but so far this approach is working great.
    Another great benefit of shared pointers is that you can completely eliminate the need for big complicated destructors like this one.  All those objects will be automatically deleted when they go out of scope:
    OpenGLCamera::~OpenGLCamera() { for (int i=0; i<8; ++i) { if (shader_ambient[i]) { shader_ambient[i]->Release(); shader_ambient[i]=NULL; } for (int n = 0; n < 2; ++n) { for (int q = 0; q < 2; ++q) { for (int p = 0; p < 2; ++p) { if (shader_directional[i][n][q][p]) { shader_directional[i][n][q][p]->Release(); shader_directional[i][n][q][p] = NULL; } if (shader_directional_volume[i][n][q][p]) { shader_directional_volume[i][n][q][p]->Release(); shader_directional_volume[i][n][q][p] = NULL; } if (shader_point[i][n][q][p]) { shader_point[i][n][q][p]->Release(); shader_point[i][n][q][p] = NULL; } if (shader_point_volume[i][n][q][p]) { shader_point_volume[i][n][q][p]->Release(); shader_point_volume[i][n][q][p] = NULL; } if (shader_spot_volume[i][n][q][p]) { shader_spot_volume[i][n][q][p]->Release(); shader_spot_volume[i][n][q][p] = NULL; } if (shader_environment[i][n][q][p]) { shader_environment[i][n][q][p]->Release(); shader_environment[i][n][q][p] = NULL; } for (int usedecal = 0; usedecal < 2; usedecal++) { if (shader_spot[i][n][q][usedecal][p]) { shader_spot[i][n][q][usedecal][p]->Release(); shader_spot[i][n][q][usedecal][p] = NULL; } } } } } } } That entire function has been commented out in Leadwerks Game Engine 5.
    Finally, shared pointers eliminate a problem that is the bane of all programmers' existence.  When used correctly, you can you can say goodbye to invalid and uninitialized pointers forever!  Yet shared pointers, unlike garbage collection, are fast to use and don't slow your game down.
    Automatic Typing
    The use of C++11 in Leadwerks Game Engine 5 gives us automatic typing of variables with the auto keyword.  We can simply something like this:
    shared_ptr<Model> model = Model::Box(); To just this:
    auto model = Model::Box(); If you have long complicated type names this makes life a million times easier:
    for (std::list<shared_ptr<Entity> >::iterator it = list.begin(); it!= list.end(); it++) { shared_ptr<Entity> entity = *it; entity->SetPosition(1,2,3); } Here's the same code simplified with auto (and range-based loops thanks to @Roland and @thehankinator.  Look how much more readable it is:
    for (auto entity : list) { entity->SetPosition(1,2,3); } This isn't completely new, but Leadwerks 5 is the first version built exclusively for C++11 features.
    More Explicit API
    Leadwerks 4 uses several bound states to store a current world and context.  These are global variables that are mostly invisible to the user.  This causes problems with multithreaded programming because two threads might try to change or access the bound state at the same time.
    World *world1 = World::Create(); Model *model1 = Model::Box(); World *world2 = World::Create(); Model *model2 = Model::Box(); World::SetCurrent(world1); Model *model3 = Model::Box(); Quick, which world does "model3" belong to?  Leadwerks 5 gets rid of the concept of bound states and requires you to explicitly specify the object you want to use.  Here's how the above code would look in Leadwerks 5:
    auto world1 = World::Create(); auto model1 = Model::Box(world1); auto world2 = World::Create(); auto model2 = Model::Box(world2); auto model3 = Model::Box(world1); Not only is the second example easier to understand, it's also one line shorter.
    In a similar manner, the idea of a "current" context will be eliminated.  When you render a world you will need to explicitly specify which context to render to:
    world->Render(context) These programming features will make it easier than ever to code games with Leadwerks.
  17. Josh
    I've got a couple days sales data from the 3.4 launch and it went well. Our conversion ratio and all that boring businessey stuff is good, and I know more now than I did last week. I think our intro video could use some updating and a little more professional polish, so I am looking for a video production company to create something new.
     
    I was planning to make a trip back to Caifornia soon. I was going to skip the GDC, but I then got invited to the Valve party. I guess they're hiring the band Glitch Mob to play at Folsom Nightclub, which is kind of awesome.


     
    This isn't enough to make me want to go, but I remember my Valve VR demo came about because I was randomly talking to someone at Steam Dev Days and they emailed me about it later. So even if you don't get something out of it every time, I think it's necessary that I do these kind of networking things. Not sure if I'll attend the GDC expo itself or not yet, I need to figure out my plans today.
     
    When I get back, work will begin on version 3.5, due out this summer. I want this update to include carving, vegetation, vertex editing, and I have a few other features in mind that will be included based on how much time I have.
     
    There's also a class of improvements I want to make that are more "systemic". This includes driver bugs from third-party vendors (looking at you AMD), bugs or bad design in third-party libraries (GTK), and some improvements I can make in our core renderer design. Uniform buffers and FBOs are two low-level systems I am looking at. I think this will solve the Linux model editor issue and improve performance quite a lot on Linux systems in particular, and have some gains on Windows.
     
    These are potentially destabilizing changes I do not want to attempt this week. I need to be able to do a quick turnaround if any small bugs are discovered right now, and having the renderer all taken apart isn't a good idea at the moment.
     
    Finally, we have a problem with tutorials that needs to be addressed. I keep seeing post after post of people asking where the tutorials are. When you see threads like this, it indicates a problem. I have tried to make the documentation and tutorials pages as "in your face" as possible, yet people still ask where they are...it's the very first thing you see when you run the program! This is probably the most important problem to solve going forward, and has a much stronger effect on us than any feature I can implement or improvement I can make to the software itself.
  18. Josh
    An update is available which is a release candidate for version 3.5. Version 3.5 adds carve and hollow CSG operations, an improved project template system, and customizable filters for scene objects. In this update I reverted the group selection behavior to the same way it works in 3.4, and decided to hold off on adding an extra grouping feature. I expect a lot of new users soon, so stability is my most important goal.
     
    The summer games tournament is coming soon! We had a really great turnout in the Halloween and Winter Games Tournament, and I am expecting a bigger result this time. There is some special surprises that make this a much bigger event, but you'll find that out soon enough.
     
    Jorn and I are working together on a new set of comprehensive tutorials that cover ever aspect of Leadwerks. The Word document containing all the info is about 50 pages right now, so it's pretty comprehensive! The idea is to have one linear list of lessons, so we can eliminate all the nested information tucked away in confusing places. This will be rolled out alongside version 3.5.
     
    The pace of new feature development has been pretty conservative lately, but there's a lot going on behind the scenes. We are working with third-party artists to prepare their content for distribution in our system. If you've been following the Skyrim news, it remains to be seen how the Steam Workshop will develop. Nothing else to say yet, but I think we will go forward with this one way or another.
     
    Leadwerks Game Launcher is also in development. I expect a long beta testing period with a very large user base. Publishing your game for Leadwerks Game Launcher is a way to instantly put it in front of a lot of people, definitely a lot more players than you would get if you uploaded it online somewhere. This is important because I don't think making games is our primary challenge anymore. Leadwerks is really good at making that process simple, and the participation we see in the game tournaments confirms this. Our primary challenge is what to do with simple fun playable games once they are made. Five years ago, the answer would have been to sell them in the iOS App Store, but that's no longer a viable option. So what to do? That's what I want to solve.
     
    A while back, the Steamworks UGC class was replaced with a newer iUGC class. This has unlimited file sizes, no upload quotas, and is more likely to be better supported than the older API. We are still using the original UGC class, but I think we need to upgrade this internally to the newer API. I suspect this will fix a number of small issues, and I don't think we can really expect Valve to keep working on the deprecated functionality, so filing bug reports there is probably not very effective. In fact, a revision of our Workshop integration is probably in order as we gear up for upcoming plans.
  19. Josh
    I rolled Newton Dynamics back to the version we were previously using due to some strange behavior. We're not utilizing any new behavior yet, and I don't want to spend time debugging it right now, so from your perspective it makes no difference.
     
    Also added a check to prevent textures from reloading when they are bound to a buffer.
     
    This update is available now on the beta branch and will be released next week on the default branch. Rich is also working on a couple of decal textures to include with the engine.
  20. Josh
    The 3.6 Release Candidate is now available on the beta branch. Since the last update, this adds camera render targets. You can set a texture to a camera's render target in the editor camera properties, and with the new command Camera::SetRenderTarget(Texture* texture). Render targets work both in the editor and in-game.
     
    A terrain offset map has been implemented in the physics system, but it is not yet integrated into the engine.
     

  21. Josh
    I'm writing this as we're a few dollars away from the mythic 30% target that has been claimed to be a "tipping point" past which Kickstarter campaigns reach critical mass. I'm not going to go into any detail about that because I don't want to jinx it, but so far I am blown away by the response. We put this up Sunday in advance of contacting bloggers, so nobody really knew about it the first day. It's Tuesday morning and we're presently at 29%.
     
    I've heard a number of people point out that putting Leadwerks on Linux would be the last tool they need to ditch Windows completely and move over to Linux. I myself am sort of platform-agnostic, and don't really get into the politics of different operating systems. However, the response we're getting with this campaign is making me realize something new.
     
    It's arguable that Microsoft has been a poor custodian of PC gaming. They haven't done much to support OpenGL, instead trying to push everyone into their own proprietary graphics API, DirectX. The problem with DirectX is it only runs on Windows and XBox, and it completely changes every few years, so developers have to rewrite all their rendering code. OpenGL has all the same functionality, it's stable, and it runs on everything (except XBox and Surface).
     
    The second problem with PC gaming on Windows is that Microsoft has a fundamental conflict of interest because they own a closed gaming platform, the XBox. Closed platforms are bad for developers because it can be expensive to push out game patches. The creator of Fez famously declared they would not be patching a known bug, because it would have cost an amount rumored to be around $40,000. It's bad for consumers because they don't get access to the same range of indie titles an open platform like Linux or the upcoming SteamBox can get. In addition, recent restrictions for the new XBox One have been announced that threaten the ability to lend games and may make the system "un-future-proof" (is there a real word for that?).
     
    Given these problems, it seems logical to us that PC gaming on Linux would grow quickly. Linux has faster OpenGL performance than Windows or Mac, and there's none of the "dueling APIs" issues and conflicts of interest Windows has. Thanks in part to Valve, the graphics drivers are now really solid. We have an optional distribution system through Steam. It's really got everything we need. So I am very optimistic about the future of PC gaming on Linux, and am really happy to be a part of this movement.
     
    The next step is for us to keep spreading the word and reaching out to publications so that we can make sure the target goal is met. Your help is appreciated. You guys are making quite a buzz on Twitter, Google+, and Facebook!
     
    To all our backers, thank you so much for sharing our vision for Linux gaming. I'm really excited to be working on this and glad I can deliver something the PC gaming community really needs right now.
  22. Josh
    Putting all the pieces together, I was able to create a GUI with a sprite layer, attach it to a camera with a texture buffer render target, and render the GUI onto a texture applied to a 3D surface. Then I used the picked UV coords to convert to mouse coordinates and send user events to the GUI. Here is the result:

    This can be used for GUIs rendered onto surfaces in your game, or for a user interface that can be interacted with in VR. This example will be included in the next beta update.
  23. Josh
    I have successfully transferred lit voxel data into a 3D texture. The texture is now being used to display the lighting at each voxel. Soft edges are appearing due to linear filtering in the texture. To achieve this, I used an OpenGL 4.2 feature which allows you to write values into any arbitrary position in a texture. This could also be used for motion blur or fluid simulations in the future. However, since Mac support for OpenGL only goes up to 4.1, it means we cannot use real-time GI on a Mac, unless a separate workaround is written to handle this, or unless a renderer is written using Vulkan / Metal. At the time I am going to stick with OpenGL, because it would be too hard to implement an experimental new architecture with an API I don't know much about.


    Now that we have our lit voxel 3D texture it should be possible to generate mipmaps and begin cone tracing to simulate global illumination.
  24. Josh
    An early build of Leadwerks Game Engine 4.2 beta is available on the beta branch on Steam. This release will update the engine with the latest C++ tools and add new graphics and other features.
    Visual Studio 2017 support
    Compatible with the latest C++11 / GCC on Linux
    Refraction: apply "Materials\Effects\glass.mat" onto any object to see this in action.
    Heat haze: drag the heat haze emitter prefab into the scene to view ("Prefabs\Effects\heathaze.pfb").
    Spotlight texture: you can add a material to a spotlight and the first texture will be rendered onto the light (for flashlights).
    New animation commands
    Analytics (not working yet)

     
    It's funny that transparency with refraction used to be explained in a
    12 minute tutorial (in Leadwerks Game Engine 2), and now it is a simple effect you can drag into the scene. 

     

     


×
×
  • Create New...