Jump to content

  • Log In with Google      Sign In   
  • Create Account

Bacterius

Member Since 28 Feb 2011
Online Last Active Today, 05:46 AM

#5070642 How do I implement a new rendering engine?

Posted by Bacterius on 17 June 2013 - 07:38 PM

OpenGL and DirectX aren't rendering engines. No. They are graphics pipeline interfaces which let you submit commands to the graphics card. Such as, "push this bunch of triangles onto the screen using this set of shaders". But you need to come up with the commands yourself. As you've probabled guessed, you can tell OpenGL to draw a million triangles in random locations on the screen, and the GPU will happily do it. But it won't look all that nice, will it? No, not really. It's a computer. It doesn't create stuff, it just executes instructions.

 

So you need to tell it how to render lighting, shadows, how to draw a realistic sky, how to shade textures properly, how to create a convincing camera, how to generate procedural content that doesn't look like complete crap, how to make tree leaves translucent, how to render fire, how to animate stuff, and so on, and so on, in a way that the graphics card will understand. Depending on how you do this, and on the quality of your assets (textures, and so on - that one is really important because the rest is more or less the same among all renderers) the end result will look more or less pleasing.

 

As an analogy to the DirectX/OpenGL thing, a computer can add and multiply numbers, but you need to come up with algorithms to actually do useful work.

 

Now your next question is going to be, "how do I make a rendering engine", the truth is, you won't be able to if you don't know what people want out of a rendering engine. If you are truly dedicated, you can try writing a game directly on top of DirectX and OpenGL, and then look at your finished code, pull out stuff that's got to do with graphics, create a library out of it, and rewrite your game using it, this will give you an idea of how a rendering engine is used. Then write another game, and you'll see there's stuff you need that your library doesn't do yet! So add it in, and try again. And again. When it's sufficiently polished, submit it to the world to see what they think, and iterate until you get something really good.

 

But keep in mind that the odds of you alone creating the next big thing in rendering engines are close to nil. Engines like CryEngine or Torque3D have - literally - millions of man hours behind them, and have bumped into problems that you cannot even imagine yet (and solved them). So you'd be mostly reinventing the wheel, which is fine as a learning exercise but if you're trying to make money making games, creating your own rendering engine is probably not cost-effective (at least not when starting out).




#5070361 Matrix math identities

Posted by Bacterius on 17 June 2013 - 01:50 AM


1. If i have a matrix for some object, with applied rotation and translation (no scaling) is it guaranteed that its basis vectors are unit vectors?

 

In theory, if the original matrix had unit basis vectors, then, yes, the transformed matrix will too as rotation/translation preserves scale. But in practice, floating-point error will screw that up, so you will be fine except if you repeatedly rotate a matrix in a feedback fashion were errors will accumulate. For instance, instead of:

 

frame 1: rotate the matrix 5 degrees

frame 2: rotate the matrix another 5 degrees

 

You should do:

 

frame 1: take the original matrix, make a copy, and rotate it 5 degrees

frame 2: take the original matrix, make a copy, and rotate it 10 degrees

 

So that the error remains constant over time, instead of getting worse and worse.

 

 

 


2. This is called orthonormal/orthogonal matrix?

 

A matrix is orthogonal if its basis vectors are perpendicular to one another (their dot products are pairwise zero). It is orthonormal if it is orthogonal and its basis vectors have unit length (actually, this is an abuse of terminology, but as far as computer graphics is concerned there isn't much difference, really, we care about matrices representing coordinate spaces here, not inner product spaces)

 

Don't know about 3, sorry. Not sure what you are asking and not too familiar with D3DX matrices.




#5070316 What video game programming language would be best for me?

Posted by Bacterius on 16 June 2013 - 08:26 PM

Dunno, flip a coin and go with that, since we don't know what language you would find most intuitive and easy to use (it varies among people). If I had to recommend one, though, I would say either C# or Python. You won't have to dabble in low level concerns and will be able to get on with making your game instead of endlessly dwelling on implementation details, which would seem to be what you want for a hobby. If you want to know how things work "under the hood", maybe C++ is for you, but it is arguably harder and the benefits are hard to see when you're starting out.

 

Another thing to try would be trying to write a pong (or other simple game) in a variety of languages and stick with whichever one you prefer to learn the basics.

 

Ultimately if you are to make this more than a hobby you will have to learn more than one language, and overall it doesn't matter what you start out with as long as you keep at it. So pick and choose, and get coding tongue.png you will invariably start looking into other languages eventually, I can guarantee that.




#5069624 Retrieving Usage Statistics

Posted by Bacterius on 13 June 2013 - 08:37 PM

If it's a single-player RPG, yes, you should always ask confirmation before sending information which contains user data (even if it is anonymous). One possible option is having a checkbox in your settings menu along the lines of "collect anonymous gameplay statistics" or something, with a helpful tooltip on mouse hover. It should preferably be unchecked by default. The checkbox needs to be visible or nobody will see it. If at all possible, find a way to display it on first launch when the player is configuring his settings, so that he is at least aware of the existence of this feature (and as such won't be surprised if the firewall informs them your game wants to use the internet).

 

Once the checkbox is ticked, the game should collect the statistics it needs, and send them whenever it deems appropriate (e.g. after each level, upon closing the game, etc..). If the player unticks the checkbox at any point, all unsent collected data should be erased. A "send" button is not good. People expect this to be automated, and nobody is going to take the time to find the file and send it to you (they will be too busy playing!). The obvious way of doing this is to just send the data to your server. If you have no server, sending an automated email from within the game would work too.

 

Also, do not continually nag the player about enabling statistics collection, and do not offer special advantages (premium level packs, gold membership subscriptions, beta access codes and so on) to players who enable it. That was a joke, obviously wink.png

 

At least that's how I would like things to be, and seems to be the safest option from a legal and ethical standpoint.

 

----

 

An exception is if you are explicitly targeting video game testers, in which case ignore all the above and your method is fine. In general, testers need to write a (more or less formal) report as part of their work anyway so asking them to attach their gameplay statistics is not really an issue.




#5069585 changing code on its roots

Posted by Bacterius on 13 June 2013 - 05:49 PM

A switch statement? It'll create a jump table to efficiently map code to execute to the value of c.

switch(c)
{
  case 0: r = a * b; break;
  case 1: r = a / b; break;
  case 2: r = 2 * a; break;
  // ...
}

Or you can directly return if you have nothing to after the conditional.

 

EDIT: damn, missed the HLSL tag, I don't think it has switch case support. In this case, does the value of c stay the same for every shader invocation? If so, you might be able to have the compiler optimize it down. Otherwise, if it changes dynamically, I'm afraid you're going to have to do the comparisons in any case.. are you looking for syntactic sugar or an actual performance improvement? GPU's aren't that good at control flow so any "clever" hacks to minimize the number of comparisons might yield even worse performance. If there's any way you can weave "c" directly into the formula that would be ideal of course, but it doesn't seem possible here.




#5069032 Transforming the Young Blank Dull Slate into a sharp Genius In Math.

Posted by Bacterius on 11 June 2013 - 10:56 PM

I have a feeling this guy would enjoy math a lot more if he was exposed to it through game programming rather than through tedious, abstract homework sheets. Perhaps he should just stop worrying so much and start writing some code. You need to learn to walk before you can learn to run, I don't know why anyone would expect anything else with programming.




#5069027 Appropriate World Scale for FPS Game

Posted by Bacterius on 11 June 2013 - 10:34 PM

There is really no answer to this question. Some games use metres as units, e.g. a gravity of -10 means a downwards acceleration of 10 meters per second. Other games use inches or kilometres (or some other funky unit, depending on their needs). So it depends on what scale units you use in your game. For instance, your art assets might have the player have a bounding box of 0.5 x 0.5 x 1. But 0.5 of what? Perhaps the player is a giant, in this case maybe this should be kilometres. Perhaps it's an ant, and then it should be millimetres. Or maybe it's just a generic soldier, so it probably stands for half a metre. Scale accordingly.

 

I'm inclined to think that for an FPS you should just follow the rule of using SI units (metres, seconds) as a base unit for your graphics/physics values to make it clearer, so that you know that your world terrain is exactly 2km by 5km and your player is 1.85 metres tall and so on instead of having to convert back and forth across different scales, but it's up to you. As long as you scale everything consistently it will look the same anyway at the end of the day (barring floating-point issues if you use ridiculous scales which you shouldn't anyway)

 

In other words, it doesn't matter, as long as you are consistent and that your assets are properly loaded in the engine. There may be issues using normal scales if you are rendering a very large or a very small world, but I don't think this will be a problem here.




#5068798 Frustum culling using a KD-tree

Posted by Bacterius on 10 June 2013 - 11:32 PM

My take on it is that there are two "types" of kd-trees, one which stores points and another which stores volumes (AABB's, probably). On the former, you do nearest-neighbour searches (kNN search) and on the latter, you do ray-AABB traversals (which probably become ray-triangle queries). You've grasped the first type.

Now the second type uses splits in three dimensions, but the meaning is different from just storing a point, it instead says "in this node, there are no AABB's left (or right) of this split in the given dimension". What this means is that in your traversal code, you only need to examine at most one side of the split.

Take a look at http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_7_Kd-Trees_and_More_Speed.shtml which I found is a decent introduction.

Dunno how that would be useful for frustum culling, though. kd-trees are generally used with raytracers which implicitly do not require frustum culling.


#5068532 [c++] Enum, sizeof

Posted by Bacterius on 09 June 2013 - 07:56 PM

Is it more safe to set value for all values of the enum or the default value is safe ?
Is it possible to safely use sizeof to serialize an enum ?

 

If no value is specified, the enumeration values will take ordinal values 0, 1, 2, .. in the order they are in in the source code. If one value N is specified for one value, all successive values will take ordinal values N + 1, N + 2, ... you can also specify a custom value for each of them should you find the need to. So it's not "more safe", it's just up to you. An enum is supposed to give express a set of distinct states so you shouldn't need to know about the underlying index in general unless you are doing stuff like serialization or other low-level things.

 

Unsure what you mean by using sizeof to serialize an enum. If you mean its size in memory, I think it's defined as an int, and hence platform-dependent, so no, it is not safe and you should cast it to a known-size type such as uint32_t.

 

 

All works for class who doesn't have pointer but if the class has a pointer like a string, I have a crash.
Is it because the pointer who is an array of data who is undefined-size, the "operator =" needs to be called ?

 

It's possible you are freeing your objects after having copied their pointers (either by accident or by design e.g. your object falls out of scope). In this case, yes, you should maintain the reference by using the class's copy constructor or modify your design such that the pointer to the object remains valid even when the original array is deleted.




#5067239 Simple and fast random number generator

Posted by Bacterius on 03 June 2013 - 06:40 PM

I just wanted to point out that using a state as small as 16 bytes is more a liability than a feature. In my limited experience writing PRNGs and hash functions, a large state is one of the easiest ways to avoid some common pitfalls.
 
Have you guys tried something like the dieharder test suite to evaluate the quality of the pseudo-random numbers generated by your code?

 

I have done extensive testing with dieharder, in fact I was trying to find the minimum number of rounds needed. Turns out three rounds passes the dieharder tests with no problems. I did not invent the internal design myself, this is Bruce Schneier's cipher, I just simplified it slightly for use as a PRNG, rewrote it with vector instructions, and did some checking to ensure I didn't break anything. Inventing a PRNG from scratch is just asking for trouble, imho, but deriving it from an existing, proven construction is a hobby of mine.

 

But just why do people care so much about periods? There is no difference between a 264 period and a 264000 period. Assuming your computer runs at 2GHz and consumes one random number every cycle (rather unlikely!), it can run for 292 years on a 264 period.

 

I don't really understand that either, to be honest. This is also why I dislike the MT. It just looks over-engineered with its 2^19937 period, I mean, who cares? If anything, having an exact, predictable period is more of a failure than a feature since true random number generators do not exhibit regular periodicity. But it doesn't matter anyway because nobody will ever reach said period. 16 bytes of internal state is cutting it a bit close if your PRNG is particularly bad, but 32 bytes is more than enough.

 

And then you see people using MT for CUDA.. good grief, what a waste of memory.




#5067096 Simple and fast random number generator

Posted by Bacterius on 03 June 2013 - 08:08 AM

I have a quite fast, excellent quality crypto-based PRNG that I always use for my OpenCL projects (it lends itself well to SIMD and MIMD architectures, even both at the same time). I might as well post it here (this is OpenCL code but should be readily convertible to whatever language you use, it uses vector types). The code below is rather barebones because it was designed to be used inside a GPU kernel, and is a bit redundant because the "wrapper" is unfinished:

 

#pragma once

/** @file prng.cl
  * @brief Kernel PRNG implementation.
**/

/** This macro converts a 64-bit integer, to a [0..1) float. **/
#define TO_FLOAT(x) ((float)x / (ulong)(18446744073709551615UL))

/** This indicates how many rounds are to be used for the pseudorandom permutation
  * function, higher means greater quality but at a higher computational cost,
  * 3 recommended at a minimum, 9 is more than enough.
**/
#define ROUNDS 4

/* This is a 256-bit -> 256-bit keyed permutation function. */
/** Keyed permutation function.
  * @param state The internal state.
  * @param seed The PRNG's seed.
  * @returns A 256-bit pseudorandom output.
**/
void renew(ulong4 *state, constant ulong4 *seed)
{
    /* Retain the PRNG's state. */
    ulong4 block = *state + *seed;

    #pragma unroll
    for (ulong t = 0; t < ROUNDS; t++)
    {
        /* Round 2t + 0 (×4 mix & permutation). */
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(14, 16));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(52, 57));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(23, 40));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)( 5, 37));
        block.hi ^= block.lo; block = block.xywz;

        /* Key addition. */
        block += *seed;

        /* Round 2t + 1 (×4 mix & permutation). */
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(25, 33));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(46, 12));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(58, 22));
        block.hi ^= block.lo; block = block.xywz;
        block.lo += block.hi; block.hi = rotate(block.hi, (ulong2)(32, 32));
        block.hi ^= block.lo; block = block.xywz;

        /* Key addition. */
        block += *seed;
    }
}

/** @struct PRNG
  * @brief PRNG internal state.
  *
  * This structure contains an instance of PRNG, which is enough information to
  * generate essentially infinitely many unbiased pseudorandom numbers.
**/
typedef struct PRNG
{
    /** @brief The 256-bit internal state. **/
    ulong4 state;
    /** @brief A pointer to the PRNG's seed, common to all instances. **/
    constant ulong4 *seed;
} PRNG;

/** This function creates a new PRNG instance, and initializes it to zero.
  * @param ID The ID to create the PRNG instance with, must be unique.
  * @param seed A pointer to the PRNG's seed.
  * @returns The PRNG instance, ready for use.
**/
PRNG init(ulong ID, constant ulong4 *seed)
{
    PRNG instance;
    instance.state = (ulong4)(ID);
    instance.seed = seed;
    return instance;
}

/** This function returns a vector of uniform pseudorandom numbers in [0..1).
  * @param prng A pointer to the PRNG instance to use.
  * @returns An vector of unbiased uniform pseudorandom numbers between 0 and 1 exclusive.
**/
float4 rand(PRNG *prng)
{
    renew(&prng->state, prng->seed);
    return TO_FLOAT(prng->state);
}

 

The word size and vector width (here, 64 bits and 4) can be tweaked easily. I actually have a WIP document (including better code) on this that I may turn into a Gamedev article if I have time, but it's not ready yet. Two rounds is far better than an LCG and mighty fast, three rounds is pretty much all you'll need, four if you want to be certain (it depends a bit on the other parameters). Anything above that is overkill, really.

 

Do not use for cryptographic purposes. The design may be derived from a cipher but.. just don't.

 

It is also reversible (there is an inverse permutation). Period is expected to be 2^255 on average for this particular set of parameters, in general 2^(n - 1) where n is the internal state size in bits.

 

I think I was the not the first to use this particular cipher (Threefish) as a performance-oriented PRNG and I know people have been playing with Serpent and Twofish for a while, but I like having things I can rely on in any situation and that I can actually understand. This is one of them.




#5066622 how do you apply a brush colour to an image professionally in an art program

Posted by Bacterius on 01 June 2013 - 01:21 AM

Yeah, it's actually the opposite. Just for completeness, it should be

 

(layer2 * alpha) + (layer1 * (1 - alpha))
 



#5065682 How can I avoid circular dependency?

Posted by Bacterius on 28 May 2013 - 08:22 PM

Well my first thought is that since the two classes seem to need each other so closely - and are apparently unable to function without each other - surely they should be merged somehow? In most designs classes do not interact mutually but only in one direction, but I suppose there are situations where you can end up with circular dependencies.

 

What is your exact situation?




#5064941 Physically Correct "Bloom"

Posted by Bacterius on 26 May 2013 - 04:19 AM

By the way, what happens when the coating is thicker than allowed by the model in your article, and cos0 is very near to zero (don't think absorption, but dispersion)?

 

When the coating becomes too large and the local entry/exit point approximation breaks down, the following happens:

 

1. interference effects disappear (in fact, the fringes become so thin that they average out to white, this isn't really captured by the BRDF but if you do any kind of anti-aliasing that's what would happen. in reality I do not recommend doing this unless you are working within a wave rendering framework, which is probably not the case)

 

2. dispersion effects in the coating start to dominate (assuming the coating is a dispersive medium) as the waves travel longer - and hence diverge more - inside the coating

 

3. you actually need some sort of method to have the exit point of light differ from the entry point, it is possible and fairly easy to calculate the distribution of the exit points so that you can sample them randomly but you'll need something akin to subsurface scattering to actually handle that feature in your rendering pipeline

 

In fact it probably makes little sense to use this model when the coating becomes so thick as to not exhibit interference effects as that's the model's raison d'etre. At that point it's probably best to actually use two parallel pieces of geometry :)

 

When cos0 tends to zero (grazing incidence angle) almost all light is reflected off the coating by Fresnel's laws so no appreciable interference or dispersion is observed. You may even get total internal reflection depending on the refractive index of the coating and of the medium the incident wave is in.




#5064917 Physically Correct "Bloom"

Posted by Bacterius on 26 May 2013 - 01:47 AM

The only thing I can think of that comes close to what you describe is multicolored noise on various objects due to interference of light at the surface, like oil film reflections but on a much smaller scale.

 

Interesting. By looking around my house, I actually discovered this when observing bright specular highlights on oiled woodwork, but something comparable also seemed to occur when I looked at the bright highlights produced by elaborate glass vases which were constructed like mosaics with many discrete glass sub-faces glued together (lot of caustic effects). I'm still trying to reproduce images. I just need to find the right time of day to take pictures, but I'm usually busy/distracted with programming.

 

At first I was thinking that you were simply observing dispersion, which makes sense for the glass vases, but that doesn't really happen on glossy wood. So it looks like a case of thin film interference, which is compatible with both situations (in the first case the film is the oil, in the second case it's the glue - or maybe it's actually dispersion in the second case and they just happen to look similar). I really cannot think of anything else at the moment. In either case, yes, what happens is only certain wavelengths of light make it to your eye depending on how you are looking at the object (others are either deflected away from your line of sight or eliminated by destructive interference) so if you move slightly the highlight will seem to change in color. This effect is of course independent of the lens system used to observe it. Is this what you see?






PARTNERS