[Patch] MicroTexture

Technical discussion for those interested in Supermodel development and Model 3 reverse engineering. Prospective contributors welcome.
Forum rules
Keep it classy!

  • No ROM requests or links.
  • Do not ask to be a play tester.
  • Do not ask about release dates.
  • No drama!

[Patch] MicroTexture

Postby HarryTuttle » Fri Mar 10, 2017 5:09 pm

As promised I'll detail my mods starting with MicroTextures. It's based upon some speculation of mine and observation/comparison of actual arcade footage.

Observing the texture memory dump we can see there're 6 LODs for mip-mapped textures:
'0' (base, biggest, nearest to camera) -> '5' (last, smallest, farthest from camera).

The 'MicroTextureMinLOD' seems to be related to the LOD of the underlying texture at which MicroTextures fades away. It's actually the "minmum" size / "maximum" LOD that can be "detailed". That's because details, if used, should be logically visible at short distance from the camera and fade away as we start to go further from it.

An example: in Scud Race MicroTextures are used to alterate the grading of the road texture to exaggerate the "speed" sensation (as in OutRun). They work beautifully at near distance but if used everywhere, especially at long distances, the effect would be "neutralized".

So, for example, if I set 'MicroTextureMinLOD' to '2', the detail texture should be visible on LODs 0,1,2 of the underlying texture, then starts to fade away and disappear at the beginning of LOD '3'.

In my implementation I do:

1) clamp the OpenGL sampler to LOD 0-5
2) in the fragment shader I fetch (with some approximation) the LOD of the current fragment of the underlying texture and make the appropriate decision.

I also disabled anisotropic filtering as it seems that on Model3 (maybe also Real3D) anisotropic filtering is never used, probably is not even capable of. In mid-late 90s it was a very "expensive" feature in terms of GPU power, so filtering is now limited to tri-linear.

As stated in the 'devguide.pdf' there's a 'SetNPScale' function that changes the LOD bias of the texture. That was an old trick to display higher detail textures at longer distance although with little "scintillating" pixels effect. You can see such effect here: https://www.youtube.com/watch?v=wl6tCbnLl7M (look at the road texture from 00:28 to 00:38, and from 00:48). Maybe it has something to do with polygon header 0x05, first 24 bits.

Anyway I'm almost sure it's used, so in my private build I've set GL_TEXTURE_LOD_BIAS to '-3.5' (a dirty hack really, and just for testing), that value gives almost arcade-perfect road textures, but obviously alters too much many other ones. So won't post it.

Here are some screenshots (I've tried to match the gamma/color temperatures/blurriness of both the source and my screen grabs):

scud1a.png
Original arcade
scud1a.png (134.59 KiB) Viewed 800 times

scud2a.png
Supermodel (with patch)
scud2a.png (130.49 KiB) Viewed 800 times


Notice the white central stripe on the road going from gray/dirt color to white. Also note the two lateral and distant darker road skids, these are just the road texture without the "detail" tile applied.

Continues....
---
Edit: I've updated the patch to include the fragment shader mods, also is attached here for easier access.
Attachments
diff.zip
MicroTexture patch
(1.88 KiB) Downloaded 29 times
Last edited by HarryTuttle on Sat Mar 11, 2017 4:02 am, edited 1 time in total.
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

[Patch] MicroTexture

Postby HarryTuttle » Fri Mar 10, 2017 5:12 pm

Two other screenshots:

scud3a.png
Original arcade
scud3a.png (114.4 KiB) Viewed 798 times

scud4a.png
Supermodel (patched)
scud4a.png (106.98 KiB) Viewed 798 times


Continues...
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Re: [Patch] MicroTexture

Postby Ian » Fri Mar 10, 2017 5:49 pm

This is what the sdk looks like

Code: Select all
void __thiscall PRO_Polygon::SetMicrotextureRelativeScale(PRO_Polygon *this, float a2)
{
  double v2; // st7@2
  PRO_Polygon *v3; // [sp+Ch] [bp-8h]@1
  signed int v4; // [sp+10h] [bp-4h]@5

  v3 = this;
  if ( a2 < 0.0 )
  {
    v4 = 0;
  }
  else
  {
    v2 = 1.0;
    if ( _adjust_fdiv )
      _adj_fdiv_m32(LODWORD(a2));
    else
      v2 = 1.0 / a2;
    v4 = (signed __int64)(v2 + 0.5);
  }
  if ( v4 > 3 )
    v4 = 3;
  PRO_Polygon::SetMicrotextureRelativeScale(v3, v4);
  if ( *((_DWORD *)v3 + 12) )
    PRO_Polygon::SetMicrotextureRelativeScale(*((PRO_Polygon **)v3 + 12), v4);
}


Code: Select all
void __thiscall PRO_Polygon::SetMicrotextureRelativeScale(PRO_Polygon *this, __int32 a2)
{
  PRO_HW_Polygon::SetMicrotextureRelativeScale(this, a2);
}


Code: Select all
void __thiscall PRO_HW_Polygon::SetMicrotextureRelativeScale(PRO_HW_Polygon *this, __int32 a2)
{
  PRO_HW_Polygon *v2; // ST0C_4@1
  unsigned __int32 v3; // ST14_4@1

  v2 = this;
  v3 = (*((_DWORD *)this + 5) & 0xFF | (unsigned __int16)(((unsigned __int16)*((_DWORD *)this + 4) << 8) & 0xFF00) | ((*((_DWORD *)this + 3) & 0xFF) << 16) | (*((_DWORD *)this + 2) << 24)) & 0xF3FFFFFF | ((a2 & 3) << 26);
  *((_DWORD *)v2 + 2) = *((_DWORD *)v2 + 2) & 0xFFFFFF00 | (unsigned __int16)(HIWORD(v3) >> 16);
  *((_DWORD *)v2 + 3) = *((_DWORD *)v2 + 3) & 0xFFFFFF00 | (v3 >> 16) & 0xFF;
  *((_DWORD *)v2 + 4) = *((_DWORD *)v2 + 4) & 0xFFFFFF00 | ((unsigned __int16)v3 >> 8);
  *((_DWORD *)this + 5) = *((_DWORD *)this + 5) & 0xFFFFFF00 | (unsigned __int8)v3;
}


The SetNPScale ( float np_scale ) as far as I know sets the 24 bit value in header 5, but exactly how it works .. who knows.

If you check out the mipmaps the real3d uses, they rarely if ever go down to 1 pixel. Ie an incomplete mipmap chain for modern hardware. Some of the textures are not mipmapped at all, you can see that in harley on the 2d map overlay. It looks aliased to hell because it doesn't use any mipmapping.

Honestly I see no downsides to letting the hardware do proper mipmapping with ani-isotropic filtering. It's what they would have done originally had they had the horse power. The lighting is also done per pixel, instead of per vertex like the original h/w. Sure this isn't 100% arcade original, it's the same math, just more accurate.
Ian
 
Posts: 879
Joined: Tue Feb 23, 2016 9:23 am

[Patch] MicroTexture

Postby HarryTuttle » Fri Mar 10, 2017 5:51 pm

Edit: moved the patch to fist post.
---
In addition that's also what should happen in the fragment shader (in pseudo-code).

Code: Select all
// http://stackoverflow.com/questions/24388346/how-to-access-automatic-mipmap-level-in-glsl-fragment-shader-texture
// Does not take into account GL_TEXTURE_MIN_LOD/GL_TEXTURE_MAX_LOD/GL_TEXTURE_LOD_BIAS,
// nor implementation-specific flexibility allowed by OpenGL spec

float getMipLevel(in const vec2 coord) // in texel units
{
   vec2  dx_vtc        = dFdx(coord);
   vec2  dy_vtc        = dFdy(coord);
   float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
   float mml = 0.5 * log2(delta_max_sqr);
   return max( 0, mml ); // Thanks @Nims
}

if (microTexture==1)
{
   vec4 tex2Data = texture2D( tex2, gl_TexCoord[0].st * 4.0);
   float lod, minLod, blendFactor;

   lod = getMipLevel(gl_TexCoord[0].st * textureSize(tex2, 0));
   minLod = microTextureScale + 1.0;
   blendFactor = max(0.0, lod - minLod);
   blendFactor = min(1.0, 0.5 + blendFactor);

   tex1Data.rgb = mix(tex2Data.rgb, tex1Data.rgb, blendFactor);
}
Last edited by HarryTuttle on Sat Mar 11, 2017 4:03 am, edited 2 times in total.
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Re: [Patch] MicroTexture

Postby HarryTuttle » Fri Mar 10, 2017 6:40 pm

Ian wrote:If you check out the mipmaps the real3d uses, they rarely if ever go down to 1 pixel. Ie an incomplete mipmap chain for modern hardware. Some of the textures are not mipmapped at all, you can see that in harley on the 2d map overlay. It looks aliased to hell because it doesn't use any mipmapping.

Honestly I see no downsides to letting the hardware do proper mipmapping with ani-isotropic filtering. It's what they would have done originally had they had the horse power.


Exactly! You anticipated another topic I'd like to discuss with you... :D "mipmaps"

I'm not a programmer, i was curious if it's possible to fetch the original 5 mips and "fake" the remaining (i.e. create all white or black textures) and feed to the GPU to satisfy the mip chain requirement. Than with 'GL_TEXTURE_BASE_LEVEL' and 'GL_TEXTURE_MAX_LEVEL' it could be possible to clamp the number of mips so the OpenGL sampler can discard the faked ones.

In SWTrilogy there are some distant ships whose lights are just textures "scintillating" on purpose. With "too much mipmapping" they'd appear blurred/splotched and basically hidden. I'll add some screens in future to show what i mean.

Also looking at the code i noticed that some texture is classified as "single texture", "mipmapped texture", "mip only". I wonder if this condition is respected in Supermodel or if all textures are always auto mipmapped.

The intention is to reproduce as much as possible the original arcade "feeling" to the best. On a second time it could still be possible to "push" the emulated GPU to use anisotropic filter, more mips, etc. by adding a proper configuration option.

Like the video resolution (496x384), it could be nice to render at the original resolution and (bilinear) scale to full screen. Then if needed/liked it could still be possible to simulate an internal higher resolution and/or widescreen aspect.

Also rendering the final composited image (2D + 3D) to texture could allow for some OpenGL post fx, like CRT arcade monitor simulation, etc.

Sometimes accuracy means "less beautiful", but once the internal workings are understood there's always room for the "special" enhancing features.

Anyway this is just to give some ideas for future development. Nothing urgent.

Ian wrote:The lighting is also done per pixel, instead of per vertex like the original h/w. Sure this isn't 100% arcade original, it's the same math, just more accurate.


Regarding lightning: looking at, for example, the shading of the skin in VF3 (especially during the attract intro) it seems that Model3 is doing per pixel lighting and I'm quite sure that specular hi-light is also done per pixel (i.e. Dirt Devils, E.C.A.). I'll get some screenshot alternating per vertex/pixel lighting and comparing them with the original counterpart, then I'll post them in a dedicated topic so we can review them.
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Re: [Patch] MicroTexture

Postby Jiterdomer » Fri Mar 10, 2017 7:45 pm

Thanks for the support! Do you know that after you insert coin and press start in Harley, there's a garbage popped up for a split second while the original board has transition effects? It also happens in LA Machineguns after the briefing screen.
Feel the heartbeat of my machine through this tight seat. I feel every motion of my machine
Image
User avatar
Jiterdomer
 
Posts: 449
Joined: Mon Sep 26, 2011 6:37 pm
Location: Los Angeles, CA

Re: [Patch] MicroTexture

Postby HarryTuttle » Sat Mar 11, 2017 2:45 am

Jiterdomer wrote:Thanks for the support! Do you know that after you insert coin and press start in Harley, there's a garbage popped up for a split second while the original board has transition effects? It also happens in LA Machineguns after the briefing screen.


I didn't notice, will check it out.

Edit:

Do you mean these?

harley1.png
harley1.png (12.91 KiB) Viewed 737 times

lamachine1.png
lamachine1.png (54.22 KiB) Viewed 737 times


They're well known bugs relating the 2D layer. They're present, for example, in ECA in the last seconds of the 'dramatic' intro, during the rapid slideshow sequence. But they're also in the horizontal scrolling text of Scud Race and Magical Track Adventure.

For what i read there isn't currently a fix, maybe a vblank issue between 2D-3D layers and the main program flow.
Last edited by HarryTuttle on Sat Mar 11, 2017 3:21 am, edited 1 time in total.
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Re: [Patch] MicroTexture

Postby Ian » Sat Mar 11, 2017 3:18 am

Also looking at the code i noticed that some texture is classified as "single texture", "mipmapped texture", "mip only". I wonder if this condition is respected in Supermodel or if all textures are always auto mipmapped.


I skip out processing the mipmap section of memory entirely. I don't really know why the hardware doesn't generate mipmaps down to 1x1, there is physical space for it. But as far as I can see the min tile size that is updated is like 8 pixels or something. It's strange also that the minimum texture size you can use is 32x32 pixels. You can't create 16x16 textures with the real3d.

If you don't create a complete mipmap chain, those textures will probably just be black. So you probably wouldn't even need to bother to create dummy ones.

Texturing is a real pain in the ass on the model3 though. If you look at the texture sheet code for the tile invalidation. Some of the games are accessing textures as if they are subtextures of other textures, and using the texture coordinates as such. So if you have 4 textures packed together, worst case scenario we would generate something like 9 textures. This is not just a hypothetical scenario games like spike out actually do this. So if you want to use the proper real3d mipmaps, you need to get your head around this clusterfuck lol.

Regarding lightning: looking at, for example, the shading of the skin in VF3 (especially during the attract intro) it seems that Model3 is doing per pixel lighting and I'm quite sure that specular hi-light is also done per pixel (i.e. Dirt Devils, E.C.A.).


I am about 99% sure the lighting is done per vertex. As far as I know, no hardware existed back then that did calculations per pixel. The exception is the real3d headlight, which is a bit of an oddball. We don't really know the low level details about how it is implemented but if I was to guess I'd say it's probably some fixed function post processing effect on the frame buffer, that also has access to the depth buffer. I wouldn't have thought it would be involved in the actual rasterization stage directly.
Ian
 
Posts: 879
Joined: Tue Feb 23, 2016 9:23 am

Re: [Patch] MicroTexture

Postby HarryTuttle » Sat Mar 11, 2017 3:39 am

Ok, so let's for now put aside the mipmap argument... :D

Ian wrote:I am about 99% sure the lighting is done per vertex. As far as I know, no hardware existed back then that did calculations per pixel. The exception is the real3d headlight, which is a bit of an oddball. We don't really know the low level details about how it is implemented but if I was to guess I'd say it's probably some fixed function post processing effect on the frame buffer, that also has access to the depth buffer. I wouldn't have thought it would be involved in the actual rasterization stage directly.


Yeah, it's strange that hardware from that era had an equivalent of a pixel shader, i just thought that 'cause comparing screenshots i noticed big differences in how light is distributed switching from per-vertex to per-pixel calculations, and the real model3 visually almost matches the per-pixel version.

Spotlights is indeed a post-processing effect accessing the depth buffer. I've tried and succeeded to simulate the 'low level math' involved by means of trial and error, empirical observations and on my graphing best friend: desmos (http://www.desmos.com). I'm not saying that's what's really happening but the final effect is almost identical.

There's also currently a bug relating to spotlight xy coordinates, they've to be treated as signed int16 otherwise you'll brake some spot effect in ECA (and maybe others). But I'll discuss that later in a dedicated post, with the usual patch attached.
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Re: [Patch] MicroTexture

Postby HarryTuttle » Sat Mar 11, 2017 4:32 am

To Ian:

I saw the new commit (thanks also for mentioning me), but there's still a bug. If you don't change the microTexture coordinate to this:

Code: Select all
int xCoords[8] = { 0,   0, 128, 128,   0,   0, 128, 128 };
int yCoords[8] = { 0, 128,   0, 128, 256, 384, 256, 384 };

(the last 4 couples are purely hypothetical, I' haven't seen any games using it, however it doesn't hurt to leave them that way)

You'll end up with this "detail" textures:

daytona2_1.png
Tires "on the rock"
daytona2_1.png (121.39 KiB) Viewed 730 times


and this:

bass1.png
Wrong floor, should be a "sand" texture
bass1.png (112.19 KiB) Viewed 730 times
User avatar
HarryTuttle
 
Posts: 320
Joined: Thu Mar 09, 2017 8:57 am

Next

Return to The Dark Room

Who is online

Users browsing this forum: Bing [Bot] and 1 guest