April 24, 2024, 07:20:38 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


3D Sprites not being positioned accurately...

Started by Kale, November 08, 2006, 03:44:50 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Kale

If you run this code (you'll need an image):

global sub main()
{
C3DScreen Screen;
C3DCamera Camera;
CDirectInput DirectInput;
C3DSprite MySprite;

float Step = 0.1f;
float SpritePosition = 0.0f;

Screen.CreateFullScreen(1280, 1024, 32, true);
DirectInput.Init(Screen);
Camera.Create(Screen);

MySprite.Load(Screen, GetStartPath() + "LogoSmall.png", 128, 128, 1, 0);
MySprite.SetPosition(0, 0);

while (!DirectInput.KeyDown(DIK_ESCAPE))
{
Screen.Clear(RGBA(32, 23, 30, 255));
Screen.BeginScene(Camera);

SpritePosition = SpritePosition + Step;
MySprite.SetPosition(0, SpritePosition);

Screen.Begin2D();
MySprite.Draw();
Screen.End2D();

Screen.RenderScene();
}
}


You will see that the sprite travels down the screen into infinity. But if you look closely at the sprite's movement, you can see that it actually jumps by a pixel at a time even though i am using floats to accurately describe it's position. Is there a reason for this? maybe a limitation of some sort? I'm sure i read about this very same issue on another programming forum for another language and the author provided code to get it to run smoothly instead of pixel jumps. I'll keep trying to find it...

Ionic Wind Support Team

How would it work otherwise?  You can't draw half a pixel.  Even though you're using floats ultimately the display is a finite integer grid and the graphics card can't draw a pixel at 1.5 x 1.5.  Depending on the rounding mode it will end up either at 1.0x1.0 or 2.0x2.0
Ionic Wind Support Team

Kale

November 09, 2006, 03:34:40 AM #2 Last Edit: November 09, 2006, 03:56:43 AM by Kale
Quote from: Paul Turley on November 08, 2006, 04:21:36 PM
How would it work otherwise?

Here's a link to a small program written in another language showing the problem. The top graphic shows Aurora's sprite movement while the bottom shows how i would of expected it to move.

http://www.kalekold.net/Aurora/SpriteTest.exe

Is this standard behaviour? It can't be a limitation on DirectX, as this test exe uses DirectX.

Ionic Wind Support Team

Don't know.

It looks like the pixels of the bottom sprite are being 'modified' through some sort of interpolation, looks really weird on my screen almost to the point of a color shift on the edges.  Which is the effect you sometimes see using a textured 3D object, such as a quad and a two color texture.

However.... if I just load a sprite here, using your code in the first post, I don't see anywhere near a 'jump' like your executable is demonstrating as the top sprite.  Even at a low resolution like 800x600x32.  Turning off vsync and the sprite makes a smooth transition down the screen.  Changed it to accross the screen and the results where the same.

The sprite I used was the caveman one, just displaying the first image:

MySprite.Load(Screen, GetStartPath() + "media\\cavemen.dds", 64, 64,16);

I'll look into it more tomorrow, time for sleep.

Paul.,
Ionic Wind Support Team

Kale

Ok, thanks. I'll take another look and try some more examples. :)

Kale


J B Wood (Zumwalt)


Kale

Here is the Purebasic source of the above test program, maybe to help you discover the prob:


UsePNGImageDecoder()

Structure vertex
    sx.f
    sy.f
    sz.f
    rhw.f
    color.l
    specular.l
    tu.f
    tv.f
EndStructure

  Structure PB_Sprite3D
     Texture.l              ; DirectX7 surface
     Vertice.vertex[4] ; The 4 vertices for the rectangle sprite
     Width.w
     Height.w
  EndStructure

InitSprite()
InitSprite3D()

OpenScreen(640,480,32,"example")

CatchSprite(0,?bitmap,#PB_Sprite_Texture | #PB_Sprite_AlphaBlending)
CreateSprite3D(0,0)
ZoomSprite3D(0,64,64)
CreateSprite3D(1,0)
ZoomSprite3D(1,64,64)

*sprite.PB_Sprite3D=IsSprite3D(1)

Sprite3DQuality(1)

x.f=0

Repeat

  x=x+0.05
  If x>576
    x=0
  EndIf

  f.f=x-Round(x,0)

  *sprite\Vertice[0]\sx=f
  *sprite\Vertice[1]\sx=64+f
  *sprite\Vertice[2]\sx=f
  *sprite\Vertice[3]\sx=64+f
   
  ClearScreen(RGB(0,0,64))
  Start3D()
    DisplaySprite3D(0,x,0,255)     
    DisplaySprite3D(1,Round(x,0),64,255)
  Stop3D()

  FlipBuffers()

Until GetAsyncKeyState_($1B)

CloseScreen()

End

DataSection

bitmap:
IncludeBinary("test.png")

EndDataSection

J B Wood (Zumwalt)

November 20, 2006, 10:34:09 AM #8 Last Edit: November 20, 2006, 11:07:08 AM by Jonathan (zumwalt) Wood
Kale, take a look at this, it something I whipped up using a modfied version of the 3d space invaders images that are on this board.
I plan on finishing this by this weekend come hell or high water, but see if this runs smooth for you.
Warning, the saucer can reach mach speed if you watch it long enough.

http://www.gamedevonline.com/subsite/demos/animation2d.zip

edit: updated it with speed limiters and stepping routine

Kale

November 20, 2006, 11:22:13 AM #9 Last Edit: November 20, 2006, 11:34:32 AM by Kale
Quote from: Jonathan (zumwalt) Wood on November 20, 2006, 10:34:09 AM
Kale, take a look at this, it something I whipped up using a modfied version of the 3d space invaders images that are on this board.
I plan on finishing this by this weekend come hell or high water, but see if this runs smooth for you.
Warning, the saucer can reach mach speed if you watch it long enough.

http://www.gamedevonline.com/subsite/demos/animation2d.zip

edit: updated it with speed limiters and stepping routine

Yep, that seems to be smoother. Can you post the source code please of this little demo? Is it as smooth ast slower speeds?

J B Wood (Zumwalt)

November 20, 2006, 11:33:29 AM #10 Last Edit: November 20, 2006, 11:38:32 AM by Jonathan (zumwalt) Wood
Here is the objects for this part of the little demo..

edit: sorry had a comment after the
else if

and it didn't like it here it is updated


also... heh...
Create a project, call it what you want, add the basic.src to it.
In resources add the 2 images, label 1 of them smallsaucer and add the saucer image, label the other background and add the background image, then compile..

Kale

Ta, but that code doesn't run. Is this the code that produced the above demo? Can you provide a working piece of code? ;D Ta.

J B Wood (Zumwalt)

November 20, 2006, 11:45:57 AM #12 Last Edit: November 20, 2006, 11:58:08 AM by Jonathan (zumwalt) Wood
Any luck yet Kale?
Yes it is as smooth at slower speeds.

Kale

Quote from: Jonathan (zumwalt) Wood on November 20, 2006, 11:45:57 AM
Any luck yet Kale?
Yes it is as smooth at slower speeds.

Nah, it's just the same. Run this piece of code:

Quote
#typedef UINT unsigned int;
#define screen_width 640
#define screen_height 480

DECLARE IMPORT,timeGetTime(),UINT;
declare import, GetLastError(),DWORD;
declare import, DEBUG alias OutputDebugStringA(string str);

struct sInvaders
{
   float x,y;             /* upper left corner of the Invaders */
   string resourceName;    /* Name of the Invaders resource */      
   int Visible;         /* Set visible value */
   float speed;         /* speed of movement */
   float drop;            /* rate of drop */
   float maxSpeed;         /* maximum object speed */
   float minSpeed;         /* minimum object speed */
}

/* main routine */
global sub main()
{
   C3DScreen Screen;
   C3DCamera Camera;
   CDirectInput DirectInput;
   #break;
   float Step = 0.5f;
   float SpritePosition = 0.0f;
   
   C3DSprite InvadersSprite,BackgroundSprite;
   CPointerList *InvadersList;
   
   Screen.CreateWindowed(0,0,screen_width,screen_height,AWS_CAPTION|AWS_VISIBLE|AWS_SIZE,0,"Flying Invaders - By Zumwalt",NULL,true);
   Camera.Create(Screen);
   DirectInput.Init(Screen);
   
   /* list to hold our space invaders */
   InvadersList = new(CPointerList,1);
   InvadersList->Create();

   float fadjust,fTarget;
   fTarget = 1.0f / 60.0f * 1000.0f;
   fAdjust = 1.0f;

   /* impliment the list and setup 1 invader */
   sInvaders *pInvaders = NEW(sInvaders,1);
   if(pInvaders == NULL)
   {
      MessageBox(NULL,"Failed to create Invaders","Error");
   }
   InvadersList->Add(pInvaders);
   pInvaders->x = 0;
   pInvaders->y = 0;
   pInvaders->resourceName = "SmallSaucer.bmp";
   pInvaders->visible = TRUE;
   pInvaders->speed=0.1f;
   pInvaders->drop=10.0f;
   pInvaders->minSpeed=1.0f;
   pInvaders->maxSpeed=5.0f;

   /* general items for the scene */
   int fps = 0;
   int startTime;
   pointer pos;
   int scrollState=0;

   /* get a handle of our first and currently only invader */
   pos = InvadersList->GetFirst();
   pInvaders = InvadersList->GetData(pos);
   pos = InvadersList->GetNext(pos);
   DEBUG(pInvaders->resourceName);

   /* set our backdrop */
   Backgroundsprite.Load(screen,"Background.bmp",screen_height,screen_width);   
   Backgroundsprite.SetPosition(0,0);

   /* load our only invader into the InvadersSprite object */
   InvadersSprite.Load(Screen,pInvaders->resourceName,27, 45);
   
   /* game loop */
   while (!DirectInput.KeyDown(DIK_ESCAPE))
   {
      /* clear the screen buffer */
      Screen.Clear(RGBA(32, 23, 30, 255));
      Screen.BeginScene(Camera);
   
      /* check to see if the invader has reached the right edge */
      if (pInvaders->x+47 > Screen_Width)
      {   
         scrollState=1;
         if (pInvaders->speed < pInvaders->maxSpeed)
            pInvaders->speed += Step;
         pInvaders->y += pInvaders->drop;
      }
      else if (pInvaders->x < 0)
      {
         /* check to see if the invader is back to the left edge */
         scrollState=0;
         if (pInvaders->speed < pInvaders->maxSpeed)
            pInvaders->speed += Step;
      }

      /* handle scroll state of invader, either go left or go right */
      switch (scrollState)
      {
         case 0:
               pInvaders->x=pInvaders->x + pInvaders->speed;
         case 1:
               pInvaders->x=pInvaders->x - pInvaders->speed;
      }
      
      /* set the invaders position, draw the background first, then draw the invader */
      InvadersSprite.SetPosition(pInvaders->x,pInvaders->y);
      Screen.Begin2D();
      Backgroundsprite.Draw();
      InvadersSprite.Draw();
      Screen.End2D();
      Screen.RenderScene();
      fAdjust = (timeGetTime() - startTime) / fTarget;
   }
   /* clean up our mess */
   Screen.CloseScreen();
   InvadersList->RemoveAll(true);
   delete InvadersList;
}

J B Wood (Zumwalt)

Probably has to do with the minimum fraction you can have for the location per render?
0.4f seems fine but I don't know how slow you want to go..

I don't know what else to tell you, I don't know enough about the back end to solve this one.

Ionic Wind Support Team

Might be driver related, or the fact I don't allow linear filtering on sprite textures since it makes the edges look fuzzy.  But As I posted I don't see the problem he originally posted about.  All my sprites are smooth at any speed.

Ionic Wind Support Team

J B Wood (Zumwalt)

I see it if I reduce the minimum speed to 0.3 or less.
Change the following in my code:

float Step = 0.1f;
pInvaders->speed=0.1f;
pInvaders->drop=0f;
pInvaders->minSpeed=0.1f;

You will see it then.

Kale

Yeah, you can see it clearly in the exe i posted.

Basically, instead of being confined to an integer grid of the screen 0, 1, 2, 3, etc... i would like to see it use 0.1, 0.2, 0.3, etc and (filter?) and position the sprite accordingly. I don't know that much about directX but this effect has been seen by others on the PB board when dealing with slow moving sprites too. The code that i posted does show that it is possible to get around but Im still scratching my head to understand how it accomplishes it. :)

Ionic Wind Support Team

Not high on my list at the moment.  I'll add a way to set linear filtering on and off.
Ionic Wind Support Team