Solved

3d rotate of 2d image

Posted on 1998-12-24
31
754 Views
Last Modified: 2012-06-27
How to rotate 2d!!! image in 3d (rotate it's surface)
0
Comment
Question by:jack_p50
  • 12
  • 6
  • 5
  • +4
31 Comments
 
LVL 1

Expert Comment

by:The_Brain
ID: 1216682
you will have to elaborate this is terribly unclear :)  just set out what you want to achieve.  

no doubt that you are going to need trigs.
Merry Christmas
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216683
I have image (BMP for example). I want to rotate it's surface in 3d (i.e. :
surface : -----------
             |          |
             -----------
image is on it; i want to do so that transformed image will fit in new surface, i.e.
         ----
         |   ---
         |      ---
         |         ---
         ---------------
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216684
I have image (BMP for example). I want to rotate it's surface in 3d (i.e. :
surface : -----------
             |          |
             -----------
image is on it; i want to do so that transformed image will fit in new surface, i.e.
         ----
      --     ---
    --          ---
  --              ---
(same then, i'm too lazy to draw it)
It's the same as 2d rotate, but i want surface to be 3d rotated    
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1216685
Still not exactly sure what you need...

Let's say you rotate the image in 3D so it looks like this when see from aside...

front side of image ->   |     <- Back side of image...
                                        |
                                        |

Is this what you wanna do??

-Viktor
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216686
Yes. I.e. when rotating on 90 degrees by x-axis or y-axis, image will convert to line.
0
 
LVL 1

Expert Comment

by:The_Brain
ID: 1216687
hmmm,  
this is a bit tricky
I could try to work it out.

If I get it, can you raise the points just a little, don't wanna sound greedy but this is really difficult.
:)
0
 
LVL 1

Expert Comment

by:The_Brain
ID: 1216688
perspective or no perspecitive
(hope fully no perspective. :)
0
 
LVL 1

Expert Comment

by:The_Brain
ID: 1216689
This is what I have worked out so far

The new height of the object if you tip it back x degrees
is AB is the height.

AB= DC.Cos(x) = new Height;
for the width
AB2 = DC2.Cos(y) = New Width;

where DC is the orig Height 2. width.

but that won't really help the image, that is just the dimentions for in which the new image will fit.
   
0
 
LVL 1

Expert Comment

by:The_Brain
ID: 1216690
Ok, I just thought about this.

Every pixel has a position on this picture.

every pixel should be stored in buffer with their original cordinates.

now the image is cleared. (this requires some mega processing.
but You can really speed it up by doing This)


Give the Picture a record:  (pascal)
or just keep 2 sets of arrays open.

Set is a record type which I am very unfimiliar with exept using their members;

Record (do what ever you have to do)
 Set
   Begin
    Bx,By :integer;
    Ex,Ey :integer;
end;

Rows : array[1..Height] of Set;
Column : array[1..Width] of Set;


Begin
  now this is not code form, but this what you have to do.

 

 

end.

But I to work on that. good luck,
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1216691
Try this in Delphi....It's not what you want but it's fun :))
==================
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

const
      pts = 3;

type TPoints = array [1..pts] of TPoint;

const
      Orig : TPoints = (
         (X : -100; Y : -50),
         (X :  100; Y : -50),
         (X :    0; Y : 100)
      );

var
      ang : double;
   Now : TPoints;

procedure PlotPoints(points : TPoints);
var
      i : integer;
   trans : TPoints;
begin
      for i := 1 to pts do begin
            trans[i].x := points[i].x + (Form1.Width shr 1);
         trans[i].y := points[i].y + (Form1.Height shr 1);
   end;
   Form1.Canvas.Polygon(trans);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
      i : integer;
   old : TPoints;
begin
      Old := Now;
      for i := 1 to pts do begin
            Now[i].x := round(Orig[i].x * cos(ang) - Orig[i].y * sin(ang));
      Now[i].y := round(Orig[i].x * sin(ang) + Orig[i].y * cos(ang));
   end;
   Canvas.Brush.Style := bsClear;
   Canvas.Pen.Color := Color;
   PlotPoints(Old);
   Canvas.Pen.Color := clBlack;
   PlotPoints(Now);
        ang := ang + 0.1;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
      ang := 0;
end;

end.
==========
-Viktor
--Ivanov
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216692
I can adjust points only a little (lack of them). Please give me some transformation formulas. I think, better rotate is so
  for y:=0 to maxy do
    for x:=0 to maxx do
      putpixel2Destbufer(x,y,getSourceColor(x,y,rotation_params));

It just goes on each point of Destination image and sees which Source point corresponds to it (rotating dest. coords back) and then plotting a point with color of such coords.
For 2d rotate it's easy, but I don't know how to do getSourceColor for 3d rotate.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1216693
The 3D color is easy also..
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216694
Give me this func., please
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1216695
ok, in DOS (VGA) when you put a pixel on the screen you do this...

NewX = (X * 256) / (Z - ZOff) + XOff
NewY = (Y * 256) / (Z - ZOff) + YOff

where x, y, and z are the 3D points... Now when you plot the NewX and NewY on the screen it will be in prespective.. The color depend on you.. YOu should decide how to work out the color....

Ok, when you put the pixel on the screen in 3D you do this...

PutPixel(NewX, NewY, Color);

and when you get the color you do this..

Color := GetPixel(NewX, NewY);

where NewX and NewY are the results from the formulas we did before...

Now you know how to get the color in 3D....

Here is a fast starfield in 3D in C++, if you want me to convert it to Pascal let me know... It's quite easy,,,,
==============
#include <conio.h>
#include <stdlib.h>
#include <utils.h>    //This is my own .H file that declares the types like unsgined char BYTE
#include <mem.h>
#include <time.h>
#include <dos.h>
#include <iostream.h>

#define num 200     //Number of stars
#define speed 7    //This speed that in which the stars are moving
#define vga 0xA000   //The address of VGA

typedef struct {
      int x;
      int y;
      int z;
} _3D;

typedef struct {
      int x;
      int y;
} _2D;

void pal(BYTE, BYTE, BYTE, BYTE);
void SetMode(WORD);
void Init();
void CalcStars();
void putpixel(int, int, BYTE, WORD);
void DrawStars();
void ClearStars();
void MoveStars(bool);
void WaitRetrace();
void GoThroughSpace();
void DisplayInfo();

_3D stars[num];
_2D pos[num];

int main()
{
      time_t t;
      srand(unsigned(time(&t)));
      DisplayInfo();
      SetMode(0x0013);
      Init();
      GoThroughSpace();
      SetMode(0x0003);
      return 0;
}

void SetMode(WORD mode)
{
      asm mov ax, [mode]
      asm int 10h
}

void pal(BYTE col, BYTE r, BYTE g, BYTE b)
{
      outp(0x3c8, col);
      outp(0x3c9, r);
      outp(0x3c9, g);
      outp(0x3c9, b);
}

void Init()
{
      for (int i = 0; i < num; i++) {
            do {
                  stars[i].x = rand() % 320 - 160;
                  stars[i].y = rand() % 200 - 100;
                  stars[i].z = i + 1 ;
            } while (!stars[i].x && !stars[i].y);    //until stars.x and stars.y <> 0
      }
//Set a few colors' RGBs
      pal(19, 5, 5, 5);
      pal(18, 25, 25, 25);
      pal(17, 32, 32, 32);
      pal(16, 63, 63, 63);
}

void CalcStars()
{
      int x, y;
      for (int i = 0; i < num; i++) {
            x = ((stars[i].x << 7) / stars[i].z) + 160;
            y = ((stars[i].y << 7) / stars[i].z) + 100;
//The following two lines declare the NewX and NewY from the example I gave you above...
            pos[i].x = x;
            pos[i].y = y;
      }
}

void putpixel(int x, int y, BYTE col, WORD where)
{
      asm {
            mov ax, [where]
            mov es, ax
            mov bx, [x]
            mov dx, [y]
            mov di, bx
            mov bx, dx
            shl dx, 8
            shl bx, 6
            add dx, bx
            add di, dx
            mov al, [col]
            stosb
      }
}

void DrawStars()
{
//Draw the stars and see what is their Z coordinate so you can calculate the color
      int x, y;
      for (int i = 0; i < num; i++) {
            x = pos[i].x;
            y = pos[i].y;
            if ((x > 0) && (x < 320) && (y > 0) && (y < 200)) {
                  if (stars[i].z > 400) putpixel(x, y, 18, vga);
                  else if (stars[i].z > 300) putpixel(x, y, 18, vga);
                  else if (stars[i].z > 200) putpixel(x, y, 17, vga);
                  else if (stars[i].z > 100) putpixel(x, y, 17, vga);
                  else putpixel(x, y, 16, vga);
            }
      }
}

void ClearStars()
{
//Clear the stars
      for (int i = 0; i < num; i++)
            putpixel(pos[i].x, pos[i].y, 0, vga);
}

void MoveStars(bool foreward)
{
//Move the stars towards you...
      if (foreward) {
            for (int i = 0; i < num; i++) {
                  stars[i].z -= speed;
                  if (stars[i].z < 1)
                        stars[i].z = num;
            }
      } else {
//Move the stars in opposite way...
            for (int i = 0; i < num; i++) {
                  stars[i].z += speed;
                  if (stars[i].z > num)
                        stars[i].z = 1;
            }
      }
}
//Wait vertical retrace
void WaitRetrace()
{
      asm mov dx,3DAh
 l1:
      asm in al,dx
      asm and al,08h
      asm jnz l1
 l2:
      asm in al,dx
      asm and al,08h
      asm jz  l2
}

void GoThroughSpace()
{
//Repeat moving the stars until the ESC key is pressed
      char ch;
      CalcStars();
      DrawStars();
      do {
            WaitRetrace();
            ClearStars();
            CalcStars();
            WaitRetrace();
            DrawStars();
            if (kbhit())
                  ch = getch();
            ch == 32 ? MoveStars(FALSE) : MoveStars(TRUE);
      } while (ch != 27);
}

void DisplayInfo()
{
//Display some info about the keys you use/...
      clrscr();
      cout << "This is a simple demo of a starfield.\n\n"
              << "Space Bar     ->  Moves stars backwards.\n"
              << "Any other key ->  Moves starts towards you.\n"
              << "Esc           ->  Exit";
      getch();
}
==================
The real formula is this,,,

void CalcStars()
{
      int x, y;
      for (int i = 0; i < num; i++) {
//The following 2 lines calculate the formula....
            x = ((stars[i].x << 7) / stars[i].z) + 160;
            y = ((stars[i].y << 7) / stars[i].z) + 100;

            pos[i].x = x;
            pos[i].y = y;
      }
}

In pascal it would be like this....

x := (((stars[i].x shl 7) div stars[i].z) + 160;
y := ((stars[i].y shl 7) div stars[i].z) + 100;

I did

X SHL 7 which is the same as X * 256... It's just a lot faster then multiplying by 256...

If you need more help understanding anything let me know...

btw- I put the comments just now and they might be a bit clumsy.. Anyway, tell me if you don't understand something...

-Viktor
--Ivanov
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216696
Viktor, please, pixels are easy in 2d or 3d no case, but I want imageS!
Plz give me the function getSourceColor
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 10

Expert Comment

by:viktornet
ID: 1216697
Same thing goes for images....ok when you plot pixels in 3D prespective it looks like this...


|\
|  \
|   |
|  /
|/

when you plot it, so for the image it works the same way...depends in the form the image takes when you plot it... I gotta try it my self sometime and tell you if it works, but no now since I dont have much time right now... maybe in a few days or a week or something...
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216698
Ok
0
 

Expert Comment

by:flobecker
ID: 1216699
Let's have a look at the problem:
There're two (at least) possibilities to rotate and write a flat image (a pixel map) to the screen:

The first method is something like "rendering": You check for every point of the screen (let's say 640 x 480) if a ray starting at this point hits the image which is somewhere in the room.

have a look at this poor (2d-) drawing:

xxxxxxxxxxxxxxxx         <-  every x is a pixel
        \      /
         \    /  <- one ray per pixel
          \  /
           X  <- like some lens
          /  \
         /    \
        /      \
       /  ##### <- the image plane
      /
     / <- this one haven't hit the image plane
             
I haven't thought much about this method because it's very slow. But on the other side it's the most exact method. Maybe you can increase speed by calculating only the area where the picture is located at.

The second method is to check for each point of the IMAGE (let's say 100x50) where it is located after rotating. Then you calulate some perspective and put a pixel with the given color to the calculated location.

Out coordinate system:
coordinates are in this format: x1/x2/x3

            X3
             |
             |
             |
             |
             |________________ X2
            /
          /  
        /
     X1

The plane is located here:
the center is at 0/0/0,
the left/top edge is at 0/-50/-25, the right/bottom edge is at 0/50/-25

            X3
             |
             |
+-----------|------------+
 |           |             |
 |           |_______ | _________ X2
 |          /              |
 |        /                |
+------/-----------------+
     X1

Let's take a random point in the 2d image map (there the top/left pixel is at 0/0). Ok, let's say we take the pixel at 15/30. The unrotated 3d-coordinates are caluclated as follows:

x1=0   (as always)
x2=15-50=-35           (2d-coordinates - center)
x3=30-25=5
so, if not rotated, the pixel would be at 0/-35/5 in the room
Now, we'll rotate around the X1-Axis where rotate_x1 is the angle (clockwise when looking at 0/0/0 from the positive x1-side).
let's have a look directly from the x1-axis to the point we want to rotate: x=out point at 0/-35/5

rotate that way around 0/0/0
       ---->                   x3
   /                            ^                        
 /                              |  
 |                              |  
 x                             |              
                                |  
-------------------------------+---------------------------> x2
                                |  
                                |              
                                |  
                                |              
                                |  

That's how it should look like:

new_x1=x1                                                          (doesn't change!)
new_x2=x2*cos(rotate_x1)+x3*sin(rotate_x1)
new_x3=x3*cos(rotate_x1)-x2*sin(rotate_x1)
you have to continue calculating with these coordinates
x1=new_x1
x2=new_x2
x3=new_x3

(If you want me to explain this, please tell me, 'cause it'll take too much time right now)

Ok, when got the new coordinates of our point. If you understand how to rotate around X1, you can do this for X2 and X3 - only if you want to. If not, just leave the coordinates.

Let's calculate the perspective (that's easy!). camera_x3 is where you're looking from, use 100 or so. Use zoom to zoom ;-). Vary with these params to get best pictures.

pixel_x=round(zoom*x2/(camera_x3-x3))
pixel_y=round(zoom*x3/(camera_x3-x3))
(there's no pixel_z - the screen is 2d !)

Now you know where to put the pixel with the color defined in the image. Just add the center of the screen to the coordinates, let's say for 640x480:

pixel_x=pixel_x+320
pixel_y=            240-pixel_y             (because top is 0 and bottom is 480 - just inverted!)

Do this for every point in the image.

the only problem is: if you zoom into the picture, there'll be holes, because there's to pixel for this point. But I'm sure this problem can be solved: when zooming to deep, you calculate not only -35/5 but also -35.0/5.5 , -35.5/5.0 and -35/5.5, always using the color of -35/5 or even average of -35/5 and the neighbour-pixel.

But to do rotations in realtime you have to use lots of tricks to increase to calculation.

Good luck,
 
 flobecker

0
 

Expert Comment

by:flobecker
ID: 1216700
Let's have a look at the problem:
There're two (at least) possibilities to rotate and write a flat image (a pixel map) to the screen:

The first method is something like "rendering": You check for every point of the screen (let's say 640 x 480) if a ray starting at this point hits the image which is somewhere in the room.

have a look at this poor (2d-) drawing:

xxxxxxxxxxxxxxxx         <-  every x is a pixel
        \      /
         \    /  <- one ray per pixel
          \  /
           X  <- like some lens
          /  \
         /    \
        /      \
       /  ##### <- the image plane
      /
     / <- this one haven't hit the image plane
             
I haven't thought much about this method because it's very slow. But on the other side it's the most exact method. Maybe you can increase speed by calculating only the area where the picture is located at.

The second method is to check for each point of the IMAGE (let's say 100x50) where it is located after rotating. Then you calulate some perspective and put a pixel with the given color to the calculated location.

Out coordinate system:
coordinates are in this format: x1/x2/x3

            X3
             |
             |
             |
             |
             |________________ X2
            /
          /  
        /
     X1

The plane is located here:
the center is at 0/0/0,
the left/top edge is at 0/-50/-25, the right/bottom edge is at 0/50/-25

            X3
             |
             |
+-----------|------------+
 |           |             |
 |           |_______ | _________ X2
 |          /              |
 |        /                |
+------/-----------------+
     X1

Let's take a random point in the 2d image map (there the top/left pixel is at 0/0). Ok, let's say we take the pixel at 15/30. The unrotated 3d-coordinates are caluclated as follows:

x1=0   (as always)
x2=15-50=-35           (2d-coordinates - center)
x3=30-25=5
so, if not rotated, the pixel would be at 0/-35/5 in the room
Now, we'll rotate around the X1-Axis where rotate_x1 is the angle (clockwise when looking at 0/0/0 from the positive x1-side).
let's have a look directly from the x1-axis to the point we want to rotate: x=out point at 0/-35/5

rotate that way around 0/0/0
       ---->                   x3
   /                            ^                        
 /                              |  
 |                              |  
 x                             |              
                                |  
-------------------------------+---------------------------> x2
                                |  
                                |              
                                |  
                                |              
                                |  

That's how it should look like:

new_x1=x1                                                          (doesn't change!)
new_x2=x2*cos(rotate_x1)+x3*sin(rotate_x1)
new_x3=x3*cos(rotate_x1)-x2*sin(rotate_x1)
you have to continue calculating with these coordinates
x1=new_x1
x2=new_x2
x3=new_x3

(If you want me to explain this, please tell me, 'cause it'll take too much time right now)

Ok, when got the new coordinates of our point. If you understand how to rotate around X1, you can do this for X2 and X3 - only if you want to. If not, just leave the coordinates.

Let's calculate the perspective (that's easy!). camera_x3 is where you're looking from, use 100 or so. Use zoom to zoom ;-). Vary with these params to get best pictures.

pixel_x=round(zoom*x2/(camera_x3-x3))
pixel_y=round(zoom*x3/(camera_x3-x3))
(there's no pixel_z - the screen is 2d !)

Now you know where to put the pixel with the color defined in the image. Just add the center of the screen to the coordinates, let's say for 640x480:

pixel_x=pixel_x+320
pixel_y=            240-pixel_y             (because top is 0 and bottom is 480 - just inverted!)

Do this for every point in the image.

the only problem is: if you zoom into the picture, there'll be holes, because there's to pixel for this point. But I'm sure this problem can be solved: when zooming to deep, you calculate not only -35/5 but also -35.0/5.5 , -35.5/5.0 and -35/5.5, always using the color of -35/5 or even average of -35/5 and the neighbour-pixel.

But to do rotations in realtime you have to use lots of tricks to increase to calculation.

Good luck,
 
 flobecker

0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216701
Good comment, I prefer 1st method (check 640x480 pixels, because 2nd is super-bad quality (there're holes in image, and other ****). So it's better for each point of screen (640x480) do rotation in back direction and see if it hits into source image, if yes, get it's color and plot to point we're checking. Please, Flobecker, give me formulas for such back direction rotation (as answer).
0
 

Expert Comment

by:PeteTheHat
ID: 1216702
Hi I have working pascal code for tranlating a rectangle 2D image to any qadrilateral ie 4 corners anywhere on screen without any trig so its fast
0
 
LVL 6

Expert Comment

by:PBall
ID: 1216703
Sounds like texture mapping problem :)
You might find some texture mapping sample at
http://www.hornet.org

basically the best site to do demo coding.  tons of sample and tutorial too.
0
 
LVL 3

Expert Comment

by:Ronald Buster
ID: 1216704
Why do it the hard way looking at all sources you were getting. Look at the picture as one big polygon based picture. You know how to draw polygons ? If you it this way your picture becomes divided in small textures (polygon) which you can move up and down like a flag rotate etc just with such a ease bill gates looks like a nerd.

However I have sources from various demos I made, but they are in C/C++ (Watcom), and in assembler (32bit). If you want them please let me know.

A friend of mine God_Ares says to me jack_p50 has his pascal unit xvga which contains just the routines to do this. semi 32bit.

regards,

Cono
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216705
First give me what I need, then answer. Thanx.
0
 

Expert Comment

by:flobecker
ID: 1216706
That's a short(!) scheme how to do it:
You better copy this text to a editor, so the graphics (?!) are readable.

We have to use lots of vectors - I hope you know how to use them.
By the way: You're working on a game or so, right? In this case, I would use
the other method I described and would try to improve the quality. "Rendering"
is realy SLOW!

Well, but that's what I found out about this (very interesting) topic:
This time I'm using an other system of axises (I read that this one is used
for 3d graphics). It's called the left-hand-coordinate-system or so.

       +Y
       |  +Z
       | /
       |/
 ------*------- +X
      /|
     / |
       |

Note: p0,p1,p2,r0,r1 are all 3d-vectors: <x,y,z>
The image we want to show is located on a infinitve plane with its center at:
 p0 = <plane_x, plane_y, plane_z>
and which is defined by like this:
 <x,y,z> = p0 + i*p1 + j*p2
 <x,y,z> = <plane_x, plane_y, plane_z> + i * <1,0,0> + j * <0,1,0>
i and j are parameters. There's one pair of i and j for each point on the
plane. To rotate the plane, just rotate the vectors p1 and p2 (I've got the
forumlas for this, just have to find them, if not: it's not too hard to find
it)

The camera is located somewhere on the z-axis (makes life much easier!) at
 r0 = <0,0,camera_z>
A ray is defined by
 <x,y,z> = r0 + k*r1
k is another parameter to describe every point on the ray.
r1 is the direction of the ray. This one is calculated like this:

 r1 = <pixel_x,pixel_y,focus>

pixel_x and pixel_y are the coordinates on the screen, while 0/0 is the
center. focus is the way between the

xxXxxxxxxxxxxxxxXxxxx   <---- screen
   \           /
    \         /
     \       /
      \     /
       \   /
        \ /
       *              <---- camera center
        / \
       /   \
      /     \
--------===========---- <---- the image plane:
                              = means this area of the plane is defined by some colors
                              - means this area of the plane is undefined, so we just look through and take the background color

Ok, now we've defined the plane and the ray:

ray:   <x,y,z> = r0 + k*r1
plane: <x,y,z> = p0 + i*p1 + j*p2

Now we have to check wether the ray crosses the plane for each pixel of the
screen. If yes, we have to check, where exactly this happens and if a color is
defined for this point of the image plane (hey, this part is easy!) or if the
background color is used instead. If the ray doesn't cross the plane, then we
just use the background color.

To cross the plane with the ray we just have to solve this equation
 r0 + k*r1 = p0 + i*p1 + j*p2
     [ray] = [plane]
Looks easy, doesn't it? It isn't! That means tons of lines and tons of
CPU-time!!! for EACH pixel!
Anyway, there're three possible cases how the solving may end:
 1. the ray doesn't touch the plane at all, there's no solution, so take
     take background color
 2. there's a infinitve number of solutions, we're looking at the plane from
     the side, what color shall we take now? we may check, from which side
     we're looking at and take the border pixel's color or we may use a common
     border color. That's another problem, I'm working on.
 3. the best case: there's exactly one solution, giving each parameters i,j,k
     exactly one value. With i and j are pointing directly on the image plane
     while i is the x-coordinate and j is the y-coordinate. You just have to
     check wether the coordinates are in the range where the colors are defined
     on the image plane (let's say i in [-50..+49] for a image width of 100).
     Sure you have to round() the i/j values or even calculate an average
     color of two pixels

I'm working on solving this equations but you better use the other method I
described in the other comment.

Anyway, I found some notes I made how to 3d-rotate a point at <X,Y,Z> around a
center at <0,0,0>, while x_rot, y_rot and z_rot are the angles by which we
rotate around the x-, y- and z-axis (in this order). We rotate clockwise around
the axis when looking from the positive side of the axis to <0,0,0>. You may
change the order of rotating or use just one or two rotations. You better
precalculate the values for SIN(x_rot), COS(x_rot), SIN(x_rot) and so on.
You may even precalculate a SIN-table with integers to increase speed.

Rotation around the X-axis
  X_new=X
  Y_new=Y*cos(x_rot)-Z*sin(x_rot)
  Z_new=Z*cos(x_rot)+Y*sin(x_rot)
 copy the new coordinates back to X,Y,Z
  X=X_new
  Y=X_new
  Z=Z_new

Rotation around the Y-axis
  X_new=X*cos(y_rot)+Z*sin(y_rot)
  Y_new=Y
  Z_new=Z*cos(y_rot)-X*sin(y_rot)
 the same again (looks better!)
  X_new=X_new
  Y_new=X_new
  Z_new=Z_new

Rotation around the Z-axis
  X_new=X*cos(z_rot)-Y*sin(z_rot)
  Y_new=Y*cos(z_rot)+X*sin(z_rot)
  Z_new=Z
 we did it!
  X=X_new
  Y=X_new
  Z=Z_new

You will have to use these formulas for rotating the vectors p1 and p2 (and
so the image-plane).

Give me some days (haven't got much time) then you'll get the other formulas
- I hope so :-)

 flobecker

0
 

Expert Comment

by:flobecker
ID: 1216707
Here it is!
that's what I wrote down:

IMAGE PLANE DEFINITION
plane: p0 + i*p1 + j*p2
middle of image plane
p0.x=plane_x
p0.y=plane_y
p0.z=plane_z
direction1 (x-axis), unrotated
p1.x=1
p1.y=0
p1.z=0
direction2 (y-axis), unrotated
p2.x=0
p2.y=1
p2.z=0

RAY DEFINITION
ray: r0 + k*r1
start
r0.x=0
r0.y=0
r0.z=camera_z
direction
r1.x=pixel_x/focus
r1.y=pixel_y/focus
r1.z=1

again, p0,p1,r0,r1,r2 are 3d-vectors:

                  / p0.x \
p0 = |  p0.y  |
                  \ p0.z /

alle we have to do is to solve this:

                   p0+r*p1+s*p2=r0+t*r1

in other words:
p0.x + i * p1.x + j * p2.x = r0.x + k * r1.x
p0.y + i * p1.y + j * p2.y = r0.y + k * r1.y
p0.z + i * p1.z + j * p2.z = r0.z + k * r1.z

i,j,k to one side:
i * p1.x + j * p2.x - k * r1.x = r0.x - p0.x
i * p1.y + j * p2.y - k * r1.y = r0.y - p0.y
i * p1.z + j * p2.z - k * r1.z = r0.z - p0.z

the matrix
p1.x  p2.x -r1.x | r0.x - p0.x
p1.y  p2.y -r1.y | r0.y - p0.y
p1.z  p2.z -r1.z | r0.z - p0.z

replace some numbers which will never change
[ i ] [ j ] [ k ]
p1.x  p2.x  -r1.x | 0        - p0.x   (1)
p1.y  p2.y  -r1.y | 0        - p0.y   (2)
p1.z  p2.z   -1   | camera_z - p0.z   (3)

let's start solving, we'll start with this:
(4)=(1)-(3)*r1.x
(5)=(2)-(3)*r1.y

our new matrix:
p1.x-p1.z*r1.x   p2.x-p2.z*r1.x  0  | -p0.x - (camera_z-p0.z) * r1.x    (4)
p1.y-p1.z*r1.y   p2.y-p2.z*r1.y  0  | -p0.y - (camera_z-p0.z) * r1.y    (5)
p1.z             p2.z            -1 | camera_z - p0.z                   (3)

I'll substitute the matrix elements like this:
a1 a2 a3 | a4
b1 b2 b3 | b4
c1 c2 c3 | c4

      a1:=p1.x-p1.z*r1.x;
      a2:=p2.x-p2.z*r1.x;
      a3:=0;
      a4:=-p0.x-(camera_z-p0.z)*r1.x;

      b1:=p1.y-p1.z*r1.y;
      b2:=p2.y-p2.z*r1.y;
      b3:=0;
      b4:=-p0.y-(camera_z-p0.z)*r1.y;

      c1:=p1.z;
      c2:=p2.z;
      c3:=-1;
      c4:=camera_z-p0.z;

We have to check, whether any value we want to divide by isn't zero!
      if a1=0 then
            if a2=0 then
                  if a4=0 then
                        begin
                              {infinitve solutions - ray hits plane directly from the side}
                              color:=getbordercolor;
                        end
                  else
                        begin
                              {no solutions - ray doesn't hit the plane}
                              color:=backgroundcolor;
                        end
            else
                  begin
                        j:=a4/a2;
                        if b1=0 then
                              begin
                                    {infinitve solutions - ray hits plane directly from the side}
                                    color:=getbordercolor;
                              end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=(b4-b2*j)/b1;
                                    color:=getimagecolor;
                              end;
                  end
      else
            if a2=0 then
                  begin
                        i:=a4/a1;
                        if b2=0 then
                              begin
                                    {infinitve solutions - ray hits plane directly from the side}
                                    color:=getbordercolor;
                              end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    j:=(b4-b1*i)/b2;
                                    color:=getimagecolor;
                              end;
                  end
            else
                  {a1<>0 and a2<>0}
                  if b1=0 then
                        if b2=0 then
                              if b4=0 then
                                    begin
                                          {infinitve solutions - ray hits plane directly from the side}
                                          color:=getbordercolor;
                                    end
                              else
                                    begin
                                          {no solutions - ray doesn't hit the plane}
                                          color:=backgroundcolor;
                                    end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    j:=b4/b2;
                                    i:=(a4-j*a2)/a1;
                                    color:=getimagecolor;
                              end
                  else
                        {a1<>0 and a2<>0 and b1<>0}
                        if b2=0 then
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=b4/b1;
                                    j:=(a4-a1*i)/a2;
                                    color:=getimagecolor;
                              end
                        else
                              {a1<>0 and a2<>0 and b1<>0 and b2<>0}
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=(a4-b4*(a2/b2))/(a1-b1*(a2/b2));
                                    j:=(b4-b1*i)/b2;
                                    color:=getimagecolor;
                              end;

Calculate k like this:
k:=(c4-i*c1-j*c2)/c3
k:=-(camera_z-p0.z-i*p1.z-g*p2.z)

You may calculate the distance between the point where the ray starts and
the point where the ray crosses the plane:

distance:=k * sqrt(sqr(r1.x)+sqr(r1.y)+sqr(r1.z));



Any questions? please ask!
Following is a pascal program I wrote using these formulas. It works!
I used a picture I converted to a 256 grey value palette and exported to RAW format with Paintshop Pro. Don't forget to correct image_height and image_width.
It's slow and there're lots of useless lines, but I guess it helps understanding how it works.
Again: If you're realy writing a game, you better use the other method and NO floating point!

0
 

Accepted Solution

by:
flobecker earned 50 total points
ID: 1216708
{$A+,B-,D+,E-,F+,G+,I+,L+,N+,O+,P+,Q-,R-,S+,T+,V+,X+}
{$M 16384,0,655360}

uses crt,graph;

{     +Y
                   |            +Z
                   |   /
                   | /
 ------*------- +X
             / |
       /   |
                   |
}

type       vector=record
                        x,y,z:double;
                  end;

const camera_z:integer=-200;
                  camera_focus=150;
                  background_color=0;
                  plane_xrot:double=0;
                  plane_yrot:double=0;
                  plane_zrot:double=0;
                  plane_x:integer=0;
                  plane_y:integer=0;
                  plane_z:integer=0;
                  backgroundcolor:byte=0;
                  image_width=150;
                  image_height=200;

var   r0,r1,p0,p1,p2:vector;
                  x,y:integer;
                  screen_width,screen_height:integer;
                  bitmap:array[0..(image_width-1),0..(image_height-1)] of byte;

procedure INITSVGA(gm:integer);

{$F+}
function TestDetect : Integer;
begin
testdetect:=1;
end;
{$F-}

var gt:integer;

begin
      gt:=installuserdriver('SVGA256',@testdetect);
      initgraph(gt,gm,'\TP\BGI');
end;

procedure PRECALC;

begin
      r0.x:=0;
      r0.y:=0;
      r0.z:=camera_z;
      p0.x:=plane_x;
      p0.y:=plane_y;
      p0.z:=plane_z;
      p1.x:=2*cos(plane_zrot)*cos(plane_yrot);
      p1.y:=2*sin(plane_zrot);
      p1.z:=2*cos(plane_zrot)*sin(plane_yrot);
      p2.x:=-2*sin(plane_zrot)*cos(plane_yrot);
      p2.y:=+2*cos(plane_zrot);
      p2.z:=-2*sin(plane_zrot)*sin(plane_yrot);
end;

function CALC_RAY(screen_x,screen_y:double):byte;

var a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4:double;
            color:byte;
            i,j,k:double;

function GETIMAGECOLOR:byte;

var image_x,image_y:longint;
            imagecol:byte;
            xx,yy:double;
            distance:double;

begin
      k:=(c4-i*c1-j*c2)/c3;
      distance:=k * sqrt(sqr(r1.x)+sqr(r1.y)+sqr(r1.z));

      xx:=i;
      yy:=j;

      image_x:=round(xx+image_width/2);
      image_y:=round(yy+image_height/2);
      if (k>0) and (image_x>=0) and (image_x<image_width) and (image_y>=0) and (image_y<image_height) then
            imagecol:=bitmap[image_x,image_y]
      else
            imagecol:=backgroundcolor;
      getimagecolor:=imagecol;
end;

function GETBORDERCOLOR:byte;

begin
      getbordercolor:=64;
end;

begin
      r1.x:=screen_x/camera_focus;
      r1.y:=screen_y/camera_focus;
      r1.z:=1;

      a1:=p1.x-p1.z*r1.x;
      a2:=p2.x-p2.z*r1.x;
      a3:=0;
      a4:=-p0.x-(camera_z-p0.z)*r1.x;

      b1:=p1.y-p1.z*r1.y;
      b2:=p2.y-p2.z*r1.y;
      b3:=0;
      b4:=-p0.y-(camera_z-p0.z)*r1.y;

      c1:=p1.z;
      c2:=p2.z;
      c3:=-1;
      c4:=camera_z-p0.z;


      if a1=0 then
            if a2=0 then
                  if a4=0 then
                        begin
                              {infinitve solutions - ray hits plane directly from the side}
                              color:=getbordercolor;
                        end
                  else
                        begin
                              {no solutions - ray doesn't hit the plane}
                              color:=backgroundcolor;
                        end
            else
                  begin
                        j:=a4/a2;
                        if b1=0 then
                              begin
                                    {infinitve solutions - ray hits plane directly from the side}
                                    color:=getbordercolor;
                              end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=(b4-b2*j)/b1;
                                    color:=getimagecolor;
                              end;
                  end
      else
            if a2=0 then
                  begin
                        i:=a4/a1;
                        if b2=0 then
                              begin
                                    {infinitve solutions - ray hits plane directly from the side}
                                    color:=getbordercolor;
                              end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    j:=(b4-b1*i)/b2;
                                    color:=getimagecolor;
                              end;
                  end
            else
                  {a1<>0 and a2<>0}
                  if b1=0 then
                        if b2=0 then
                              if b4=0 then
                                    begin
                                          {infinitve solutions - ray hits plane directly from the side}
                                          color:=getbordercolor;
                                    end
                              else
                                    begin
                                          {no solutions - ray doesn't hit the plane}
                                          color:=backgroundcolor;
                                    end
                        else
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    j:=b4/b2;
                                    i:=(a4-j*a2)/a1;
                                    color:=getimagecolor;
                              end
                  else
                        {a1<>0 and a2<>0 and b1<>0}
                        if b2=0 then
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=b4/b1;
                                    j:=(a4-a1*i)/a2;
                                    color:=getimagecolor;
                              end
                        else
                              {a1<>0 and a2<>0 and b1<>0 and b2<>0}
                              begin
                                    {exactly one solution - let's calculate i and j and get the color}
                                    i:=(a4-b4*(a2/b2))/(a1-b1*(a2/b2));
                                    j:=(b4-b1*i)/b2;
                                    color:=getimagecolor;
                              end;
      CALC_RAY:=color;
end;

procedure setpalette;

var b:byte;

begin
      for b:=0 to 63 do
            begin
                  setrgbpalette(b,b,b,b);
            end;
      for b:=0 to 63 do
            begin
                  setrgbpalette(b+64,63-b,b,0);
            end;
      for b:=0 to 63 do
            begin
                  setrgbpalette(b+128,0,63-b,b);
            end;
      for b:=0 to 63 do
            begin
                  setrgbpalette(b+192,b,0,63-b);
            end;
end;

procedure loadbitmap;

var f:file;
            a,b:integer;
            col:byte;

begin
      assign(f,'anyimagename.raw');
      reset(f,1);
      for a:=0 to image_height-1 do
            for b:=0 to image_width-1 do
                  begin
                        blockread(f,col,1);
                        bitmap[b,image_height-1-a]:=col shr 2;
                  end;
      close(f);
end;

var c:char;
            col:double;

begin
      initsvga(2);   {640x480x256}
      setpalette;
      loadbitmap;
      screen_width:=getmaxx+1;
      screen_height:=getmaxy+1;
      repeat
      PRECALC;
      for y:=(-screen_height div 2) to (screen_height div 2-1) do
            for x:=(-screen_width div 2) to (screen_width div 2-1) do
                  begin
                        col:=CALC_RAY(x,y);
                        putpixel(screen_width div 2+x,screen_height div 2-y+1,round(col));
                  end;

      if keypressed then c:=readkey;
      plane_yrot:=plane_yrot+0.1;
      plane_zrot:=plane_zrot+0.2;
      inc(plane_z,100);
      until c=#27;
      closegraph;
end.

0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216709
Thanx, flo, you're really a man of action. Sorry for don't accepting it so long, I wasn't in net for a week. I'll use it for game, but only when creating graphics for it.
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216710
The only thing I want to know is why it's not rotating around x-axis (it works and doesn't care what is plane_xrot). ??? Please, answer it, I want to rotate around x-axis too.
0
 

Expert Comment

by:flobecker
ID: 1216711
You're right. I didn't implement rotating around the X-axis because I thought two rotations shall be enough. Replace the following lines in the PRECALC-routine
  p1.x:=2*cos(plane_zrot)*cos(plane_yrot);
  p1.y:=2*sin(plane_zrot);
  p1.z:=2*cos(plane_zrot)*sin(plane_yrot);
  p2.x:=-2*sin(plane_zrot)*cos(plane_yrot);
  p2.y:=+2*cos(plane_zrot);
  p2.z:=-2*sin(plane_zrot)*sin(plane_yrot);
with those:
  p1.x:=1*cos(plane_yrot)*cos(plane_zrot);
  p1.y:=1*cos(plane_yrot)*sin(plane_zrot);
  p1.z:=-1*sin(plane_yrot);
  p2.x:=1*sin(plane_xrot)*sin(plane_yrot)*cos(plane_zrot)-1*cos(plane_xrot)*sin(plane_zrot);
        p2.y:=1*cos(plane_xrot)*cos(plane_zrot)+1*sin(plane_xrot)*sin(plane_yrot)*sin(plane_zrot);
  p2.z:=1*sin(plane_xrot)*cos(plane_yrot);

Now the plane will be rotated clockwiese around the axis (when looking from the positive half of the axis to <0,0,0> in this order: X - Y - Z
Hope it works, but the tests looked good.
Maybe you can send me a copy of your game when finished :-)

flobecker
0
 
LVL 4

Author Comment

by:jack_p50
ID: 1216712
BIG thanx.
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Capture cookies with delphi 5 993
detect keyboard input monitoring 3 391
Delphi Skype API 2 1,733
Conversion ? 15 85
In this article, I will show you HOW TO: Suppress Configuration Issues and Warnings Alert displayed in Summary status for ESXi 6.5 after enabling SSH or ESXi Shell.
Hyena v12.2 is now available for downloading and is available in English, French, German and Spanish versions.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now