• Advertisement


  • Content count

  • Joined

  • Last visited

  • Days Won


Hodgman last won the day on February 19

Hodgman had the most liked content!

Community Reputation

51710 Excellent

About Hodgman

  • Rank
    Moderator - APIs & Tools

Personal Information


  • Twitter
  • Github

Recent Profile Visitors

81559 profile views
  1. Lighting space

    I agree with your conclusions and think that's a pretty common way to go. If you're dealing with a very large world, float starts to get really bad precision a few kilometres away from the origin, enough to cause moving lights to flicker as their positions are quantised. In that case, it's common to use an offset-world-space, where you move the "shading origin" to the cameras position from time to time. Also, going from object, to world, to camera has worse precision when going from object to camera directly. In something like a planetary / solar scale renderer, you would notice this, so would be back to updating constant data per object per frame just to get stable vertex positions, in which case you may as well do camera space shading. Another older convention you missed is tangent space, where +Z is the surface normal and X/Y are the surface tangents. This was popular during the early normal mapping era, as you could transform your light and view directions into tangent space in the vertex shader, and then in the pixel shader the raw normal map is the shading normal (no TBN matrix multiply required per pixel).
  2. How Important are extra features?

    Coming up with extra features is easy. The hard part is throwing out the ones that distract from the good parts of the game or only serve to complicate things without making it more fun.
  3. C++ OOP and DOD methodologies

    They're not distinct or mutually exclusive. It's not just one or the other in different parts of the code, but you can use both at the same time! Also, a lot of the Anti-OOP rants that you see on the internet are from people who have unfortunately had to work on badly written OOP projects and think that OOP=inheritance (when inheritance isn't even present in OOPs formal description, and any decent OOP practitioner will tell you that a core tenet of OOP is the preference for composition over inheritance). The purpose of OOP is to develop useful abstractions that reduce the surface area of your components to the minimum necessary, allowing million-line-of-code projects to remain maintainable as a collection of decoupled components. OOP is a 'paradigm' in that it provides a bunch of tools and hen it defines a structure using those tools. The purpose of DOD is to analyse the flow of data that's actually required by your results, and then structure your intermediate and source data structures in a way that results in the simplest data transformations. The goal is to produce simpler software that performs well on real hardware. If using OOP, this analysis tells you how your should structure your classes. I wouldn't call DOD a 'paradigm' like OOP, it's more of a methodology, which can be applied to almost any programming paradigm. You should apply both if you're making a large game that you want to be able to maintain, but also want good performance and simple algorithms. Because OOP is about components and their interfaces (while hiding their implementations), you're free to do whatever you want within the implementation of a component too. Also, once an OOP component is created, it can be used by other OOP components, or can be used by procedural-programming algorithms, or functional-programming algorithms, etc... A common trend in my recent experience is actually to merge functional-programming techniques with OOP too. Components in OOP are typically mutable (e.g. Some core OOP rules are actually defined in terms of how the component's state changes/mutates...) but functional code typically works with immutable components and pure-functions, which IMHO leads to better maintainability as the code is easier to reason about. It's also common to use procedural programming to define the' script' of high level loops, like the rendering flow or the game update loop. One reason for C++'s popularity in games is that it is happy to let you write in this mixture of procedural, pure functional, object oriented and data oriented paradigms. [edit] I'd highly recommend reading Albrecht's Pitfalls of Object Oriented Programming ( https://drive.google.com/open?id=1SbmKU0Ev9UjyIpNMOQu7aEMhZBifZkw6 ), which could be interpreted as being Anti-OOP, but I personally interpret as anti-naive-OOP and a practical guide on applying DOD to existing code that already works but has been badly designed regarding performance. The design he ends up with could still have an OOP interface on top of it, but strays from the common OOP idea of associating algorithms with just a single object.
  4. I get mine from the back end. I simply wrap a pool allocator in a mutex. If you've got lots of threads constantly trying to lock the same mutex, you'll kill performance, but if if it's only occasionally locked, it will be rare for one thread to have to wait on another one and the mutex overhead will be quite low.
  5. DX11 Asynchronous Texture Creation DX11

    Do you upload the data using the "initial data" parameter of CreateTexture2D? Maybe the driver is doing this transfer using the GPUs 3D engine, which could stall it for many milliseconds with a block of data that size... If so, you could create the texture with no contents, and also create a smaller staging texture. Then use your extra thread to, over time, copy different rectangles of your texture into the staging texture, then ask the GPU to move the staging data into the right part of your 8k texture using CopySubresourceRegion. Doing this would help you split the work over multiple frames and avoid a single spike.
  6. DX11 Asynchronous Texture Creation DX11

    You can use this code to ask the driver whether it supports multi-threaded resource creation. D3D11_FEATURE_DATA_THREADING threadingCaps = {}; device.CheckFeatureSupport(D3D11_FEATURE_THREADING, &threadingCaps, sizeof(threadingCaps)); check if true ---> threadingCaps.DriverConcurrentCreates <--- If so, calling CreateTexture2D another thread should help you. I do it in my game (not unity) and it helps me a lot.
  7. C++ Gameplay in C++

    Hah, sorry for your dev-hell I'd be interested to know their setup though. It sounds like whoever made that decision at this company didn't bother to flesh out the workflow and forced a terrible mess onto everyone ;( I'd think that C was horrible if the coding environment consisted of notepad and mingw too! We had an IDE with full debugging (line by line stepping, locals, auto, watches, breakpoints, etc), visual studio integration, hot reloading of code, assertions with cross Lua/C call stacks, etc. Often if you hit a bug, you'd fix it while the game was still in the background, reload the code and continue running from the failed call. To avoid mis-naming bugs, you can modify the global-variable table to assert on writes, and should also use a good linter to catch them during compile time (most typos like that would fail the build for us, not be lurking timebombs waiting to fail at runtime). The same features that let you do breakpoints also let you collect code coverage stats, so you can tell if you're shipping code that's never been tested. On top of that, our build server would build/lint your code, and run it on every platform with AI players to test for bugs, BEFORE allowing it to be committed to the master branch. It was pretty hard to break the build with obviously broken C++ or Lua code Off the shelf C++/Lua bindings are pretty sucky, and yeah it did take us a few iterations to make our own that didn't suck, but binding is simple for us now and doesn't cause any issues. The vanilla VM is pretty slow (but still super fast compared to other scripting languages), so we used LuaJIT instead. On PC it's got great performance, and on console where JITing is banned, it's still 2x faster than vanilla Lua even with JIT compilation disabled. AFAIK we did have to sponsor the LuaJIT dev into supporting PPC and x64 CPUs though. We did a shitload of math in Lua and usually the only things that need to be ported are enginey-type systems, such as animation controllers, intense AI internals, etc, or stuff where you're doing math on a huge embarrassingly parallel dataset and the SIMD/threading benefits are obvious. Usually these kinds of systems were a natural fit for engine land anyway, so we ended up with a pretty natural C++ systems / Lua rules fit. This is off topic though - so to bring it back around, I still write C++ gameplay on my current project because I'm comfortable with it! We also use a 600Hz fixed update rate for accurate simulation on this project so I'm pretty performance sensitive... Another story - at the company before that one, we wrote the gameplay in C++, but the engine was mandated to have a C interface to force simplicity. Some of the engine used C++ internally in some modules, but still hid it behind a C API. The game would often then wrap up those simple C APIs in more C++ code to make them easier to use!!
  8. C++ Gameplay in C++

    The last big developer that I worked for did engine in C++, tools / data compilers in C#, and gameplay in Lua and C++. Lua and C# were used because they're more productive languages. Code is less complex than equivalent C++ translations, which makes maintenance easier and development/debugging quicker. Moreover different paradigms/features are available, such as duck typing, garbage collection, mixins or the prototype pattern. Things that require silly/complex "component frameworks" in C++ can just be don't out of the box in Lua. Things like reference counting and weak pointers don't require a library Most gameplay code isn't performance sensitive, but the bits that show up on the profiler would be ported to C++ and given some love. All the programmers are C++ coders who are taught Lua - you wouldn't bother hiring a Lua-only coder for a programmer's role. In my current game, we do most of the gameplay in C++, but pulling all tweakables/configuration data from Lua. Lua can be used to configure the game at a high level (plugging different components/systems together) and then the real frame-to-frame logic happens in C++. This gives us a lot of flexibility that you could get from something like ECS, without having to actually make a C++ component framework. C++ is an extremely dangerous language though, and has to be written with care. The more projects I ship, the more I come to fear C++ for its ability to create extremely subtle yet extremely dangerous bugs, mostly revolving around memory management So, we use a lot of discipline around pointers to help mitigate these risks, such as templates that: tag raw pointers with ownership semantics (and do leak checks in dev builds), tag pointers with array semantics (and do range checks in dev builds), zero initialise pointers (and do uninitiated read checks in dev builds), etc, etc... We also use scope-stack allocations for most things rather than heap allocations to make leaks impossible at a semantic level.
  9. OpenGL Packing char in float texture

    GLSL? floatBitsToInt / intBitsToFloat
  10. There's no reason a multi-threaded update can't be just as deterministic as a single-threaded one. It helps if you do batch processing instead of "spaghetti flow" where sending a message (e.g. Calling a function) results in immediately sending and handling another message (calling another function), and so on. Alternatively if you write the results of a large batch of operations into array, then that gives you another batch to handle/process next. If you distribute work amongst threads by giving each a range in a batch, then you can keep their results in order (range 1's results come before range 2's results). Another strategy for generating unique IDs is to base them on the parent/creating object's ID, especially if you can defer assignment of IDs. e.g. At the end of a frame, once all threads are done creating new objects, use one thread to stable-sort all the new objects by the ID of the object that created them, and then assign new IDs in that order. In your case of an object created based on a prediction, it's ID could be derived from the user input /request that resulted in it's creation. e.g. If user fires a grenade, they send a 'shoot' message to the server, with a sequence ID attached. The server and the predicting client spawn a grenade that references this sequence ID. The client can then later match up the server's spawn message with their local proxy/prediction object, or use responses that reference higher sequence numbers to deduce that the server ignored the shoot request and didn't spawn a grenade.
  11. There's endless different mathematical conventions for different things, most of which are equally valid and arbitrary choices. Historically, D3D and GL have disagreed with which way is up (do coordinates start at the top of the screen and increase downward, or start at the bottom and increase upwards?), and back in the early versions whether you should write vectors across the page or down the page... Most of the time you should be able to use whatever conventions you like at your application-level, and then do a bit of mathematical fiddling to translate that into D3D/GL's conventions. e.g. You could choose to have viewpoints be defined from the top corner or bottom corner, have Y be up or Z be up, use right-handed or left-handed coordinates, have NDC Z=1 be the near plane or far plane, use row-vectos or column-vectors, store 2D arrays in row-major or column-major order, etc.... Their NDC definitions also vary in Z: D3D uses a 0 to 1 range and GL uses a -1 to 1 range (by default - GL4 allows changing it). This is one case where there is an objective reason for the choice though. GL's convention here has a nice symmetry to it, but D3Ds offers precision benefits due to how floating point numbers work, allowing much better z-buffer precision.
  12. On the big AAA games (that can have over 1000 staff on them), often one team will be the core, who actually design everything, and the rest of the staff are basically in-house outsourcing (or actual outsourcing) with zero autonomy / personal connection. The core team doesn't just define the game /story, but technology too. Asset naming conventions, ideal node layouts, animation rigs, shader suites, etc... The following staff then work from these exact specs. Yep, that's a great way to burn out naturally-creative staff if you keep it up For content heavy games though, it's actually not too inefficient to distribute content production like that.
  13. What are you going to do on other sized screens? Run in windowed mode with a non-resizable window? Draw black borders on the edges? Rescale from one of your supported resolutions to the screen resolution? That last one would require care around aspect ratios.
  14. So... what did you post to get banned from reddit?
  15. Is adverts in game worth it?

    As mentioned in another post, it does let you sell a no-ads IAP It also depends on how/when you show them. A common trend now seems to be opt-in fullscreen video ads, either on a timer in the main menu (e.g. Once per hour to get a prize) or after each level/death/etc (to get a bonus, extra life, etc). Once-per-day bonuses also seem to be a common strategy often a with a phone notification reminding players to open the game and get their bonus (a nudge to help retention). These choices won't be arbitrary or devised in advance perfectly for most successful games though. It's common to soft-launch in one territory only and then do lots of A/B testing (use science to find out which variations get best results). New Zealand seems to be a common target as the small population means you don't waste a lot of opportunity, but they still have similar tastes/habits to North America (assuming that's your real target market -- a NZ soft launch won't help you tune the strategy for China). The "AAA Mobile" studios that make millions per month likely have a lot of people full time on looking at analytics and devising experiments... At any scale you at least want to know why/when people are quitting your game, and whether people are opting in to your bonuses or not. Things like offering a bonus life at the start vs end of a level, or even just the color of a button could potentially be the thing that makes a feature work! To get ARPU up though, besides optimizing your ad usage so that people are happy to see a lot of them, you need IAP. Your ARPU for just the IAP-engaged segment can be several dollars, which gets dragged down to a tens of cents average by the freeloaders. Loot boxes seem to be the current fad - play the game and watch ads to get coins, spend them on boxes, get prizes... Then directly sell coins/boxes/prizes too. As posted above, the most successful games will be very scummy... However I love Crossy Road as an example of a less scummy option - the gameplay is just endless frogger an exist in full out of the box. Collecting coins in black game, opting in to videos, once-per-day bonuses and IAP let you get loot boxes, which give you re-skins of the artwork - no effect on gameplay, but made a huge amount (for an indie dev). It is a little scummy to people who feel the compulsion to unlock everything in that you can't buy prizes directly, just gacha boxes... Flappy bird also just had banner ads on death with no 'scummyness' but made a huge amount (for an indie dev) simply off volume of players.
  • Advertisement