Jump to content

Josh

Staff
  • Posts

    23,222
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh

    Articles
    You probably have noticed that our entire community has been migrated from the leadwerks.com domain to our new ultraengine.com domain. In this article I am going to describe recent changes to our website, the process by which these decisions were made, and the expected outcomes. These are not just superficial changes, but rather it is a fundamental restructuring of the way our business works. This is the execution of a plan I have had for several years.
    When we first starting selling on Steam and I saw the revenue it was bringing in, my reaction was to focus entirely on Steam and try to align everything we did to that. The idea was that if I could bring that advantage to you, we would all benefit from the massive gaming traffic that goes through Steam. I replaced many of our community features with Steam-centric equivalents. Our website gallery, videos, and downloads were replaced by the Steam equivalent. To view this content on our website I used the Steam web API to hook into our application ID and retrieve content.
    The screenshots and videos were a success. Leadwerks Editor allows publishing a screenshot directly to Steam, and we have gained a very big collection of screenshots and videos on Steam. However, there are two problems that have caused me rethink this approach:
    First, when it came to monetization, Steam seems to be a one-trick pony. Try as I could, Steam users just don't buy things through Steam Workshop. Our own sales in the web-based Marketplace are outperforming Steam.

    Second, Steam has flooded their marketplace with new titles. This incentivizes competition for digital shelf space. Instead of investing in Steam features for one application ID, it makes more sense to release multiple products on Steam and not tie yourself to one Steam application ID. Valve's position seems to be that you are responsible for driving traffic to your game, but if that is the case why are they still charging 30%? Our situation on Steam is still good, but I am not throwing everything 100% into Steam in the future and I prefer to drive traffic to our store on our own website.

    Based on what I have seen, it makes sense to move our center of activity back to our own website. Recent technological advances have made this easier. Cheap file storage backend systems have eliminated the expenses and technical problems of storing large amounts of user data. RSS feed importers have allowed us to hook into the Steam web API to feed all our Steam screenshots and videos into our own system.
    Videos
    We have a new video section on our site. You can paste a YouTube link through our web interface or upload a video file directly. Any videos you publish on Steam will be automatically fed in as well. You will notice in the tutorials section I am now hosting tutorial videos on our own site. They are also uploaded on YouTube, but I am not relying on YouTube anymore for video hosting.

    In the future I plan to support user-created paid video tutorials, with the same rules as paid items in the Marketplace.
    Gallery
    A new screenshot gallery is up, with images hosted on our own site again. I hope to find a way to migrate all our content on Steam into this system, like we did with videos. I also want to bulk upload all our old screenshots from before Steam.
    The Steam-based gallery and videos can still be viewed on the leadwerks.com website, as well as the Leadwerks documentation.
    Marketplace Games
    The Marketplace we have now is a 2.0 version of our original system before Steam, with a new Games category. Back in the days before Steam it always amazed me that Furious Frank had over 20,000 downloads. This was from the days before itch.io and gamejolt, and there was a big appetite for indie games. The Games database of our website never reached that level, and I think the reason was that we should have focused on the content. If people want to watch videos they will go to the videos section. If people want to download free games they will go to the Games category in the Marketplace. Having a customized page on our website with a lot of information and links all in one place is about as pointless as having a Facebook fan page. There's no reason for it, all it does is slow down the delivery of the actual content. It looks kind of cool, but I think the viewer just wants to get to the content (download the game, watch videos, view screenshots) instead of wading through a lot of custom CSS pages. If you want to drive traffic to your website or to your Steam page, post a video and put links in the description where you want the viewer to go next.
    In addition to uploading free games, you can now sell your games in the Marketplace. I have plans to attract a lot of new traffic to the site in 2021, so maybe your games can get more sales at the same time. The same 70/30 split we use for Marketplace assets applies to games.
    Furious Frank is starting over from zero and I realize he would have been enjoyed by over 100,000 players had I not pushed our traffic towards Steam so hard.
    Email Marketing (and leaving social media behind)
    At a startup event I attended years ago, one of the speakers told me that email was actually their best marketing tool. I was kind of surprised because to me it seemed archaic, but that conversation stuck in my mind. According to conventional wisdom, if you want to get the word out about your product you should crete an Instagram account, upload your images, and then when you invariably get no traffic you should blame yourself because your content sucks. Who is pushing this "conventional wisdom"? It is being pushed by giant tech companies that seek to absorb and monetize all your content, and a network of parasitical "gurus" who want to sell you useless advice and then blame you when it fails. This is not the way online customer acquisition actually works.
    I started looking at traffic on our social media accounts and comparing it to email and web traffic, and the results are shocking. Our email newsletters regularly result in 30x more clicks than anything I write on social media. Not only are they failing to bring in an acceptable level of traffic, Twitter and even Steam are actively preventing us from reaching our customers by censoring our content.
    Email is the only direct line of communication you have with your own customers. All third-party middlemen have the potential to abuse their position. They will flood their marketplace with products, change their algorithms, arbitrarily censor or shadowban content. The only thing that will provide a counterweight to that abuse is a good BATNA. If you don't have that you can expect to be treated badly. (It's really a miracle that email was invented early enough to become a common open standard. This would never happen today. "Blue Sky" is probably a sabotage effort.)
    In that light, the advice I got makes a lot of sense. Once I realized this I stopped posting on Facebook and Twitter and just left a pinned message directing people to the mailing list:

    Our new website also features a mailing list sign-up form featured prominently in the website footer.

    Instead of wasting time shouting into the wind on (anti)social media I am going to instead focus on writing quality articles that will be posted on our site and sent out to the email list.
    Store
    Valve has made it clear that game developers should not rely on Steam alone to drive traffic to their game. Okay, well if I am responsible for bringing in traffic, I am going to direct it to my own store, not to Steam.
    The MBA in me realizes two things:
    Getting a user's email address is good and has a quantifiable value. Getting a user's credit card system stored in our system is even better. (It doesn't actually store credit cards on our server, it stores a token that can only be used with our domain.) These two steps are serious hurdles to overcome for any web store. Now that I am selling Ultra App Kit directly on our own site, I have seen an increase in sales of items in our Marketplace. This is not a coincidence. People buy one thing and then it becomes a habit. A subscription option will be available for future software products. All new software I release is going to require an initial sign-in to your forum account. We have tens of thousands of users on Steam that I have no email addresses for or ability to contact, and that is not going to work going forward. (I will make sure an override is built into the software that can be activated by a dead man switch.)

    This system gives me the ability to offer software products under a subscription model for the first time ever. This is preferable from my point of view, but I understand it's not for everyone and a conventional software license will also be available.
    We also have an automated system to send out Steam keys, so I am now able to sell Steam keys directly in our store. When you order you will receive an email with a link to retrieve your key. Once you enter the key in Steam it is added to your Steam account just as if you bought it on Steam.
    To make payments easier we are now accepting PayPal and cryptocurrency payments, in addition to credit cards.
    (Valve clearly recognizes a problem with visibility on Steam and is desperately trying to convince you to stay engaged in their system so they can take their 30%. I don't mean to say they are bad guys, I am just saying in any partnership both parties will have some divergent interests and must stick up for themselves. The day that mine is the only company selling products on Steam is when I will consider going Steam-exclusive again. What indie developers should be doing right now is selling their own games on their own websites, in addition to third-party stores like Steam.)
    Rolling Out Ultra Engine (Leadwerks 5)
    Breaking off the GUI features of the new engine and releasing it early as the standalone product Ultra App Kit was a great idea because it allows me to implement all these things early, test them out, and ensures a smoother release of the finished 3D engine later this year. The basic theme we see here is that these social and gaming platforms are no longer doing their job effectively and we must build something of our own. Withdrawing our content from them and building up our own website only makes sense if there is a way to drive more traffic here. If Steam is flooded and social media is saturated, how can we attract traffic? Email is good for engaging customers you have already made contact with, but how do you attract new people in large numbers? I have an answer to that, but it really deserves a whole article itself.
    Conclusion
    Here is where we were before:
    Domain name no one could pronounce or spell. It was literally impossible to tell someone to go to our website without explaining the spelling. User content hosted on Steam and YouTube Almost all sales through Steam Ineffective outreach through social media Single product for sale with perpetual free upgrades No ability to collect customer information Here is where we are now:
    Domain name that can easily spread by word of mouth Most user content hosted on our own website Direct sales through our own website and many third-party stores Effective outreach through email (and other means I will talk about later) Ability to sell annual paid updates or subscription model Growing customer database of people I can directly contact I hope I have shown how all these changes were not just random decisions I made, but are part of a "holistic" strategy, for lack of a better word.
  2. 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!
  3. Josh
    I skipped the GDC for a couple of years, because I just wanted to focus on developing our technology. This was my first year back since our engine came to be. I was surprised how many people were familiar with our engine, and I got to talk to a few users (who probably aren't active on the forum). I also got to chat briefly with Tom Spilman, David Helgason, and Mike Wuetherick. It's really fun to see what everyone is up to, and how far they have come since a few years ago.
     
    We met new friends including the FaceWare team, the PureLight guys, and the GameDev.net team (they are launching a new site soon, so stay tuned!). I got to talk at length to some nVidia employees, and we had a very interesting discussion about the future of mobile graphics...very interesting.
     
    Oh, did I mention OpenGL 4.0 was announced while we were there? I am very excited about this new technology, and really happy with how Khronos has come through for us.
     
    We also got to talk to a few potential investors. There is a well defined plan for the future of Leadwerks technology, but I can't make that information public quite yet.
     
    If you've never been to the GDC, I highly recommend you attend this event at least once. We've uploaded a ton of videos on our YouTube channel to give you a taste of what it's like. I'm looking forward to GDC 2011, especially if we have a booth of our own. If you're looking for publicity for your game, we will be looking for projects to show the potential of the engine, and there's a good chance we can get your game seen.
  4. Josh
    I signed up for a free year of OnLive. I received a response email within 24 hours, so I think they just are choosing applicants based on connection speed and location. I've been extremely skeptical of this service, but I can report that it works, and it doesn't suck. I can play UT3 on my netbook. There is some slight lag, but it's not bad. Fast mouse looking can amplify it, so I slowed down my mouse speed to compensate. I had no trouble getting headshots with the sniper rifle, and the gameplay experience was very good. As far as technical performance, OnLive has delivered.
     
    As for the product itself, I don't see any reason to jump onboard yet. Wi-fi connections aren't allowed, so the fun of using my netbook anywhere in the house is mitigated. Without that, there's no reason not to use my desktop PC. The lineup of games is very limited. No Crysis, and it looks like the servers have the games running on low to medium settings. This puzzles me, because the quality settings the servers run with should be trivial. That's the whole point of OnLive. With the games and settings they are offering right now, you could get the same results with a five year old PC.
     
    The pricing model is where OnLive fails. After the first year, you pay $4.95 a month for the service. On top of that, you have to "buy" each game you play, but you don't really own it, and the game may be taken down after 2013. With a revolutionary new delivery system like this, the choice to use an outdated purchasing model is baffling. What if you had to pay a monthly cable TV bill, and then "buy" each show you wanted to enable? It doesn't make sense. OnLive should charge a higher monthly fee, around $29.99-49.99 for access to all games on their servers. OnLive would take their cut of the sale, and the rest would be divided up among the game providers based on the percentage time players spent in their game. This would encourage developers to make games with long-term replay value. It would create a continuous revenue stream for developers, instead of just making money off one-time purchases. It would lessen the complaints people have when an old game if retired off OnLive's servers. And finally, it would deliver a lot of value to the customer. Which would you rather pay for, a $200 XBox plus $60 for a game, or pay $40 this month and play every game? The choice for a lot of people would be obvious. Hopefully OnLive will come to see this. I am surprised it isn't already obvious to them.
     
    As of right now, I don't know who would use this service. Who is the target market? People who can't afford a decent PC, but still have $50 to spend on a game they don't own? Maybe some Mac owners will pay for it. I think they should be targeting console players who want the ultimate graphics, but the OnLive console isn't available yet.
     
    Still, OnLive has delivered from a technical standpoint, and they may become something amazing and unique. I look forward to seeing what it might grow into.
  5. Josh
    I can now load models in Leadwerks Engine 3 (as of this morning):

    Edit - Here's a demonstration of buffers working (as of this afternoon):

    Edit - And here's a comparison of a multisampled buffer next to a regular one (as of this evening):

    It's nice to see a feature in Leadwerks 3.0 that 2.0 doesn't have.
     
    I'm getting my iMac this week. I'm going for the dual core 3.2 ghz with an upgrade to an ATI Radeon 5750. Mac is still using OpenGL 2.1, and I have no idea how good the drivers are, but at least I know it will be stable. I am working with the OpenGL 3.3 renderer right now, which requires a Shader Model 4 card. OpenGL 4.0 is just like 3.3, with a few added features, and it will need a separate renderer. So right now we are looking at:
    -OpenGL 4.0
    -OpenGL 3.3
    -OpenGL 2.1 (for Mac)
     
    Those versions are just variations of one another, and I know OpenGL pretty well, so it's mostly just a matter of copying and pasting code. Since I have to deal with three versions of OpenGL anyways, it's not a big deal to add an OpenGL 1 renderer using the fixed function pipeline. Then of course we have OpenGL ES for the mobile platforms, but I won't be dealing with that myself. A DirectX renderer will only be needed for XBox 360, when the time comes.
     
    That's all for now. The material / shader / model systems are pretty crucial to LE3, especially how they are designed to be reloadable, so I have plenty of work to do! The most critical features in LE3 are the asset handling and the interaction system. In LE2 we created a system whereby programmers could share programmed game objects with Lua script, but we found that without an official visual interaction system, there were limits to how interesting your game components could get. With LE3, a totally new visual system will provide a framework with which your game components can interact, so everyone can create complex game interactions. In plain terms, that means I can easily drop a character into the scene, and set it up so when they die, a door opens, or something like that...with no programming.
     
    By the way, I recommend catching "The Social Network" in theaters. Some of the dialog is cheesy, but it's an interesting look into tech startups (and an unflattering portait of Mark Zuckerberg). The most interesting parts to me were the scenes in Palo Alto, which were a lot more familiar to me than the Boston setting. Plus, the soundtrack is by Trent Reznor:
     

    http://www.youtube.com/watch?v=qy8qDXQQZ3U
  6. Josh
    Leadwerks Engine 2.43
    ...will be released tomorrow, along with a new source distro. I've fixed a number of bugs, but I don't like compiling releases when I am tired because there's a lot of little steps to mess up, so I will do it in the morning.
     
    Leadwerks Engine 3
    Optics was always my favorite subject in physics, and I've been getting some amazing results lately by modeling computer graphics after real lighting phenomena.
     
    Once I decided to make the materials system like 3ds max, everything became easy. The engine chooses an "ubershader" variation based on what texture slots a material has a texture assigned to. Creating a normal mapped material is as easy as creating a material and adding two textures. The engine will assume texture slot 0 is the diffuse map and slot 1 is the normal map, and will load a shader based on that. Predefined slots include diffuse, normal, specular, displacement, reflection, emission, refraction, and opacity maps. Of course, you can still explicitly assign a shader if you need something special. The material below was created just by dragging some textures into different slots and adjusting their strength:

     
    Cubemaps are built into the model ubershader, and there's support for reflection, refraction, or both using a fresnel term to combine them. Chromatic aberrtion is also supported, which splits refracted light into its RGB components:

     
    While I was getting into all these advanced optics, I decided to take a stab at color grading, and the results are great. You create a 3D texture (it's easier than it sounds) which gets used as a color lookup table in the post-processing filter. To make a new color table you can just run the source 2D image through a photoshop filter and save it. Color grading gives a scene an overall feel and makes colors look consistent. It's a technique that's used extensively in film, starting with 2000's Oh Brother Where Art Thou:

     
    Here's anpther example:

     
    And here's a simple shot in the engine. The original:

     
    And graded with a "cool" color table:

     
    It's more advanced than just tinting the screen a certain color, because this effect will actually emphasize a range of colors.
     
    Preparing the Asset Store
    Now that Leadwerks.com is hosted on our own dedicated server, I was able to create a more secure folder to store asset store files in that can only be accessed by the forum system. Previously, we had dynamic download URLs working, but the same file could still be downloaded from any browser within a few minutes before the dynamic URL changed. This will give better security for asset store merchants. According to my big flowchart, the only things left to do are to fix the side-scrolling main page and set up a merchant account with our bank, and then we'll be ready to launch.
     
    Great movie and soundtrack, by the way:


  7. Josh
    Lately I've been talking a lot about making non-programmers happy, so here's something for the coders. B)
     
    For Leadwerks3D documentation, I considered three possibilities:
    -IPB-based docs
    -Wiki
    -Offline CHM files
     
    Each has their own strengths and weaknesses, as always seems to be the case.
     
    IPB
    A bit slower, harder to organize, harder to edit, looks really good and consistent with the site, search requires quite a few clicks to get where you want to go, missing table of contents is a bummer for long pages.
     
    Wiki
    A target for spam, doesn't match the main website, user-written docs cause fragmention and a mix of official and unnofficlal information, nice table of contents, good searchability.
     
    Offline CHM
    Fast, doesn't require internet connection, easy to edit, Windows-only.
     
    I dismissed offline docs simply because we wouldn't be able to post a link to refer people to a certain page. I decided on a wiki because of the better search functionality, table of contents, and ease of editing.
     
    Here's what I have in mind for the docs. Because Leadwerks3D is written in C++, we're able to document members, constructors, operators, and other stuff we haven't had access to in the past. Best of all, almost everything works exactly the same in Lua, including function and operator overloading.
    http://www.leadwerks.com/newwiki/index.php?title=Vec3
     
    I'm also a big fan of the ease with which we can add internal links. For example, the Vec3 members in the AABB class documentation link straight to the Vec3 class page:
    http://www.leadwerks.com/newwiki/index.php?title=AABB#Members
     
    To avoid spam, and to make sure I can answer any questions about the contents of the wiki, it's going to be read-only. Community tutorials have been very useful in the past, and we're going to continue that going forward, either through a subforum or database for Leadwerks3D tutorials.
     
    I think having one page per command and an example for every single command has been more redundant and time-consuming that we have needed. I want to list the syntax for each command only once, like this:
    http://www.leadwerks.com/newwiki/index.php?title=Entity#SetPosition
     
    Instead of making a lot of redundant examples (Do we really need a page of code for Entity::SetPosition() AND Entity::SetRotation()?) I hope to provide more comprehensive examples showing how to actually do something, and how the functions can be used together to do interesting things.
     
    In general, I want to go into much more depth with the Leadwerks3D documentation, on all aspects of using the program, because I plan for this iteration of our technology to have a pretty long life. If you have any suggestions, just let me know.
  8. Josh
    I've got orthographic viewport navigation done. I decided to build some grid commands into the camera class so that the graphics driver itself can handle the grid rendering, rather than having the editor make a bunch of OpenGL calls in a callback function. The grid can be rendered from any angle, and the math was a little tricky, but I got it worked out. I paid extra attention to showing the border where the world ends. The sliders that pan the viewport are very accurate, and stop right at the end of the world space. By default, this is one kilometer, but the world size can be changed at any time.
     
    One thing that was tricky was that the grid can be any resolution, and the world can be any size, so there's no guarantee the edge of a grid patch will match the edge of the world. I ended up using clipping planes to solve this problem.
     

     


  9. Josh
    Ultra Engine makes much better use of class encapsulation with strict public / private / protected members. This makes it so you can only access parts of the API you are meant to use, and prevents confusion about what is and isn't supported. I've also moved all internal engine commands into separate namespaces so you don't have to worry about what a RenderMesh or PhysicsNode does. These classes won't appear in the intellisense suggestions unless you were to add "using namespace UltraRender" to your code, which you should never do.
    There's still a lot of extra stuff intellisense shows you from Windows headers and other things:

    Using the __INTELLISENSE__ macro in Visual Studio, I was able to trick the intellisense compiler into skipping include files that link to third party libraries and system headers the user doesn't need to worry about. This strips all the unnecessary stuff out of the API, leaving just basic C++ commands, some STL classes, and the Ultra Engine API. With all the garbage removed, the API seems much friendlier:

    This is one more detail that I feel helps make C++ with Ultra Engine about as easy as C# programming. You can disable this feature by adding _ULTRA_SIMPLE_API=0 in your project macros.
  10. Josh
    Step 1. Add your image files into the project directory. I just added a bunch of TGA files, and they show up in the editor right away:

     
    Step 2. Right-click on a texture and select the "Generate Material" menu item.

     
    Step 3. There is no step 3. Your material is ready to use. The normal map was automatically detected and added to the material.

     
    Here it is in the material editor.

  11. Josh
    I borrowed Shadmar's terrain splatting shader. This is the result after fiddling around with it for a few minutes in Leadwerks 3. (No normal mapping yet, but that's easy to add.)
     
    Physics can be added by generating a physics shape from the terrain model. It doesn't allow heightmap editing in the editor, but I think this will serve as a good solution until our super uber mega streaming terrain system is built.
     
    Thanks to Shadmar for the assets.
     
    Klepto is also looking into a few OpenGL ES emulators to see if there is a way to test mobile shaders on a PC.
  12. Josh
    A new update to Leadwerks 3.0 is now available. Registered developers can run the Leadwerks updater to download and install the patch. This update adds terrain, bug fixes, and a few small feature enhancements.
    Our new terrain system, described in our Kickstarter campaign to bring Leadwerks to the Linux operating system, is based on a unique "dynamic megatextures" approach. This technique renders sections of the terrain into virtual textures and places them around the camera. The terrain presently allows a maximum size of 1024 meters and 16 texture layers, but these constraints can be lifted in the future once it's been thoroughly tested. You can see an example terrain the the "terrain.map" scene included in the example project folder.

    With the increased scene geometry terrain brings, I found it necessary to precalculate navmeshes in the editor. To calculate a navmesh for a map, select the Tools > Build NavMesh menu item to being up the Build NavMesh Dialog. The navigation data will be saved directly into your map file for pathfinding. Two values have been exposed to control the navmesh calculation and the appearance of the navmesh has been improved to allow easier visual debugging. Additionally, the new World::BuildNavMesh command lets you calculate navigation meshes in code.
    The bug report forum contains info about recently fixed problems. The most notable fix was for character controller physics. Some frame syncing issues were fixed which were causing entities to sometimes pass through walls and floors. This problem was very apparent in the recent game demo GreenFlask,
    A new command World::SetPhysicsDetail allows you to balance the speed and accuracy of the physics simulator.
    The Transform::Plane command has been enhanced to work with Lua, which had trouble understanding the syntax of the command.
  13. Josh
    A new map called "09-Change Map.map" has been added to the example game. This demonstrates how to use the new TriggerChangeMap.lua script to make your player progress from one level to the next.
     
    In order to use this script, you must update your project with the new executables. Select the File > Project Manager menu to open the Project Manager, then press the "Update" button to update your project.
     
    A new chunk of code has been added to App.lua to handle map changes. This code will be found in the main loop of the new App.lua script:

    --Handle map change if changemapname~=nil then
     
    --Clear all entities
    self.world:Clear()
     
    --Load the next map
    Time:Pause()
    if Map:Load("Maps/"..changemapname..".map")==false then return false end
    collectgarbage()
    Time:Resume()
     
    changemapname = nil
    end
     
    Using the TriggerChangeMap script is easy. Just attach it to a CSG brush and set the name of the next map you want to load, without the path or file extension. For example, to load the map "Maps/09-Change Map.map" you just type in "09-Change Map" in the "Map Name" field. When the player collides with the brush, the new map will be loaded. You can make the brush a panel on the floor, or an invisible trigger field.
     
    You must opt into the beta branch on Steam to get these changes.
  14. Josh
    Looking back at a recent blog, I talked briefly about my plans for 2016: My goals were the following:
    Paid Workshop items
    Release Game Launcher on Steam proper.
    More features.

     
    These goals are actually linked together. Let's focus on the amount and quality of games being released for the game launcher. Right now, we have a lot of variety of simple games, and some that are very fun, but we don't have any must-play hits yet. As long as the reviews look like this, the game launcher isn't ready to release.
     
    What can we do to facilitate better and more complex games? From what I have seen, reusable scripts have given Leadwerks users a huge boost in productivity, especially when combined with a 3D model. For example, the zombie DLC, FPS weapons, first-person player, and other reusable items have gotten a ton of use and allowed creation of many different games. Continuing to build a deeper more robust script environment will allow developers to easily set up more advanced gameplay. The SoldierAI and the way it breaks down the bullets into a separate script are a good example of this direction. For example, the same projectile script can be used for a turret. Our design of self-contained Lua scripts with inputs and outputs will prevent the system from getting overly complicated, as a complex C++ hierarchy of classes would.
     
    In the future, I think releasing more game-ready items in the Workshop, first with official Leadwerks scripts, and then with third-party scripts, will allow us to leverage the design of Leadwerks Game Engine and the tools like the flowgraph.
     
    Features I implement next are going to be specifically chosen because of their capacity for increasing the gameplay potential of Leadwerks games. Easy networking and a GUI come to mind.
     
    When I feel like we are really hitting our stride in terms of the games you can make with Leadwerks, that is when game launcher will be released. Leadwerks Game Engine is all about what the user can make.
  15. Josh
    I've taken your suggestions and incorporated the fixes into the new documentation system here:
    https://www.leadwerks.com/learn
     
    All classes and commands are alphabetized, with classes listed first.
     
    All pages in the API Reference should be working now.
     
    If a page does not appear in the old docs, or if a command does not have an example, it will not appear in the new docs, as I am not changing the content right now.
     
    Please let me know if the table of contents of pages have any errors.
  16. Josh
    Leadwerks Game Engine 4.4 features an upgrade to the latest version of Newton Dynamics, along with a bunch of new features to enhance physics.
    Kinematic Controller
    The new kinematic controller is a joint that lets you specify a position, rotation (Euler or quaternion), or a 4x4 matrix to orient the body to.  You can set the maximum linear and angular force the joint may use to orient the entity.  This allows you to create a kinematic controller that only affects position, only affects rotation, or one that controls both at once.  In the video below I am using a kinematic controller to create a simple IK system with two hinge joints.  The end effector is controlled by the mouse position, while the base entity stays in place, since it has zero (infinite) mass:
    The kinematic controller provides much more stable collisions than the Entity PhysicsSetPosition() and PhysicsSetRotation() commands, and should be used in place of these.  In fact, these commands will be removed from the documentation and should not be used anymore, although they will be left in the engine to ensure your code continues to work.  The FPS player script will be updated to use a kinematic control for objects you are holding, which will eliminate the energetic collisions the script currently produces if you pick up a crate and push it into the wall.
    The new joint commands are as follows:
    static Joint* Kinematic(Entity* entity, const Vec3& position); virtual void SetTargetMatrix(const Mat4& mat); virtual void SetTargetPosition(const float x, const float y, const float z, const float blend = 0.5); virtual void SetTargetPosition(const Vec3& pos, const float blend = 0.5); virtual void SetTargetRotation(const float pitch, const float yaw, const float roll, const float blend = 0.5); virtual void SetTargetRotation(const Vec3& rotation, const float blend = 0.5); virtual void SetTargetRotation(const Quat& rotation, const float blend = 0.5); For improved constistency in the API, the joint SetAngle function will be renamed SetTargetAngle, but a copy of the old command will remain in the engine:
    virtual void SetTargetAngle(const float angle); Joint Friction
    Hinge joints can now accept a friction value to make them more resistant to swinging around.  I used this in the example below to make the joints less "loose", while a kinematic controller positions the green box:
    New Vehicle Model
    Newton 3.14 features a new vehicle model with a realistic simulation of a slip differential.  Power is adjusted to each wheel according to the resistance on each tire.

    Watch closely as the wheels below act just like a real car does when its tires slip:
    The realistic vehicle models gives vehicles a much more visceral and fun feeling.  The new vehicle also uses actual bodies for the tires, instead of convex raycasts, so the sudden bouncing the old vehicles could exhibit if the chassis didn't encompass the tires is eliminated.
    Springs
    Slider and hinge joints now have optional spring behavior you can enable with one command.  Use this to make our own custom suspension system, or anything else you need.
    void SetSpring(const float spring) These changes will be available next week on the beta branch on Steam.
  17. Josh
    An update is available on the beta branch on Steam that adds support for multiplayer games with the following features:
    NAT punch-through with relay server fallback. Connectionless peer-to-peer UDP messages with multiple channels and optional reliable flag. Public server list of available games to play. Voice-over-IP for in-game chat (and taunts). The new multiplayer system will open up a new range of game types that can be easily created with Leadwerks Game Engine.
    These features are still being tested and are only available in the Windows build right now.
  18. Josh
    I got the remaining glitches worked out, and the deal is that clustered forward rendering works great. It has more flexibility than deferred rendering and it performs a lot faster. This means we can use a better materials and lighting system, and at the same time have faster performance, which is great for VR especially. The video below shows a scene with 50 lights working with fast forward rendering
    One of the last things I added was switching from a fixed grid size of 16x16x16 to an arbitrary layout that can be set at any time. Right now I have it set to 16x8x64, but I will have to experiment to see what the optimum dimensions are.
    There are a lot of things to add (like shadows!) but I have zero concern about everything else working. The hard part is done, and I can see that this technique works great.
  19. Josh
    I've got the basic GI algorithm working but it needs a lot of work to be correct. I tend to do very well when the exact outcome is well-defined, but I am not as good at dealing with open-ended "artistic" programming. I may end up outsourcing the details of the GI shader to someone else, but the underlying data management is solid enough that I am not scared of it anymore.
    There's a lot of aspects of the design I'm not scared of anymore. We worked out smart pointers (including Lua integration), physically-based rendering, and most importantly the crazy ideas I had for the super efficient architecture work really well.
    At this point I think I am going to put the GI on hold, since I could play around with that endlessly, and focus on getting a new build out to the beta subscribers. We're going to just use a single skybox for ambient and specular reflections right now, and when it's ready GI and environment probes will provide that. 
    After that I think I will focus on the physics and navigation systems, exposing the entire API to Lua, and getting some of the outsourced work started. There's a few things I plan to farm out:
    Visual Studio Code Lua debugger GI details Weather system Water and clouds systems Everything else is pretty well under my control. This started out as an idea for an impossible design, but everything has fallen into place pretty neatly.
  20. Josh

    Articles
    Before proceeding with multiple GI volumes, I decided to focus on just getting the lighting to look as close to perfect as possible, with a single stage.
    Injecting the ambient light into the voxel data made flat-lit areas appear much more "3D", with color bleeding and subtle contours everywhere.
    Lighting only:

    Lighting + albedo

    Some adjustments to the way the sky color is sampled gave a more lifelike appearance to outdoor lighting.
    Before:

    After. Notice the shaded area still has a lot of variation:

    Initial performance testing gives results consistent with my expectations. I'm running at half of 1920x1080 resolution, on a GEForce 1660 TI, and performance is about a third what it would be without GI. At 1920x1080, that drops to 90 FPS. Because it is so resource-intensive, I plan to render the effect at half-resolution, then upscale it and use an edge detection filter to fill in info for any pixels that need it. This card has only 1536 stream processors, about half as much as a 2080.

    Further experiments with motion did not resolve the artifacts I was experiencing earlier, and in fact caused new ones because of the flickering introduced by the GPU voxelization. You can read a detailed discussion of these issues on the Gamedev.net forum. My conclusion for now is that moving objects should not be baked into the voxelized data, because they cause a lot of flashing and flickering artifacts. These could be added in the future by storing a separate voxel grid for each dynamic object, along with some kind of data structure the shader can use to quickly find the objects a ray can pass through.
    This is great though, because it means voxelization only has to be updated when the camera moves a certain distance, of if a new static object is created or deleted. You still have completely dynamic direct lighting, and the GI system just follows you around and generates indirect lighting on the fly. I could run the update in the background and then show a smooth transition in between updates, and all the flickering problems go away. Performance should be very good once I have further optimized the system. And every surface in your game can show reflections everywhere. Moving lights work really really well, as you have seen.
    The end is in sight and I am very pleased how this system is turning out. My goal was to create a completely dynamic system that provided better 3D reflections than cubemaps, and did not require manual placement or baking of probes, fast enough to use on older mid-range discrete GPUs, and that is what we got.
  21. Josh
    Their prices are more than 250% the price of a comparable PC. Even their "most expensive" laptop is using a budget GPU! So for less than half the price, you can actually get a laptop with a much better GPU!
     
    $999:
    http://www.newegg.co...=laptop%209800m
     
    $2499:
    http://store.apple.c...mco=MTM3NDcyOTc
     
    Just for fun, I checked all the most expensive options. The grand total was $7305.35. Who spends $7000 on a laptop with a budget GPU???
     
    I can't believe how dense their management is. It's as if they don't want to succeed.
  22. 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.
  23. 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.
  24. Josh
    I got touch input and text rendering working on Android. Happily, I have not encountered any issues with different behavior on any tested OpenGLES devices, including iOS. The framerate on my HTC Evo jumps around quite a bit, which appears to be an issue with the Java garbage collector. Framerate on iOS is a solid 60 FPS, so we should be able to get this sorted out.
     
    Here's a video:
    http://www.leadwerks.com/werkspace/page/videos/_/leadwerks-engine-3/android-progress-r100
     
    I also discovered that LuaJIT for ARM processors was recently released. This is fantastic because it means Lua script will run on Android and iOS at about the same speed as C# and Java. I knew this would eventually be supported, but I didn't know until yesterday it was released about a month ago.
     
    We've had a surprisingly strong positive response from developers over our support for mobile platforms, especially Android. This feedback has been coming from both the Leadwerks community, as well as other places like Google+. My estimation is there's probably ten times as many people interested in mobile game development as there are interested in PC development. Since Android especially is going to be an important platform for us to support, I've decided to implement an OpenGL 2.0 renderer, and make that a higher priority than the OpenGL 1 fallback I originally planned. Leadwerks Engine 2 used OpenGL 2.1, but this will be a much simpler renderer that just matches the functionality of the mobile renderer, so you can get the exact same pixel output across all supported platforms. Expect to see something about as capable as the Half-Life 2 engine.
     
    Of course, the OpenGL 3.2/4 renderer will still be available on Windows. At this time, Apple's OpenGL 3.2 drivers are not functional, but when they are it will be no problem to enable the OpenGL 3 renderer for Mac computers as well. (Tim Cook: Please see bug report #9896622.)
  25. Josh
    The design of the Leadwerks website involves organizing a lot of different kinds of data that are continually growing, including forum posts, blog entries, gallery images, videos, and downloadable files.
     
    All this information was organized in categories, and sub-categories, and in some cases, sub-sub-categories. The depth of categorization made it impossible to follow all the information that was flowing through the site, and users frequently posted in the wrong place. We recently underwent a restructuring of this information in an attempt to make all categorization only one level deep and streamline the viewer's experience. In this article, I will share with you some ideas I learned from this process that were not immediately evident to me.
     
    Programming Forums
    Originally, we had one main "Programming" forum for general programming discussion with several sub-forums which were meant to be used only for discussion of issues specific to each language, like compiling or editor problems. It didn't work out that way, and the community was fragmenting along programming language. Each group tended to participate in only the sub-forum of their language of choice, and I found myself answering the same questions repeatedly, for different languages. I don't know if this was related, but there was also a lot of territorialism among the various factions, with many arguments over which language should "win". Arguments occurred over which languages warranted their own forums. I also felt like the forum had grown beyond my ability to absorb, and had stopped reading the programming forums some time ago.
     
    With the arrival of the tagging feature in our community software, I felt it was time to merge all the programming forums into one, using tags as a 'light' way to sub-categorize posts. I chose to leave the Lua "Script" forum separate for two reasons:
    If we do an "indie" script-only version of Leadwerks3D in the future I want separate permissions for that forum.
    To protect beginners from intimidating low-level programming discussions. Which isn't to say anyone using Lua is a beginner, but beginners tend to prefer script.

    Although there was initial protest against this plan, I went ahead and closed the programming sub-forums for new discussion, without losing them just yet. I also made the Lua sub-forum a top-level forum and renamed it to "Script". My job is not about promoting other technology's brand names, and the user doesn't care much about the underlying technology, so I felt this was more appropriate than "Lua".
     
    Other Forum Categories
    We also had forum categories for sound, materials, modeling, and shaders. All of these sub-forums were merged into a single forum called "3D Artwork". Calling game sounds "3D artwork" may not be terribly accurate, but I'll get to that later.
     
    Gallery and Videos
    At the same time, I was working to simplify the entire contents of the Leadwerks website. Previously, we had gallery images and videos divided up by product. The gallery had four sections for Leadwerks Engine, 3D World Studio, our upcoming game development software Leadwerks3D, and a fourth category for miscellaneous pictures and photos. The videos section was also divided into three categories, by product.
     
    I decided to merge all videos into a single category, and replaced the gallery with a custom implementation that simply displays all images in chronological order, with no attempt to categorize them.
     
    Asset Store
    The Leadwerks Asset Store too was broken up into many sub-categories. The code section was subdivided by programming language, and we had similar issues as we experienced with the programming forums. Although Java was not an officially supported language, there was a lot of material available for the language, so a sub-category was created for it. I felt odd having all these "brand names" scattered across the Leadwerks website.
     
    We moved everything into a single "Code" category, using tags to specify what language a file was for.
     
    Portal
    Additionally, I implemented a community portal page which shows all recent forum posts, images, videos, status updates, blog entries, and asset store files. Items are displayed in chronological order, with no sub-categories.
     




    The new face of the Leadwerks community.


     
    The Result
    The reorganization of the programming forums was the most drastic change, and I think the community has generally agreed the change was for the better. I am once again active in the programming forums, and it's easy to keep up with current discussions. I made the final change and merged all posts from the programming sub-forums into the main programming forum, then deleted the sub-forums.
     
    The site overall is much easier to follow, especially the videos and gallery images. A chronological stream of recent items trumps sub-categorization, any day. Because there are fewer sub-sections to check on, it's much easier for me to keep up with the flow of content. Although I don't have any statistics to back this up, I feel like the community is more active now than before the change.
     
    Choosing Titles
    I have learned that slightly inaccurate and specific titles are better than encompassing but vague titles. For example, I removed the "Sound" forum and moved all posts into the "3D Artwork" forum. Is it accurate to include posts talking about video game sound and music in a forum that is mostly devoted to discussion of 3DS Max and Photoshop? Probably not exactly. Would it be better to call the forum "Game Assets"? You might be inclined to go with this suggestion, if you are an analytical type, but consider the following:
     
    iTunes is Apple's online music store. It was originally built as a program to purchase and sync music for iOS devices. Movies were added to the program's features, and the title "iTunes" was no longer exactly accurate. Would it have been better for Apple to rename the application to "iMedia" like "Windows Media Player"? It would be more accurate, but no one would have any idea what it did. When apps were added to iOS, iTunes gained the ability to manage applications as well. Should the program be renamed to "iContent"? It's a more accurate description, but it's so vague it loses meaning.
     




    iStuff?


     
    The name "iTunes" is catchy, and it describes the main point of the program, even if it doesn't encompass all functionality of the program. This is a weird idea to me, because as a programmer, my inclination is always use a broader and broader term until I reach one that encompasses all characteristics of the thing it describes. However, I am certain that a catchy title that describes the main point of the thing it describes is superior. With this idea in mind, it makes perfect sense to include game sounds and music in a forum about 3D game artwork. It is exciting to me to learn something that is illogical but self-evident.
     
    Conclusion
    When you categorize things, choose fewer categories with descriptions that encompass most of what they contain. Never get too analytical about the categorization and naming of things. Instead, just go with what feels more natural and catchy, even if your nomenclature is slightly inaccurate.
     
    We still have one big contradiction of this idea on our site, the use of the term "Asset Store". Leadwerks3D actually uses a class called "Asset" as a base class for textures, materials, shaders, and other objects, but about 40% of total files, and 100% of paid files in the store are 3D models. Additionally, the term "Asset" still isn't broad enough, because code files and games are not an extension of the Asset class. It would not be out of the question to rename the Leadwerks Asset Store to the "Leadwerks Model Store". The analytical (and much worse) extreme would be to call it the "Leadwerks Digital Goods Store".
     
    Keep your names short and catchy, and don't try to broaden them to encompass every aspect of the thing that they describe.
×
×
  • Create New...