pixies - sprites with zero filtering
Blitz3D Forums/Blitz3D Programming/pixies - sprites with zero filtering
| ||
The following was created while fixing my original overlay system in code archives. It demonstrates use of sprites to achieve perfect pixel-texel mapping which results in zero filtering / blurring. Odd sized textures and zoomed cameras may require some tweaks. ; pixies.bb ; by simon armstrong ; pixies are pixel perfect sprite overlays ; LoadPixie(camera,file$) ; CreatePixie(camera,texture) ; returns a sprite parented to a camera ; with following features ; 1:1 pixel-texel scale for zero filtered sharp overlays ; position pixies in screen coordinates ; 20.8.2003 untested with odd sized sprites displaywidth=800 displayheight=600 Graphics3D displaywidth,displayheight cam=CreateCamera() CameraRange cam,.1,1000 pixie=LoadPixie(cam,"simon2.bmp") ;800,600, While Not KeyHit(1) PositionEntity pixie,MouseX(),MouseY(),0 RenderWorld UpdateWorld TurnEntity cam,1,2,0 ;test texel drift Flip Wend End Function LoadPixie(camera,file$) texture=LoadTexture(file) Return CreatePixie(camera,texture) End Function Function CreatePixie(camera,texture) ; change these for viewports viewwidth=GraphicsWidth() viewheight=GraphicsHeight() ; find existing pixiespace parented to camera magic=0 n=CountChildren(camera) For i=1 To n If EntityName(GetChild(camera,i))="pixiespace" magic=GetChild(GetChild(camera,i),1) EndIf Next If magic=0 magic=CreatePivot(camera) NameEntity(magic,"pixiespace") aspect#=Float(viewheight)/viewwidth PositionEntity magic,-1,aspect,1 scale#=2.0/viewwidth ScaleEntity magic,scale,-scale,-scale magic=CreatePivot(magic) PositionEntity magic,-.5,-.5,0 EndIf ; create sprite from texture as child of magic overlay sprite=CreateSprite() ;,magic ??? EntityParent sprite,magic ;cludge for blitz bug in createsprite(parent) brush=CreateBrush() BrushFX brush,1 BrushTexture brush,texture PaintEntity sprite,brush FreeBrush brush SpriteViewMode sprite,2 scale#=1.0/viewwidth ScaleSprite sprite,TextureWidth(texture)*scale,TextureHeight(texture)*scale Return sprite End Function |
| ||
The displayed sprite is twice larger than the the file bitmap ? |
| ||
Not in my tests, what size image are you using? |
| ||
Impressive - I didn't think pixel-perfect sprites were possible to be honest, and after looking at your code, I'm still unsure as to what exactly your magic trick is to make them unfiltered. Anyway, will probably be using this code for my Super Hamster Ball editor, and possibly the game too, so thanks in advance! |
| ||
His "magic trick" is twofold. 1. The sprite is at the same resolution as the size of the region it covers at a specific resolution. Ie, a 256x256 sprite covers a 256x256 pixel region, regardless of the screen resoltion. In other words, at higher resoltions, your HUD objects will be smaller. 2. He offsets the object by half a pixel towards the top left of the screen. The reason for this has to do with how bilinear filtering works. Unless you offset by half a pixel, then each pixel is actually displaying a point in the center of 4 pixels. So every pixel's getting averaged with the 4 colors that surround it. The result is that if you took a texture which is vertical or horizontal white and black lines, then unless you offset it like this, what you will actually see on the screen is a solid 50% gray square. Of course there's one little problem with doing this, I think and that is that there may be a one pixel wide border outside your 640x480 region on the right and bottom of the screen. Though I have not actually tested this to see if that is what you get or not. I do know what if you offset towards the bottom right instea dof towards the upper left you get a border on the top and left sides of the screen. |
| ||
Cool, I've been experimenting trying to get this effect for quite a while. Thanks for your help! |
| ||
Ah, I see. Thanks for the explanation sswift. |
| ||
uhm...![]() i obtain simon.bmp with the saveimage command. Here the file |
| ||
Ouch, yes, blitz is scaling/blurring textures to nearest power of 2 internally (your bitmap ends up as 256x64 texture in blitz). I can fix this soon by copying pixie images to a large texture page, which I was going to do for an optimized version that uses a single surface collection of quads. In the meantime, stick with 32,64,128,256 wide bitmaps for your pixies and you should be ok. |
| ||
All fixed, no it will still be broken for odd sizes, but of for non power of 2...; pixies.bb ; by skidracer ; pixies are pixel perfect sprite overlays ; LoadPixie(camera,imagefile$) ; returns a sprite parented to a camera ; with following features ; 1:1 pixel-texel scale for zero filtered sharp overlays ; position pixies in screen coordinates ; 20.8.2003 untested with odd sized sprites ; 21.8.2003 modified to handle odd textures displaywidth=800 displayheight=600 Graphics3D displaywidth,displayheight cam=CreateCamera() CameraRange cam,.1,1000 pixie=LoadPixie(cam,"quitter.bmp") While Not KeyHit(1) PositionEntity pixie,MouseX(),MouseY(),0 RenderWorld UpdateWorld TurnEntity cam,1,2,0 ;test texel drift Flip Wend End Function LoadPixie(camera,file$) ; load squared texture texture=LoadTexture(file) width=TextureWidth(texture) height=TextureHeight(texture) image=LoadImage(file) iwidth=ImageWidth(image) iheight=ImageHeight(image) If iwidth<>width Or iheight<>height buffer=TextureBuffer(texture) ibuffer=ImageBuffer(image) For y=0 To height-1 For x=0 To width-1 WritePixel x,y,ReadPixel(x,y,ibuffer),buffer Next Next ScaleTexture texture,Float(width)/iwidth,Float(height)/iheight ; will blitzmax need float()? width=iwidth height=iheight EndIf FreeImage image ; change these for viewports viewwidth=GraphicsWidth() viewheight=GraphicsHeight() ; find existing pixiespace parented to camera magic=0 n=CountChildren(camera) For i=1 To n If EntityName(GetChild(camera,i))="pixiespace" magic=GetChild(GetChild(camera,i),1) EndIf Next If magic=0 magic=CreatePivot(camera) NameEntity(magic,"pixiespace") aspect#=Float(viewheight)/viewwidth PositionEntity magic,-1,aspect,1 scale#=2.0/viewwidth ScaleEntity magic,scale,-scale,-scale magic=CreatePivot(magic) PositionEntity magic,-.5,-.5,0 EndIf ; create sprite from texture as child of magic overlay sprite=CreateSprite() EntityParent sprite,magic ;cludge for blitz bug in createsprite(parent) brush=CreateBrush() BrushFX brush,1 BrushTexture brush,texture PaintEntity sprite,brush FreeBrush brush SpriteViewMode sprite,2 scale#=1.0/viewwidth ScaleSprite sprite,width*scale,height*scale Return sprite End Function |
| ||
Oh, good stuff. Looking forward to trying this later, as I didn't think it was possible either! I still say Death to the Pixies, though. |
| ||
This has been very helpful guys, thanks. My only curiousity, as the code is a bit beyond me, is how I can modify this so I can change my camera zoom level. Any thoughts? Tyler |
| ||
Use a second, static camera far away from the main scene and render it on top of the main camera. This way the main camera's zoom is irrelevant. Something like this .... GUIcamera = CreateCamera() CameraClsMode GUIcamera,False,True CameraRange GUIcamera, .1,5 PositionEntity GUIcamera, 10000,10000,10000 EntityOrder GUIcamera,-999 Then use GUIcamera instead of Camera in the pixie routines. Stevie |
| ||
I use multiple cameras in my stuff. Rather than keeping stuff 'far away' which is potentially problematic I keep EVERYTHING hidden by default and show stuff only for rendering. HUD items might be parented to a pivot called HUD_SWITCH (or even the hud camera) to make this easy.showentity GAME_SWITCH ;pivot which is the parent of everything in game, including the main camera renderworld() hideentity GAME_SWITCH showentity HUD_SWITCH renderworld() hideentity HUD_SWITCH or better still just have a function that takes ths switch as a parent function do_render_world(switch) showentity (switch) renderworld() hideentity (switch) end function |
| ||
has there been anything added to the code archives that is better than this? its been 3 years |