Revision as of 10:26, 12 July 2019 by Kenny2scratch (talk | contribs) (pretty sure this is what you meant?)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Note Note: This tutorial is recommended for more experienced Scratchers due to its difficulty.

What is a Three-Dimensional Environment?

A 3D environment is a place that involves the common X and Y axes, as well as the additional Z axis. The Z axis is a Cartesian coordinate, much like the X and Y axes, but the Z axis usually is the axis for depth. In real life, the Z axis exists, but in Scratch, it does not. We can incorporate size and movement that causes an illusion of depth.

Three-Dimensional Graphics Tutorial

The illusion of 3D on a flat surface, such as a computer screen, is achieved by projecting a three-dimensional point onto a two-dimensional surface.

Three-dimensional objects may be manipulated with matrix transformations.

The model also has a "transform" consisting of its translation, rotation and scale. Transformations are a way to describe the movement of shapes.

To implement 3D, one first needs to calculate the model's vertices' positions in the map ("worldspace"). Then, the programmer must determine the worldspace coordinates' positions relative to the viewer by applying the opposite of the camera's transform to the points. Points that are not in the camera's field of vision ("clipspace") may be dropped. Finally, the clipspace coordinates are projected onto the screen.

Preparation

You will need to create these variables:

(old x)
(old y)
(old z)
(new x)
(new y)
(new z)
(size::variables)
(x transformation)
(y transformation)
(z transformation)
(angle)
(2D x)
(2D y)
(3D x)
(3D y)
(3D z)
(focal length)
(x)
(y)
(z)
(scale factor)
(roll)
(temp)
(translation x)
(translation y)
(translation z)
(camera x)
(camera y)
(camera z)
(cam roll)
(cam pitch)
(cam yaw)

The vertices of models may be stored in a list.

Data Representation

A model needs a data representation. Let a "model" consist of an array of vertices and an array of faces. Each vertex has an x, a y and a z component. Each face is an array of vertex indices.

Transformations

Here are the code for transformations:

Scale

The scale of a shape is its size. For example, the set size to () and change size by blocks dilate sprites.

set [new x v] to ((old x) * (size::variables))
set [new y v] to ((old y) * (size::variables))
set [new z v] to ((old z) * (size::variables))

Translation

Translation is the movement of a shape across the coordinate plane. The change x by and change y by blocks translate sprites.

set [new x v] to ((old x) + (x transformation))
set [new y v] to ((old y) + (y transformation))
set [new z v] to ((old z) + (z transformation))

Rotation

Rotations turn shapes. The turn () degrees blocks rotate sprites.

Rotations are a bit more complicated. They consist of three components: yaw, pitch and roll. Each component can be thought of as applying a 2D rotation around an axis.

Trigonometry Angle Addition

Rotations use these trigonometry rules:
sin(A1 + A2) = sin(A1) * cos(A2) + sin(A2) * cos(A1)
cos(A1 + A2) = cos(A1) * cos(A2) - sin(A1) * sin(A2)
sin(A1 - A2) = sin(A1) * cos(A2) - sin(A2) * cos(A1)
cos(A1 - A2) = cos(A1) * cos(A2) + sin(A1) * sin(A2)
[1]

2D Rotations

This code rotates a sprite on a two-dimensional plane:

set [new x v] to (((old x) * ([cos v] of (angle))) - ((old y) * ([sin v] of (angle))))
set [new y v] to (((old x) * ([sin v] of (angle))) + ((old y) * ([cos v] of (angle))))

[2]

Roll

The roll is the rotation around the y-axis.

set [new x v] to (((old x) * ([cos v] of (angle))) - ((old z) * ([sin v] of (angle))))
set [new z v] to (((old x) * ([sin v] of (angle))) + ((old z) * ([cos v] of (angle))))
Pitch

The pitch is the rotation around the x-axis.

set [new y v] to (((old y) * ([cos v] of (angle))) + ((old z) * ([sin v] of (angle))))
set [new z v] to (((-1) * ((old y) * ([sin v] of (angle)))) + ((old z) * ([cos v] of (angle))))

The pitch uses the angle subtraction formula rather than the angle addition formula because the pitch is clockwise, not counterclockwise.

Yaw

The yaw is the rotation around the z-axis.

set [new x v] to (((old x) * ([cos v] of (angle))) - ((old y) * ([sin v] of (angle))))
set [new y v] to (((old x) * ([sin v] of (angle))) + ((old y) * ([cos v] of (angle))))

The order that these transformations are applied is:

Vertex -> Worldspace (Model transform):
1. Scale
2. Rotation
3. Translation

Worldspace -> Clipspace (Camera transform):
1. Translation
2. Rotation

Note Warning: Remember, when applying the camera's transformations to the worldspace coordinates, do the opposite. For example, if the camera's translation is (5, 6, -2), do (x - 5, y - 6, z + 2) instead.

Projection

The code for projecting a point is:

set [2D x v] to (((3D x)/(3D z))*(focal length))
set [2D y v] to (((3D y)/(3D z))*(focal length))

This code can be thought of as a proportion.

The code for the size of a point is:

set [2D size v] to ((focal length) / (3D z))

To draw bigger points, multiply "2D size" by some number.

Putting Everything Together

Now that we understand how to get a point of a model and calculate its position on the computer screen, let's put everything together.

For this tutorial, we will have a camera move around the world. It will have a translation and rotation. Any translation and rotation applied to the camera should be reversed for world models.

Rendering a Point

This custom block takes a point on a model and calculates its projected position on the screen by implementing all of the transformations discussed above.

define process vertex
set [x v] to ((x) * (scale factor)) //Scale
set [y v] to ((y) * (scale factor))
set [z v] to ((z) * (scale factor))
set [temp v] to (x) //Roll
set [x v] to (((x) * ([cos v] of (roll))) - ((z) * ([sin v] of (roll)))
set [z v] to (((temp) * ([sin v] of (roll))) + ((z) * ([cos v] of (roll)))
set [temp v] to (y) //Pitch
set [y v] to (((y) * ([cos v] of (roll))) + ((z) * ([sin v] of (roll)))
set [z v] to (((-1) * ((temp) * ([sin v] of (angle)))) + ((z) * ([cos v] of (angle))))
set [temp v] to (x) //Yaw
set [x v] to (((x) * ([cos v] of (angle))) - ((y) * ([sin v] of (angle))))
set [y v] to (((temp) * ([sin v] of (angle))) + ((y) * ([cos v] of (angle))))
change [x v] by (translation x) //Translation
change [y v] by (translation y)
change [z v] by (translation z)
change [x v] by ((-1) * (camera x)) //Camera translation
change [y v] by ((-1) * (camera y))
change [z v] by ((-1) * (camera z))
set [temp v] to (x) //Camera Roll
set [x v] to (((x) * ([cos v] of (cam roll))) + ((z) * ([sin v] of (cam roll)))
set [z v] to (((-1) * ((temp) * ([sin v] of (cam roll)))) + ((z) * ([cos v] of (cam roll)))
set [temp v] to (y) //Camera Pitch
set [y v] to (((y) * ([cos v] of (cam pitch))) - ((z) * ([sin v] of (cam pitch)))
set [z v] to (((temp) * ([sin v] of (cam pitch))) + ((z) * ([cos v] of (cam pitch)))
set [temp v] to (x) //Camera Yaw
set [x v] to (((x) * ([cos v] of (cam yaw))) + ((y) * ([sin v] of (cam yaw)))
set [y v] to (((-1) * ((temp) * ([sin v] of (cam yaw)))) + ((y) * ([cos v] of (cam yaw)))
set [2D x v] to ((x) / (z))
set [2D y v] to ((y) / (z))

Example using size to create a 3D effect

Preparation

You will need to create these variables:

(scroll z)
(scroll y)
(scroll x)

You will not need to create any lists.

Tutorial

This script uses sprites and size change for depth perception:

when green flag clicked
set [scroll z v] to [60]
set [scroll y v] to [0]
set [scroll x v] to [-30]
forever
  set size to ((scroll z) + ((40) * (0)))%
  set x to ((scroll x) + ((480) * (0)))
  set y to ((scroll y) + ((360) * (0)))
  if <key [up arrow v] pressed?> then
    change [scroll z v] by ((size) / (45))
    change [scroll x v] by ((x position) / (55))
  end
  if <key [down arrow v] pressed?> then
    change [scroll z v] by ((size) / (-45))
    change [scroll x v] by ((x position) / (-55))
  end
  if <key [left arrow v] pressed?> then
    change [scroll x v] by ((size) / (55))
  end
  if <key [right arrow v] pressed?> then
    change [scroll x v] by ((size) / (-55))
  end
  if < <(scroll z) < [20]> or <(scroll z) > [217]> > then
    hide
  else
    show
  end

The "scroll x" and "scroll y" variables' value can be changed so the sprite's position can be changed. The "scroll z" variable is rather special. It does not change the sprite's position, but it changes The size of the sprite.

This method of 3D scripting is very rudimentary, and it does not involve any collision detection, and it would not apply to a moving object.

This is one of the ways you can make the illusion of 3D. Scratch doesn't allow you to make three dimensional games, but it allows you to make the illusion of one. The X axis is the sprites position from left to right. The Y axis is the position from top to bottom, and the Z axis is the sprites size, allowing you to make the sprite small or large. As said in the beginning of this article, we can always incorporate size and movement to create the 3D illusion. If you stroll down a street, you will notice that the farther the things are, the smaller they look. If you put this same principle in video games, you will get a 3D effect. A Raycaster is a more efficient way of 3D in Scratch.

Example using pen and layering

This is a slightly more efficient way of making a 3D illusion. This technique uses layering and stamping. Here is the script:

when flag clicked
forever
  erase all
  go to x(0) y(0)
  stamp
  change y by(2)
  stamp
  change y by(2)
  stamp
  change y by(2)
  stamp
  change y by(2)
  stamp
  change y by(2)
  stamp
  change y by(2)
  stamp
end
when green flag clicked
forever
  point towards [mouse-pointer v]
end

This method does not use size to create the 3D effect. It changes the position of the sprite and stamps the sprite on the background. This makes several copies of the same sprite, in different positions. This creates a 3D effect.

See Also

References

  1. http://mathworld.wolfram.com/TrigonometricAdditionFormulas.html
  2. http://ogldev.atspace.co.uk/www/tutorial07/tutorial07.html