This repository was archived by the owner on Jan 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathTChecker.cls
More file actions
575 lines (512 loc) · 17.7 KB
/
TChecker.cls
File metadata and controls
575 lines (512 loc) · 17.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "RayMappedCheckerboard"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
' A textured checkerboard in a plane.
Implements RayTraceable
' The texture picture's pixels.
Private TexturePixels() As RGBTriplet
Private Point1 As Point3D ' Point on corner.
Private Point2 As Point3D ' Point on 1st corner of first rectangle.
Private Point3 As Point3D ' Point on 2nd corner of first rectangle.
Private NumSquares1 As Integer ' # squares in 1st direction.
Private NumSquares2 As Integer ' # squares in 2nd direction.
' Ambient light parameters.
Private AmbientFactor As Single
' Diffuse light parameters.
Private DiffuseFactor As Single
' Specular reflection parameters.
Private SpecularN As Single
Private SpecularK As Single
' Reflected light parameters.
Private ReflectedKr As Single
Private ReflectedKg As Single
Private ReflectedKb As Single
' Refracted light parameters.
Private TransN As Single
Private n1 As Single ' Index of refraction outside the object.
Private n2 As Single ' Index of refraction inside the object.
Private TransmittedKr As Single
Private TransmittedKg As Single
Private TransmittedKb As Single
Private IsReflective As Boolean
Private IsTransparent As Boolean
Private DoneOnThisScanline As Boolean
' We had a hit on this scanline.
Private HadHit As Boolean
' We have had a hit on a previous scanline.
Private HadHitOnPreviousScanline As Boolean
' We will not be visible on later scanlines.
Private ForeverCulled As Boolean
' Get the point's checkerboard coordinates.
' Return True if the point is on a square.
Private Function GetCheckerboardCoordinates(ByRef i As Single, ByRef j As Single, ByVal X As Single, ByVal Y As Single, ByVal Z As Single) As Boolean
Dim px As Single
Dim py As Single
Dim pz As Single
Dim v1x As Single
Dim v1y As Single
Dim v1z As Single
Dim v2x As Single
Dim v2y As Single
Dim v2z As Single
' Get the square vectors.
px = Point1.Trans(1)
py = Point1.Trans(2)
pz = Point1.Trans(3)
v1x = Point2.Trans(1) - px
v1y = Point2.Trans(2) - py
v1z = Point2.Trans(3) - pz
v2x = Point3.Trans(1) - px
v2y = Point3.Trans(2) - py
v2z = Point3.Trans(3) - pz
' Get the i and j values for this point.
If (Abs(v1x) > 0.001) And (Abs(v1y * v2x - v2y * v1x) > 0.001) Then
j = (v1y * (X - px) + v1x * (py - Y)) / (v1y * v2x - v2y * v1x)
i = (X - px - v2x * j) / v1x
ElseIf (Abs(v1y) > 0.001) And (Abs(v1z * v2y - v2z * v1y) > 0.001) Then
j = (v1z * (Y - py) + v1y * (pz - Z)) / (v1z * v2y - v2z * v1y)
i = (Y - py - v2y * j) / v1y
Else
j = (v1x * (Z - pz) + v1z * (px - X)) / (v1x * v2z - v2x * v1z)
i = (Z - pz - v2z * j) / v1z
End If
' See if the point is ok.
If (i < 0) Or (j < 0) Or (i > NumSquares1) Or (j > NumSquares2) Then
' Not on the area of interest.
GetCheckerboardCoordinates = False
ElseIf (Int(i) + Int(j)) Mod 2 <> 0 Then
' Not on a drawn square.
GetCheckerboardCoordinates = False
Else
' We had a hit.
GetCheckerboardCoordinates = True
End If
End Function
' Return an appropriate color for this object.
Private Function GetColor() As Long
Dim R As Integer
Dim G As Integer
Dim B As Integer
R = 255 * (DiffuseFactor + AmbientFactor): If R > 255 Then R = 255
G = R
B = R
GetColor = RGB(R, G, B)
End Function
' Return the right shade for this polygon.
Private Function GetShade(ByVal pgon As SimplePolygon) As Long
Dim i As Integer
Dim px As Single
Dim py As Single
Dim pz As Single
Dim light_source As LightSource
Dim total_r As Single
Dim total_g As Single
Dim total_b As Single
Dim R1 As Integer
Dim g1 As Integer
Dim b1 As Integer
Dim empty_objects As Collection
With pgon
' Find a central point on this polygon.
For i = 1 To .PointX.Count
px = px + .PointX(i)
py = py + .PointY(i)
pz = pz + .PointZ(i)
Next i
px = px / .PointX.Count
py = py / .PointX.Count
pz = pz / .PointX.Count
' Add up the light components.
Set empty_objects = New Collection
For Each light_source In LightSources
CalculateHitColorDSA _
1, empty_objects, Nothing, _
EyeX, EyeY, EyeZ, _
px, py, pz, .Nx, .Ny, .Nz, _
DiffuseFactor, DiffuseFactor, DiffuseFactor, _
AmbientFactor, AmbientFactor, AmbientFactor, _
SpecularK, SpecularN, R1, g1, b1
total_r = total_r + R1
total_g = total_g + g1
total_b = total_b + b1
Next light_source
End With
If total_r > 255 Then total_r = 255
If total_g > 255 Then total_g = 255
If total_b > 255 Then total_b = 255
GetShade = RGB(total_r, total_g, total_b)
End Function
' Return the unit surface normal.
Private Sub GetUnitNormal(ByRef Nx As Single, ByRef Ny As Single, ByRef Nz As Single)
Dim v1x As Single
Dim v1y As Single
Dim v1z As Single
Dim v2x As Single
Dim v2y As Single
Dim v2z As Single
Dim n_len As Single
' Get the square vectors.
v1x = Point2.Trans(1) - Point1.Trans(1)
v1y = Point2.Trans(2) - Point1.Trans(2)
v1z = Point2.Trans(3) - Point1.Trans(3)
v2x = Point3.Trans(1) - Point1.Trans(1)
v2y = Point3.Trans(2) - Point1.Trans(2)
v2z = Point3.Trans(3) - Point1.Trans(3)
' Calculate the normal.
m3Cross Nx, Ny, Nz, v1x, v1y, v1z, v2x, v2y, v2z
n_len = Sqr(Nx * Nx + Ny * Ny + Nz * Nz)
Nx = Nx / n_len
Ny = Ny / n_len
Nz = Nz / n_len
End Sub
' Add non-backface polygons to this collection.
Public Sub RayTraceable_GetPolygons(ByRef num_polygons As Integer, polygons() As SimplePolygon, ByVal shaded As Boolean)
Dim pgon As SimplePolygon
Dim px As Single
Dim py As Single
Dim pz As Single
Dim v1x As Single
Dim v1y As Single
Dim v1z As Single
Dim v2x As Single
Dim v2y As Single
Dim v2z As Single
Dim i As Integer
Dim j As Integer
' Get the square vectors.
px = Point1.Trans(1)
py = Point1.Trans(2)
pz = Point1.Trans(3)
v1x = Point2.Trans(1) - px
v1y = Point2.Trans(2) - py
v1z = Point2.Trans(3) - pz
v2x = Point3.Trans(1) - px
v2y = Point3.Trans(2) - py
v2z = Point3.Trans(3) - pz
' Make the squares.
For i = 0 To NumSquares1 - 1
For j = 0 To NumSquares2 - 1
If (i + j) Mod 2 = 0 Then
' Make a polygon.
Set pgon = New SimplePolygon
pgon.AddPoint px + i * v1x + j * v2x, py + i * v1y + j * v2y, pz + i * v1z + j * v2z
pgon.AddPoint px + (i + 1) * v1x + j * v2x, py + (i + 1) * v1y + j * v2y, pz + (i + 1) * v1z + j * v2z
pgon.AddPoint px + (i + 1) * v1x + (j + 1) * v2x, py + (i + 1) * v1y + (j + 1) * v2y, pz + (i + 1) * v1z + (j + 1) * v2z
pgon.AddPoint px + i * v1x + (j + 1) * v2x, py + i * v1y + (j + 1) * v2y, pz + i * v1z + (j + 1) * v2z
' See if we are shaded.
If shaded Then
' We are shaded. Get the right color.
pgon.ForeColor = GetShade(pgon)
pgon.FillColor = pgon.ForeColor
Else
' We are not shaded. Use the normal colors.
pgon.ForeColor = vbBlack
pgon.FillColor = GetColor()
End If
' Add the polygon to the list.
num_polygons = num_polygons + 1
ReDim Preserve polygons(1 To num_polygons)
Set polygons(num_polygons) = pgon
End If
Next j
Next i
End Sub
' Draw a wireframe for this object.
Public Sub RayTraceable_DrawWireFrame(ByVal pic As PictureBox)
Dim px As Single
Dim py As Single
Dim v1x As Single
Dim v1y As Single
Dim v2x As Single
Dim v2y As Single
Dim i As Integer
Dim j As Integer
' Use an appropriate color.
pic.ForeColor = GetColor()
' Get the square vectors.
px = Point1.Trans(1)
py = Point1.Trans(2)
v1x = Point2.Trans(1) - px
v1y = Point2.Trans(2) - py
v2x = Point3.Trans(1) - px
v2y = Point3.Trans(2) - py
' Draw the squares.
For i = 0 To NumSquares1 - 1
For j = 0 To NumSquares2 - 1
If (i + j) Mod 2 = 0 Then
pic.Line (px + i * v1x + j * v2x, py + i * v1y + j * v2y)-(px + (i + 1) * v1x + j * v2x, py + (i + 1) * v1y + j * v2y)
pic.Line -(px + (i + 1) * v1x + (j + 1) * v2x, py + (i + 1) * v1y + (j + 1) * v2y)
pic.Line -(px + i * v1x + (j + 1) * v2x, py + i * v1y + (j + 1) * v2y)
pic.Line -(px + i * v1x + j * v2x, py + i * v1y + j * v2y)
End If
Next j
Next i
End Sub
' Initialize the object using text parameters in
' a comma-delimited list.
Public Sub SetParameters(ByVal pic As PictureBox, ByVal txt As String)
Dim file_name As String
Dim bits_per_pixel As Integer
On Error GoTo CheckerboardParamError
' Read the parameters and initialize the object.
' Load the texture file.
file_name = GetDelimitedToken(txt, ",")
pic.AutoSize = True
pic.AutoRedraw = True
pic.Picture = LoadPicture(file_name)
GetBitmapPixels pic, TexturePixels, bits_per_pixel
' Geometry.
NumSquares1 = CInt(GetDelimitedToken(txt, ","))
NumSquares2 = CInt(GetDelimitedToken(txt, ","))
Point1.Coord(1) = CSng(GetDelimitedToken(txt, ","))
Point1.Coord(2) = CSng(GetDelimitedToken(txt, ","))
Point1.Coord(3) = CSng(GetDelimitedToken(txt, ","))
Point1.Coord(4) = 1
Point2.Coord(1) = CSng(GetDelimitedToken(txt, ","))
Point2.Coord(2) = CSng(GetDelimitedToken(txt, ","))
Point2.Coord(3) = CSng(GetDelimitedToken(txt, ","))
Point2.Coord(4) = 1
Point3.Coord(1) = CSng(GetDelimitedToken(txt, ","))
Point3.Coord(2) = CSng(GetDelimitedToken(txt, ","))
Point3.Coord(3) = CSng(GetDelimitedToken(txt, ","))
Point3.Coord(4) = 1
' Ambient light.
AmbientFactor = CSng(GetDelimitedToken(txt, ","))
' Diffuse reflection.
DiffuseFactor = CSng(GetDelimitedToken(txt, ","))
' Specular reflection.
SpecularN = CSng(GetDelimitedToken(txt, ","))
SpecularK = CSng(GetDelimitedToken(txt, ","))
' Reflected light.
ReflectedKr = CSng(GetDelimitedToken(txt, ","))
ReflectedKg = CSng(GetDelimitedToken(txt, ","))
ReflectedKb = CSng(GetDelimitedToken(txt, ","))
IsReflective = (ReflectedKr > 0) Or (ReflectedKg > 0) Or (ReflectedKb > 0)
' Transmitted light.
TransN = CSng(GetDelimitedToken(txt, ","))
n1 = CSng(GetDelimitedToken(txt, ","))
n2 = CSng(GetDelimitedToken(txt, ","))
TransmittedKr = CSng(GetDelimitedToken(txt, ","))
TransmittedKg = CSng(GetDelimitedToken(txt, ","))
TransmittedKb = CSng(GetDelimitedToken(txt, ","))
IsTransparent = (TransmittedKr > 0) Or (TransmittedKg > 0) Or (TransmittedKb > 0)
Exit Sub
CheckerboardParamError:
MsgBox "Error initializing checkerboard parameters."
End Sub
' Apply a transformation matrix to the object.
Public Sub RayTraceable_Apply(M() As Single)
' Transform the points.
m3Apply Point1.Coord, M, Point1.Trans
m3Apply Point2.Coord, M, Point2.Trans
m3Apply Point3.Coord, M, Point3.Trans
End Sub
' Apply a transformation matrix to the object.
Public Sub RayTraceable_ApplyFull(M() As Single)
' Transform the points.
m3ApplyFull Point1.Coord, M, Point1.Trans
m3ApplyFull Point2.Coord, M, Point2.Trans
m3ApplyFull Point3.Coord, M, Point3.Trans
End Sub
' Draw the object with backfaces removed.
' Draw the whole wire frame for planes.
Public Sub RayTraceable_DrawBackfacesRemoved(ByVal pic As PictureBox)
RayTraceable_DrawWireFrame pic
End Sub
' Return the red, green, and blue components of
' the surface at the hit position.
Public Sub RayTraceable_FindHitColor(ByVal depth As Integer, Objects As Collection, ByVal eye_x As Single, ByVal eye_y As Single, ByVal eye_z As Single, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByRef R As Integer, ByRef G As Integer, ByRef B As Integer)
Dim Nx As Single
Dim Ny As Single
Dim Nz As Single
Dim Vx As Single
Dim Vy As Single
Dim Vz As Single
Dim NdotV As Single
Dim ambient_kr As Single
Dim ambient_kg As Single
Dim ambient_kb As Single
Dim diffuse_kr As Single
Dim diffuse_kg As Single
Dim diffuse_kb As Single
Dim checker_x As Single
Dim checker_y As Single
Dim clr As Long
Dim base_r As Single
Dim base_g As Single
Dim base_b As Single
' Find the unit normal at this point.
GetUnitNormal Nx, Ny, Nz
' Make sure the normal points towards the
' center of projection.
Vx = EyeX - px
Vy = EyeY - py
Vz = EyeZ - pz
NdotV = Nx * Vx + Ny * Vy + Nz * Vz
If NdotV < 0 Then
Nx = -Nx
Ny = -Ny
Nz = -Nz
End If
' Get the point's checkerboard coordinates.
GetCheckerboardCoordinates checker_x, checker_y, px, py, pz
If checker_x >= 1 Then checker_x = checker_x - Int(checker_x)
If checker_y >= 1 Then checker_y = checker_y - Int(checker_y)
' Get the color of the texture picture at
' this point.
InterpolateColor base_r, base_g, base_b, _
TexturePixels, _
checker_x * UBound(TexturePixels, 1), _
checker_y * UBound(TexturePixels, 2)
base_r = base_r / 255
base_g = base_g / 255
base_b = base_b / 255
' Get the hit color.
CalculateHitColor depth, Objects, Me, _
eye_x, eye_y, eye_z, _
px, py, pz, _
Nx, Ny, Nz, _
DiffuseFactor * base_r, DiffuseFactor * base_g, DiffuseFactor * base_b, _
AmbientFactor * base_r, AmbientFactor * base_g, AmbientFactor * base_b, _
SpecularK, SpecularN, _
ReflectedKr, ReflectedKg, ReflectedKb, IsReflective, _
TransmittedKr, TransmittedKg, TransmittedKb, TransN, n1, n2, IsTransparent, _
R, G, B
End Sub
' See if the scanline plane with the indicated
' point and normal intersects this object.
Public Sub RayTraceable_CullScanline(ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Nx As Single, ByVal Ny As Single, ByVal Nz As Single)
' Do not scanline cull.
DoneOnThisScanline = False
End Sub
' Return the value T for the point of intersection
' between the vector from point (px, py, pz) in
' the direction <vx, vy, vz>.
'
' direct_calculation is true if we are finding the
' intersection from a viewing position ray. It is
' false if we are finding an reflected intersection
' or a shadow feeler.
Public Function RayTraceable_FindT(ByVal direct_calculation As Boolean, ByVal px As Single, ByVal py As Single, ByVal pz As Single, ByVal Vx As Single, ByVal Vy As Single, ByVal Vz As Single) As Single
Dim A As Single
Dim B As Single
Dim C As Single
Dim D As Single
Dim Nx As Single
Dim Ny As Single
Dim Nz As Single
Dim denom As Single
Dim t As Single
Dim Cx As Single
Dim Cy As Single
Dim Cz As Single
Dim dx As Single
Dim dy As Single
Dim dz As Single
Dim X As Single
Dim Y As Single
Dim Z As Single
Dim checker_x As Single
Dim checker_y As Single
' See if we have been culled.
If direct_calculation And DoneOnThisScanline Then
RayTraceable_FindT = -1
Exit Function
End If
' Find the unit normal at this point.
GetUnitNormal Nx, Ny, Nz
' Compute the plane's parameters.
A = Nx
B = Ny
C = Nz
D = -(Nx * Point1.Trans(1) + _
Ny * Point1.Trans(2) + _
Nz * Point1.Trans(3))
' If the denominator = 0, the ray is parallel
' to the plane so there's no intersection.
denom = A * Vx + B * Vy + C * Vz
If denom = 0 Then
RayTraceable_FindT = -1
Exit Function
End If
' Solve for t.
t = -(A * px + B * py + C * pz + D) / denom
' If there is no positive t value, there's no
' intersection in this direction.
If t < 0.01 Then
RayTraceable_FindT = -1
Exit Function
End If
' Get the point of intersection with the plane.
X = px + t * Vx
Y = py + t * Vy
Z = pz + t * Vz
' See if the point is on a square.
If GetCheckerboardCoordinates(checker_x, checker_y, X, Y, Z) Then
' The point is on a square.
' We had a hit.
If direct_calculation Then HadHit = True
RayTraceable_FindT = t
Else
' The point is not on a square.
RayTraceable_FindT = -1
End If
End Function
' Return the minimum and maximum distances from
' this point.
' Use the wireframe points.
Private Sub RayTraceable_GetRminRmax(new_min As Single, new_max As Single, ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
Dim dx As Single
Dim dy As Single
Dim dz As Single
Dim px As Single
Dim py As Single
Dim pz As Single
Dim v1x As Single
Dim v1y As Single
Dim v1z As Single
Dim v2x As Single
Dim v2y As Single
Dim v2z As Single
Dim i As Integer
Dim j As Integer
Dim dist As Single
new_min = 1E+30
new_max = -1E+30
' Get the square vectors.
px = Point1.Trans(1)
py = Point1.Trans(2)
pz = Point1.Trans(3)
v1x = Point2.Trans(1) - px
v1y = Point2.Trans(2) - py
v1z = Point2.Trans(3) - pz
v2x = Point3.Trans(1) - px
v2y = Point3.Trans(2) - py
v2z = Point3.Trans(3) - pz
For i = 0 To NumSquares1 Step NumSquares1
For j = 0 To NumSquares2 Step NumSquares2
dx = X - (px + i * v1x + j * v2x)
dy = Y - (py + i * v1y + j * v2y)
dz = Z - (pz + i * v1z + j * v2z)
dist = Sqr(dx * dx + dy * dy + dz * dz)
If new_min > dist Then new_min = dist
If new_max < dist Then new_max = dist
Next j
Next i
End Sub
' Reset the ForeverCulled flag.
Private Sub RayTraceable_ResetCulling()
ForeverCulled = False
HadHitOnPreviousScanline = False
End Sub