添加旋轉
按照上面的算法我們只能看到北面。不同的角度需要多行代碼來旋轉坐標。
def Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height):
# precalculate viewing angle parameters
var sinphi = math.sin(phi);
var cosphi = math.cos(phi);
# Draw from back to the front (high z coordinate to low z coordinate)
for z in range(distance, 1, -1):
# Find line on map. This calculation corresponds to a field of view of 90°
pleft = Point(
?。?cosphi*z - sinphi*z) + p.x,
( sinphi*z - cosphi*z) + p.y)
pright = Point(
?。?cosphi*z - sinphi*z) + p.x,
?。?sinphi*z - cosphi*z) + p.y)
# segment the line
dx = (pright.x - pleft.x) / screen_width
dy = (pright.y - pleft.y) / screen_width
# Raster line and draw a vertical line for each segment
for i in range(0, screen_width):
height_on_screen = (height - heightmap[pleft.x, pleft.y]) / z * scale_height. + horizon
DrawVerticalLine(i, height_on_screen, screen_height, colormap[pleft.x, pleft.y])
p1eft.x += dx
p1eft.y += dy
# Call the render function with the camera parameters:
# position, viewing angle, height, horizon line position,
# scaling factor for the height, the largest distance,
# screen width and the screen height parameter
Render( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )
123456789101112131415161718192021222324252627282930313233
更多的性能說明
當然,要想達到更高的性能,還有很多小技巧可以使用。
與從后面到前面繪制相比,從前面到后面進行繪制會更好。優(yōu)點之一就是我們不必每次都因為遮擋而需要在屏幕的底部畫線。但是,為了保證遮擋,我們需要一個額外的Y緩沖區(qū)。對于每一列來說,相當于y的最高位置已經存儲了。因為我們是按照從前面到后面這個順序進行繪制的,那么下一行的可見部分只能大于先前繪制的最高行。
詳細的渲染程度。前面的細節(jié)渲染多一點,遠處的細節(jié)渲染的少一點。
def Render(p, phi, height, horizon, scale_height, distance, screen_width, screen_height):
# precalculate viewing angle parameters
var sinphi = math.sin(phi);
var cosphi = math.cos(phi);
# initialize visibility array. Y position for each column on screen
ybuffer = np.zeros(screen_width)
for i in range(0, screen_width):
ybuffer[i] = screen_height
# Draw from front to the back (low z coordinate to high z coordinate)
dz = 1.
z = 1.
while z 《 distance
# Find line on map. This calculation corresponds to a field of view of 90°
pleft = Point(
?。?cosphi*z - sinphi*z) + p.x,
?。?sinphi*z - cosphi*z) + p.y)
pright = Point(
?。?cosphi*z - sinphi*z) + p.x,
(-sinphi*z - cosphi*z) + p.y)
# segment the line
dx = (pright.x - pleft.x) / screen_width
dy = (pright.y - pleft.y) / screen_width
# Raster line and draw a vertical line for each segment
for i in range(0, screen_width):
height_on_screen = (height - heightmap[pleft.x, pleft.y]) / z * scale_height. + horizon
DrawVerticalLine(i, height_on_screen, ybuffer[i], colormap[pleft.x, pleft.y])
if height_on_screen 《 ybuffer[i]:
ybuffer[i] = heightonscreen
p1eft.x += dx
p1eft.y += dy
# Go to next line and increase step size when you are far away
z += dz
dz += 0.2
# Call the render function with the camera parameters:
# position, viewing angle, height, horizon line position,
# scaling factor for the height, the largest distance,
# screen width and the screen height parameter
Render( Point(0, 0), 0, 50, 120, 120, 300, 800, 600 )
評論