Page 1 of 2 12 LastLast
Results 1 to 10 of 14
  1. #1
    EmuTalk Member
    Join Date
    Nov 2012
    Posts
    2
    Mentioned
    0 Post(s)

    N64 Emulating Nintendo 64 3-sample Bilinear Filtering using Shaders.

    Hello, I'm sorry if I'm posting this in the wrong section.



    As most of you know, the way bilinear filtering was implemented on the Nintendo64 is different from PC or any other hardware. In order to lower the price of the hardware at the time, Nintendo did their own hack, and used 3 samples to filter the textures, instead of 4. Thanks to this, when the texture is filtered it creates a hexagonal pattern (that I like to call the "rupee" pattern, because it looks like a rupee from Zelda), instead of a diamond pattern (like it happens on PC). This technique is obviously inferior to the 4 sampled bilinear, as it is not a true bilinear filter, but it gives the Nintendo64's blurry mess it's unique "blurryness". Since most of the textures on the Nintendo64 were pretty low-res, this effect was pretty obvious.

    At first, I tried to create a a Hi-res texture pack with the pre-applied filters. It worked, somewhat, but it was hard to apply it to every texture, also the textures didn't tile properly.
    I thought if it would be possible to implement it using a HLSL Shader, and I was able to do one.

    Now, the reason I've posted this here, it because I'm wondering if some dev would like to try to implement this in his plugin.
    I though about posting this in the Direct64 topic, but since this could be implemented on any plugin that could use the programmable pipeline (both DirectX and OpenGL), I decided to post here.

    If the plugin is already using the programmable pipeline, I believe it would be pretty straightforward to implement this.
    In order for the filter to work, it needs two constants: the texture dimensions, both width and height, also the texture sampler must be point (nearest neighbor) instead of linear, since the shader itself is going to interpolate between texels.

    Here's the HLSL code:
    Code:
    float4 n64BilinearFilter( in float4 vtx_color : COLOR, in float2 texcoord_0 : TEXCOORD0) : COLOR {
    	
    	float2 tex_pix_a = float2(1/Texture_X,0);
    	float2 tex_pix_b = float2(0,1/Texture_Y);
    	float2 tex_pix_c = float2(tex_pix_a.x,tex_pix_b.y);
    	float2 half_tex = float2(tex_pix_a.x*0.5,tex_pix_b.y*0.5);
    	float2 UVCentered = texcoord_0 - half_tex;
    	
    	float4 diffuseColor = tex2D(ColorSampler,UVCentered);
    	float4 sample_a = tex2D(ColorSampler,UVCentered+tex_pix_a);
    	float4 sample_b = tex2D(ColorSampler,UVCentered+tex_pix_b);
    	float4 sample_c = tex2D(ColorSampler,UVCentered+tex_pix_c);
    	
    	float interp_x = modf(UVCentered.x * Texture_X, Texture_X);
    	float interp_y = modf(UVCentered.y * Texture_Y, Texture_Y);
    
    	if (UVCentered.x < 0)
    	{
    		interp_x = 1-interp_x*(-1);
    	}
    	if (UVCentered.y < 0)
    	{
    		interp_y = 1-interp_y*(-1);
    	}
    	
    	diffuseColor = (diffuseColor + interp_x * (sample_a - diffuseColor) + interp_y * (sample_b - diffuseColor))*(1-step(1, interp_x + interp_y));
    	diffuseColor += (sample_c + (1-interp_x) * (sample_b - sample_c) + (1-interp_y) * (sample_a - sample_c))*step(1, interp_x + interp_y);
    
        return diffuseColor * vtx_color;
    }
    The pixel interpolation algorithm I got from .oisyn, from this forum:

    devmaster.net/forums/topic/13338-bilin-filtering-with-3-samples/

    Here's a screenshot: (you'll have to copy and paste the URL, because I couldn't post this link here)

    i.imgur.com/oRETY.png

    On the left is the standard bilinear filtering implementation, on the right is how Nintendo implemented it in the Nintendo 64.
    This is, of course, not inside an emulator, but inside nVidia's FX Composer, where I was coding it. Still, the effect is just like it would look like on the real hardware.

    And I understand most people might think of this as a downgrade, and that there is no reason to implement this.
    But I think that this is something unique to the Nintendo64, I mean, really, you won't see this kind of filtering anywhere else.
    It really gives that "N64" feeling, at least for me it does. It is less smooth, a little more rough than the proper bilinear filter, and I think it gives a little more texture to the game.

    So, what do you guys think?

  2. #2
    EmuTalk Member
    Join Date
    Aug 2007
    Location
    Moscow, Russia
    Posts
    50
    Mentioned
    0 Post(s)
    The exact algorithm the RDP uses for this triangular filtering has been reverse-engineered in MAME/MESS. See method N64TexturePipeT::Cycle() here: http://mamedev.org/source/src/mame/v...dptpipe.c.html
    The RDP decides which three texels out of four to sample depending on the fractional part of a texture coordinate. If I understand your code correctly (having myself zero knowledge of HLSL), you haven't implemented this. Also, the precision of these fractional parts used as interpolation factors is only 5 bits, and everything is done in fixed-point arithmetics.
    Anyway, just my two cents. And yeah, the N64 is famous for its jagged texture patterns caused by this filter.
    Last edited by angrylion; November 8th, 2012 at 22:02.

  3. #3
    EmuTalk Member
    Join Date
    Nov 2012
    Posts
    2
    Mentioned
    0 Post(s)
    I didn't know that MAME had this, thanks.

    Originally, based on the algorithm in this topic (that's not the real one though, just something that looks close), it uses an if to detect what pixels to sample,
    since (based on my outdated knowledge) that Ifs are no good in shaders, I've done it in a more hacky way:
    Code:
    diffuseColor = (diffuseColor + interp_x * (sample_a - diffuseColor) + interp_y * (sample_b - diffuseColor))*(1-step(1, interp_x + interp_y));
    	diffuseColor += (sample_c + (1-interp_x) * (sample_b - sample_c) + (1-interp_y) * (sample_a - sample_c))*step(1, interp_x + interp_y);
    I use the step() function (Intrinsic HLSL function) to black out the bottom right after interpolating, then, I black out the top-left when interpolating the bottom-right pixel, then, I sum up both of them together.
    This gives the same effect. I tested both using if and this method and the results were almost the same, if there is any difference, it was pretty small.
    Last edited by ArthurCarvalho; November 8th, 2012 at 21:49.

  4. #4
    EmuTalk Member
    Join Date
    Aug 2007
    Location
    Moscow, Russia
    Posts
    50
    Mentioned
    0 Post(s)
    Ah, thanks for explaining, I should have read your code more carefully.

  5. #5
    EmuTalk Member
    Join Date
    Jan 2014
    Posts
    1
    Mentioned
    0 Post(s)
    hi ArthurCarvalho.

    your idea has just been implemented into mupen64plus-libretro, and the result looks really great !! it is a definitive improvement to standard bilinear filtering for N64 games in my opinion.

    it will become available with the next release of retroarch, but you can already get the source from git and compile it yourself if you want :

    https://github.com/libretro/mupen64plus-libretro

    you can toggle between bilinear and 3-sample filtering in "core options" in retroarch's main menu (F1).
    Last edited by aliaspider; January 31st, 2014 at 12:31.

  6. #6
    EmuTalk Member
    Join Date
    Jan 2006
    Posts
    10
    Mentioned
    0 Post(s)
    Here is an ingame comparison -

    http://imgur.com/a/M9nRP

    Top shows the game with 3-sample filtering applied through a shader, the second shot shows the game running with plain hardware bilinear.

  7. #7
    Texture Pack Invader NES_player4LIFE's Avatar
    Join Date
    Nov 2005
    Location
    Earth
    Posts
    2,168
    Mentioned
    20 Post(s)
    Looking good.
    -NES
    We are in the process of archiving all qualifying texture packs!
    Contact me via PM to have your N64 texture pack hosted on Emulation64.com!
    Having a hard time loading Large packs? Be sure to patch your emulator.
    Can't load .DAT or .HTC archives? Look no further then this shiny Tutorial, Android users may use this Tutorial.

      Spoiler:

  8. #8
    EmuTalk Member
    Join Date
    Mar 2012
    Posts
    998
    Mentioned
    5 Post(s)
    This was posted (and revived from) over a year ago.

  9. #9
    Texture Pack Invader NES_player4LIFE's Avatar
    Join Date
    Nov 2005
    Location
    Earth
    Posts
    2,168
    Mentioned
    20 Post(s)
    Quote Originally Posted by Fanatic 64 View Post
    This was posted (and revived from) over a year ago.
    With relevant information thus it was not closed.
    -NES
    We are in the process of archiving all qualifying texture packs!
    Contact me via PM to have your N64 texture pack hosted on Emulation64.com!
    Having a hard time loading Large packs? Be sure to patch your emulator.
    Can't load .DAT or .HTC archives? Look no further then this shiny Tutorial, Android users may use this Tutorial.

      Spoiler:

  10. #10
    EmuTalk Member
    Join Date
    Mar 2012
    Posts
    998
    Mentioned
    5 Post(s)
    ...Well yeah. I was half asleep when I wrote that. Maybe this could be implemented in some plugin? Would anybody want to propose it to Gonetz?

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •