This belongs in Games and Graphics but it seems that posting rates are so low nobody goes there. But a mod could always move this too.
I was curious as a non-graphics programmer how people do things like spin a globe without carrying around pretty massive amounts of image data (individual frames).
I noticed that flat rectangular "cylindrical projection" images are often used, but I wasn't sure how.
Here is a hack that came to me:
This uses a ton of CPU and it probably isn't "correct" because the compression as we approach each pole probably shouldn't be linear across each scanline. But is this sort of technique considered "good enough" for most non-cartographic purposes?
Is there a better, maybe even more obvious technique without using 3D graphics libraries?
Or if "good enough" is there a better approach (coordinate transforms?) that isn't as expensive as painting line by line?
![Name: sshot.png
Views: 53
Size: 9.0 KB]()
I was curious as a non-graphics programmer how people do things like spin a globe without carrying around pretty massive amounts of image data (individual frames).
I noticed that flat rectangular "cylindrical projection" images are often used, but I wasn't sure how.
Here is a hack that came to me:
Code:
Option Explicit
'Obviously for a real program you'd replace these VB6 drawing methods with the underlying
'GDI calls, e.g. StretchBlt() and friends. But this is just a test of concept. I was
'trying out an idea to see how close it got me to the desired result.
'
'Basic concept here:
'
' StretchBlt lines pole to pole, narrowing toward each pole of the sphere.
Private OrigSourceWidthPixels As Single
Private SourceCopyWidth As Single
Private OnePixel As Single
Private Center As Single
Private Radius As Single
Private OffsetPixels As Long
Private Sub PaintGlobe()
Dim Offset As Single
Dim ScanLine As Single
Dim Distance As Single
Dim Chord As Single
If OffsetPixels > OrigSourceWidthPixels Then
OffsetPixels = OffsetPixels - OrigSourceWidthPixels
End If
With picDest
Offset = .ScaleX(OffsetPixels, vbPixels)
For ScanLine = 0 To .ScaleHeight - OnePixel Step OnePixel
Distance = Abs(Center - ScanLine)
Chord = 2 * Sqr(Radius * Radius - Distance * Distance)
picDest.PaintPicture picSource.Picture, _
(.ScaleWidth - Chord) / 2, _
ScanLine, _
Chord, _
OnePixel, _
Offset, _
ScanLine, _
SourceCopyWidth, _
OnePixel
Next
End With
End Sub
Private Sub Form_Load()
Dim OrigSourceWidth As Single
'Enlarge by half, copying the left "half" to the new "third" of the image. We use
'this to "wrap around" the globe:
With picSource
OrigSourceWidth = .ScaleWidth
.Width = ScaleX(OrigSourceWidth * 1.5, .ScaleMode)
.AutoRedraw = True
.PaintPicture .Picture, _
OrigSourceWidth, _
0, _
OrigSourceWidth / 2, _
.ScaleHeight, _
0, _
0, _
OrigSourceWidth / 2
.AutoRedraw = False
Set .Picture = .Image
End With
With picDest
OrigSourceWidthPixels = .ScaleX(OrigSourceWidth, picSource.ScaleMode, vbPixels)
SourceCopyWidth = .ScaleX(OrigSourceWidth / 2, picSource.ScaleMode)
OnePixel = .ScaleX(1, vbPixels)
Center = (.ScaleHeight - OnePixel) / 2
Radius = .ScaleHeight / 2
End With
PaintGlobe
Timer1.Enabled = True
End Sub
Private Sub Timer1_Timer()
OffsetPixels = OffsetPixels + 2
PaintGlobe
End Sub
Is there a better, maybe even more obvious technique without using 3D graphics libraries?
Or if "good enough" is there a better approach (coordinate transforms?) that isn't as expensive as painting line by line?