Understanding computer graphics algorithms. Part 2 – “The Tunnel from the Second Reality Demo”

Today we will try to reproduce one of the effects demonstrated in this demo, namely the floating tunnel effect.

Frame from demo "Second Reality"
Frame from the demo “Second Reality”

On the screen we see a set of ellipses consisting of individual points. Ellipses, gradually increasing, move towards us. Far points appear dimmer than foreground points. The overall animation creates the illusion of movement through a tunnel winding through space.

By the method of on-screen display of points, you can see a lot in common with the previous part (link to part 1). The main difference is that here not randomly distributed points are used, but collected in the form of a figure.

Since we need to draw a lot of ellipses, then we need to immediately remember their number somewhere, and we need some kind of list circles, to store the characteristics of all ellipses. Let’s remember their number in a constant COUNT_CIRCLEand let them be 100.

What characteristics can one ellipse have: this is the X,Y coordinate of the center, radius and color. Those. four numeric values. The radius of the ellipse will replace for us such a characteristic as depth, or the Z axis, as you noticed, I do not use it here. The further the ellipse is from us, the smaller its size will be.

The Circles list will store a list of small lists, these are the characteristics of one ellipse. Once again, these will be: X, Y, Radius, Color.

Initially, all ellipses are placed in the center of the screen.

If you take a closer look at the original demo, you can see that at the maximum distance deep into the tunnel, it does not collapse into a point. Those. the size of the farthest ellipse is not zero.

Therefore, we will generate a new ellipse with a diameter other than 0, for example 100. This value can be twisted as you like, as you like.

The color in the very depths of the tunnel is also not completely black, so I will make the initial value of the color equal to 50, at my discretion.

Now for some math: how do you draw an ellipse on the screen? The pygame library has a function that can draw circles and ellipses. But with its help, we will not draw an ellipse consisting of points. Therefore, you will have to do it yourself.

In this case, the trigonometric functions of sine and cosine will come to our aid. Their combination together and allows you to create a circle, and then an ellipse.

If greatly simplified, then there will be the following formula for a point of a circle:

y = \cos(alpha)x = \sin(alpha)

where alpha is the angle by which the point on the circle is separated.

those. to completely draw a circle, we need to go through its entire length, and this, if you remember the geometry:

2 * \pi * radius

But we do not need to calculate its length, but only need to change the angle for the point, a full circle around the circle is 360 degrees, or

2*\pi

To get an ellipse from a circle, flattened in height, it is enough to divide the final Y value by some factor, for example, by 1.5.

Let’s repeat once again how to form an ellipse from points: in a cycle from 0 to 360, we calculate the coordinates of the points that make up the circle. These are the s_x and s_y coordinates.

We also divide s_y by 1.5, this is so that we get an ellipse flattened in height.

Let there be 100 points in each ellipse, then the increment step for the angle is calculated as:

\pi * 2 / 100

Naturally, in the function of drawing an ellipse, it is necessary not to display points that are not included in the screen by coordinates.

To make the end of our tunnel meander “like a snake”, we will also use the sine and cosine functions. Let’s make the center of the generated ellipses go around the circle. The angle by which our tunnel will shift at each step will be stored in the rot variable, it must be described before the game cycle, let it be equal to 0.05.

To evenly distribute the color of the ellipses along the tunnel, you can calculate and store the value of the color increment in a constant:

STEP\_COLOR = (255-50) / COUNT\_CIRCLE

Here the number 50 is the initial color value so that the ellipses farthest from us are not completely black.

The increment in the radii of the ellipses will also be stored in the STEP_RADIUS constant, and let it be equal to 10.

Now the most interesting part of the algorithm – how to make the illusion of movement through the tunnel?

In the loop, we take one ellipse from the list. We increase the value of its radius and brightness using the coefficients calculated earlier. We return this ellipse to the list not to its place, but to the ordinal place N + 1, where N is the index of our ellipse in the list, i.e. its serial number.

Thus, each ellipse moves in one pass of the game cycle, one cell forward in the list, while the coordinate of its center remains the same, but the size increases and the color becomes brighter. Thanks to this, the effect of a tunnel wagging its tail appears.

A small note – it is more convenient to go through the list from the end, from the circle N-1 and move to the beginning of the list. That is, the cycle is in the opposite direction, in this case there are fewer calculations. And we automatically overwrite the last circle in the list.

For one game cycle, each of the ellipses increases its size and color, and also moves in the queue “to the exit”, i.e. to be removed from the list. As soon as it exits, a new ellipse takes its place, with default parameters, at the top of the list.

Let’s look at the resulting code:

import pygame
import math

SX = 800
SY = 800

pygame.init()
screen = pygame.display.set_mode((SX, SY))
running = True

COUNT_CIRCLE = 100                      # Всего эллипсов.
STEP_RADIUS = 10                        # Шаг увеличения радиуса.
STEP_COLOR = (255-50) / COUNT_CIRCLE    # Шаг увеличения цвета.

Circles = []    # Список содержащий эллипсы, каждый из них
                # является списком с: X, Y, RADIUS, COLOR

X = 0       # Номер координаты X в списке единичного эллипса.
Y = 1       # Номер координаты Y в списке единичного эллипса.
RADIUS = 2  # Номер радиуса в списке единичного эллипса.
COLOR = 3   # Номер цвета в списке единичного эллипса.

rot = 0.05  # Угол смещения центра туннеля.

# ---------------------------------------------------------------------------------------------
# Отрисовка одного эллипса на экране.
# На вход поступает эллипс circle из списка Circles.
# ---------------------------------------------------------------------------------------------
def draw_circle(circle):
    alpha = 0                   # Угол перемещения по эллипсу, для отрисовки точки.
    step = math.pi * 2 / 100    # Шаг, с которым рисуются точки эллипса.
    while alpha < math.pi * 2:
        s_x = round(circle[X] + math.sin(alpha) * circle[RADIUS])
        s_y = round(circle[Y] + math.cos(alpha) * circle[RADIUS] / 1.5)
        color = round(circle[COLOR])
        if 0 < s_x < SX and 0 < s_y < SY:
            pygame.draw.circle(screen, (color, color, color), (s_x, s_y), 2)
        alpha += step

# ---------------------------------------------------------------------------------------------
for i in range(0, COUNT_CIRCLE):
    Circles.append([SX // 2, SY // 2, 100, 50])       # Заполняем список с эллипсами, инициализируя их

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((0, 0, 0))

    for i in range(len(Circles) - 2, -1, -1):
        c = Circles[i]
        c[RADIUS] += STEP_RADIUS
        c[COLOR] += STEP_COLOR
        Circles[i + 1] = c

        draw_circle(c)

    sx = SX // 2 + math.sin(rot) * 50.0        # Вычисление координаты X,Y для нового эллипса
    sy = SY // 2 + math.sin(rot) * 50.0

    Circles[0] = [sx, sy, 100, 50]
    rot += 0.05

    pygame.display.flip()

pygame.quit()

We get something like this picture:

On the gif, the animation turned out to be quite jerky, because it had to be done with an interval of three frames.  Live looks pretty smooth.
On the gif, the animation turned out to be quite jerky, because it had to be done with an interval of three frames. Live looks pretty smooth.

In the next part, we will implement a rather old algorithm that simulates the image of a flame.

simple flame
simple flame

Link to part 1 – “Starfield Simulation” algorithm

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *