Jump to content
  • Advertisement

Promit

Senior Moderator
  • Content count

    15770
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Promit

  1. Promit

    Closed

    This classified is now closed.
  2. I think this might be helpful - https://github.com/Dan6040/SharpDX-Rastertek-Tutorials
  3. Any chance I can push you towards C#? It's still fully UWP capable, you can still use DirectX, but it will be dramatically easier to move into from a Java background.
  4. It all depends. GLUT is ancient and irrelevant, but several other foundational libraries are perfectly viable as long as they're open source. The real issue nowadays is that graphics APIs are changing, platforms are coming and going, and professional studios need to be buffered against all of those changes. A math library needs to be flexibly ported to different CPU architectures with different SIMD instruction sets. Windowing libraries need to be expandable to handle platforms that may not even be publicly announced. You can't very well have MS come to you for an Xbox 4 demo and not be able to adapt to the platform. For those reasons, these core libraries can act as very short term gains, but in the long view it's more beneficial to control the underpinnings yourself.
  5. Promit

    Assembly language?

    I have to add some caveats in here. True, nobody builds games in assembly. But there are certainly uses for it. It's still common to write SIMD routines in assembly, especially newer instruction sets where the compiler intrinsic support is either not available or just doesn't work that well. PS3 SPUs were frequently coded in assembly. And debugging often involves going over the assembly code being emitted and run, in order to understand what's going on. Performance optimization also frequently requires analysis of the compiler output to fully achieve the desired results. We're not writing in assembly or even reading it on a regular basis, but you better believe that it comes up plenty in games.
  6. Promit

    Defining AAA

    It's unclear to me which days were the "romantic" ones, but I did want to try and put some numbers on budgets over the years. Luckily, some guy at Kotaku did the legwork already: https://kotaku.com/how-much-does-it-cost-to-make-a-big-video-game-1501413649. I should mention that some of these budget numbers are direct budget and don't count things like the effort put into building a publisher-shared engine, and often times the marketing budgets can be quite large. There's never been any doubt that budgets have inflated massively over the course of the game industry's evolution. The definition I was given around 2007 for a AAA title was simply, a game expected to sell more than a million copies. (Successful indie games might sell those kinds of numbers, but that was not usually the expectation.) If the term ever meant anything about the innovation of said games, that went out the door at least 20 years ago.
  7. cracks knuckles Alright, let's talk seriously about what it means to roll your own. For context, I've worked at Microsoft and had access to the Windows source code. I've worked at NVIDIA and had access to the D3D driver source code. I'm software architect of a group which has a completely C++ tech stack which is essentially custom, save a few helper libraries that are part of it. I say this only to provide some context for where I'm coming from - rolling your own is a very familiar world to me. I'm going to ignore Casey/HMH from here on out because I don't care enough about him to say more on that subject. That's great. Do you have time to do both? More on that in a moment. I'm a little concerned that you don't actually know what you are trying to accomplish here. In general, there are two ways to come at building games. You can start with something very high level and learn all about how to structure the high level structures of a game, filling in low level knowledge over time. Or you can start very low level with the individual pieces, eventually figuring out how to connect them into a working whole. Both are perfectly valid approaches, but it's very difficult to accomplish both missions simultaneously. The people we're talking about in this thread have many years of professional experience under their belts, and are usually doing this in their spare time too. You can choose to roll your own tech, as we did, and it can pay dividends long term. But that choice will kick your actual game back by years, especially if you're still learning the fundamentals as you do it. Witness was mentioned above - that game took eight years and an ultimate team of 15 people to create. So it becomes necessary to decide what your priorities are, because we're no longer talking about short term gratification. You've demurred on that choice so far, though I like @MonterMan's comment on integrating outside libraries, particularly open source ones. I don't like the concept that some stick to of not having dependencies, because that's not reality. You always have dependencies, you're just choosing not to acknowledge them. The OS and platform SDK, the graphics API and drivers, the C++ runtime, etc. I just include the dependencies in the source tree whenever possible, rather than doing package manager stuff. At the end of the day, you're going to have to decide that you're writing some part of the system yourself, and some part just already exists there for you and functions in its own mysterious ways. There are many places to draw that line, but you should have a good understanding of why you placed it where you did and what the goals are. No matter what you choose, some things are going to be closer and some things are going to be farther away. It will take a long time to have both the low level and high level under your belt - and I have to mention that very few professional game developers ever do that. Most inhabit just one section of that world, relying on the rest of the team to build a complete product.
  8. Introduction There has been a lot of discussion about whether managed code is "good enough" and "fast enough" for writing graphics code and games in. Many people have touted its ability to make developing games faster and easier. However, there hasn't been much discussion about specific ways to more effectively leverage the new abilities that managed code gives us. There are some very interesting advantages to working on Microsoft's .NET platform, which can be applied to graphics programming in order to solve some difficult problems. The problem I'll be examining in this article is how to robustly expose shader constant parameters from an application. Many shader constants in modern games are data driven; they are pulled from material files and the like. However, some constants are not data driven but are inherent to the code itself. The model, view, and projection matrices are good examples. The rendering pipeline computes these matrices as part of rendering; they are not part of the data that is loaded from file. When dealing with these values, there are generally 4 steps that need to be taken to handle such a constant: Store the value in the application somewhere Set the value of that parameter on the application side Check if a given shader uses that parameter, and obtain an API handle to the parameter if it does Propagate the parameter's value to the shader at the appropriate time Every time we add or remove a new constant parameter, we need to touch code in four different places. This is error prone and generally just a total pain to deal with. While steps 1 and 2 can't really be avoided, 3 and 4 are irritatingly repetitive. The code required to deal with step 3 usually looks something like this: this.ModelHandle = shader.GetParameter("Model"); this.ViewHandle = shader.GetParameter("View"); this.ModelViewProjHandle = shader.GetParameter("ModelViewProj"); this.ColorHandle = shader.GetParameter("Color"); ... The code is quite repetitive, but the differences between each line are just enough to make refactoring difficult. We can try to attack the problem by storing a table of parameter handles that are keyed by string. Then we could simply iterate over the table to initialize all of the handles. However, that requires us to maintain some sort of hard coded string table of all of the available parameters, which isn't much of an improvement over this version. And it still won't help us in simplifying the code required for step 4: if(this.ModelHandle != null ) shader.SetValue(this.ModelHandle, Constants.Model); if(this.ViewHandle != null ) shader.SetValue(this.ViewHandle, Constants.View); if(this.ModelViewProjHandle != null ) shader.SetValue(this.ModelViewProjHandle, Constants.ModelViewProj ); if(this.ColorHandle != null ) shader.SetValue(this.ColorHandle, Constants.Color); ... The table we wanted to use in step 3 doesn't help us because we can't use those string keys to look up members of the Constants class that we're using to hold all of our shader parameters. Or can we? Reflection Reflection is a particularly powerful ability of code that is running on the .NET platform. It allows us to examine the structure of our classes, getting information about what members they contain, what metadata (attributes) has been attached, and more. There's a lot of information out there about reflection, and I won't cover it in detail here. So how can we make reflection work for us? Remember that I discussed hard coding a table of strings and parameter handles. We can use reflection to make that table for us. It allows us to obtain all of the member variables of a class as an array. By consolidating that information into a Constants class (as appears in the pseudo-code for step 4), we can easily create that table without being forced to hard code it alongside the actual member variables. Type type = typeof( ConstantMap ); FieldInfo[] fields = type.GetFields( BindingFlags.Public | BindingFlags.Instance ); Now we have an array describing all of our available constants. We can use the Name property on FieldInfo to get the string name for the field, and we can also use it to access the value of the field for a given instance. Now we can switch over steps 3 and 4 to using much simpler loops to do their work. For step 3: for( int i = 0; i = shader.GetParameter( fields.Name ) { } And for step 4 (note that some type casting details have been omitted): for( int i = 0; i != null) { shader.SetValue(this.Handles, fields.GetValue(Constants); } Now, all we have to do to add a new constant parameter is to add it as a member of ConstantMap, and update its value appropriately. The reflection and loops will automatically deal with looking it up as a shader parameter, and propagating its value down to the shader. Problem solved, right? Unfortunately, no. It's not quite that simple. Reflection is not especially fast. In particular, that GetValue function takes a very long time compared to the direct member access which we were using in the hard coded version. And because this is something that will be called thousands of times per frame, we can't be wasting so much time just accessing members of a class. Luckily, .NET still has one trick up its sleeve. Metaprogamming Metaprogramming refers to writing code which itself writes new code. The term is very broad, and anything that creates new code (even outputting text to a BAT file and running it) counts. The type of metaprogramming we'll be doing was added for .NET 2.0, and is called DynamicMethod. (You can accomplish what I'm about to describe using purely 1.1 functionality, but it's a little more involved.) DynamicMethod provides an extremely lightweight way to build functions at runtime. You can write CIL byte codes to it (these are the byte codes that .NET natively runs), and then use it to create a callable delegate, which is as fast to invoke as a virtual function call. The first time it's called, all of the byte code will be run through the JIT and converted to native code, and there will be no overhead after that. Setting up the DynamicMethod involves providing a description of the function it defines, and then retrieving an ILGenerator object which allows us to write the actual CIL. After that, we write our byte code, and then create the actual delegate object and store it. The code ends up looking something like this: DynamicMethod dynMethod = new DynamicMethod( "SetConstants", typeof( void ), new Type[] { typeof( Effect ), typeof( EffectHandle[] ), typeof( ConstantMap ) }, typeof( ConstantMap ), true ); ILGenerator ilGen = dynMethod.GetILGenerator(); //Use the ILGenerator to write all of the bytecode here m_SetConstants = (SetConstantsDelegate) dynMethod.CreateDelegate( typeof( SetConstantsDelegate ) ); Our goal is to recreate the hard coded version of the shader binding. First, the reflection API will generate a complete list of available shader parameters for us. Then, we will create a DynamicMethod that runs through each parameter, checks if the shader uses that parameter, and propagates the value if it does. The final generated byte code will be completely identical to the original hard coded version, but we won't be the ones who wrote it, and it will automatically update as members are added or removed from the ConstantMap class. (To get a feel for how CIL looks, I'd suggest playing with the ILDasm tool that is included in the .NET Framework SDK.) The full code is too long to show here; see the attached file for an example using Managed DirectX and the Effect framework. All of the heavy lifting is done in the static constructor for ConstantMap. It goes through each member field, storing its name in a string array and writing the byte code to test for null and call SetValue for each field. Another helper is also provided that simply generates an array of all of the parameter handles for a shader and returns it. This is stored along with the shader and then passed back to the ConstantMap along with the shader just before rendering. Using and maintaining this system is exceedingly simple. To add a shader constant parameter, add a new member to ConstantMap. To remove the parameter, remove the member. Clients of this class only have three responsibilities. The first is to update the values in the constant map. Second, they need to store the parameter handle array returned by ConstantMap.LoadParameters() for each shader. Lastly, they need to pass the shader and its accompanying parameter array to the ConstantMap.SetConstants(). Everything else is handled by the ConstantMap itself. Getting an array of constant parameter handles is a single line of code: EffectHandle[] effectParams = Constants.LoadParameters(effect); And after updating all of the parameter values, setting up the shader is also a single line: Constants.SetConstants(effect, effectParams); Problem Solved What we have now is an extremely robust and efficient system for exposing shader constants from the rendering pipeline to shaders. All of the expensive reflection work is done during application startup, where the cost is relatively miniscule. At runtime, there is no work being done that wasn't being done in the hard coded version. Yet with zero performance overhead, we've managed to make huge gains in terms of reliability and ease of use. There is still room for improvement, though. Right now, it's assumed that all the data is contained within the ConstantMap itself. This means that some situations could require a lot of data to be copied. You can adapt the code generation so that it can handle members that are reference types that expose shader data. This way, data could be stored elsewhere and referenced rather than copied. It's also possible to add lazy evaluation. For example, not every shader is going to need the ModelInverseTranspose matrix, so computing it repeatedly is a waste of time. The code generation could conceivably be set up so that it only computes these quantities when they are actually used by the current shader, and those values could even be cached. This design forms an extremely flexible base on which to build simple or sophisticated shader systems.
  9. I don't know how much more there is to say without digging into the series and cherry picking all the stuff I hate, and I got bored of that long ago. It's simply not representative of anything beyond a fanciful imagined time where people totally built stuff up from nothing. It's like a game-sized programming test rather than focusing on things that are actually productive. I just think it's a mistake to think that this is what a "real game programmer" does.
  10. No, it's not. I'm sorry to all the fans but HMH is an entertainment show with no relevance to reality. On the ground game development is a totally different ballgame, even in the indie world. By all means watch Casey if you want, but don't mistake it for a productive use of time or an educational product. It is not, and Casey's not qualified to teach anybody anything. This is the key point, because it really tends to discourage the "roll your own" path. I have a lot of problems with Unity and we don't (and couldn't) use it for our own work. But you need to be really careful about whether you're misusing a tool, using the wrong tool, or doing something which doesn't have good tools available. For starters, I'd tend to push you back to C#/.NET. It's a powerful and productive environment that you're clearly familiar with, and nothing in your stated needs or desires suggests a change to C++ is called for or helpful. Assuming that Unity is indeed the wrong tool for what you want, it's worth looking at some of the 2D libraries available for C# already. https://duality.adamslair.net/ http://flatredball.com/ https://waveengine.net/ Unfortunately I can't vouch for these selections and there are likely many other choices out there. But I feel like you've decided you don't like Unity and then gone much, much too far in the opposite direction.
  11. Promit

    What do you think about JAI

    I googled Jai to see what kind of write-ups are currently available about it. First hit is a third party GitHub page with: Are you kidding me? Why are we even talking about this when there's no spec, no compiler, nothing except some unofficial write-ups fabricated from a freaking YouTube series? At least most of the other languages du jour are functioning pieces of technology I can poke and prod. This is insanity. So to answer the OP's question, I think it's fine if you're enjoying JB's videos and talks about this, but to actually discuss it seriously doesn't even begin to make sense to me.
  12. Looks like the Solo under-performance is having some real fallout: IMO this is probably the correct outcome (and I didn't realize they were actually planning to make all these extra movies). All of them feel every bit as cynical and cash-grabby as Solo, created not so much to add anything material as to just drag more audience dollars into the theater on name recognition alone.
  13. Ohhh, you mean cynical in being produced as fan service. I gotcha.
  14. Strange, I would describe TLJ as easily the most cynical of the Disney era movies. A film where the protagonists all either fail outright or actively worsen the Rebels' situation through their actions? That sees our long-missing hero die? TLJ offers up nothing in hopes or accomplishments.
  15. Setting aside the episodes for the moment - As far as Star Wars goes... I'm just so damn bored at this point. It's instructive to look at the Marvel crew next door, who are pushing out even more movies and have been for some time with great success. If you consider Avengers analogous to the SW Episodes, they're not actually the best of the MCA despite being the motivating force behind them. Each movie revolves around its own characters and does its own thing, much like Solo. Except, MCA is wildly successful and Solo seems pointless. Why is that? It comes down to the reason for any given movie to be made, in my view. The MCA movies all function together, building a story in pieces that are related and connected and serve to move an overarching plot and universe forward. The SW movies, on the other hand, have so far been looking backwards and add nothing to the Episodes or the rest of the universe. Rogue One teetered on the edge and was mostly saved by being a movie that uniquely rests on names and faces we don't recognize. Solo feels cynical in comparison - it's a cheap cash-in on a central character but adds nothing to his identity and nothing to the universe of Star Wars as a whole. Give me films that fill in actual gaps in the story, or serve to better explain what's happening now, and they'd at least have my attention. But I'm not going to go see a movie because "well it's Star Wars and it's decent". Lucas, for all his faults, was a universe builder and everything he did was part of a unified global theme. In contrast I'm not sure what the hell Disney-Lucas is trying to accomplish, where it's going, or who is important in that universe. I'm not even sure they know where the Episodes are going.
  16. Promit

    How to use DirectX Control Panel

    I don't think any of these options work since Windows 8 came out. You might look into debugging through PIX or Visual Studio's graphics debugger instead.
  17. Promit

    Why are enums broken

    The problem with this approach is that it doesn't create a type or type alias that you can use to cue in what values are actually expected for a given parameter or variable. If I have a function, I can say that the type of one argument is Thing and then i know that Thing::FOO and Thing::BAR are valid options. Can't do that if Thing is a namespace. I get around this with some magic macros that create a struct named Thing with an int cast, and create the enum values inside that struct.
  18. Promit

    How important is 1 big vertex buffer ?

    It's not so important to have one huge vertex buffer, but it's better not to have thousands of small ones. The more you can combine them, the better. Usually it's not going to be your big bottleneck - CPU and GPU profilers can give you hints as to what is actually slowing you down.
  19. Promit

    Messagebox gives errors after compiler installation

    The easy way to deal with this problem is just to use the function MessageBoxA instead. See, MessageBox isn't a function - it's a macro. It becomes either MessageBoxA or MessageBoxW, depending on whether the compiler defines UNICODE at the time of compilation. While you can remove UNICODE from the project properties, I find it much cleaner to simply skip the macro and call the function you actually want.
  20. fragPos = vec3(model * vec4(vertex, 1.0)); camPosition = camera; gl_Position = mvp * vec4(fragPos, 1.0); Didn't you just multiply through with model twice here? fragPos already contains model when you hit it with mvp.
  21. Because email addresses and phones get stolen all the damn time. The idea of two factor authentication is to avoid having a single point of compromise become built into a major breach.
  22. If nothing else, I consider 4 GB of memory unacceptable in a modern dev machine. I have a 4 GB surface and it struggles to actually load and build our project due to memory issues. Not struggles to run it - struggles to build it.
  23. Promit

    A batch of opengl questions

    Man, the guys above are too dire. I wrote most of this same stuff when I was fifteen, what’s with all this “this is hard to do without an engine” nonsense? Don’t know what the point is if we’re not going to help the newbies do real work. Let’s get down to it. Terrain: it’s a nice idea that might need a few tweaks. My suggestion is to look up terrain “splatting” or “splat maps”. It’s not quite what you asked for but I think it’ll be helpful. Collision: object space AABB per model, world space AABB per instance. Drawing collision: I prefer to run these and all other debug rendering through a separate render pipeline based entirely on dynamic buffers and streaming vertex rendering. This makes it a lot easier to add additional displays/modes and info. Shaders: both good choices, roll with what works
  24. Promit

    Backups (online and image)

    I'm using Crashplan for Business - the personal product was discontinued recently. I'll likely change soon, as the business offering is likely not the most cost effective choice. No image support though, so if you're going to insist then no dice.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!