_TITLE "3D Render" ' B+ started 2019-10-20 ' Based on notes provided to QB64 forum by William F Barnes, on 2019-10-19
' https://www.qb64.org/forum/index.php?topic=1782.0
' A vector's dimension is the number of components it has.
' Here is code for processing 2 and 3 dimension vectors.
'2019-11-20 add STxAxTIC's conversion code for new sub screenXY
' Nice cube corners maker and nice wireframe cube
CONST xmax
= 700, ymax
= 700 CONST tlx
= -100, tly
= 100, brx
= 100, bry
= -100 ' Cartesian Coordinate System corners for WINDOW command ' to convert mouse coordinates to WINDOW after call look up PMAP
' notation 0 w/arrowHat (no way of telling if 2, 3 or more dimensions)
v2zero.x = 0: v2zero.y = 0
v3zero.x = 0: v3zero.y = 0: v3zero.z = 0
'Basis Vectors, isolate components e sub x Dot V w/arrowHat = V sub x
v2e(1).x = 1: v2e(1).y = 0
v2e(2).x = 0: v2e(2).y = 1
v3e(1).x = 1: v3e(1).y = 0: v3e(1).z = 0
v3e(2).x = 0: v3e(2).y = 1: v3e(2).z = 0
v3e(3).x = 0: v3e(3).y = 0: v3e(3).z = 1
fovd = 10 '???
'==================================================================================== test area 2019-11-20
WINDOW (tlx
, tly
)-(brx
, bry
) ' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< get a Cartesian Coordinate System started ' >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> to convert mouse coordinates to WINDOW after call look up PMAP
'all z's must be negative!!!! there seems a flip flop mirror upside down image passing zero top pos hit inf at 0!!!!!!!!!
newCube x, y, z, 10, testCube()
'FOR i = 0 TO 7
' PRINT v3$(testCube(i))
'NEXT
'good! now convert these to screen projection points
screenXY testCube(i), screenTest(i)
'PRINT screenTest(i).x, screenTest(i).y
drawWireCube screenTest()
PRINT "Press any to wakeup from sleep, esc to quit..." newCube
RND * 100 - 50, RND * 100 - 50, -30 * RND - 6, 10, testCube
() 'good! now convert these to screen projection points
screenXY testCube(i), screenTest(i)
PRINT screenTest
(i
).x
, screenTest
(i
).y
drawWireCube screenTest()
SUB drawWireCube
(corners
() AS xyType
) 'front face
LINE (corners
(0).x
, corners
(0).y
)-(corners
(1).x
, corners
(1).y
) LINE -(corners
(2).x
, corners
(2).y
) LINE -(corners
(3).x
, corners
(3).y
) LINE -(corners
(0).x
, corners
(0).y
) 'back face
LINE (corners
(4).x
, corners
(4).y
)-(corners
(5).x
, corners
(5).y
) LINE -(corners
(6).x
, corners
(6).y
) LINE -(corners
(7).x
, corners
(7).y
) LINE -(corners
(4).x
, corners
(4).y
) 'connect from to back
LINE (corners
(0).x
, corners
(0).y
)-(corners
(4).x
, corners
(4).y
) LINE (corners
(1).x
, corners
(1).y
)-(corners
(5).x
, corners
(5).y
) LINE (corners
(2).x
, corners
(2).y
)-(corners
(6).x
, corners
(6).y
) LINE (corners
(3).x
, corners
(3).y
)-(corners
(7).x
, corners
(7).y
)
SUB newCube
(cx
, cy
, cz
, side
, cubeCorners
() AS xyzType
) DIM sd2
, lx
, rx
, ty
, by
, fz
, bz
sd2 = side / 2
rx = cx + sd2: lx = cx - sd2
ty = cy + sd2: by = cy - sd2
fz = cz + sd2: bz = cz - sd2
cubeCorners(0).x = lx: cubeCorners(0).y = ty: cubeCorners(0).z = fz
cubeCorners(1).x = rx: cubeCorners(1).y = ty: cubeCorners(1).z = fz
cubeCorners(2).x = rx: cubeCorners(2).y = by: cubeCorners(2).z = fz
cubeCorners(3).x = lx: cubeCorners(3).y = by: cubeCorners(3).z = fz
cubeCorners(4).x = lx: cubeCorners(4).y = ty: cubeCorners(4).z = bz
cubeCorners(5).x = rx: cubeCorners(5).y = ty: cubeCorners(5).z = bz
cubeCorners(6).x = rx: cubeCorners(6).y = by: cubeCorners(6).z = bz
cubeCorners(7).x = lx: cubeCorners(7).y = by: cubeCorners(7).z = bz
' project (x, y, z) point in real space to screenXY of user's eye-line
SUB screenXY
(xyzReal
AS xyzType
, xyScreen
AS xyType
) 'convert STxAxTIC's code to my code here
' https://www.qb64.org/forum/index.php?topic=1904.msg111304#msg111304
' vec3Ddotnhat = vec(i, 1) * nhat(1) + vec(i, 2) * nhat(2) + vec(i, 3) * nhat(3)
' vec2D(i, 1) = (vec(i, 1) * uhat(1) + vec(i, 2) * uhat(2) + vec(i, 3) * uhat(3)) * fovd / vec3Ddotnhat
' vec2D(i, 2) = (vec(i, 1) * vhat(1) + vec(i, 2) * vhat(2) + vec(i, 3) * vhat(3)) * fovd / vec3Ddotnhat
'my comments and conversion
'fovd seems like a variable that should be globally shared, maybe constant?
vec3Ddotnhat = v3DotProduct(xyzReal, v3e(3))
xyScreen.x = v3DotProduct(xyzReal, v3e(1)) * fovd / vec3Ddotnhat
xyScreen.y = v3DotProduct(xyzReal, v3e(2)) * fovd / vec3Ddotnhat
'================================================= subs and fuctions from Vector Math.bas 2019-10-20
SUB setV3
(x
, y
, z
, setMe
AS xyzType
) setMe.x = x: setMe.y = y: setMe.z = z
v3$ = "[" + ts$(showMeInnards.x) + ", " + ts$(showMeInnards.y) + ", " + ts$(showMeInnards.z) + "]"
'notation UppercaseLetter w/arrowhat + uppercase Letter w/arrowHat
SUB v2Add
(A
AS xyType
, B
AS xyType
, Sum
AS xyType
) Sum.x = A.x + B.x
Sum.y = A.y + B.y
SUB v3Add
(A
AS xyzType
, B
AS xyzType
, Sum
AS xyzType
) Sum.x = A.x + B.x
Sum.y = A.y + B.y
Sum.z = A.z + B.z
'notation UppercaseLetter w/arrowHat - UppercaseLetter w/arrowHat
SUB v2Subtr
(A
AS xyType
, B
AS xyType
, Sum
AS xyType
) Sum.x = A.x - B.x
Sum.y = A.y - B.y
SUB v3Subtr
(A
AS xyzType
, B
AS xyzType
, Sum
AS xyzType
) Sum.x = A.x - B.x
Sum.y = A.y - B.y
Sum.z = A.z - B.z
'notation lowercaseletter (for a number next to (times)) UppercaseLetter w/arrowHat
Scale.x = mult * A.x
Scale.y = mult * A.y
Scale.x = mult * A.x
Scale.y = mult * A.y
Scale.z = mult * A.z
'notation the inverse of A w/arrowHat is -A w/arrowHat
SUB v2Inverse
(A
AS xyType
, Inverse
AS xyType
) ' A + InverseOfA = 0 Inverse.x = -A.x
Inverse.y = -A.y
SUB v3Inverse
(A
AS xyzType
, Inverse
AS xyzType
) ' A + InverseOfA = 0 Inverse.x = -A.x
Inverse.y = -A.y
Inverse.z = -A.z
'notation: A w/arrowHat Dot B w/arrowHat v2 Dot Product is a number, v3 Dot Product is a vector
FUNCTION v2DotProduct
(A
AS xyType
, B
AS xyType
) 'shadow or projection if A Dot B = 0 then A , B are perpendicular v2DotProduct = A.x * B.x + A.y * B.y
FUNCTION v3DotProduct
(A
AS xyzType
, B
AS xyzType
) 'shadow or projection if A Dot B = 0 then A , B are perpendicular v3DotProduct = A.x * B.x + A.y * B.y + A.z * B.z
'notation absolute value bars about A w/arrowHat OR just an UppercaseLetter (with no hat), its just a number
FUNCTION v2Magnitude
(A
AS xyType
) 'hypotenuse of right triangle v2Magnitude
= SQR(v2DotProduct
(A
, A
))FUNCTION v3Magnitude
(A
AS xyzType
) 'hypotenuse of cube v3Magnitude
= SQR(v3DotProduct
(A
, A
))
'notation: A w/arrowHat X B w/arrowHat, X is a Cross get it?
FUNCTION v2CrossProduct
(A
AS xyType
, B
AS xyType
) ' a vector perpendicular to both A and B, v2 is a magnitude v2CrossProduct = A.x * B.y - A.y * B.x
SUB v3CrossProduct
(A
AS xyzType
, B
AS xyzType
, Cross
AS xyzType
) ' v3 cross product is a 3d vector perpendicular to A and B 'notice x has no x components, y no y componets, z no z components
Cross.x = A.y * B.z - A.z * B.y
Cross.y = A.z * B.x - A.x * B.z
Cross.z = A.x * B.y - A.y * B.x
'notation: A w/caratHat = A w/arrowHat divided by A (UppercaseLetter) or scaled by 1/A magnitude (no hats)
SUB v2Unit
(A
AS xyType
, Unit
AS xyType
) m = v2Magnitude(A)
v2Scale 1 / m, A, Unit
SUB v3Unit
(A
AS xyzType
, Unit
AS xyzType
) m = v3Magnitude(A)
v3Scale 1 / m, A, Unit