Jump to content
The Dark Mod Forums

TDM Engine Development Page


zergrush

Recommended Posts

Wow, amazing stuff!! =)

 

Is the depth of the water surface known, too? I am asking, because if both surface and ground depth are known, we could also render murky water I guess... :) The deeper the water, the less transparent it becomes. Might be problematic though, since we don't have any "correct" specular reflections on the water surface.

 

 

gallery_82_9_151704.jpg

 

 

 

Hehe, when I googled for example images, I also stumbled over this one showing a bug in ass creed that I also came accross. :D

 

I also saw this. Blending waterborders might be another nice improvement. :)

Sorry about the delayed reply. I spotted this when trawling through the thread trying to pick out all nbohr1more's posts on custom light shaders.

 

Yes all the depths are known so we could shade according to the depth/distance of the water visible between the surface and the bottom of the pool. Mappers achieve that with an embedded fog light but I've noticed some unsatisfactory results when using a fog. If you are far above the water surface the fog vanishes. I suspect (but not checked yet) that fog doesn't linearize the depth difference, so when you are some distance away the thickness of the water fog becomes negligible.

 

Transparent water surfaces that let you see the surface behind are post-process effects, which means they don't react to lights. That would be a problem for accurate specular reflections. In real life of course most water is not transparent in any meaningful sense. You can't see anything below the surface in rivers or harbours, especially ones churned up by human activity, and especially not at night. That water in AC2 isn't transparent except at the very edges, so there's no reason we couldn't try to rep it. I guess the reflections are faked using the cubemap method..

 

We do have a "fresnel.vfp" shader program which I guess is meant for this job, and at least one opaque water surface (cave water, I think it's called). I'm travelling so can't have a play with it.

 

We could even try transparent water with "correct" specular/Fresnel effect like in the skyrim pic above. Rather than hack the engine to use the actual scene lighting, the mapper could set 2 shaderparms to indicate the main direction and color of incoming light. The standard heat haze shader could then be fixed up to apply the effect. It already knows and uses the local surface normal direction to apply the distortion, so there's no reason it couldn't apply consistent specular too.

  • Like 1
Link to comment
Share on other sites

Cool stuff, I thought Arcturus's water materials were impressive so I guess this will just be the cherry on the top. :)

 

Since I'm at a bit of a stall point for Penumbra Wedges I'm gonna temporarily switch gears and see if I can get surfaces to run

their own unique light shader pass in somewhat of the reverse of my previous example. There is a separate pass for "non-ambient"

surfaces in the code and there is also the spectrum keyword to tie specific lights to specific surface materials so I think the

ingredients are all there.

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Since I'm at a bit of a stall point for Penumbra Wedges

I'll gladly join you on that experiment when I'm done with my 2.03 issues :)

I'm gonna temporarily switch gears and see if I can get surfaces to run

their own unique light shader pass in somewhat of the reverse of my previous example. There is a separate pass for "non-ambient"

surfaces in the code and there is also the spectrum keyword to tie specific lights to specific surface materials so I think the

ingredients are all there.

Is that the "drawShaderPasses" step in the renderer? That's where particles and transparent surfaces get drawn, basically every surface that isn't affected by light and isn't a pp effect. There's no separate list of surfaces for it; it just draws any leftover drawsurfs after each light has drawn its interactions. It relies on those surfaces being sorted after all the light interactions. If you plan to add a new type of light interaction you'd have to flag it so it doesn't get drawn in the main lighting pass, or make it so the main lighting pass uses your new methods for given surfaces/lights. I guess that's where "spectrum" could come in useful. Thinking about it, drawing a fresh set of interactions for existing lights in a later pass would be problematic because you'd have to draw the shadow volumes into the stencil buffer a second time, so a new spectrum value, i.e.different lights used, or doing the drawing in the main light interaction pass would work better.
Link to comment
Share on other sites

OK, I see that Sikk started on this endeavor in his branches. Look at "SL_SHADER" as apposed to "SL_BUMP" but I am guessing he

got stumped at the same point or he wasn't quite intending the same scope. If you follow the orthodoxy, you could just increase the

length of the interaction shader but this is just a christened version of what shader mods do when they grab a texture from the

alpha of a normal-map etc. IE adding a new official stage just leads to a longer shader everywhere just like shader mods do.

 

yeah... a bit tricky... I guess the SL_SHADER attribute could pre-toggle the something like "IsCustomLight" in my previous

example... argh. I guess this would lead to more conditional contortions about the program keywords if we tried to use those

so we'd just need to make sure that the syntax is not inheriting that... probably also means that my slick workaround is gonna

lead to other problems. We need new program type keywords that don't affect the new-stage stuff in the parser rather than

the branching hack. Oh well... it's not too bad it just spoils my fun little trick.

 

 

https://github.com/RobertBeckebans/Sikkpin-Feedback

Edited by nbohr1more

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

While looking at what my Intel drivers support, I see that I've got ARB_depth_clamp available....

 

These two commits from jblade would add that feature to TDM:

 

https://github.com/ljbade/doom3.gpl/commit/c7146a573d360f3061b3a9b142b34f58527d3f5e

 

https://github.com/ljbade/doom3.gpl/commit/52e0ea896387b6bbf134294f7718cd00b91877a7

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Uh oh if i where you id stay clear of that part from ljbade as it causes shadows to behave allmost the same as with msvc2012 and newer

(rather funny actually as the two bugs have nothing at all to do with eachother).

 

Im investigating a means to get this working correctly and i might have the solution allready but its up for testing.

 

/*
====================
GL_Cull
This handles the flipping needed when the view being
rendered is a mirored view.
====================
*/
void GL_Cull(int cullType) {
if (backEnd.glState.faceCulling == cullType) {
 return;
}
// enable depth clamping when face culling is off
if (cullType == CT_TWO_SIDED) {
 glEnable(GL_DEPTH_CLAMP);
 glDisable(GL_CULL_FACE); 
}
else  {
 // disable depth clamping again when face culling is on
 if (backEnd.glState.faceCulling == CT_TWO_SIDED) {
  glDisable(GL_DEPTH_CLAMP);
  glEnable(GL_CULL_FACE);
 }
 if (cullType == CT_BACK_SIDED) {
  if (backEnd.viewDef->isMirror) {
   glCullFace(GL_FRONT);
  }
  else {
   glCullFace(GL_BACK);
  }
 }
 else {
  if (backEnd.viewDef->isMirror) {
   glCullFace(GL_BACK);
  }
  else {
   glCullFace(GL_FRONT);
  }
 }
}
backEnd.glState.faceCulling = cullType;
}

Link to comment
Share on other sites

Yep works quite nicely like this :) no shadow bugs whatsoever and it took a bit of the strain off the stencil shadows, runs really well actually.

Not sure if its useable with the light volumes also, but it seems the culltype is autoset to CT_TWOSIDED for things like flares / sprites and generally disables shadows hmm ???.

 

 // twoSided
 else if (!token.Icmp("twoSided")) {
  cullType = CT_TWO_SIDED;
  // twoSided implies no-shadows, because the shadow
  // volume would be coplanar with the surface, giving depth fighting
  // we could make this no-self-shadows, but it may be more important
  // to receive shadows from no-self-shadow monsters
  SetMaterialFlag(MF_NOSHADOWS);
 }

 

its also disable for CT_BACKSIDED so it seems only CT_FRONTSIDED is valid for shadows.

Link to comment
Share on other sites

I gather it stops models being clipped by the near plane. So if you noclipped into a solid model with it turned on, you'd still see the front of the model on screen instead of the hollow inside. It can cause visual artefacts if you have overlapping models at the near plane, such as a wall and a particle, for example, and it'd probably let you see particles that are technically behind you if you walk through a cloud etc.

What's the use case guys? Would you use it for the stencil shadow volumes instead of visible models, so that you don't have to calculate and draw a cap on a shadow volume that the player is standing inside?

Link to comment
Share on other sites

btw test code here based on the exp renderer for drawing the depthmap.

 

/*
====================
RB_STD_RenderViewDepthImage
=====================
*/
static void RB_STD_RenderViewDepthImage(void) {
// we can use the depth buffer we already have in most cases
if (backEnd.viewDef->viewEntitys) {
 globalImages->currentDepthImage->CopyDepthbuffer(
 backEnd.viewDef->viewport.x1,
 backEnd.viewDef->viewport.y1,
 backEnd.viewDef->viewport.x2 -
 backEnd.viewDef->viewport.x1 + 1,
 backEnd.viewDef->viewport.y2 -
 backEnd.viewDef->viewport.y1 + 1, true);
}
else {
 // render the depth to the new size
 GL_Viewport(0, 0, glConfig.vidWidth, glConfig.vidHeight);
 GL_Scissor(0, 0, glConfig.vidWidth, glConfig.vidHeight);
 glClear(GL_DEPTH_BUFFER_BIT);
 glStencilFunc(GL_ALWAYS, 0, 255);
 // the first texture will be used for alpha tested surfaces
 GL_SelectTexture(0);
 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 GL_State(GLS_DEPTHFUNC_LESS);
 RB_RenderDrawSurfListWithFunction(backEnd.viewDef->drawSurfs, backEnd.viewDef->numDrawSurfs, RB_T_FillDepthBuffer);
 // copy it to a texture
 globalImages->currentDepthImage->Bind();
 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, glConfig.vidWidth, glConfig.vidHeight);
 // reset the window clipping
 glMatrixMode(GL_PROJECTION);
 glLoadMatrixf(backEnd.viewDef->projectionMatrix);
 glMatrixMode(GL_MODELVIEW);
 GL_Viewport(tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1);
 GL_Scissor(tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
   tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
   backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
   backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1);
 // the current modelView matrix is not valid
 backEnd.currentSpace = NULL;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

 

seems to work ok but i noticed that it slows down the engine a bit even if i dont draw anything.

Link to comment
Share on other sites

Its an optimization for shadow volumes to turn off clipping against the near and far planes.

Theres some info here http://books.google....H_CLAMP&f=false

+

 

Unfortunately, the book was written by Chef Tom and all i understood was Bork! Bork! Yere wee Arwe Clampnun da Shadun! Bork! Bork!

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

Hmm ok ill see if i can explain it, basically using this you wont get hollow shadows when stepping inside an objects shadow (will clip the shadow looking rather strange)

a bit like two pieces of black paper where one is either seen through the other or obscured by the other.

 

final version of the depth renderer i hope but feel free to correct it ->

 

/*
====================
RB_STD_DrawDepthBuffer
=====================
*/
static void RB_STD_DrawDepthBuffer(drawSurf_t **drawSurfs, int numDrawSurfs) {
// if we are just doing 2D rendering, we dont draw the depth buffer image
if (!backEnd.viewDef->viewEntitys) {
 return;
}
// get screen size
int width = tr.GetScreenWidth();
int height = tr.GetScreenHeight();
// we can use the depth buffer we already have in most cases
if ((width = backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1) &&
 (height = backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1)) {
 globalImages->currentDepthImage->CopyDepthbuffer(
 backEnd.viewDef->viewport.x1,
 backEnd.viewDef->viewport.y1,
 backEnd.viewDef->viewport.x2 -
 backEnd.viewDef->viewport.x1 + 1,
 backEnd.viewDef->viewport.y2 -
 backEnd.viewDef->viewport.y1 + 1, true);
}
else {
 // render depth to screen size
 GL_Viewport(0, 0, width, height);
 GL_Scissor(0, 0, width, height);
 glClear(GL_DEPTH_BUFFER_BIT);
 glStencilFunc(GL_ALWAYS, 0, 255);
 // the first texture will be used for alpha tested surfaces
 GL_SelectTexture(0);
 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 GL_State(GLS_DEPTHFUNC_LESS);
 RB_RenderDrawSurfListWithFunction(drawSurfs, numDrawSurfs, RB_T_FillDepthBuffer);
 // copy it to a texture
 globalImages->currentDepthImage->Bind();
 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
 // reset the window clipping
 glMatrixMode(GL_PROJECTION);
 glLoadMatrixf(backEnd.viewDef->projectionMatrix);
 glMatrixMode(GL_MODELVIEW);
 GL_Viewport(tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
 tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
 backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
 backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1);
 GL_Scissor(tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
   tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
   backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
   backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1);
 // the current modelView matrix is not valid
 backEnd.currentSpace = NULL;
}
// this is a gray scale image hence the GL_NONE
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}

 

call it in RB_STD_DrawView after RB_STD_FillDepthBuffer

 

like so

 

// fill the depth buffer and clear color buffer to black except on

// subviews

RB_STD_FillDepthBuffer(drawSurfs, numDrawSurfs);

// render the depthbuffer image revelator.

RB_STD_DrawDepthBuffer(drawSurfs, numDrawSurfs);

  • Like 2
Link to comment
Share on other sites

+

 

Unfortunately, the book was written by Chef Tom and all i understood was Bork! Bork! Yere wee Arwe Clampnun da Shadun! Bork! Bork!

 

Here's a more technical take on this in english ;)https://www.opengl.org/registry/specs/ARB/depth_clamp.txt

 

Now I'm puzzling over what seems to be an impossible code design.

 

The SL_XXXXX stages specify bump, specular, diffuse, etc stages to be marked in the interaction table as I take it.

This is meant to ensure that the interaction only processes bump for triangles that are indexed.

The ARB shader doesn't branch so it's impossible for it to exclude any part of the chain.

 

Why wouldn't they have created different ARB shaders for each stage (eg interaction_bump.vfp, interaction_specular.vfp, etc)?

 

Is the whole thing relying on some quirk in the specification that says "If no texture is supplied don't execute this part"?

 

Or is all this stage stuff just part of the legacy cruft for cards incapable of running shaders therefore requiring multiple passes

for each operation?

Please visit TDM's IndieDB site and help promote the mod:

 

http://www.indiedb.com/mods/the-dark-mod

 

(Yeah, shameless promotion... but traffic is traffic folks...)

Link to comment
Share on other sites

Hmm that's definitely something to test alongside penumbra wedges. I wonder why there was such a fuss over the depth-pass / depth-fail patent when depth-clamping side-steps the problem and is surely faster? Maybe it wasn't available back then.

Link to comment
Share on other sites

It was originally a nvidia extemsion but got merged in to the ARB spec around opengl 2.2 i think.

btw my implementation is better but it was not totally bug free i noticed when standing near a wall with player shadows on the shadow would sometimes cast outwards as a big black blob depending on the orientation i faced.

Edited by revelator
Link to comment
Share on other sites

Btw might be worth it looking at doing batch proccesing, vanilla still uses the old opengl 1.1 vertex arrays but i played with replacing them with glVertexAttribPointer and to some extent it was working. My biggest problem was getting the right attribs in some places.

Edited by revelator
Link to comment
Share on other sites

Btw might be worth it looking at doing batch proccesing, vanilla still uses the old opengl 1.1 vertex arrays but i played with replacing them with glVertexAttribPointer and to some extent it was working. My biggest problem was getting the right attribs in some places.

 

Model instancing (is this the same you are talking abut) would also be a benefit for vegetation. SEED does a poor job (it was written before we had the source) in drwing thousands of models by combing them all into one giant model and then draws it. That saves draw calls, but still could be done much better by sending the model to the graphic cardonce and let the card draw it multiple times.

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

That saves draw calls, but still could be done much better by sending the model to the graphic cardonce and let the card draw it multiple times.

Would that be as simple as passing the model once, and applying a different transformation for each draw in the vertex shader? Does that still take multiple draw calls, or is there a way to request the multiple instances in a single call? I guess you'd have to pass all the different origins, orientations, and scales too, an array of projection matrices. And for animated models like AI, a list of joint positions for each draw too.

 

So far it seems to work hmm can anyone confirm ?

Not tested yet, but I think we might have a problem with our particle materials if we co-opt GL_CULL to do the work. They don't cast shadows but they are two-sided, some correctly (stationary, non-view-aligned particles like the electrical discharge on generators), and many incorrectly (a lot of view-aligned particles are two-sided unnecessarily. Looks like a mistake got into a template). We can still try the technique, but we might have to put the toggle elsewhere in the code.

Link to comment
Share on other sites

Would that be as simple as passing the model once, and applying a different transformation for each draw in the vertex shader? Does that still take multiple draw calls, or is there a way to request the multiple instances in a single call? I guess you'd have to pass all the different origins, orientations, and scales too, an array of projection matrices. And for animated models like AI, a list of joint positions for each draw too.

 

For static meshes (leaving aside animated things for now), I guess passing along the transformation (offset + rotation) plus a color value (so you can randomly re-color the vegetation and add variety this way) would probably be enough. I'm not sure if a vertex shader can re-draw the same thing twice (with tesselation, it might generate new triangles?) but you could call the same shader multiple times. But I'm not an expert.

 

https://en.wikipedia...etry_instancing

 

Apparently it is in OpenGL, too:

 

https://www.opengl.org/registry/specs/EXT/draw_instanced.txt

 

Not tested yet, but I think we might have a problem with our particle materials if we co-opt GL_CULL to do the work. They don't cast shadows but they are two-sided, some correctly (stationary, non-view-aligned particles like the electrical discharge on generators), and many incorrectly (a lot of view-aligned particles are two-sided unnecessarily. Looks like a mistake got into a template). We can still try the technique, but we might have to put the toggle elsewhere in the code.

 

Could the two-sided particles get fixed? Is this a simple keyword in their materials ("onesided") that needs to be added? That might gain us a cheap bit of performance.

Edited by Tels

"The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man." -- George Bernard Shaw (1856 - 1950)

 

"Remember: If the game lets you do it, it's not cheating." -- Xarax

Link to comment
Share on other sites

Could the two-sided particles get fixed? Is this a simple keyword in their materials ("onesided") that needs to be added? That might gain us a cheap bit of performance.

It's just a keyword that wants removing from the material file -- twoSided. We'd have to check the material wasn't used in any genuine 2-sided scenarios though. We have 300-odd particle definitions sharing 97 materials, and the twoSided keyword goes in the material decl. We could safely remove it for any material that's used only in view-oriented particles.

 

I looked up the instancing function. There's a specific draw command for it glDrawElementsInstanced to complement the glDrawElements that our code uses. You need a vertex program as expected, and you can pass it a load of data for individual instances in a "Uniform Buffer Object", or for repetitive stuff like a field of grass, you can make it repeat with variations on the gpu without needing to pass data. It would be good for vegetation or a forest but I'm not sure we'd notice any benefit for existing maps. You apparently need 100s of instances of something on screen before it becomes the must-have choice. Your SEED method is probably as good as instancing for the kind of things we've seen in maps (so far).

Link to comment
Share on other sites

mmm :) batch processing would save a ton of client calls, i dont have the magic down to an art yet but mh seems to be back at the inside3d forums and he has

made the RMQ engine to use batch processing for a nice ammount of speed so it would probably not hurt to ask him for advise on doing this part.

 

I hope he has the time to look at this :) hees a very experienced programmer.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recent Status Updates

    • Ansome

      Finally got my PC back from the shop after my SSD got corrupted a week ago and damaged my motherboard. Scary stuff, but thank goodness it happened right after two months of FM development instead of wiping all my work before I could release it. New SSD, repaired Motherboard and BIOS, and we're ready to start working on my second FM with some added version control in the cloud just to be safe!
      · 0 replies
    • Petike the Taffer  »  DeTeEff

      I've updated the articles for your FMs and your author category at the wiki. Your newer nickname (DeTeEff) now comes first, and the one in parentheses is your older nickname (Fieldmedic). Just to avoid confusing people who played your FMs years ago and remember your older nickname. I've added a wiki article for your latest FM, Who Watches the Watcher?, as part of my current updating efforts. Unless I overlooked something, you have five different FMs so far.
      · 0 replies
    • Petike the Taffer

      I've finally managed to log in to The Dark Mod Wiki. I'm back in the saddle and before the holidays start in full, I'll be adding a few new FM articles and doing other updates. Written in Stone is already done.
      · 4 replies
    • nbohr1more

      TDM 15th Anniversary Contest is now active! Please declare your participation: https://forums.thedarkmod.com/index.php?/topic/22413-the-dark-mod-15th-anniversary-contest-entry-thread/
       
      · 0 replies
    • JackFarmer

      @TheUnbeholden
      You cannot receive PMs. Could you please be so kind and check your mailbox if it is full (or maybe you switched off the function)?
      · 1 reply
×
×
  • Create New...