Author Topic: My Game Engine is too Lame  (Read 58208 times)

0 Members and 2 Guests are viewing this topic.

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Slow
Bleh. I don't know what to do with my physics anymore.  :(

I've been struggling with the same problem in various forms for months now: how to achieve stable contact between rigid bodies. That is, with no jitter, no sinking into each other, and no aphysical adhesive properties. That last one is new, because I hadn't realized it was a problem until recently.

Also in case it wasn't obvious: it needs to run at a playable speed.



Things I've tried (but not necessarily in all combinations):
  • Magic anti-penetration displacement
  • Generating multiple contact points
  • Adhesion threshold
  • Convex meshes instead of multispheres (multisphere = convex hull around a collection of spheres)
  • More constraint solver iterations / smaller "wakeup" thresholds for the constraints so it actually does all of those iterations

Things I haven't tried:
  • Continuous collision detection
  • Contact points persisting between physics ticks

Australian doofus who dislikes FreeSpace suggests a combination of continuous collision detection and magic anti-penetration displacement... but implementing continuous collision detection would be a big undertaking.

 :sigh: :sigh: :sigh:

 

Offline Mika

  • 28
Re: My Game Engine is too Slow
First thing I'd like to ask is, what do you think is causing the jitter? Are the crates moving or stationary? Is the ground they are placed at a plane or a polygon? If looking at the force gradients of the crates, do you see sudden spiky increases in them?

Could you describe what you are actually doing with the bodies in the code?
Relaxed movement is always more effective than forced movement.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
What's causing the jitter? I don't know / it depends. I've tried various things and depending which thing I'm trying it fails in various ways. Part of it is gravity adding extra energy to the system. When there are multiple contact points, (e.g. the corners of a box) the impulse applied at one corner will nullify any "inward" velocity at that corner, but may produce an upward velocity at one of the other corners.

Are the crates moving or stationary? Initially they fall from the sky onto either a level ground plane or a terrain mesh. The initial "bouncy" collisions are ok, but when the boxes should eventually be coming to rest (i.e. they should be stationary) they instead jitter. Note that "rolling contact" is something I need to get right as well, and it's kind of similar to static contact. I'm not sure under which conditions rolling contact jitters.

Is the ground they are placed at a plane or a polygon? Are you talking normal vectors or finite vs. infinite? I've done two different tests: one has a level ground plane which is effectively infinite; the other has a terrain mesh made of triangles.

Force gradients: wat :confused:





Could you describe what you are actually doing with the bodies in the code?


Ok well... here's pseudocode of what my "main loop" does every tick:
Code: [Select]
UpdateVel all the dynamic collision objects (effectively all rigid bodies); includes something like vel += gravity * timestep;
UpdateVel all the RayColliders

RayTestPrivate all the RayColliders

Do collision detection --> populate a list of ContactPoints

DoUpdateAction all the persistent PhysicsConstraints (e.g. JointConstraint) and collect them in a list of PhysicsConstraints
DoUpdateAction all the ContactPoints and add them to the list as well magic anti-penetration displacement directly modifies pos here

Solve the constraint graph (i.e. repeatedly DoConstraintAction all the PhysicsConstraints in the list we just built) modifies vel to keep objects from going through each other, etc.

UpdatePos all the dynamic collision objects includes something like pos += vel * timestep
UpdatePos all the RayColliders


And here's the basic idea of ContactPoint::DoConstraintAction:
Code: [Select]
Vec3 dv = GetRelativeLocalVelocity(); // i.e. the difference between the local velocities of each object at the point
float nvdot = Vec3::Dot(normal, dv);

if nvdot < adhesion_threshold:

Vec3 normal_nvdot = normal * nvdot;

// normal force aka restitution
float use_restitution_coeff = nvdot < bounce_threshold ? restitution_coeff : 1.0f;
Vec3 restitution_impulse = rlv_to_impulse * normal_nvdot * -use_restitution_coeff;

// friction
Vec3 full_friction_impulse = rlv_to_impulse * (normal_nvdot - dv);
float fric_fraction = min(1.0f, fric_coeff * restitution_impulse.ComputeMagnitude() / full_friction_impulse.ComputeMagnitude());

// apply computed impulses
Vec3 apply_impulse = restitution_impulse + full_friction_impulse * fric_fraction;
ApplyImpulse(apply_impulse);

if apply_impulse.ComputeMagnitude() > impulse_threshold:
wake up adjacent constraint edges in the constraint graph

rlv_to_impulse is an awesome 3x3 matrix which tells me what impulse I need to apply at the point in order to achieve a particular change in the relative local velocity.

GetRelativeLocalVelocity is effectively b.vel - a.vel + Vec3::Cross(pos - b.com, b.angular_vel) - Vec3::Cross(pos - a.com, a.angular_vel) (where pos is the "position" of the contact point, i.e. whatever value I gave it in the collision detection code when I created it.

ApplyImpulse is effectively
Code: [Select]
a.vel += impulse / a.mass;
b.vel -= impulse / b.mass;
a.angular_vel += Mat3::Inverse(a.moi) * Vec3::Cross(impulse, pos - a.com);
b.angular_vel -= Mat3::Inverse(b.moi) * Vec3::Cross(impulse, pos - b.com);




Could you describe what you are actually doing with the bodies in the code?

Well uh... pseudocode...  :nervous:
« Last Edit: March 08, 2013, 02:57:57 pm by Aardwolf »

 

Offline Mika

  • 28
Re: My Game Engine is too Jittery
Okay, I'll try to get through of that during this weekend since my own stuff struck a wall (Just why isn't there an easy way to create a scalable 2D graph for Windows from the get go?).

Meanwhile, think of gradient as a multidimensional derivative of a multivariate function :D I know that sounds awful (which is the reason why I said it that way), but don't get scared, it sounds more worse than it actually is. Take a look at here. Basically, if you have a three dimensional vector function like velocity parameterized by a single parameter t as in v(t)=[x(t), y(t), z(t)], the gradient is then the partial derivative of each coordinate function like grad(v) = [x'(t), y'(t), z'(t)]. What's the relevance of this you are probably asking? Well, gradient of the velocity vector is the acceleration vector, and looking at the lengths of the gradients, you could see if there are sudden force spikes being applied to the crates when they are nearby. One of the reasons that could happen is numerical precision.

Suppose a crate is resting on a edge of two triangles of a single polygon. In general case, these triangles have slightly different normal vectors (unless the polygon is a plane). If it so happens that the box is starting to lean on either side due to gravity, you'll apply slight amount of rotational momentum on it, which will momentarily cause the edge of the crate to hit the other triangle. Since there is a bit of energy coming back from the ground (I understood your code that way) the crate now sees as a new force. If we happen to be doing updates on forces on certain time intervals, it may happen that the acceleration applied to the crate within this short time interval is much higher than expected, which would lead the edge of the crate bouncing off, leading to a rotational momentum that will then turn the crate to face the other triangle, rinse and repeat.

I don't know whether that is the actual cause, but I'd take a look on the acceleration (or force) vectors of the objects, as they might hold a clue why you see things happening in a way they do. Actually, instead of gradients, try drawing the combined force vector of a single object while you are running the game.
Relaxed movement is always more effective than forced movement.

 

Offline Tomo

  • 28
Re: My Game Engine is too Jittery
no sinking into each other
Genuinely, I'm pretty certain this is where the jitter really comes from, as real objects are neither infinitely hard nor infinitely rigid.

When you get down to the molecules and atoms, every contact is actually a spring and an adhesion force, with the sizes of each depending on distances between the atoms.*

In any physical contact, there is always some interpenetration and deformation - usually small, but always non-zero.
So any scheme that tries to ensure this can't happen tick-to-tick can't work, and it seem is unlikely to work in the steady state either.

You're going to need to allow at least one of 'sinking into each other', or 'deformation' at some scale, and base the final the 'adhesion' and 'restitution' forces on the amount of interpenetration/deformation  - because that's how the real world works.

Also, in control theory - as in 'driving a real robot's joints' - there is always an error between the 'desired' final position and the actual final steady-state result. The constants are chosen to minimise it, but it's always there.

Perhaps one approach to finding a solution is to start from the steady-state:
What should the final resting place look like?
How can the algorithm know it's reached it?

* This is of course a lie, but it's reasonably close if you ignore chemistry.
« Last Edit: March 09, 2013, 02:18:26 am by Tomo »

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Re: My Game Engine is too Jittery
The jitter could be just noise in the calculations, possibly from floating point errors?
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
@Mika: I am familiar with the concept of a gradient. I do not have any nonplanar polygons; in my TriangleMeshShape I have only triangles, and in my ConvexMeshShape I have only convex planar polygons. But yes, the jitter is probably something like that?



@Tomo: I am willing to permit a small amount of initial penetration between a pair of objects. I am not willing to permit those objects to continue moving further into each other over time. I chose the gerund form "sinking" because I am talking about an ongoing process, not a stable state.

RE: robots: I've put that on hold until I can get the physics working satisfactorily.

RE: steady-state: Ultimately the objects should be completely stationary. However, in the similar case of "rolling contact", the objects should have no relative local velocity at the point(s) of contact, and the objects should not penetrate into one another any further than they already are.

Edit: what I said earlier: no jitter, no sinking into each other, and no aphysical adhesive properties.



@z64555: Didn't you ask this before? I'm pretty sure I already said "no" to it being floating point imprecision.
« Last Edit: March 09, 2013, 06:56:06 pm by Aardwolf »

 

Offline Mika

  • 28
Re: My Game Engine is too Jittery
Okay, I went through a bit of your math

dv is the local relative velocity.
n is the local surface normal (normalized to unity, I suppose). Now, nvdot = n *dv is a scalar that can get pretty much all real values since there is no guarantee that the both vectors are positive, or that their dot-product would be positive.

The next row is:
Code: [Select]
if nvdot < adhesion_threshold
This comparison is dangerous, given the above. Hopefully, what actually reads in the code is
Code: [Select]
if fabs(nvdot) < adhesion_thresholdThis will make sure that the adhesion threshold comparison is always carried out in cases where it needs to be carried out.

The next line made me to check the ANSI C reference, since I haven't used ternary operators before (always done it with if constructs)
Code: [Select]
float use_restitution_coeff = nvdot < bounce_threshold ? restitution_coeff: 1.0f
I would write (nvdot < bounce_threshold) if the pre-processor just accepts it, these assignments can sometimes evaluate to something completely different without parentheses. I'm not sure how the expressions and operator precedence work in this construct, but from the charts, you should be safe. Basically what you are doing with this is just applying a modifier to the normal (force) in case of a partially inelastic collision where it is expected that there will be a shape change on either of the objects and there are losses of energy. If nvdot exceeds bounce_threshold, you apply the elastic collision model? Additionally, related to the earlier comment, think what happens if nvdot < 0 here...

The line
Code: [Select]
Vec3 restitution_impulse = rlv_to_impulse * normal_vector * (-1)*use_restitution_coeff)made me scratch my head for a while since impulse as I know it is force multiplied by time, thus it's unit is [kg m/s]. Okay, after a while I realized what it actually does, so no problem any more. Again, make sure the normal vector is pointing at the direction you want it to be pointing at, since there is no general guarantee that the surface normal is doing that. Ditto for the signs of the elements of the rlv_to_impulse. Additionally, there is a possibility for discontinuous derivatives at this point, since the restitution coefficient is basically calculated inside an if-loop. I have occasionally seen a local optimizer written by a certain person (cough cough) approach a local minimum, and assault a limiting condition that had a very heavy weight, which consequently threw the search out of the immediate area of the minimum since the derivative grew so large on the other side... Lesson learned, if the result doesn't improve, don't try to improve things by always going to max iterations. :D

For the fraction of friction
Code: [Select]
float fric_fraction = min(1.0f, fric_coeff*|restitution_impulse|/|full_friction_impulse|)at the current state, this should evaluate with positive numbers, so that's clear. How was the comparison actually implemented in the code?

That's for what I could see from the code itself. I'll try to think it from the physics perspective next.
Relaxed movement is always more effective than forced movement.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
Re: absolute value: nope; a negative nvdot indicates the objects are moving toward each other, and therefore I should do something to keep them from going through each other. The small positive "adhesion threshold" is just a hack I came up with to eliminate jitter. More on that at the end of this post.

Re: "impulse": I mean Δ(mv)

Re: fric_fraction: the actual line is
Code: [Select]
float fric_fraction = min(1.0f, fric_coeff * sqrtf(restitution_impulse.ComputeMagnitudeSquared() / full_friction_impulse.ComputeMagnitudeSquared()));
Which is mathematically equivalent, but only calls sqrtf once.



Really what I posted was almost an exact copy of my actual code.




I think I can solve the jitter issue with something like my adhesion threshold, but comparing to a constant isn't a solution that works in general. It kind of depends on the geometry of the contact region. Basically, shorter edges are stickier.

 

Offline Mika

  • 28
Re: My Game Engine is too Jittery
Quote
Re: absolute value: nope; a negative nvdot indicates the objects are moving toward each other, and therefore I should do something to keep them from going through each other. The small positive "adhesion threshold" is just a hack I came up with to eliminate jitter. More on that at the end of this post.

Ah, so adhesion_threshold, tries to make things stick in that way. I'm trying to think what happens next if the velocity is small but negative, leading to a small, but negative nvdot value. Especially if it so happens that the crate is very near the intersection plane, and in the next step it would be very slightly inside the other object? What happens then? Does this attempt to push the crate back up?
Relaxed movement is always more effective than forced movement.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
A little explanation of how my SolveConstraintGraph thing works may be in order:

If a constraint applies a sufficiently large impulse it wakes up adjacent constraints, meaning it calls DoConstraintAction on them in the next iteration. This continues for up to 200 iterations. So by the time it finishes iterating, the objects should hypothetically never have an "inward" velocity at any of their contact points.



The jitter happens when one of the corners of the box ends up with an "outward" velocity, and thus in the next physics step it ends up not being in contact. But in another physics step or two, it will be in contact again (if it's the case of a box "resting" on the ground, anyway).

The "adhesion threshold" has the effect of preventing the corners from separating unless they really want to. It's a start, but as I said before, using a constant m/s value to determine that isn't good enough, because it effectively makes shorter edges more resistant to rolling. But unfortunately "edge length" isn't a real thing. What I have are ContactPoint objects each with a Vec3 pos. Maybe I could change it so all the contact points between two convex primitives are stored in a single place, and then actually make "edge length" be a thing? Idunno.



Edit: I am so smrt. :rolleyes:

I have a m/s quantity, and the values are too small for short edges. To compensate for this, I could divide by edge length, but then I get a s-1 quantity. Wtf is that? Hertz?

And then I realized: angular velocity!
« Last Edit: March 12, 2013, 02:50:58 pm by Aardwolf »

 

Offline Mika

  • 28
Re: My Game Engine is too Jittery
Would it make sense to allow the crate to sink a bit in the ground? That way, all corners should be touching the ground? I think this would reduce the jitter quite a bit.

Please tell how your modification to the adhesion threshold works out.
Relaxed movement is always more effective than forced movement.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
Yes, a stable state for these crates will typically involve all four corners of one face being in contact with the ground.

I decided to change stuff a bit... now I have a ContactRegion class which is derived from PhysicsConstraint, which wraps a collection of ContactPoint objects. This may make it easier to do stuff where one ContactPoint "knows about" the shape of the contact region. It also means less edges for my ConstraintGraphSolver to deal with, because they're all bundled together now.

I haven't actually done anything like what I was planning for the adhesion threshold yet, though :blah:

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Jittery
Double-post because update.

Poop. I should've expected this, actually. The adhesion threshold hack-fix for jitter is broken. That's because constraints in my ConstraintGraphSolver can only wake up adjacent constraints, and not themselves... but with the new ContactRegion changes, a lone box resting on the ground is just a single constraint, which evaluates for the first iteration and then stops. It takes multiple iterations for the adhesion threshold to do its thing.

It seems like I have three options here:
  • Revert the ContactRegion changes.
  • Modify the ConstraintGraphSolver to let a constraint wake itself up.
  • Modify ContactRegion to somehow come to a stable state in a single iteration.

Option #1 would probably be the easiest, but it doesn't help me at all as far as eliminating jitter. Likewise for option #2, which I think would only be a little harder.

I already tried a little bit of option #3... my idea was to do make ContactRegion::DoConstraintAction do multiple iterations of ContactPoint::DoConstraintAction for all of the contained ContactPoint constraints, but it turns out I need a lot of iterations for it to be stable, and I can't afford to be doing ~16 iterations for every pair of convex primitives in contact with each other. Maybe if I only did it when it's an isolated ContactRegion constraint? I don't currently have any way to check for that, and it might still end up finishing iteration prematurely.



I don't know if the contact points really need to know about each other after all.

Maybe I need to actually have some sort of buffer zone that I allow the objects to sink into each other a little bit... but with a limit on how deep they can go. I remember when I was using Bullet it had something called margins which I think might have been similar?

I don't know how I would implement that, but it sounds like it might work.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Lame
Long time no update.

I decided to take a break from the physics, and to go back to trying to achieve Character Physics Happy Fun Time™ by other means.



I made a PlacedFootConstraint which constrains a point on a foot in place relative to another object, and optionally locks the orientation as well. The idea here is that it's much more reliable than the collision-detection + dynamics approach, which was always jittering, or allowing the foot to sink into the ground, or some other stupid thing like that. The exact setup for creating and breaking PlacedFootConstraint instances is still subject to change, but the basic idea is that when a Dood steps, a collision detection callback for the foot will execute, and if my code decides it likes it it will create a PlacedFootConstraint based on the ContactPoint data. Then when the Dood wants to lift that foot off the ground, it will destroy that constraint. Also in theory it will be possible for the constraint to "break" from the physics side, e.g. if the Dood gets hit really hard and goes flying.



I've made a few tweaks to my "cheaty character physics system" since the last time I mentioned it here. Previously, it conserved linear momentum but not angular. Now it conserves both. Here's the gist of the algorithm:

          Compute initial net linear and angular velocity of the Dood
          Dood::DoCheatyPose directly modifies the linear/angular velocity of each bone
          Compute change in net linear and angular velocity, aka "cheaty velocity"
          Dood::MaybeSinkCheatyVelocity has the option to modify the "cheaty velocity", e.g. in order to sink some of it into the ground via the PFCs
          Uniformly distribute the undoing of the remaining cheaty velocity

I believe this should be a good framework to build off of. I expect it will be easier to implement something that works in these terms than something that works in terms of per-joint torques, like I was trying to do before. I think the tiny amount of physical cheaty-ness is worth it.



My original approach (from earlier versions of the cheaty physics system) was to specify an orientation for each joint (and the root bone of the skeleton), and then set the linear and angular velocities of each bone to whatever they need to be to get them into position by the next tick. This technique produces the best out-of-the-box results: if I tell it to do the rest pose, and the PFCs are positioned properly for that, the Dood stands there very nicely... not quite rigid, but it gets the rigid bodies into a state that very nearly matches the pose I gave it.

But my goal is to make it stand and walk on varied terrain. It needs to be able to satisfy any configuration of the feet (within reason), not just the rest pose. And I don't know how to implement that.



One big problem with a per-joint orientation approach is that if there are multiple PFCs, not every configuration of joint orientations is going to be valid (let alone "good"). That is, if I start with one PFC's constrained pos/ori and move through the chain of joints to get to a second PFC, rotating and translating my pos/ori according to each joint, the pos/ori I end up with isn't necessarily going to match the constrained pos/ori of the second PFC.

About a year ago (well before I came up with the cheaty physics system) I experimented with a minimization-based approach to IK, where I told it the goal pos/ori of a foot relative to the pelvis, and it would figure out how to do it. But it was expensive and I had to spread the work over multiple simulation steps. That was good enough when I was telling a foot where to step, but I don't think it will work when there are multiple constraints on the skeleton: I don't think I can rely on this sort of "WIP over multiple simulation steps" solution to be a valid configuration.

Most recently I tried an approach where I just picked a pos/ori for the pelvis bone, and then the knee joint's position is constrained to a circle... and I would then select a point on that circle, and orientations for the two leg bones. But it hasn't been working, and I have no ****ing clue why. I've been reduced to shotgun-programming :( There are a few things I've figured while messing with this approach, though. One, I noticed that my Mat4::FromPositionAndOrientation method transposes the 3x3 rotation matrix portion of the Mat4, while Mat4::FromQuaternion does not. Sorting that one out is going to be a doozy, as Mat4::FromPositionAndOrientation is used all over the place, and I'm pretty sure Mat4::FromQuaternion is too. Second, I've noticed that if I try to tell the per-joint-orientation cheaty physics thing to do an orientation that exceeds a particular joint's rotation limits, bad stuff happens.



I also tried a more forward-dynamics-ish approach where I only modified the velocity data of select bones within the Dood. Specifically, I told the bones of the spinal column to orient to face the "yaw" direction, I told the pelvis to move up, and I told the feet to stay in their PFC-constrained pos/ori. At first this looked like it was going to turn out nicely... but it didn't. It only worked if I kept all the "cheaty velocity" (i.e. MaybeSinkCheatyVelocity changes the linear and angular "cheaty velocity" to zero, so nothing is undone). And anyway it looked much worse "out-of-the-box" than the per-joint orientation scheme.



So uh... I don't know what to do. I'm leaning toward something that uses the per-joint orientation scheme, though.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Re: My Game Engine is too Lame
So, ah. Any news there, friend?
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Lame
O HAI!

I wasn't able to make any definite progress with getting the Dood to stand/walk, so I decided I'd come up with a list of stuff I can work on that doesn't depend on the Dood being able to walk... I posted it on my Facebook, but didn't want to post it here because it was turning into a monologue. :blah:

Here's the list:
  • Get the upper body to aim so the head and gun point in a particular direction, with the proper pose for the arms (i.e. not using a pistol-grip for a fully automatic rifle)
  • Spectator mode (fly around the map freely without physics)
  • Adding giant space brambles back in
  • Make a CollisionShape from the Destructible Terrain mesh
  • Make shadows better, so it's always nearly 1 shadow-map texel per pixel (or something like that)
  • Make lighting affect particles, so particles in shadow aren't full brightness
  • Make dust particles for collisions between Doods and the ground (walking or otherwise)
  • Additional sound effects for walking/colliding with the ground, bullet impact sounds, and bug noises
  • Implement decals (for stuff like blood splats, explosion scorch marks, and bullet holes)


I've started on making the soldier hold the gun with both hands... I converted an updated version of the soldier model, as well as a newer gun model, and I've set up the relative transform between the gun and each hand. I'm seriously considering making the gun actually be a RigidBody. To that end, I created a new FixedJointConstraint class, and renamed JointConstraint to "SkeletalJointConstraint". And I briefly played around with a collision shape for the gun, but it wasn't very good... either I need to implement compound collision shapes sooner rather than later, or I'll just have to accept that the collision shape doesn't match the actual shape of the object very well.



I've also done a little thinking about my Destructible Terrain rendering, and I thought of something that could significantly improve the performance of it! Currently I have to draw a VBO for each material in each chunk, and they're drawn additively. This works mostly, but on rare occasions the depth test will say the depths for two fragments are "equal" when it shouldn't (because there isn't enough precision in the depth buffer). This results in two polygons' worth of materials being drawn on a single pixel, which means I've got a random double-bright pixel.

My new idea is to draw the whole thing to the depth buffer (technically this is already being done), and then do the per-material additive stuff in screen-space. My fragment shader would use the camera-space coords of the fragment and the depth value that was written there to reconstruct what the world-coords position of the point it's drawing must have been. I can then look up the amount of each material I need in a 3d texture. This will simultaneously improve performance and fix the double-bright pixels nonsense.

But there's a complication: up until now, I've been manually encoding and decoding depth info into an additional 3 color channels instead of using the built-in depth buffer. I know it's possible to get access to a depth buffer from a shader, but I don't know how to set it up. Just yesterday I did some fiddling trying to get it to work the "correct" way, but ultimately I got frustrated and reverted the changes. When I eventually get it working, I think it may also improve the performance of my deferred lighting and shadow-mapping stuff.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Re: My Game Engine is too Lame
Sounds good, sounds good. How are your particles rendered? Simple face-to-camera planes, or something volumetric?
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline Aardwolf

  • 211
  • Posts: 16,384
    • Minecraft
Re: My Game Engine is too Lame
For the most part my particles are square billboards (so yeah, "face-to-camera planes"). I don't use OpenGL's point sprites because they clip based on the center of the sprite... I'm pretty sure I could control that using a custom vertex shader, but I can't be bothered. I also have "billboard trails" which are ribbony things used for bullet trails, impact spark effects, and blood spurts... those are done as quad strips with the 'wide' axis aligned orthogonal to the camera (by taking the cross product of the along-the-ribbon axis and the from-the-camera axis). The stitching between segments could use some improvement one of these days, but it generally looks decent.

I don't know squat about volumetrics. :ick:

I really don't know how I would go about making particles be affected by lighting. The big reason I want this is because when a particle is in an area that should be shadowed, it currently shows up with full brightness, and that's not very good. The thing is, I'm doing deferred lighting (or shading? not sure) and that means for opaque objects multi-source lighting is considerably simplified. I don't have to do any silly business like selecting the 8 most relevant light sources :) But if I'm going to change how I render translucent stuff so that it can be affected by lighting, I don't have the luxury of being able to do each light in sequence. I could do the select-the-8-lights business, but I'm not very eager too.

I had an idea for something interesting but possibly expensive... I could have something like a normal map on my particles, and do lighting sort of like normal... so the side of a dust particle closer to the light source is brighter, for example. Currently my dust particle texture just has the top lighter and the bottom darker, which looks pretty good from any angle except straight up or straight down... and when it's in shade.



I haven't really done anything this past week, except a tiny bit of "thinking" :( Maybe I'll make some progress on the two-handed-grip business this week. I need to spend less time on Youtube, Minecraft, Minesweeper, and Soldat, and more time working on the game engine.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Re: My Game Engine is too Lame
Volumetric particles can have lighting and shading applied to them very easily, trouble is getting a good looking texture on them so that they look like a cloud or puff and not a pokey tetrahedron.

If you're doing raytracing, or shadow volumes, you can detect when a particle is within the shadow volume and tell the engine to turn down the lights.
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.