 # Thread: 3D Math: how draw a 3D cube?

1. ## Re: 3D Math: how draw a 3D cube?

but like you see i'm using the rectangle center:
Code:
```Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(5) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D
FillPosition3D RotatedPosition, Size.Width / 2, Size.Height / 2, Size.ZDepth / 2

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint```
Code:
```Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition.X = (Position.Z + PositionRotated.Z) * Sin(RotationInRads.Y) + (Position.X + PositionRotated.X) * Cos(RotationInRads.Y)
ConvertedPosition.Y = (Position.Y + PositionRotated.Y) * Cos(RotationInRads.X) - (Position.Z + PositionRotated.Z) * Sin(RotationInRads.X)
ConvertedPosition.Z = (Position.Y + PositionRotated.Y) * Sin(RotationInRads.X) + (Position.Z + PositionRotated.Z) * Cos(RotationInRads.X)
Rotate = ConvertedPosition
End Function```
but i don't understand why isn't using the rectangle center i'm still confused... sorry  Reply With Quote

2. ## Re: 3D Math: how draw a 3D cube?

Step through the code and look at what values your are rotating.
If you want to rotate around the center of the rectangle, then the center of the rectangle has to be 0,0,0 at the time of the rotation. Rotation is always around 0,0,0, so your points have to be translated so that they are relative to 0,0,0.

If you have a position.X of 10, your current code says the X values are 10 - 5 (i.e. 5) and (10 + 5) (i.e. 15).

So, you will be rotating the points at X = 5 and X = 15 around 0, when what you want them to rotate around is 10 (10 is your position, so is your world center for the rectangle).

Since the equation rotates around 0, you need to move your points mathematically to rotate around 0. You do that by subtracting the world position from the points.
X = 5 - 10 (X = -5)
X = 15 - 10 (X = 5)

Now, if you rotate, the -5 and +5 points will rotate around 0, which now is the mathematical center of the rectangle.
Once you've rotated, lets say you have the resulting values in RotatedPoint.
Now, you can move the rotated points of the rectangle back out to the position where they originally were.
RotatedPoint.X = RotatedPoint.X + Position.X

So, in summary.
1. Subtract the position from the coordinates to make the coordinates relative to 0,0,0
2. Rotate the resulting coordinates.
3. Add the position to the rotated coordinates to put them back to the place they came from.  Reply With Quote

3. ## Re: 3D Math: how draw a 3D cube?

- so i must re position the rectangle center on position (0, 0, 0);
- rotate it;
- and then re position on right place?  Reply With Quote

4. ## Re: 3D Math: how draw a 3D cube?

finally i put it to work:
Code:
`FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2`
and now the rotation:
Code:
```Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

'rotate from center rectangle from 0,0,0 position:
ConvertedPosition.X = (Position.Z - PositionRotated.Z) * Sin(RotationInRads.Y) + (Position.X - PositionRotated.X) * Cos(RotationInRads.Y)
ConvertedPosition.Y = (Position.Y - PositionRotated.Y) * Cos(RotationInRads.X) - (Position.Z - PositionRotated.Z) * Sin(RotationInRads.X)
ConvertedPosition.Z = (Position.Y - PositionRotated.Y) * Sin(RotationInRads.X) + (Position.Z - PositionRotated.Z) * Cos(RotationInRads.X)
'postion the rectangle on right position:
ConvertedPosition.X = ConvertedPosition.X + Position.X
ConvertedPosition.Y = ConvertedPosition.Y + Position.Y
ConvertedPosition.Z = ConvertedPosition.Z + Position.Z
Rotate = ConvertedPosition
End Function```
big problem from what i see: the rectangle size is more big
another problem: the Z rotation don't works heres the entire project:
Code:
```Option Explicit

Private Type POINTAPI
X As Long
Y As Long
End Type

Private Declare Function Polygon Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long

Private Type Position3D
X As Long
Y As Long
Z As Long
End Type

Private Type Angle3D
X As Double
Y As Double
Z As Double
End Type

Private Type Size3D
Width As Long
Height As Long
ZDepth As Long
End Type

Private Type Player
Position As Position3D
Angle As Angle3D
End Type

Private Const Pi As Double = 3.14159265358979
Dim World3D As Size3D
Dim Angletest As Angle3D

Private Sub LetPoint3dArray(la() As Position3D, ParamArray va() As Variant)
' No error trapping, so use with caution.
Dim i       As Long
Dim j       As Long
Dim k      As Long

k = (UBound(va) + 1) \ 3 - 1
ReDim la(k)
For i = 0& To k
la(i).X = va(j): j = j + 1
la(i).Y = va(j): j = j + 1
la(i).Z = va(j): j = j + 1
Next
End Sub

Private Sub FillPosition2D(Position As POINTAPI, X As Long, Y As Long)
Position.X = X
Position.Y = Y
End Sub

Private Sub FillPosition3D(Position As Position3D, X As Long, Y As Long, Z As Long)
Position.X = X
Position.Y = Y
Position.Z = Z
End Sub

Private Sub FillSize3D(Size As Size3D, Width As Long, Height As Long, ZDepth As Long)
Size.Width = Width
Size.Height = Height
Size.ZDepth = ZDepth
End Sub

Private Function ConvertPositon3DTo2D(Position As Position3D, World3DSize As Size3D) As POINTAPI
Dim ConvertedPosition As POINTAPI
Dim PosZZDepth As Integer

PosZZDepth = Position.Z + World3DSize.ZDepth

If (PosZZDepth = 0) Then PosZZDepth = 1 'avoiding division by zero

ConvertedPosition.X = Position.X * World3DSize.ZDepth / PosZZDepth
ConvertedPosition.Y = Position.Y * World3DSize.ZDepth / PosZZDepth
ConvertPositon3DTo2D = ConvertedPosition
End Function

Private Function ConvertDegreesToRadians(Rotation As Angle3D) As Angle3D

End Function

Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition.X = (Position.Z - PositionRotated.Z) * Sin(RotationInRads.Y) + (Position.X - PositionRotated.X) * Cos(RotationInRads.Y)
ConvertedPosition.Y = (Position.Y - PositionRotated.Y) * Cos(RotationInRads.X) - (Position.Z - PositionRotated.Z) * Sin(RotationInRads.X)
ConvertedPosition.Z = (Position.Y - PositionRotated.Y) * Sin(RotationInRads.X) + (Position.Z - PositionRotated.Z) * Cos(RotationInRads.X)
ConvertedPosition.X = ConvertedPosition.X + Position.X
ConvertedPosition.Y = ConvertedPosition.Y + Position.Y
ConvertedPosition.Z = ConvertedPosition.Z + Position.Z
Rotate = ConvertedPosition
End Function

Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(5) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint

'Vector2
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Vector5
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

Polygon Me.hdc, Vertices(0), 5
End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If (KeyCode = vbKeyEscape) Then End
End Sub

ScaleMode = vbPixels
AutoRedraw = True

World3D.Width = Me.ScaleWidth
World3D.Height = Me.ScaleHeight
World3D.ZDepth = 1000
HScrollChanged

End Sub

Private Sub HScroll1_Change()
HScrollChanged
End Sub
Private Sub HScroll1_Scroll()
HScrollChanged
End Sub

Sub HScrollChanged()
Me.Cls
Angletest.X = HScroll1.Value
Me.Caption = CStr(HScroll1.Value)
Dim RecPosition As Position3D
FillPosition3D RecPosition, 10, 10, 1

Dim RecSize As Size3D
FillSize3D RecSize, 10, 10, 1
DrawRectangle RecPosition, RecSize, Angletest, World3D
VScrollChanged
ZScrollChanged
End Sub

Sub VScrollChanged()
Angletest.Y = VScroll1.Value
Me.Caption = CStr(VScroll1.Value)
Dim RecPosition As Position3D
FillPosition3D RecPosition, 10, 50, 1

Dim RecSize As Size3D
FillSize3D RecSize, 10, 10, 1
DrawRectangle RecPosition, RecSize, Angletest, World3D
End Sub

Sub ZScrollChanged()
Angletest.Z = HScroll2.Value
Me.Caption = CStr(HScroll2.Value)
Dim RecPosition As Position3D
FillPosition3D RecPosition, 10, 50, 1

Dim RecSize As Size3D
FillSize3D RecSize, 10, 10, 1
DrawRectangle RecPosition, RecSize, Angletest, World3D
Me.Refresh
End Sub

Private Sub HScroll2_Change()
HScrollChanged
End Sub

Private Sub HScroll2_Scroll()
HScrollChanged
End Sub

Private Sub VScroll1_Change()
HScrollChanged

End Sub

Private Sub VScroll1_Scroll()
HScrollChanged
End Sub```  Reply With Quote

5. ## Re: 3D Math: how draw a 3D cube? Originally Posted by joaquim ...
big problem from what i see: the rectangle size is more big
another problem: the Z rotation don't works ...
Well the rectangle may be bigger than the size you gave because you're doing a 3d perspective projection. If you were doing a raw 3d projection, i.e. an ISO projection where you didn't modify the 3D points for Z depth, then the size of the rectangle would be fixed regardless of depth.

But since you're doing a perspective projection, then the size depends on your viewing frustum, which depends on the eye distance from the viewing plane. For a give size of rectangle, the rectangle will be larger if it is closer to the eye, and smaller if it is further from the eye (i.e. viewpoint).

I haven't looked at all the values to try to figure what your frustum is, and how your Z value affects the perceived size of the rectangle.

As far as the Z rotation not working, that is because you aren't doing any Z rotation.
The fact is you aren't doing X rotation and Y rotation either.
For 2d rotation, there is only one rotation, which is around the "missing" Z axis. The screen represents the Z plane which is a single level, i.e. 0, so your X,Y values rotate around on that plane.
For 3d rotation, there are three rotations needed because you have three planes to rotate around, the X,Y plane (Z plane), the X,Z plane (Y plane) and the Y,Z plane (X plane).

You only have one rotation, which is a mixture of both X and Y. I don't know that it is properly rotating the points around X and Y planes, but it appears to be. But since it is a mixture, it may actually be rotating around a plane that is a combination of the two and is not technically orthogonal to the Z axis.

If you want to be able to rotate around the Z axis, then you need to fix the rotation sub so that it rotates around all three axis, that is three rotations, not one.
I don't have time to investigate it right now, but various of the articles that I've linked to explain this from various sources, so if you read them, you can probably play with different ones and decide which method of rotation code you want to use, but in the end, it will involve three rotations, not one.  Reply With Quote

6. ## Re: 3D Math: how draw a 3D cube?

now the Z rotation works:
Code:
```Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition = Position

If (Rotation.X <> 0) Then
ConvertedPosition.Y = (Position.Y - PositionRotated.Y) * Cos(RotationInRads.X) - (Position.Z - PositionRotated.Z) * Sin(RotationInRads.X)
ConvertedPosition.Z = (Position.Y - PositionRotated.Y) * Sin(RotationInRads.X) + (Position.Z - PositionRotated.Z) * Cos(RotationInRads.X)
End If

If (Rotation.Y <> 0) Then
ConvertedPosition.X = (Position.Z - PositionRotated.Z) * Sin(RotationInRads.Y) + (Position.Z - PositionRotated.Z) * Cos(RotationInRads.Y)
ConvertedPosition.Z = (Position.Z - PositionRotated.Z) * Cos(RotationInRads.Y) - (Position.Z - PositionRotated.Z) * Sin(RotationInRads.Y)
End If

If (Rotation.Z <> 0) Then
ConvertedPosition.X = (Position.X - PositionRotated.X) * Cos(RotationInRads.Z) - (Position.Y - PositionRotated.Y) * Sin(RotationInRads.Z)
ConvertedPosition.Y = (Position.X - PositionRotated.X) * Sin(RotationInRads.Z) + (Position.Y - PositionRotated.Y) * Cos(RotationInRads.Z)
End If

ConvertedPosition.X = ConvertedPosition.X + Position.X
ConvertedPosition.Y = ConvertedPosition.Y + Position.Y
ConvertedPosition.Z = ConvertedPosition.Z + Position.Z
Rotate = ConvertedPosition
End Function```
but i see 2 things:
- the Z rotation change the scale too;
- the X and Y, now, don't center the rotation   Reply With Quote

7. ## Re: 3D Math: how draw a 3D cube?

after several times and more thinking, the rotation works fine...
but see these function:
Code:
```Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition = Position

If (Rotation.X <> 0) Then
ConvertedPosition.Y = (Position.Y - PositionRotated.Y) * Cos(RotationInRads.X) - (Position.Z - PositionRotated.Z) * Sin(RotationInRads.X)
ConvertedPosition.Z = (Position.Y - PositionRotated.Y) * Sin(RotationInRads.X) + (Position.Z - PositionRotated.Z) * Cos(RotationInRads.X)
End If

If (Rotation.Y <> 0) Then
ConvertedPosition.X = (Position.Z - PositionRotated.Z) * Sin(RotationInRads.Y) + (Position.X - PositionRotated.X) * Cos(RotationInRads.Y)
ConvertedPosition.Z = (Position.Z - PositionRotated.Z) * Cos(RotationInRads.Y) - (Position.X - PositionRotated.X) * Sin(RotationInRads.Y)
End If

If (Rotation.Z <> 0) Then
ConvertedPosition.X = (Position.X - PositionRotated.X) * Cos(RotationInRads.Z) - (Position.Y - PositionRotated.Y) * Sin(RotationInRads.Z)
ConvertedPosition.Y = (Position.X - PositionRotated.X) * Sin(RotationInRads.Z) + (Position.Y - PositionRotated.Y) * Cos(RotationInRads.Z)
End If

If (Rotation.X <> 0 Or Rotation.Y <> 0 Or Rotation.Z <> 0) Then
ConvertedPosition.X = ConvertedPosition.X + PositionRotated.X
ConvertedPosition.Y = ConvertedPosition.Y + PositionRotated.Y
ConvertedPosition.Z = ConvertedPosition.Z + PositionRotated.Z
End If
Rotate = ConvertedPosition
End Function```
these function works... but if the angle is Zero, i get 1 different position... but above zero i get the same position... why?  Reply With Quote

8. ## Re: 3D Math: how draw a 3D cube?

Are you not able to step through the code?

If you change the X angle what happens?
You compute a new Y and Z value, but you don't change X.

But at the end of the function you add the positions to all three coordinates, even the one you didn't change, so the X position jumps to a new position because you're adding a position to an axis that you didn't subtract a position from.

The code skips subtracting off the position if the rotation is 0, but never skips adding the position when the rotation value is 0, so you get an offset on the axis that is set to 0.
If you set both X and Y to non-zero values, then you will see the rectangle jump back to the original position.

However, the rotations are still not done correctly.
If you move the Z slider so that you rotate around the Z axis some amount, then you can slide the X and Y sliders and nothing will happen. The Z rotation, being the last one done is the only one that has an effect on your rotation.

But that isn't the way it should be done. You should always do all three rotations, and each rotation should feed the next, not be three independent rotations, each done on the original values of X,Y,Z.

I don't know that doing them in X, Y, Z order is the "correct" order, but assuming it is a chosen order, even though perhaps not a conventional one, you should do the steps in sequence.

1. Subtract the position from your X,Y,Z coordinates so the rotation will rotate around the position (now relative to the object's position), not around the world center. Let's call the results X1, Y1, Z1.
2. Rotate X1,Y1,Z1 around the X axis, so you have a new coordinates, lets call them X2, Y2, and Z2.
3. Rotate X2,Y2 and Z2 values around the Y axis, so now you have X3, Y3 and Z3
4. Rotate X3, Y3, and Z3 values around the Z axis, so now you have your final coordinates, X4, Y4 and Z4
5. Add the position offsets back to X4, Y4 and Z4 and return them as the fully rotate coordinate, relative to the world position.

Even though your X and Y rotation might sort of look correct to you, and both sliders seems to be working independent of each other, unlike the Z which stops the X and Y sliders completely, the X and Y are not working correctly.

If you set the X to 45, the rectangle will get thinner, as it would appear if you're looking at it straight on. But if you then rotate around Y, the rectangle should not look like a rectangle any longer, it should look like a parallelogram type shape, because the rectangle should be "leaning back" or "leaning forward", with the Z depth of the upper and lower edges being at different depths in Z.

When you rotate in Y, that difference in Z depth of lower and upper lines should cause the side lines to draw at a slant as the rectangle rotates around the Y.

Since you clobber the Z value computed in the X rotation with the value computed in the Y rotation (rather than using the Z value from the X rotation in the Y rotation), Your Z values all end up being two dimensional so the rectangle remains a rectangle when projected since the Z depth is essentially not affected by the rotation around the X axis.

If you rotate around the X axis to 90 degrees you should see a line, along the X axis, which will be the bottom or top edge of the rectangle, depending on which way you rotated.
If you then start rotating around the Y axis, the Line should increase in size, as you see both the (bottom or top) edge of the rectangle, and one of the sides. The maximum length of the line should be when the Y reaches 45, as the size of the (top/bottom) and the side should each look to be around 70% of their length. The line should then appear to shorten as yo increase the angle, and when you reach 90 degrees in Y, it should be a line the length of the side.

Assuming you have a square rectangle, the line should never be shorter than the length of an edge, but will be longer if you can see two edges in the same plane at the same time.

Since you are not doing the rotation correctly, if you rotate around the X axis to 90 degrees, and then rotate around the Y axis to 90 degrees, the line edges reduces to a point.  Reply With Quote

9. ## Re: 3D Math: how draw a 3D cube?

I also cleaned up the vscroll1 and hscroll2 code, where you were doing additional rectangle drawings, that were in addition to the rectangle you were drawing in the hscrollChanged sub.
I changed the name of the hscrollChanged sub to just scrollChanged, as it is less confusing since it is called when any scroll changes, not just horizontal scroll control.

I changed the size and placement of the rectangle to make it easier to see. A 10x10 pixel square was a bit small, so I made it 50x50 and positioned it out at 100,100.
That seemed to be working fine.

I then decided to copy your five coordinates in the DrawRectangle sub, and added 50 to the Z value for second five coordinates. This should draw another rectangle 50 pixels behind the first in Z, to give you more sense of what the rotations are doing, since you have two rectangles rotating together, but 50 pixels apart in depth.

You're still using 0,0 upper left corner of the window as your camera center field of view, so your drawing reflects that, i.e. the deeper Z values are drawn toward the upper left, i.e. your vanishing point is the upper left corner.

So, full code:
Code:
```Option Explicit

Private Type POINTAPI
X As Long
Y As Long
End Type

Private Declare Function Polygon Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long

Private Type Position3D
X As Long
Y As Long
Z As Long
End Type

Private Type Angle3D
X As Double
Y As Double
Z As Double
End Type

Private Type Size3D
Width As Long
Height As Long
ZDepth As Long
End Type

Private Type Player
Position As Position3D
Angle As Angle3D
End Type

Private Const Pi As Double = 3.14159265358979
Dim World3D As Size3D
Dim Angletest As Angle3D

Private Sub LetPoint3dArray(la() As Position3D, ParamArray va() As Variant)
' No error trapping, so use with caution.
Dim i       As Long
Dim j       As Long
Dim k      As Long

k = (UBound(va) + 1) \ 3 - 1
ReDim la(k)
For i = 0& To k
la(i).X = va(j): j = j + 1
la(i).Y = va(j): j = j + 1
la(i).Z = va(j): j = j + 1
Next
End Sub

Private Sub FillPosition2D(Position As POINTAPI, X As Long, Y As Long)
Position.X = X
Position.Y = Y
End Sub

Private Sub FillPosition3D(Position As Position3D, X As Long, Y As Long, Z As Long)
Position.X = X
Position.Y = Y
Position.Z = Z
End Sub

Private Sub FillSize3D(Size As Size3D, Width As Long, Height As Long, ZDepth As Long)
Size.Width = Width
Size.Height = Height
Size.ZDepth = ZDepth
End Sub

Private Function ConvertPositon3DTo2D(Position As Position3D, World3DSize As Size3D) As POINTAPI
Dim ConvertedPosition As POINTAPI
Dim PosZZDepth As Integer

PosZZDepth = Position.Z + World3DSize.ZDepth

If (PosZZDepth = 0) Then PosZZDepth = 1 'avoiding division by zero

ConvertedPosition.X = Position.X * World3DSize.ZDepth / PosZZDepth
ConvertedPosition.Y = Position.Y * World3DSize.ZDepth / PosZZDepth
ConvertPositon3DTo2D = ConvertedPosition
End Function

Private Function ConvertDegreesToRadians(Rotation As Angle3D) As Angle3D

End Function

Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition = Position
ConvertedPosition.X = PositionRotated.X - Position.X
ConvertedPosition.Y = PositionRotated.Y - Position.Y
ConvertedPosition.Z = PositionRotated.Z - Position.Z
Dim T As Position3D

T = ConvertedPosition

T = ConvertedPosition

T = ConvertedPosition

ConvertedPosition.X = ConvertedPosition.X + PositionRotated.X
ConvertedPosition.Y = ConvertedPosition.Y + PositionRotated.Y
ConvertedPosition.Z = ConvertedPosition.Z + PositionRotated.Z
Rotate = ConvertedPosition
End Function

Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(5) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint

'Vector2
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Vector5
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

Polygon Me.hdc, Vertices(0), 5

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint

'Vector2
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Vector5
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

Polygon Me.hdc, Vertices(0), 5
End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If (KeyCode = vbKeyEscape) Then End
End Sub

ScaleMode = vbPixels
AutoRedraw = True

World3D.Width = Me.ScaleWidth
World3D.Height = Me.ScaleHeight
World3D.ZDepth = 1000
ScrollChanged
End Sub

Private Sub HScroll1_Change()
ScrollChanged
End Sub
Private Sub HScroll1_Scroll()
ScrollChanged
End Sub

Sub ScrollChanged()
Me.Cls
Angletest.X = HScroll1.Value
Angletest.Y = VScroll1.Value
Angletest.Z = HScroll2.Value

Me.Caption = Angletest.X & ", " & Angletest.Y & ", " & Angletest.Z

Dim RecPosition As Position3D
FillPosition3D RecPosition, 100, 100, 1

Dim RecSize As Size3D
FillSize3D RecSize, 50, 50, 1
DrawRectangle RecPosition, RecSize, Angletest, World3D
Me.Refresh
End Sub

Sub VScrollChanged()
ScrollChanged
End Sub

Sub ZScrollChanged()
ScrollChanged
End Sub

Private Sub HScroll2_Change()
ScrollChanged
End Sub

Private Sub HScroll2_Scroll()
ScrollChanged
End Sub

Private Sub VScroll1_Change()
ScrollChanged
End Sub

Private Sub VScroll1_Scroll()
ScrollChanged
End Sub```  Reply With Quote

10. ## Re: 3D Math: how draw a 3D cube?

Decided to change the Draw Rectangle sub again. Doubled the size of the vertices array so that we can have both rectangles in the array at the same time. Then moved the drawing of the rectangles to the end of the sub, and added to variables to track the updated Z depth of the two rectangles, so we can chose to draw the one further away first, and the closer one second.

Also, changed the FillStyle so the polygons are filled, and fill each with a different color.
That way it is more obvious when one moves behind the other during rotations.
The Z rotation didn't look like what I would expect, and I think that is because the rotations weren't done in the order that I'm use to.

The order that seems correct to me is Roll (around Z axis), Pitch(around X axis), Yaw(around Y axis), for body rotation.

So, this is the modified Rotate function, with the Z rotation moved so it is done first, and then the DrawRectangle function that fills the polygons with different colors and changes which is drawn first depending on Z depth.
I think this looks like it is working much better.
Code:
```Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition = Position
ConvertedPosition.X = PositionRotated.X - Position.X
ConvertedPosition.Y = PositionRotated.Y - Position.Y
ConvertedPosition.Z = PositionRotated.Z - Position.Z
Dim T As Position3D

'Z axis  (Roll)
T = ConvertedPosition

'X axis  (Pitch)
T = ConvertedPosition

'Y axis  (Yaw)
T = ConvertedPosition

ConvertedPosition.X = ConvertedPosition.X + PositionRotated.X
ConvertedPosition.Y = ConvertedPosition.Y + PositionRotated.Y
ConvertedPosition.Z = ConvertedPosition.Z + PositionRotated.Z
Rotate = ConvertedPosition
End Function

Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(9) As POINTAPI

Dim NewPoint As POINTAPI

Dim Z1 As Long, Z2 As Long

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint
Z1 = NewPosition3D.Z

'Vector2
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Vector5
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(5) = NewPoint
Z2 = NewPosition3D.Z

'Vector2
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(6) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(7) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(8) = NewPoint

'Vector5
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + 50
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(9) = NewPoint

FillStyle = vbFSSolid
If Z2 < Z1 Then
FillColor = vbRed
Polygon Me.hdc, Vertices(0), 5
FillColor = vbBlue
Polygon Me.hdc, Vertices(5), 5
Else
FillColor = vbBlue
Polygon Me.hdc, Vertices(5), 5
FillColor = vbRed
Polygon Me.hdc, Vertices(0), 5
End If
End Sub```  Reply With Quote

11. ## Re: 3D Math: how draw a 3D cube?

passel: on rotation i see 1 strange thing see that 1 rectangle go above the other.... something about z order or something...
move the rotation and see more carefully... unless you tell me that's normal.

correct me anotherthing: on DrawRectangle() i only get once the rotation position... is these correct or i must change for all vertices?

anotherthing: the 2D rotation must use the same method:
1 - center of shape position to 0,0;
2 - rotate;
3- go to normal position.  Reply With Quote

12. ## Re: 3D Math: how draw a 3D cube?

As for z order, yes that is an issue.
If you go back to my example in post #5, in that program I take the average Z depth of the four points that make up a rectangle (square actually) and sort the squares by that value, and then draw the squares in that order, which will draw all the squares from back to front so that those that closer to the eye should cover those that are further from the eye.

I would have to look back at the code, but I also may filter out the polygons that make up the sides you can't see (you can only see at maximum, three sides of the overall big collection of sides), so rather than sort all 54 polygons that make up the big cube, only sort the 27 polygons that are possibly visible of the three large faces.

This is a very "simple" z-ordering, and it will still have overlapped areas where the polygon Z order conflicts, when a level of cubes start revolving independent of the other levels.

For a more complete z-ordering solution, and more in line with what the 3d-engines have to do, is a Z-buffer value, where each pixel in the scene z-depth is compared to a buffer that is maintained when drawing. For every pixels on the screen, you have the color of the pixel that is being drawn there, and in a parallel buffer you have the z-depth of the pixel being drawn. If the zbuffer pixel is empty, then you draw the pixel's color in the pixel buffer and draw the depth of the pixel in the zbuffer. Before you draw a pixel's color in the pixel buffer, you always check to the zbuffer first and if a pixel has already been drawn there, if the depth of the current pixel being drawn is shallower (closer to the eye), then you put its color in the pixel buffer, and its depth in the zbuffer.

That way all the pixels that you see in the end are the pixels that are closest to the eye, and the ones "behind" are clobbered (unless you have transparency, in which case the behind pixels will change the color of the fore pixels in some way depending on translucency calculations (not to mention lighting calculations and reflection calculations and surface material type (bump mapping) type calculations being done in a "real" 3D engine).

Mikle's example in post #55 demonstrates the use of the Zbuffer to handle the overlapping and intersection conflicts of the order that pixels should be drawn in to avoid discontinuities in the drawing order.

Another approach to handling the z-order issue is a tessellation process of the polygons. The polygons used are not rectangles as we are using here, primarily because using four points for a polygon, there is no guarantee that the four points will be in the same plane so can't be depended on to always represent a flat surface.
Triangles are used, because the three points of a triangle have to be in a plane, i.e. the three points of a triangle will define the orientation of a plane that contains the three points. You can thus calculate the 90 degree (orthogonal) vector of that plane for lighting and reflection calculations and 3D graphic hardware is designed to fill triangles with a texture very quickly as the mapping of the texture to the plane of the triangle is straight forward.

In that case, a rectangle would be made up of two triangles with a common diagonal along one side edge of the triangle (i.e. diagonally bisecting the rectangle). When two triangular polygons that make up all the surfaces of all the objects in a scene end up intersecting or overlapping in z-order, the triangles are divided into two smaller triangles at the line of intersection where the two planes cross. That is the tessellation process, subdividing triangular planes into smaller triangular planes before rendering, so you can properly render the smaller triangles in the proper order to maintain z-ordering of the pixels use to fill the triangles.

So, z-ordering is a complexity, that will have to be addressed in some manner if you want to have good looking graphic interactions in 3D.

I'm not sure I understand the second question about the "get once the rotation position".
I think if I'm understanding you, your asking if you need to only calculate the rotation values (essentially the rotation matrix) for the rectangle once, rather than for each point in the rectangle.

That is true. For a given object, which could be made up of many rectangles, as long as all the points of all the rectangles belong together, so have a common position that is the center of rotation for that object, then yes, you determine what the rotation matrix values are once, then loop through all the points and apply it to get the new positions for all the points that are part of the overall object.

Third, yes 2D rotation is the same principle. 3D rotation is just 2D rotation done three times.  Reply With Quote

13. ## Re: 3D Math: how draw a 3D cube?

seems that using a cube, i must get the rotated position from all vertices... is what i see from an error drawing here.
correct me anotherthing: when the player direction(Y angle) is changed all the world must be rotated without the rotated position(center of the plane)?
i must update the World Center.... using the form size, i get the CX and CY... but from Z, i only know ZDepth/2.... what you can tell me more about Z? the Z positive is for me or far of me?  Reply With Quote

14. ## Re: 3D Math: how draw a 3D cube?

I believe the code you're using has Z increasing as it goes into the screen.

There are multiple ways to go about it, but in my case, there is a 0,0,0 reference that is the center of your world.
Then you have objects in that world, so they have position in that world. For objects that move around, it is usual for their position reference to be the center of gravity of the object. That makes it easy to spin the object around its center of gravity.
Another popular reference for vehicles would be at the center of the vehicle, between the wheels, and the plane at at bottom of the wheels.

In any case, you are currently using a corner of your rectangle as the position of the rectangle, which is why it tends to rotate off center.

So you would also have a position in this world, and where your eye is (the eye point also know as the camera position especially when not associated with a player).

You can also have a lot of fixed objects in the world, so the world position of those points never change.

Now, if you want to render a scene, you have a lot of things to do.

First would be to determine where you are in the world, and the direction you're looking and what objects are within the frustum so you know what objects will need to be included in your calculations.

Second are all the moving objects that are in the scene. For each of objects you have to do what we've been doing lately in this program. If the object has moved or turned since the last time you calculated the vertices (assuming you hang on to the 3D verticies for each object), you have to recalculate them so they reflect their current position in the 3D world. If you don't hang on to the calculated 3D vertices, you'll have to calculate them now.

Once the moving objects have been updated so their vertices reflect where they are in the 3D world, you have to convert the world coordinates for the things you're going to draw into camera relative coordinates. because where everything appears is relative to where you view them from.
That calculation is pretty simple, you just subtract the X,Y,Z position of the camera (eye point) from the vertices of the objects you're going to draw.

Next, you do the 3D rotation of all the vertices around the eyepoint.
After you have all the relative points for you given view, now would be when you would to z-ordering sorting to figure the order things should be drawn in, unless you will do pixel z-buffer processing when drawing. The z-buffering approach requires you are doing your drawing at the pixel level, rather than using API polygon or other larger area drawing methods.

The last step is the perspective projection of the 3D points to the 2D screen and doing the actual drawing.  Reply With Quote

15. ## Re: 3D Math: how draw a 3D cube?

"That calculation is pretty simple, you just subtract the X,Y,Z position of the camera (eye point) from the vertices of the objects you're going to draw."
and better after the rotation calculation thank you so much for all.. thank you  Reply With Quote

16. ## Re: 3D Math: how draw a 3D cube?

i'm sorry Passel, but i need understand more 2 things(again):
1 - when we draw the plane(floor, the sky or other), normally we use only(besides position) width and ZDepth or we must use, too, Height? if i must use the Height, isn't depend or calculated from ZDepth?(yah i'm confused on something here, like you had seen on previous post)
when i think on floor, the Height seems to be zero... but my thot may be wrong... here i need a correction... sorry

2 - when the player changes the direction, the entire world(items, walls, enemies and more) rotates the X... but the rotation position\center is the player position, right?  Reply With Quote

17. ## Re: 3D Math: how draw a 3D cube?

from '1': can you explain more how you calculated the floor?
i did the same on VB6 but isn't drawed Code:
```Private Sub DrawPlane(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D, Optional blnRotatedPositionX As Long = 0, Optional blnRotatedPositionY As Long = 0, Optional blnRotatedPositionZ As Long = 0)
Dim Vertices(5) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D
Dim FloorZDepthWorldSize As Long
FloorZDepthWorldSize = Size.ZDepth * WorldSize.ZDepth
If (FloorZDepthWorldSize = 0) Then FloorZDepthWorldSize = 1

Dim FloorZWorldSize As Long
FloorZWorldSize = Position.Z + WorldSize.ZDepth
If (FloorZWorldSize = 0) Then FloorZWorldSize = 1

Dim Z1 As Long, Z2 As Long

If (blnRotatedPositionX = 0) Then
FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2
Else
FillPosition3D RotatedPosition, Me.ScaleWidth / 2, Me.ScaleHeight / 2, WorldSize.ZDepth / 2
End If

'Back Plane:

'Vector1

NewPosition3D = Rotate(Position, Rotation, RotatedPosition)
FillPosition2D NewPoint, (NewPosition3D.X) * WorldSize.ZDepth / FloorZWorldSize, (NewPosition3D.Y) * WorldSize.ZDepth / FloorZDepthWorldSize

Vertices(0) = NewPoint

'Vector2
'FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z - Size.ZDepth
'NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
'NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)

NewPosition3D = Rotate(Position, Rotation, RotatedPosition)
FillPosition2D NewPoint, (NewPosition3D.X + Size.Width) * WorldSize.ZDepth / FloorZWorldSize, NewPosition3D.Y * WorldSize.ZDepth / FloorZDepthWorldSize

Vertices(1) = NewPoint

'Vector3
'FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z - Size.ZDepth
'NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
'NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
NewPosition3D = Rotate(Position, Rotation, RotatedPosition)
FillPosition2D NewPoint, (NewPosition3D.X + Size.Width) * WorldSize.ZDepth / FloorZWorldSize, (NewPosition3D.Y + Size.Height) * WorldSize.ZDepth / FloorZWorldSize
Vertices(2) = NewPoint

'Vector4
'FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z - Size.ZDepth
'NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
'NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
NewPosition3D = Rotate(Position, Rotation, RotatedPosition)
FillPosition2D NewPoint, (NewPosition3D.X + Size.Width) * WorldSize.ZDepth / FloorZWorldSize, (NewPosition3D.Y + Size.Height) * WorldSize.ZDepth / FloorZWorldSize
Vertices(3) = NewPoint

'Vector5
'FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z - Size.ZDepth
'NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
'NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)

NewPosition3D = Rotate(Position, Rotation, RotatedPosition)
FillPosition2D NewPoint, (NewPosition3D.X) * WorldSize.ZDepth / FloorZWorldSize, (NewPosition3D.Y) * WorldSize.ZDepth / FloorZWorldSize

Vertices(4) = NewPoint

FillColor = vbRed
Polygon Me.hdc, Vertices(0), 5
End Sub```  Reply With Quote

18. ## Re: 3D Math: how draw a 3D cube?

Well, I think the main problem is that you are trying to define a simple figure like a Rectangle as a modified 2D object, which makes it hard to orient it in 3D space, because you are defining it in terms of Height, width and depth, which by definition means the rectangle has to be aligned with two of the X,Y or Z axis. In order to have it not align, you have to define the correct rotation values for the three axis so the corners end up in 3D space where you want them.

That is a hard way to define the four points of an arbitrary rectangle.

It would be much easier to define the four corners of the rectangle in 3D coordinates and be done with it.

Assume your eyepoint is looking down the Z axis, into the screen and you want a wall in front of you.
And it would probably make sense to say the floor is at Y = 0, so we will use that.

(Note: although the height of the ceiling is 6000 pixels, remember that the Y axis is reversed so ceiling will -6000 above the floor
Ok, say we decided the eye distance to the screen is 1000 pixels.
And lets assume if you're standing, your eye point is -3000 pixels above the floor.
Now, we already said the floor's level will be 0, so it is 3000 pixels below our eye.
And, lets say the room if fairly tall, so the height of the ceiling we will make 6000 pixels.

So, any wall that goes from Floor to ceiling will be -6000 pixels tall.
And lets say the room or hallway is 10000 pixels wide.
In camera coordinates, lets define a wall that is 24000 pixels in front of us.
Lets say our eyepoint in world coordinates is {100000, -3000, 200000}

Lets define a wall that would be 24000 pixels in front of us (camera coordinates) at our currently location.

By the way, you've been defining 5 coordinates for your rectangles, the last being the same as the first, but you don't have to do that to close the polygon. The polygon will automatically be closed from the last point, to the first point, so that is extra work on your part, and probably extra work for the polygon function.

{left, floor, Z},{left,ceiling,Z},{right,ceiling,Z},{right,floor, Z}
Front wall = {95000, 0, 224000}, {95000, -6000, 224000}, {105000, -6000, 224000}, {105000, 0, 224000}

When you convert that to camera coordinates, it will become:
Front wall = {-5000, 3000, 24000}, -5000, -3000, 24000}, {5000, -3000, 24000}, {5000, 3000, 24000]

So, in our world, we're defining a rectangle that is 6000 pixels in height, 10000 pixels wide, and is aligned with the Z axis at 224000.
If you want to use the bottom left corner of the rectangle as your position, then the position is our first coordinate, {95000, 0, 224000}.

Lets assume the side walls, ceiling and floor will all start at our current eyepoint Z location + 4000 ( 204000), and end at the wall in front of us (Z = 224000}

Floor
{95000, 0, 204000}, {95000, 0, 224000}, {105000, 0, 224000}, {105000, 0, 204000}

Ceiling (same as floor, except y is at ceiling height)
{95000, 6000, 204000}, {95000, 6000, 224000}, {105000, 6000, 224000}, {105000, 6000, 204000}

Left Wall
{95000, 0, 204000}, {95000, 6000, 204000}, {95000, 6000, 224000}, 95000, 0, 224000}

Right wall (same as left wall, but X is aligned with right side)
{105000, 0, 204000}, {105000, 6000, 204000}, {105000, 6000, 224000}, 105000, 0, 224000}

Its late, so I didn't try to change all your code to work with coordinates like this, but I did do a quick test based on the above coordinates, so you could see the projection of a floor, ceiling and the left wall.

First, a fix to the ConvertPosition3DTo2D Function.
You had PosZZDepth defined as an Integer, but all your positions are Longs, so that needed to be changed to a long to not overflow with the above world coordinates.
Also, since we don't want the eyepoint to be located in the upper left corner when projecting the view, added the half height and width values to the coordinates so the eye point is centered in the window.
Code:
```Private Function ConvertPositon3DTo2D(Position As Position3D, World3DSize As Size3D) As POINTAPI
Dim ConvertedPosition As POINTAPI
Dim PosZZDepth As Long

PosZZDepth = Position.Z + World3DSize.ZDepth

If (PosZZDepth = 0) Then PosZZDepth = 1 'avoiding division by zero

ConvertedPosition.X = (Position.X * World3DSize.ZDepth / PosZZDepth) + World3DSize.Width / 2
ConvertedPosition.Y = (Position.Y * World3DSize.ZDepth / PosZZDepth) + World3DSize.Height / 2
ConvertPositon3DTo2D = ConvertedPosition
End Function```
Then for testing the above values, I just patched the values for the three wall into the vertices array in the DrawRectangle Sub.
I did some minor fixes in the Rotate sub to get the Y values moving in the right direction (+ moves down the screen).
I also used an instance of the Player UDT to serve as the Camera Position, and change the rotated coordinates to camera coordinates as the last step of the Rotate Sub.

You can't rotate very far left or right, or up and down, because there is no protection in the code for clipping the 3d line vectors properly when the rotation takes points behind the camera. If you draw things that are behind the camera, you get inverted drawing in both axis, so your polygons get twisted. They shouldn't be drawn when in that condition. I haven't worked out that fix in the past, so handling that would be new territory for me, and I don't know if I will have the time to try to work that. I shouldn't even be doing this post, as I have a busy day tomorrow, and its getting extremely late.

Since I made a number of changes, and may miss something if I just try to post updated code, I'll post the complete code again.
Code:
```Option Explicit

Private Type POINTAPI
X As Long
Y As Long
End Type

Private Declare Function Polygon Lib "gdi32" (ByVal hdc As Long, lpPoint As POINTAPI, ByVal nCount As Long) As Long

Private Type Position3D
X As Double
Y As Double
Z As Double
End Type

Private Type Angle3D
X As Double
Y As Double
Z As Double
End Type

Private Type Size3D
Width As Long
Height As Long
ZDepth As Long
End Type

Private Type Player
Position As Position3D
Angle As Angle3D
End Type

Private Const Pi As Double = 3.14159265358979
Dim World3D As Size3D
Dim Angletest As Angle3D

Dim Player1 As Player

Private Sub LetPoint3dArray(la() As Position3D, ParamArray va() As Variant)
' No error trapping, so use with caution.
Dim i       As Long
Dim j       As Long
Dim k      As Long

k = (UBound(va) + 1) \ 3 - 1
ReDim la(k)
For i = 0& To k
la(i).X = va(j): j = j + 1
la(i).Y = va(j): j = j + 1
la(i).Z = va(j): j = j + 1
Next
End Sub

Private Sub FillPosition2D(Position As POINTAPI, X As Long, Y As Long)
Position.X = X
Position.Y = Y
End Sub

Private Sub FillPosition3D(Position As Position3D, X As Double, Y As Double, Z As Double)
Position.X = X
Position.Y = Y
Position.Z = Z
End Sub

Private Sub FillSize3D(Size As Size3D, Width As Long, Height As Long, ZDepth As Long)
Size.Width = Width
Size.Height = Height
Size.ZDepth = ZDepth
End Sub

Private Function ConvertPositon3DTo2D(Position As Position3D, World3DSize As Size3D) As POINTAPI
Dim ConvertedPosition As POINTAPI
Dim PosZZDepth As Long

PosZZDepth = Position.Z + World3DSize.ZDepth

If (PosZZDepth = 0) Then PosZZDepth = 1 'avoiding division by zero

ConvertedPosition.X = (Position.X * World3DSize.ZDepth / PosZZDepth) + World3DSize.Width / 2
ConvertedPosition.Y = (Position.Y * World3DSize.ZDepth / PosZZDepth) + World3DSize.Height / 2
ConvertPositon3DTo2D = ConvertedPosition
End Function

Private Function ConvertDegreesToRadians(Rotation As Angle3D) As Angle3D

End Function

Private Function Rotate(Position As Position3D, Rotation As Angle3D, PositionRotated As Position3D) As Position3D
Dim ConvertedPosition As Position3D

ConvertedPosition = Position
ConvertedPosition.X = Position.X - PositionRotated.X
ConvertedPosition.Y = -(PositionRotated.Y - Position.Y)  'reversed because Y increments down
ConvertedPosition.Z = Position.Z - PositionRotated.Z
Dim T As Position3D

'Z axis  (Roll)
T = ConvertedPosition

'X axis  (Pitch)
T = ConvertedPosition

'Y axis  (Yaw)
T = ConvertedPosition

ConvertedPosition.X = ConvertedPosition.X + PositionRotated.X
ConvertedPosition.Y = ConvertedPosition.Y + PositionRotated.Y
ConvertedPosition.Z = ConvertedPosition.Z + PositionRotated.Z

'Convert to Camera Coordinates
ConvertedPosition.X = ConvertedPosition.X - Player1.Position.X
ConvertedPosition.Y = ConvertedPosition.Y - Player1.Position.Y
ConvertedPosition.Z = ConvertedPosition.Z - Player1.Position.Z

Rotate = ConvertedPosition
End Function

Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(11) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

'    FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2
With Player1.Position
FillPosition3D RotatedPosition, .X, .Y, .Z  'Camera Position
End With

'Vector1
' FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
FillPosition3D NewPosition3D, 95000, 0, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint

'Vector2
FillPosition3D NewPosition3D, 95000, 0, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, 105000, 0, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, 105000, 0, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Vector1
FillPosition3D NewPosition3D, 95000, -6000, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

'Vector2
FillPosition3D NewPosition3D, 95000, -6000, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(5) = NewPoint

'Vector3
FillPosition3D NewPosition3D, 105000, -6000, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(6) = NewPoint

'Vector4
FillPosition3D NewPosition3D, 105000, -6000, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(7) = NewPoint

'Vector1
FillPosition3D NewPosition3D, 95000, 0, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(8) = NewPoint

'Vector2
FillPosition3D NewPosition3D, 95000, -6000, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(9) = NewPoint

'Vector3
FillPosition3D NewPosition3D, 95000, -6000, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(10) = NewPoint

'Vector4
FillPosition3D NewPosition3D, 95000, 0, 224000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(11) = NewPoint

FillStyle = vbFSSolid

FillColor = vbRed
Polygon Me.hdc, Vertices(0), 4

FillColor = vbBlue
Polygon Me.hdc, Vertices(4), 4

FillColor = vbGreen
Polygon Me.hdc, Vertices(8), 4
End Sub

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If (KeyCode = vbKeyEscape) Then End
End Sub

ScaleMode = vbPixels
AutoRedraw = True

FillPosition3D Player1.Position, 100000, -3000, 200000   'Camera Position

World3D.Width = Me.ScaleWidth
World3D.Height = Me.ScaleHeight
World3D.ZDepth = 1000
ScrollChanged
End Sub

Private Sub HScroll1_Change()
ScrollChanged
End Sub
Private Sub HScroll1_Scroll()
ScrollChanged
End Sub

Sub ScrollChanged()
Me.Cls
Angletest.X = HScroll1.Value
Angletest.Y = VScroll1.Value
Angletest.Z = HScroll2.Value

Me.Caption = Angletest.X & ", " & Angletest.Y & ", " & Angletest.Z

Dim RecPosition As Position3D
FillPosition3D RecPosition, 100, 100, 1

Dim RecSize As Size3D
FillSize3D RecSize, 50, 50, 1
DrawRectangle RecPosition, RecSize, Angletest, World3D
Me.Refresh
End Sub

Sub VScrollChanged()
ScrollChanged
End Sub

Sub ZScrollChanged()
ScrollChanged
End Sub

Private Sub HScroll2_Change()
ScrollChanged
End Sub

Private Sub HScroll2_Scroll()
ScrollChanged
End Sub

Private Sub VScroll1_Change()
ScrollChanged
End Sub

Private Sub VScroll1_Scroll()
ScrollChanged
End Sub```  Reply With Quote

19. ## Re: 3D Math: how draw a 3D cube?

Thanks so much. Yesterday I couldn't login on pc. I did now using the mobile phone. Maybe after some time I can login again on pc.
Correct me 1 thing: using the new convert3Dto2D function we can create rectangles without using Z and Zdepth?
I must retest the code, but yesterday was hard reload the page. For that I used another page for load the page. Thanks for all  Reply With Quote

20. ## Re: 3D Math: how draw a 3D cube? Originally Posted by joaquim ...
Correct me 1 thing: using the new convert3Dto2D function we can create rectangles without using Z and Zdepth?
...
The ConvertPositon3DTo2D function isn't really New, it works the same as it did before. I just fixed a Type on the local variable (changing from Integer to Long), and added the center of the window offsets to the returned X,Y values, so the projection's center (0,0) was in the center of the form, rather than in the upper left corner of the form.

You've been leaving the center of the projection in its default position, i.e. the Upper-Left corner of the form, so you could never see things that were to the left of your eye/camera or above your eye/camera.

Those fixes or additions have no impact on how you define objects in your world, so have nothing to do with using Z and Zdepth in your rectangle definitions.
Using Z and Zdepth in your rectangle definitions is a standalone design decision, which I didn't fully understand and just added confusion for me.
Bottom line, however you choose to define an object, in the end the points that make up the object have to be converted to 3D world coordinates.

So, if you want to use a 3D position, and 3D dimension, and 3D angles to define your object, and use those to convert to 3D world coordinates before calling the Rotate function, that is up to you, but I find that hard to work with.

Since you need the objects to end up in 3D world coordinates, then I find it easier to either define the object in 3D world coordinates to begin with, in the case where the object is a permanent part of the 3D world, or define them using local (body reference coordinates), i.e. the center of a figure of a character that is moving in your 3D world may be a point in the center of the character, near the waist, so the position of the head would normally be a negative value (because of the way the Y axis is defined) some distance above the center, and the feet would be a positive value some distance below the center.

If you want to rotate the character around the three axis, then you just use the local body coordinates to do the rotation since they are already relative to the center of the body, you don't need to subtract the position, do the rotation, and then add the position back.
You only need to add the position to the local coordinates to "move" the object to where it is located in your 3D world, i.e. you add the object's position to the object's local rotated body coordinates to convert the vertices to 3D world coordinates.

Which is why I think you have two much code in the Rotate function. Ideally, the Rotate function should just rotate the points it is given, it shouldn't be responsible for converting 3D world coordinates into local body coordinates, doing the rotation and converting them back to 3D world coordinates. The World to local and local to World conversions should be done outside that function.

Because you are doing those conversions inside the function, then in the case where we want to rotate the world, so the world is essentially our local coordinates, we have to do the extra work of undoing the local to World conversion done in the Rotation. That is why I had to add this second set of translations
Code:
```        'Convert to Camera Coordinates
ConvertedPosition.X = ConvertedPosition.X - Player1.Position.X
ConvertedPosition.Y = ConvertedPosition.Y - Player1.Position.Y
ConvertedPosition.Z = ConvertedPosition.Z - Player1.Position.Z```
to the end of the rotate function, essentially undoing the previous local to World translation that was done in front of it.

Bottom line, the Rotate function should just Rotate, and any Translations of coordinates that need to be done should be their own function or done directly in the code that calls the rotate function, so you don't have all these extra parameters and hacks in the rotate function to deal with coordinate translations.

p.s. I do believe the ConvertPositon3DTo2D function will have to be modified to truncate points, i.e. modify points that lie behind the eyepoint to values that are in front of the eyepoint (but most likely still outside the viewing frustum, or perhaps all points that end up outside the viewing frustum could be truncated to the edge of the frustum), so that you don't get the twisted/inverted view of things behind you showing up in front of you in the window.
You can't simple just limit the X and/or Y value to the frustum, the X and/or Y value has to be calculated to end where the line they are a part of intersect the plane of the frustum, otherwise the angle of the line is changed.

That is something I haven't worked out before, but SeabrookStan's example in post #52 says it does it, so it would be worth checking out that code as a possible reference, in addition to any web searches on the subject.
You didn't have VB6 installed previously, apparently, so you may not have looked at his Demo. You should probably look at it now, since it is an interesting demo.  Reply With Quote

21. ## Re: 3D Math: how draw a 3D cube?

i'm sorry... but i need understand more 1 thing: please see these line:
Code:
`FillPosition3D Player1.Position, 100000, -3000, 200000   'Camera Position`
how do you know that coordinates are the form center? how do you get that values?

on DrawRectangle() function: why you use a number positions instead the variables?
Code:
```Private Sub DrawRectangle(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(11) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

'    FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2
With Player1.Position
FillPosition3D RotatedPosition, .X, .Y, .Z  'Camera Position
End With

'Vector1
' FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
FillPosition3D NewPosition3D, 95000, 0, 204000 'why numbers instead variables?
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)```  Reply With Quote

22. ## Re: 3D Math: how draw a 3D cube? Originally Posted by joaquim i'm sorry... but i need understand more 1 thing: please see these line:
Code:
`FillPosition3D Player1.Position, 100000, -3000, 200000   'Camera Position`
how do you know that coordinates are the form center? how do you get that values?
Those numbers aren't the form center, they are arbitrary values chosen for the example.
Wherever the player is, in this case, is where the camera is, at the players eye level. This is what is known as a First Person View (FPV), as in FPS (First Person Shooter) type game. You are seeing the world as you would see the world through your eyes as a character in the game.

I could have chosen any values, but since your Z Depth calculations are based on Pixel coordinates (i.e. the eye is 1000 pixels from the screen), then I was using pixel coordinates for everything else, in the world, as I explain.
For instance, as I said, I chose the eye level to be 3000 pixels above the floor, so that is why the Y value is -3000.

For the other numbers (X and Z), I figured the player should be in the 3D World someplace, and since pixels are a very small unit of measurement (in the Simulation world, we usually use meters as our coordinate units, not pixels), I chose relative large numbers, but 100000 pixels would only be a 30 to 40 meters into the real 3D world at normal scale. Of course, if you had a miniature world where people and cars for instance were only 100 pixels tall, and could only move 100s of pixels per second instead of 50 meters per second, for instance, then the world would appear much larger to the small objects that occupied it.

So, the X and Z values were arbitrary, just giving a current reference point for where the character is in the 3D world. In a FPV, the character is always the center of the view, no mater where they go. So, for projection on the screen, all world coordinates will be converted to character eyepoint (camera) coordinates to produce the scene. Originally Posted by joaquim ...

DrawRectangle() function: why you use a number positions instead the variables?
Simple answer, because this was an example, and the numbers were already explained as being world coordinates and were defined to be in front of the world position of the First Person View, it was easier to patch the literal numbers into a series of vertices calculations so you could see them all in one set of steps.

Because this was just patched in numbers to illustrate what I was talking about, i.e. simple World coordinates for the Floor, Ceiling and Wall.
You have multiple structucture that have to be passed as parameters, i.e. Position, Size, Rotation and WorldSize, and that is for one rectangle.
You then create the points of the rectangle based on combinations of values from those various structures.

If I was to use those structures and variables, I would have to figure out how to simple world coordinates for a vertex (e.g. 95000, 0, 204000), and figure out how to break it apart and create values in Position and size structures that would convert back to the proper values I wanted at that point.
And since the example was creating three rectangles, that would be a lot of additional setup and calling code outside the function to make that happen.
I didn't want to spend that much time working that out, especially since I had just said that is expressing simple 3D things in a complicated modified 2D manner of defining objects.

So, rather than use the function to draw a rectangle and generate the misshaped structures needed to use the function, I just in-lined the code to draw the three rectangles within the function. The steps taken to convert the numbers from world coordinates to projected coordinates is thus right there to step through.

I figured once you see the process steps in line, you can decide if you want to change your structure, or calls, or simply take the literal numbers used in the example, and create the initialization of whatever variables you see fit to hold those values outside the function, and pass them in as three separate calls to create the three rectangles. If you wanted them in variables, I assumed you could put them in variables. That would give you the opportunity to decide if you wanted to restructure the way you managed storing the rectangles as well, to make things easier to work with.

You were defining a plane function, and a rectangle function. What is the real difference between a plane and a rectangle. It seems like you were started down a rabbit hole, and I didn't want to follow.  Reply With Quote

23. ## Re: 3D Math: how draw a 3D cube?

now i understand much more about it.
but correct me anotherthing: the World3D.ZDepth is 1000, but the camera Z position is 200000... what these means? the ZDepth don't must be more big that the camera Z position?
the same happens with World3D size.  Reply With Quote

24. ## Re: 3D Math: how draw a 3D cube?

You called it World3d.ZDepth, but it doesn't have anything to do with the world's 3D depth.
It is the distance from your eye to the screen.

So, as you sit at the computer, we're saying your eye is about 1000 pixels distance from the screen.
It doesn't matter where you move in the world that is projected on the screen, the distance from your eye to the screen should be the same, in theory.

If you take the code from the bottom of post #98 in a new project, so you don't disturb anything you have been doing, you can add a couple of thin pictureboxes (like scrollbar shaped) to the form to use as "touchpads" to change the player's X and Z position in the world, i.e. you're moving the eyepoint, aka the camera viewpoint. That way you can back away from the initial starting position, 100000, -3000, 200000, and see the walls move away from the screen, and if you move left and right, you see the walls move and change perspective. If you're careful, you can back away, move to one side, spin the view slightly to keep the walls in the middle, and continue moving to the side, and once the walls are far enough to the right of your position, you can start moving up in Z and make your way to the other side of the walls, and then continue turning around and, moving in X and Z and eventually be on the other side from where you started, and looking south instead of north, and the green wall will be on your right, instead of on your left.

Eventually you could add controls that would be easier to manipulate the position and view direction, but adding two pictureboxes to use as "touchpads", and a little bit of code will be the quickest and easiest to give you a little bit of rudimentary movement.

The first picturebox should be oriented like a vertical scrollbar, so tall and skinny. The second picturebox should be oriented like a horizontal picturebox, so short and wide. You don't need to change the scalemode, as moving 12 to 15 pixels at a time (or whatever your twips conversion values are) is not too slow. Moving only 1 pixel at a time would be extremely slow.

So, if you add the two pictureboxes, this is the code to go with them.
Code:
```Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Static lx As Single, ly As Single
If Button = vbLeftButton Then
Player1.Position.Z = Player1.Position.Z + (ly - Y)
ScrollChanged
End If
lx = X: ly = Y
End Sub

Private Sub Picture2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Static lx As Single, ly As Single
If Button = vbLeftButton Then
Player1.Position.X = Player1.Position.X + (X - lx)
ScrollChanged
End If
lx = X: ly = Y
End Sub```
Dragging the mouse on the pictureboxes will player's X or Z position, and the view will be updated because of the call to the ScrollChanged sub.  Reply With Quote

25. ## Re: 3D Math: how draw a 3D cube?

i'm using the timer without success Code:
```Private Sub Timer1_Timer()
Const Speed As Integer = 1
If GetKeyState(vbKeyA) And KEY_DOWN Then
Angletest.Y = Angletest.Y + 1
ScrollChanged
ElseIf GetKeyState(vbKeyD) And KEY_DOWN Then
Angletest.Y = Angletest.Y - 1
ScrollChanged

ElseIf GetKeyState(vbKeyLeft) And KEY_DOWN Then
Player1.Position.X = Player1.Position.X - 1
Player1.Movement.X = Player1.Movement.X - 1
ScrollChanged
ElseIf GetKeyState(vbKeyRight) And KEY_DOWN Then
Player1.Position.X = Player1.Position.X + 1
Player1.Movement.X = Player1.Movement.X + 1
ScrollChanged
ElseIf GetKeyState(vbKeyUp) And KEY_DOWN Then
Player1.Position.Z = Player1.Position.Z - Speed
ScrollChanged
ElseIf GetKeyState(vbKeyDown) And KEY_DOWN Then
Player1.Position.Z = Player1.Position.Z + Speed
ScrollChanged
End If
End Sub```
lets see the keydown and keyup...
Code:
```Sub ScrollChanged()
Me.Cls
'Angletest.X = HScroll1.Value
'Angletest.Y = VScroll1.Value
'Angletest.Z = HScroll2.Value

Label1.Caption = Angletest.X & ", " & Angletest.Y & ", " & Angletest.Z
Label1.Caption = Label1.Caption & vbNewLine & Player1.Movement.X & ", " & Player1.Movement.Y & ", " & Player1.Movement.Z

Dim RecPosition As Position3D
FillPosition3D RecPosition, 95000, 0, 204000
Dim RecSize As Size3D
FillSize3D RecSize, 10000, -6000, 20000
DrawCube RecPosition, RecSize, Angletest, World3D
Me.Refresh
End Sub```
and i updated the drawrectangle to drawcube and using variabels names:
Code:
```Private Sub DrawCube(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Vertices(11) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

'FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2
With Player1.Position
FillPosition3D RotatedPosition, .X, .Y, .Z  'Camera Position
End With

'Floor:
'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
'FillPosition3D NewPosition3D, 95000, 0, 204000
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(0) = NewPoint

'Vector2
'FillPosition3D NewPosition3D, 95000, 0, 224000
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(1) = NewPoint

'Vector3
'FillPosition3D NewPosition3D, 105000, 0, 224000
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(2) = NewPoint

'Vector4
'FillPosition3D NewPosition3D, 105000, 0, 204000
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(3) = NewPoint

'Roof:
'Vector1
'FillPosition3D NewPosition3D, 95000, -6000, 204000
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(4) = NewPoint

'Vector2
'FillPosition3D NewPosition3D, 95000, -6000, 224000
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(5) = NewPoint

'Vector3
'FillPosition3D NewPosition3D, 105000, -6000, 224000
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(6) = NewPoint

'Vector4
'FillPosition3D NewPosition3D, 105000, -6000, 204000
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(7) = NewPoint

'Left:
'Vector1
'FillPosition3D NewPosition3D, 95000, 0, 204000
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(8) = NewPoint

'Vector2
'FillPosition3D NewPosition3D, 95000, -6000, 204000
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(9) = NewPoint

'Vector3
'FillPosition3D NewPosition3D, 95000, -6000, 224000
FillPosition3D NewPosition3D, Position.X, Position.Y + Size.Height, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(10) = NewPoint

'Vector4
'FillPosition3D NewPosition3D, 95000, 0, 224000
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Vertices(11) = NewPoint

FillStyle = vbFSSolid

FillColor = vbRed
Polygon Me.hdc, Vertices(0), 4

FillColor = vbBlue
Polygon Me.hdc, Vertices(4), 4

FillColor = vbGreen
Polygon Me.hdc, Vertices(8), 4
End Sub```
for now i'm trying the Z and X movement without success   Reply With Quote

26. ## Re: 3D Math: how draw a 3D cube?

Perhaps add some Debug.Print statements in the timer code to see if you're getting into any of the If conditions, and to make sure the timer code is running.  Reply With Quote

27. ## Re: 3D Math: how draw a 3D cube?

you don't belive: now works... i just change the speed:
Code:
```Private Sub Timer1_Timer()
Const Speed As Integer = 20
If KeyState(vbKeyA) = True Then
Angletest.Y = Angletest.Y + 1
ScrollChanged
ElseIf GetKeyState(vbKeyD) And KEY_DOWN Then
Angletest.Y = Angletest.Y - 1
ScrollChanged

ElseIf GetKeyState(vbKeyLeft) And KEY_DOWN Then
Player1.Position.X = Player1.Position.X - Speed

ScrollChanged
ElseIf GetKeyState(vbKeyRight) And KEY_DOWN Then
Player1.Position.X = Player1.Position.X + Speed
ScrollChanged
ElseIf GetKeyState(vbKeyUp) And KEY_DOWN Then
Player1.Position.Z = Player1.Position.Z + Speed
ScrollChanged
ElseIf GetKeyState(vbKeyDown) And KEY_DOWN Then
Player1.Position.Z = Player1.Position.Z - Speed
ScrollChanged
End If
End Sub```
now i need understand how i can change how can i calculate for draw the visible vertices  Reply With Quote

28. ## Re: 3D Math: how draw a 3D cube?

Yeah, I was about to say it worked for me. I changed the timer interval to 1, so the timer would fire as fast as possible, and I changed the speed to 20 (which you did also), so the movement would happen faster.
As I said, using pixels as the world units is pretty small units to use, so things move very little when you only move 1 pixel in world space.
And since you are looking at the world from 1000 pixels away, i.e. the screen, and then the walls themselves are even further away, more than 4000 pixels in z, up to 24000 pixels in z, then moving your view point by 1 pixel, moves the world view in subpixel steps, i.e. the farther something is from your eye, the slower it appears to move in the scene compared to your eye.

I don't know if you had the experience when you were a small child of looking out the side window of a moving car and thinking that the moon was following your car because you could see the trees and other things outside the car whizzing past the window, but the moon looked like it was keeping pace with the car. Because it is so far away, it looks when you change your position (i.e. you're moving with the car and the window is moving with the car, and you are seeing the world through the frame of the window), the moon does not appear to be moving across the window as you move.

Figuring out how to clip the polygons as they reach the edge of your view, or not drawing them at all if they are completely out of view, is the next big challenge, and is much more complicated than anything done so far.  Reply With Quote

29. ## Re: 3D Math: how draw a 3D cube?

maybe thinking on these way:
1 - testing the 3D collision between the vertice and the camera view;
2 - testing if the next vertice is inside de view for we change the distance between the 2 vertices;
3 - we now get the new vertice...
maybe is these the best for don't show hidded vertices... but items and the NPC's in back wall are more difficulty to think... unless i drawed them any way thinking on Z order  Reply With Quote

30. ## Re: 3D Math: how draw a 3D cube?

now i have seen how you work with camera... on rotation, you use:
1 - the rotation camera position;
2 - you add the camera position after rotate the vertice.

i need ask more 2 things:
1 - is my thot, about don't draw the camera outside vertices right?
2 - even using the ZOrder, the items after a wall(what we don't see because another object is on front) must be drawed(even thinking on a window or a door)?  Reply With Quote

31. ## Re: 3D Math: how draw a 3D cube?

1. You don't draw things that are completely outside the camera view, but you may need to draw things that are in view, but extend outside the view. In that case, you'll need to truncate the object going out of view.

The way you currently draw that may be difficult. If you look at SeabrookStan's code, all his objects and things he draws are made up of lines.
So as each line is drawn, it can determine if the line will exceed the frame, and the line shortened to stop at that frame.

Since you are filling a polygon, you may have to shorten two lines, and you can't eliminate the line that may be completely off screen, because you still need it to close the polygon.

2. Yes, a simple approach is to draw everything, back to front. If you don't have a hole in a foreground object, then perhaps you could skip drawing some things, but of course, you have to know that what is in front does fully block something behind it. When you're rotating around and seeing things from different angles, that may be hard to determine.

There is a mode of Ray Tracing that is suppose to be pretty quick, where you scan pixels horizontally looking for the first object hit in z-depth, and then draw the vertical line associated with that object for that horizontal position. Don't think that will work for you since you aren't mapping a texture to an object, but filling with a polygon call, so you don't really have a vertical line of pixels to transfer.
I may not be remembering the details correctly, haven't tried the method myself.

I've just drawn everything from back to the front. But, for individual objects, like a cube, you can of course not draw the backside of the cube.
The standard way of doing backface culling is to always define your polygons in a clockwise direction, from the perspective of facing the polygon.
So the polygons on the back of the cube would be define in a counter-clockwise direction. When you rotate a view, and get the new coordinates, a test to see if the coordinates are clockwise or not determines whether you draw it or not. For instance, if the cube is rotated so that the back is facing the camera, the counter-clockwise coordinates of the back face, will become clockwise after the rotation, so you draw it.

With that method, if you want to see both sides of a wall, as we are currently seeing if we rotate, you have to define the rectangle twice, one clockwise, and one counter-clockwise, so one of them will be drawn depending on which side of the wall you're looking at.  Reply With Quote

32. ## Re: 3D Math: how draw a 3D cube?

i have the 3D collision function:
Code:
```Private Function IsCollission3D(ObjectPosition1 As Position3D, ObjectSize1 As Size3D, ObjectPosition2 As Position3D, ObjectSize2 As Size3D)
IsCollission3D = ((ObjectPosition1.X <= (ObjectPosition2.X + ObjectSize2.Width)) And ((ObjectPosition1.X + ObjectSize1.Width) >= ObjectPosition2.X) And (ObjectPosition1.Y <= (ObjectPosition2.Y + ObjectSize2.Height)) And ((ObjectPosition1.Y + ObjectSize1.Height) >= ObjectPosition2.Y) And (ObjectPosition1.Z <= (ObjectPosition2.Z + ObjectSize2.ZDepth)) And ((ObjectPosition1.Z + ObjectSize1.ZDepth) >= ObjectPosition2.Z))
End Function

Private Function IsVerticeCollission3D(Vertice1 As Position3D, Vertice2 As Position3D)
IsVerticeCollission3D = ((Vertice1.X <= (Vertice2.X)) And ((Vertice1.X) >= Vertice2.X) And (Vertice1.Y <= (Vertice2.Y)) And ((Vertice1.Y) >= Vertice2.Y) And (Vertice1.Z <= (Vertice2.Z)) And ((Vertice1.Z) >= Vertice2.Z))
End Function```
now i need ask(speaking on same line): how can i add\sub X,Y,Z camera view to the vertice?  Reply With Quote

33. ## Re: 3D Math: how draw a 3D cube?

I don't know.
If you are doing the collisions in cameraview coordinates, then you would convert the coordinates to cameraview coordinates and pass those to the function.
The function should only be doing collision testing on a set of coordinates, not be concerned what the reference for the coordinates are.

Just looking at it the IsVerticeCollission3D function.
(Vertice1.X <= (Vertice2.X)) And ((Vertice1.X) >= Vertice2.X)

That will only be True if Vertice1.X equals Vertice2.X, so why not just have (Vertice1.X = Vertice2.X), i.e. a single comparison rather than two comparisons and a logical operation.  Reply With Quote

34. ## Re: 3D Math: how draw a 3D cube?

i still confused with 1 thing: i think the avoid draw everything is for don't use severy the CPU... that i understand... so what i'm asking!?!
that code works fine but something don't make sence to me...
see these normal draw when i start:

https://imgur.com/yHN339L

now see these bug draw after some move to front(player\camera Z):

https://imgur.com/dRq42TD

i know the draw is more big than window size, but is these normal?

edit: the X and Y calculations seems correct, but not the Z calculation
edit2: the problem have to do with 'World3D.ZDepth = 1000': the more less number will get more quickly that second image...  Reply With Quote

35. ## Re: 3D Math: how draw a 3D cube?

Post #50 Originally Posted by passel ...
That is an issue as you move through an environment, eventually, some of the points are going to be outside your field of view, or behind your eyepoint. You have to accommodate those situations, because in some cases, the calculation will wrap in a way so instead of a trapezoidal type shape, the edges may cross each other and you end up with a twisted, hourglass shaped polygon.

I haven't really worked out how to truncate the shape when it goes out of bounds, so you'll have to do some research on an approach.
Since the original DOOM engine code is online, perhaps examining that code could be instructive, but I haven't the time myself.
Post #98 Originally Posted by passel ...
You can't rotate very far left or right, or up and down, because there is no protection in the code for clipping the 3d line vectors properly when the rotation takes points behind the camera. If you draw things that are behind the camera, you get inverted drawing in both axis, so your polygons get twisted. They shouldn't be drawn when in that condition. I haven't worked out that fix in the past, so handling that would be new territory for me, and I don't know if I will have the time to try to work that.
...
Post #100 Originally Posted by passel ...
p.s. I do believe the ConvertPositon3DTo2D function will have to be modified to truncate points, i.e. modify points that lie behind the eyepoint to values that are in front of the eyepoint (but most likely still outside the viewing frustum, or perhaps all points that end up outside the viewing frustum could be truncated to the edge of the frustum), so that you don't get the twisted/inverted view of things behind you showing up in front of you in the window.
You can't simple just limit the X and/or Y value to the frustum, the X and/or Y value has to be calculated to end where the line they are a part of intersect the plane of the frustum, otherwise the angle of the line is changed.

That is something I haven't worked out before, but SeabrookStan's example in post #52 says it does it, so it would be worth checking out that code as a possible reference, in addition to any web searches on the subject.
...
Post #108 Originally Posted by passel ...
Figuring out how to clip the polygons as they reach the edge of your view, or not drawing them at all if they are completely out of view, is the next big challenge, and is much more complicated than anything done so far.  Reply With Quote

36. ## Re: 3D Math: how draw a 3D cube?

finally i'm doing something:
Code:
```Private Function IsCollision3D(ObjectPosition1 As Position3D, ObjectSize1 As Size3D, ObjectPosition2 As Position3D, ObjectSize2 As Size3D)
IsCollision3D = ((ObjectPosition1.X <= (ObjectPosition2.X + ObjectSize2.Width)) And ((ObjectPosition1.X + ObjectSize1.Width) >= ObjectPosition2.X) And (ObjectPosition1.Y <= (ObjectPosition2.Y + ObjectSize2.Height)) And ((ObjectPosition1.Y + ObjectSize1.Height) >= ObjectPosition2.Y) And (ObjectPosition1.Z <= (ObjectPosition2.Z + ObjectSize2.ZDepth)) And ((ObjectPosition1.Z + ObjectSize1.ZDepth) >= ObjectPosition2.Z))
End Function

Private Function IsCollisionVertice3D(Vertice1 As Position3D, ObjectPosition2 As Position3D, ObjectSize2 As Size3D)
IsCollisionVertice3D = ((Vertice1.X <= (ObjectPosition2.X + ObjectSize2.Width)) And ((Vertice1.X) >= ObjectPosition2.X) And (Vertice1.Y <= (ObjectPosition2.Y + ObjectSize2.Height)) And ((Vertice1.Y) >= ObjectPosition2.Y) And (Vertice1.Z <= (ObjectPosition2.Z + ObjectSize2.ZDepth)) And ((Vertice1.Z) >= ObjectPosition2.Z))
End Function

Private Sub DrawPlane(Position As Position3D, Size As Size3D, Rotation As Angle3D, WorldSize As Size3D)
Dim Points(4) As POINTAPI

Dim NewPoint As POINTAPI

Dim NewPosition3D As Position3D
Dim RotatedPosition As Position3D

'FillPosition3D RotatedPosition, Position.X + Size.Width / 2, Position.Y + Size.Height / 2, Position.Z + Size.ZDepth / 2
With Player1.Position
FillPosition3D RotatedPosition, .X, .Y, .Z  'Camera Position
End With

If (IsCollision3D(Player1.Position, World3D, Position, Size) = False) Then Exit Sub

'Floor:
'Vector1
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
If (IsCollisionVertice3D(NewPosition3D, Player1.Position, World3D) = False) Then
NewPosition3D.Z = Player1.Position.Z
End If
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Points(0) = NewPoint

'Vector2
FillPosition3D NewPosition3D, Position.X, Position.Y, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
If (IsCollisionVertice3D(NewPosition3D, Player1.Position, World3D) = False) Then
NewPosition3D.Z = Player1.Position.Z
End If
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Points(1) = NewPoint

'Vector3
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z + Size.ZDepth
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
If (IsCollisionVertice3D(NewPosition3D, Player1.Position, World3D) = False) Then
NewPosition3D.Z = Player1.Position.Z
End If
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Points(2) = NewPoint

'Vector4
FillPosition3D NewPosition3D, Position.X + Size.Width, Position.Y, Position.Z
NewPosition3D = Rotate(NewPosition3D, Rotation, RotatedPosition)
If (IsCollisionVertice3D(NewPosition3D, Player1.Position, World3D) = False) Then
NewPosition3D.Z = Player1.Position.Z
End If
NewPoint = ConvertPositon3DTo2D(NewPosition3D, WorldSize)
Points(3) = NewPoint

FillStyle = vbFSSolid

FillColor = vbRed
Polygon Me.hdc, Points(0), 4
End Sub```
these code draw 1 line... the 1st 'if' seems working:
Code:
`If (IsCollision3D(Player1.Position, World3D, Position, Size) = False) Then Exit Sub`
but i'm doing 1 thing wrong: i don't test it with rotated positions...
but i have another error: i'm testing if the point\vertice is on player front:
Code:
```If (IsCollisionVertice3D(NewPosition3D, Player1.Position, World3D) = False) Then
NewPosition3D.Z = Player1.Position.Z
End If```
is my 'if' thinking wrong or the IsCollisionVertice3D() function is wrong?
Code:
```Private Function IsCollisionVertice3D(Vertice1 As Position3D, ObjectPosition2 As Position3D, ObjectSize2 As Size3D)
IsCollisionVertice3D = ((Vertice1.X <= (ObjectPosition2.X + ObjectSize2.Width)) And ((Vertice1.X) >= ObjectPosition2.X) And (Vertice1.Y <= (ObjectPosition2.Y + ObjectSize2.Height)) And ((Vertice1.Y) >= ObjectPosition2.Y) And (Vertice1.Z <= (ObjectPosition2.Z + ObjectSize2.ZDepth)) And ((Vertice1.Z) >= ObjectPosition2.Z))
End Function```
sometimes isn't showed correctly... can you please see these 2 functions?  Reply With Quote

#### Posting Permissions

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

Featured