Gopher-kun's Go Episode II-A solar system simulator that even Daphnia can make overnight, and the dark side

Introduction

This article tells the story of republican knights who maintain the peace and order of the galaxy struggling to complete a planetary simulator overnight.

As long as you have a basic knowledge of programming, you will be able to ** easily create the following CG program ** by reading this article while actually moving your hands. jupiter_animation.gif

Gopher-kun goes series

This article is a sequel to "Gopher Kimi ga Gou Episode I".

For those who value the story, we recommend reading from Episode I first, but since it is not relevant to the technical theme you are dealing with, reading from this article will not interfere with your understanding.

If you're interested in Gopher's physical fitness, take a look at the five GIF animations embedded in Episode I before proceeding to the main story.

Character

Name residence Overview
Padawan
(Daphnia)
Planet tatooine With exceptional talent and incredible Midi-Chlorian value.
He has just graduated from the initiative and is still in training.
Master Planet tatooine An unconventional knight who ignores the council's intentions.
Has high ability and leadership.
Gopher Indefinite Agents dispatched to various parts of the galaxy.
It has an amazing physical ability and a sense of balance.
Young night Planet coruscant A hot-blooded man who burns in justice.
It has been several years since I was promoted from Padawan to Knight.
Grand Master Planet coruscant An elder who leads the Supreme Council of Republican Knights.
Supreme Chair Planet coruscant 銀河共和国 元老院のSupreme Chair。

Prerequisites

Development and operating environment

The program described in this volume has been confirmed to work only in the following environments, but Processing is multi-platform compatible. If you can confirm the operation on Linux or Mac OS, I would be grateful if you could let me know.

Development tools

category tool Use
Language and IDE Processing 3.5.4 Programming 3DCG in Java-based languages
Graphic editing Gimp 2.10.10 Image material creation and background processing

Both are free tools.

Disclaimer

Main story

A long time ago in a galaxy far, far away.... (Long ago, in a galaxy far away ...)

Galactic Senate Was swirling in confusion. [Confederacy of Independent Systems] led by the Droid Army (https://starwars.fandom.com/ja/wiki/%E7%8B%AC%E7%AB%8B%E6%98%9F%E7%B3%BB%E9% Congress was confused as to whether an army should be created to counter 80% A3% E5% 90% 88).

Behind the scenes, the Republican Knight , Master and Padawan in secret [Planet Tatooine](https://starwars.fandom.com/ja/wiki/%E3%82%BF%E3%83%88%E3%82%A5%E3%82 It was called from% A4% E3% 83% BC% E3% 83% B3).

8 pm | Prologue

Planet Coruscant At the Republic Knights Council Room ...

Grand Master "I had a hard time in the distance"

Master "No, it's ridiculous. Padawan is a big fan in the big city after a long time." Master "By the way ..."

Grand Master "That story ..." Grand Master "Actually, in case the controversial bill in the Senate is passed ..."

Grand Master "I'm looking for a star that can secretly manufacture and train clone troopers." Grand Master "I want you to simulate the star system that is a candidate as soon as possible." Master "I see. So which system is it?"

Grand Master "A star system called the" solar system "in the Milky Way galaxy." Master "Are you in such a remote area?"

Grand Master "Oh, that's where the Confederacy of Independent Systems won't go around"


At the Planet Coruscant / Republic Knight Temple ...

Young night "Hi, Daphnia" Young Night "What are you making a simulator for the solar system?"

Padawan (Muka ...)

Padawan "Yeah. I just heard from the master." Padawan "Why do you call me Daphnia !?"

Young Night "Gahaha. That's because you're still small like a daphnia." Young Night "I wonder if Daphnia can make a simulator ???"

Padawan (This guy is really crazy !!!)

Young Night "Oh, it looks like your master has come"

Young Night "Then I'm about to go!" Young Night "Do your best at best" Young Night (That little boy, he still doesn't seem to be able to control his emotions well) Young Night (Midi-Chlorian value is unusually high, so it smells dangerous)

Master "Oh! Padawan" Master "Did you stay here!"

Master "What's wrong?" Padawan "..."

Padawan "Hey, am I a Daphnia?"

Master "Did you say that?" Master "Gahaha! Because you are short"

Padawan "..."

Master "Okay, what is Daphnia?" Master "You can jump more than 20 times your body length!" Master "Such a knight wouldn't look for it in the galaxy."

Padawan "Suge!" Padawan "Greater than Gopher!" Padawan "Daphnia is the best!"

Padawan "Can I make a simulator?" Master "Of course!" Master "This time, as part of my training, I have been instructed to make it by yourself."

Padawan "Hey, what is the solar system like?" Padawan "Wow, it's the countryside !?"

Master "There is a rocky planet called Earth on the 3rd planet." Master "The satellite'Moon'is a huge star."

Master "The main purpose of this simulation" Master "To know how much the gravity of the moon affects the earth."

Padawan "Hey, what kind of race lived ???" Master "It seems that crustal movements are active and the amount of methane and carbon dioxide is large." Master "There is also information that there seems to be a living organism"

Master "This was obtained at the Republic Knight Library" Master "The only image of an earthling"

Padawan "Gee!" Padawan "Earthlings!"

(Source: [Pixabay](https://pixabay.com/ja/vectors/%E3%83%86%E3%82%A3%E3%83%A9%E3%83%8E%E3%82%B5% E3% 82% A6% E3% 83% AB% E3% 82% B9-% E3% 83% AC% E3% 83% 83% E3% 82% AF% E3% 82% B9-305349 /))

9 pm | Introduction of Processing, Introduction to 3DCG

Master "Let's get started!"

Master "Originally, in C ++ etc. [OpenGL](https://ja.wikipedia.org/wiki/OpenGL#:~:text=OpenGL%EF%BC%88%E3%82%AA%E3%83%BC % E3% 83% 97% E3% 83% B3% E3% 82% B8% E3% 83% BC% E3% 82% A8% E3% 83% AB% E3% 80% 81Open% 20Graphics,% E3% 82% B0% E3% 83% A9% E3% 83% 95% E3% 82% A3% E3% 83% 83% E3% 82% AF% E3% 82% B9% E3% 83% A9% E3% 82% A4% I would like to use E3% 83% 96% E3% 83% A9% E3% 83% AA% E3% 81% A7% E3% 81% 82% E3% 82% 8B% E3% 80% 82). " Master "This time I'm going to use a saver for art, Processing"

Master "It's a Java-based environment, so it's almost Java." Padawan "Gee! Java. That saver feels solid," Padawan "It was a red dot when I was an initiator ..."

Padawan "Yana memories ..."

Master "Even though it's Java-based" Master "Variables and methods needed for graphics are already prepared" Master "You can start using Saver suddenly without being aware of the class." Master "With OpenGL, before you get into the 3DCG sword fight (coding) you really want to focus on" Master "I have to do a lot of troublesome rituals," Master "In that respect, Processing can be said to be positive."

21:05 | Download and install Processing

Master "Processing IDE can be downloaded here"

Processing Download

Master "I'd like to say download and install!" Master "No installer" Master "Unzip the zip and just throw it in a suitable directory"

21:10 | Starting Processing

Master "Double-click processing.exe in the unzipped directory" Padawan "Oh, double click, super good !!!" image.png

Master "Galaxy Standard Basic (Footnote: Japanese) Please enter something" Padawan "Gee, garbled characters !!!" image.png

Master "In that case, in [File] [Settings ...]," image.png

Master "Choose the right font!" image.png

Padawan "Oh! Healed!" image.png

21:20 | Perceive space

Master "Well, what's important in 3DCG is neither trigonometric functions nor matrix operations!" Master "The most important thing is spatial awareness! (Finally)"

Master "The world of 3DCG is the same as outer space"

Master "Once you jump in, there is no top or bottom." Master "I don't know if the other person is moving or if I am moving."

Master "Okay, look closely at this figure." image.png

Master "This is the coordinate space of Processing's world coordinate system."

Master "Red is X-axis, green is Y-axis, blue is Z-axis" Master "First of all, hit this image thoroughly into your head."

Master "Try to shape your left hand while imagining this figure!" Padawan "Oh, Fleming's Law!"

Master "Yes, it's the same shape as that." Master "Make the thumb, index finger, and middle finger cross 90 degrees." Master "Thumb is X-axis, index finger is Y-axis, middle finger is Z-axis," Master "The direction that each finger points is the right side (positive infinity direction)"

Master "Keep your thumb to the right and your index finger down, not to break that shape." Master "Then, where does the middle finger point?" Padawan "Well, I'm facing myself!"

Master "Yes. This is the processing coordinate system, called the'left-handed system'." Padawan "If so, is there a'right-handed'?" Master "Yes, the right-handed system has the opposite Z-axis orientation to the left-handed system."

Master "Also, be careful because the Y-axis is downward in the Processing coordinate system!"

Master "Look with your thumb pointing to the right and your index finger pointing up." Padawan "Oh, the middle finger is pointing to the master ..."

Master "Yes. Even in the same left-handed system, in a library with the Y axis facing up" Master "Be careful because the direction of the Z axis is reversed"

Master "Imagine the color and direction of each axis again!"

Padawan "Red X-axis points to the right ..." Padawan "Green Y-axis points down ..." Padawan "The blue Z axis is facing this way ..."

Master "That's right. Let it soak into your body."

Master "Also keep in mind the three coordinate planes"

Master "First of all, the XY plane. This is a high wall that stands in front of you." Master "In the era of initiation in a two-dimensional coordinate system" Master "I've seen you many times" image.png

Master "Next on the ZX plane, this is the floor" Master "Even in today's work, this plane should come out a lot." Master "Remember it well" image.png

Master "Finally the YZ plane" Master "When I mistakenly say'I'm sorry!'" Master "It's the shape of a palm" image.png

21:30 | Creating a new sketch

Master "In Processing, a project is called a'sketch'." Padawan "Drawing!"

Master "Yes, when you launch Processing." Master "Because a new sketch is created automatically" Master "Save an already open sketch as" image.png Master "Choose a location to save and save it as" Learning "for now."

Padawan "Oh! There is a folder called Learning." Padawan "Learning.pde is created in it"

Master "Yes, that's Processing." Master "`` Sketch folder ``and Sketch file` ``

Master "I'm going to add more here little by little" Master "Don't forget to save with Ctrl + S``` frequently"

21:40 | First coding

Master "Then we will finally enter the sword fight" Master "Enter the following in the IDE!" image.png Padawan "Gee, don't you need a class definition or main method ?!" Padawan "It's too easy to be happy (laughs)"

Learning.pde


size(1200, 800, P3D);

beginShape();
vertex(-50, -50, -500);
vertex( 50, -50, -500);
vertex( 50,  50, -500);
vertex(-50,  50, -500);
endShape(CLOSE);

Master "explain this meaning"

Master "Okay, if the image of the world coordinate system is difficult" Master "First, think only about the XY plane." image.png Master "Once you have an image of the XY plane, next is the Z coordinate." Master "Every vertex has a Z coordinate of -500"

Master "Which is -500 in the world coordinate system when viewed from the origin (0,0,0)?"

Padawan "Well, the thumb of the left hand is X, the index finger is Y ..." Padawan "Thumb X to the right and index finger Y to the bottom ..." Padawan "Middle finger Z has a big number from a distance toward here ..."

image.png

Padawan "-500 is far behind the front!"

Master "Then let's see if it's correct" Master "Click the run button (playmark icon just above the tab)" image.png Padawan "Oh! It worked! It moved!" Padawan "Hmm? What is this ???" image.png Padawan "One small square ..." Padawan "I don't know if this is the front or the back!" Padawan "It's too dumb, this!"

10 pm | Dominate the World Coordinate System

Master "Then, to get a better picture of the world coordinate system" Master "Try writing a little differently"

22:00 | Preparation for later animation

Master "Enter the following code" Master "Enter with your own hands, not copy!"

Learning.pde


// setup()Is called only once immediately after starting the program
void setup() {
  size(1200, 800, P3D); //Specifying window size and 3DCG
  frameRate(24);        //frame rate(fps)
}

// draw()Is called many times until the end of the program
// (fps==If 24, it will be called 24 times per second)
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white

  //From here on down is the same as before
  beginShape();
  vertex(-50, -50, -500);
  vertex( 50, -50, -500);
  vertex( 50,  50, -500);
  vertex(-50,  50, -500);
  endShape(CLOSE);
}

Padawan (It's hard to enter unless it's Vim)

Master "explain this meaning"

Master "Try clicking the run button" Padawan "Gee, when the background is white, it's more sober than before ..." image.png Padawan "It's harder to understand than before ..."

22:20 | Separate drawing objects into methods

Master "Let's make it a little easier to understand" Master "Modify as follows"

Learning.pde


// setup()Is called only once immediately after starting the program
void setup() {
  size(1200, 800, P3D); //Specifying window size and 3DCG
  frameRate(24);        //frame rate(fps)
}

// draw()Is called many times until the end of the program
// (fps==If 24, it will be called 24 times per second)
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white
  updateObject1();
}

// (1)Rectangle drawing(Rest)
void updateObject1() {
  fill(240, 240, 240); //Fill color(R,G,B)
  stroke(255, 0, 255); //Border color(R,G,B)
  strokeWeight(2);     //Border thickness

  beginShape();
  vertex(-50, -50, -500);
  vertex( 50, -50, -500);
  vertex( 50,  50, -500);
  vertex(-50,  50, -500);
  endShape(CLOSE);
}

Master "The changes are as follows"

Padawan clicked the Run button.

image.png

Padawan "It's not very flashy ..."

22:40 | Introduction of development utility

Master "I'll make this easier to understand from now on." Master "Click the [▼] button in the IDE and select [New Tab]" image.png

Master "When the New Name dialog opens, type" DevUtils "and click OK." (The name can be anything) image.png

Master "Copy the following code into the newly created tab [DevUtils]" Master "You don't have to understand the content for the time being. Copy and paste without thinking!"

Expand the code of DevUtils.pde

DevUtils.pde


// Processing Utility DevRoom
// (c) 2020 y-bash
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php
public void setupDevRoom(float len, int hnum, int vnum) {
  float radius = len * hnum * 1.25;
  float depth  = len * vnum / 2;
  int   period = 16;
  setupDevRoom(len, hnum, vnum, radius, depth, period);
}
public void setupDevRoom(float len, int hnum, int vnum,
                         float radius, float depth, int period) {
  gCubeSideLength = abs(len);
  gCubeHNum       = (hnum >= 0) ? hnum : 0;
  gCubeVNum       = (vnum >= 0) ? vnum : 0;
  setCameraOrbitalRadius(radius);
  setCameraMaxDepth(depth);
  setCameraOrbitalPeriod(period);
}
public void setDevRoomAutoCameraEnabled(boolean isEnabled) {
  gIsCameraEnabled = isEnabled;
}
public void setDevRoomVisible(boolean isVisible) {
  gIsDevRoomVisible = isVisible;
}
public void setCameraOrbitalRadius(float radius) {
  if (radius == 0.0) radius = 0.1;
  gCameraOrbitalRadius = radius;
}
public void setCameraMaxDepth(float depth) {
  gCameraMaxDepth = depth;
}
public void setCameraOrbitalPeriod(int period) {
  if (period  == 0  ) period = 1;
  gCameraOrbitalPeriod = period * 1000;
}
public void updateDevRoom() {
  pushStyle();
  if (gIsCameraEnabled ) updateCamera();
  if (gIsDevRoomVisible) drawDevRoom(gCubeSideLength, gCubeHNum, gCubeVNum);
  popStyle();
}
public void mouseClicked() {
  gIsDevRoomVisible = !gIsDevRoomVisible;
}
private boolean gIsDevRoomVisible    = true;
private boolean gIsCameraEnabled     = true;
private float   gCubeSideLength      =   200;
private int     gCubeHNum            =     4;
private int     gCubeVNum            =     2;
private float   gCameraOrbitalRadius =  1000;
private float   gCameraMaxDepth      =   200;
private int     gCameraOrbitalPeriod = 16000;
private void updateCamera() {
  int ms = millis();
  float hAngle = TWO_PI * ms / gCameraOrbitalPeriod;
  float x = gCameraOrbitalRadius * sin(hAngle);
  float z = gCameraOrbitalRadius * cos(hAngle);
  float y = sin(hAngle) * gCameraMaxDepth;
  camera(x, y, z, 0, 0, 0, 0, 1, 0);
}
private void drawDevRoom(float len, int hnum, int vnum) {
  strokeWeight(1);
  stroke(214, 214, 214);
  drawCubes(len, hnum, vnum);
  strokeWeight(3);
  drawFloor(0, len, hnum);
  drawAxes(len, hnum, vnum);
}
private void drawCubes(float len, int hnum, int vnum) {  float v1 = -len * vnum / 2;
  for (int i = 0; i <= vnum; i++) {
    float y = v1 + i * len;
    drawFloor(y, len, hnum);
  }
  float h1 = -len * hnum / 2;
  float v2 = -v1;
  for (int i = 0; i <= hnum; i++) {
    float x = h1 + i * len;
    for (int j = 0; j <= hnum; j++) {
      float z = h1 + j * len;
      line(x, v1, z, x, v2, z);
    }
  }
}
private void drawFloor(float y, float len, int num) {
  float h1 = -len * num / 2;
  float h2 = -h1;
  for (int i = 0; i <= num; i++) {
    float cp = h1 + i * len;
    line(h1, y, cp, h2, y, cp);
    line(cp, y, h1, cp, y, h2);
  }
}
private void drawAxes(float len, int hnum, int vnum) {
  strokeWeight(2);
  stroke(255, 0, 0);
  drawXAxis(len, hnum, vnum);
  stroke(0, 255, 0);
  pushMatrix();
  rotateZ(0.5 * PI);
  drawXAxis(len, hnum, vnum);
  popMatrix();
  stroke(0, 0, 255);
  pushMatrix();
  rotateY(-0.5 * PI);
  drawXAxis(len, hnum, vnum);
  popMatrix();
}
private void drawXAxis(float len, int hnum, int vnum) {
  float h1 = -len * (hnum + 2) / 2;
  float h2 = -h1;
  line(h1, 0, 0, h2, 0,  0);
  float al = len * max(hnum, vnum) /  60;
  float aw = al / 3;
  float ax = h2 - al;
  line(ax, -aw,   0, h2, 0,  0);
  line(ax,  aw,   0, h2, 0,  0);
  line(ax,   0, -aw, h2, 0,  0);
  line(ax,   0,  aw, h2, 0,  0);
}

Padawan "I'm very good at copying! Galactic Ichi" <img width="500", alt="image.png " src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634588/fb074189-d4a2-a8f8-3b36-62cefb8cc959.png "> Master "If you paste it, do the following:" Master "Add a line to the draw () method in the Learning tab"

Learning.pde


...
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white

  updateDevRoom();                                        // <=====Postscript=====

  updateObject1();
}
...

updatedevroom();Toupdateobject1();Added before, Padawan[Run button]Clicked. Padawan "Oh, something is going around ..."

updateObject1.gif (Although it is frame-by-frame to save space, it works more smoothly in the actual program)

Master "Actually, everything in this is stationary." Padawan "What ??? Because it's going around!"

Master "It's the camera that's spinning" Master "If you change the viewpoint of the camera, you can see the shape of the three-dimensional object well, right?" Padawan "I see ..."

Master "This utility reduces the effort in the early stages of development." Master "From the perspective, first of all, there are X, Y, Z coordinate axes, right?" Master "The point where the three intersect is the origin (0, 0, 0)" Master "Do you remember the color?"

Padawan "Yeah. Red is from left to right on the X axis." Padawan "Green is from top to bottom on the Y axis," Padawan "Blue faces this side from the far front on the Z axis ..." Padawan "Oh, really. The directions of the arrows are correct!"

Master "Next, there are cubic boxes lined up, right?" Master "Because there are 4 x 4 in the horizontal direction and 2 steps in the vertical direction" Master "It's made up of 32 cubes in all." Master "One side of the cube is 200" Master "Keep that in mind and take a look at the rectangle you drew."

Padawan "Well, two cubes are 400 ..." Padawan "Purple square ..." Padawan "Oh, a little farther than -400 and stuck in the z-axis!"

Master "Yes. Can you get a rough idea of the position ?!"

Master "If you click the screen again," Master "Cubes and axes will disappear"

Padawan "Oh, really. Somehow sober (laughs)"

Master "Click again to go back" Padawan "Oh, I'm back. I'm back."

11:00 pm | Move objects

23:00 | Move straight

Master "This time, rewrite the saver as follows!"

Learning.pde


// setup()Is called only once immediately after starting the program
void setup() {
  size(1200, 800, P3D); //Specifying window size and 3DCG
  frameRate(24);        //frame rate(fps)
}

// draw()Is called many times until the end of the program
// (fps==If 24, it will be called 24 times per second)
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white

  updateDevRoom();

  //updateObject1();                                      // <=====Comment out=====
  updateObject2();                                        // <=====Postscript=====
  
}

// (1)Rectangle drawing(Rest)
void updateObject1() {
  fill(240, 240, 240); //Fill color(R,G,B)
  stroke(255, 0, 255); //Border color(R,G,B)
  strokeWeight(2);     //Border thickness

  beginShape();
  vertex(-50, -50, -500);
  vertex( 50, -50, -500);
  vertex( 50,  50, -500);
  vertex(-50,  50, -500);
  endShape(CLOSE);
}

// (2)Rectangle drawing(Pseudo constant velocity linear motion)                          // <=====Added after this ↓=====
float gZ = -600;
void updateObject2() {
  gZ+=10;              //Update Z coordinate

  fill(255, 255, 255); //Fill color(R,G,B)
  stroke(0, 255, 255); //Border color(R,G,B)
  strokeWeight(2);     //Border thickness

  beginShape();
  vertex(-40, -40, gZ);
  vertex( 40, -40, gZ);
  vertex( 40,  40, gZ);
  vertex(-40,  40, gZ);
  endShape(CLOSE);
}

Padawan "Well ..."

Padawan "Create ʻupdateObject2 () ``, " Padawan "Call from within draw () ``, " Padawan "Comment ```updateObject1 () ..."

Padawan (Damn, copy and paste!)

Master "explain"

Padawan clicked the Run button.

Padawan "Oh, it worked!" updateObject2.gif

Master "But there is a problem with this implementation method" Master "Try running with a frame rate of 12"

Learning.pde


  ...
  frameRate(12);
  ...

Padawan "Oh, I'm sloppy ..." Master "Yes. This implementation is affected by the frame rate."

23:20 | Move without being affected by frame rate

Master "Enter the following" Master "Be careful because some parts have been omitted."

Learning.pde


...
void draw() {
  ...
  //updateObject2();                                      // <=====Comment out=====
  updateObject3();                                        // <=====Postscript=====
}

...

// (3)Rectangle drawing(Real constant velocity linear motion)                        // <=====Added after this ↓=====
void updateObject3() {
  final float START_Y = -600;   //Y coordinate at the start
  final float SPEED   =  200;   //per second

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dy = ms * SPEED / 1000; //Moving distance(Y coordinate) 
  float y = START_Y + dy;       //present location(Y coordinate)

  noFill();                     //No fill
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness

  beginShape();
  vertex(-30, y, -30);
  vertex( 30, y, -30);
  vertex( 30, y,  30);
  vertex(-30, y,  30);
  endShape(CLOSE);
}

Padawan "Well, comment on ```updateObject2 () `` as before." Padawan "Create ʻupdateObject3 () `` and call it from draw () ..."

Master "explain"

Padawan "Just move from top to bottom, it doesn't change much ..."

Master "Try changing the frame rate" Master "You can see that there is no difference in the amount of movement per hour."

Master "Don't forget to set the frame rate back at the end!"

Learning.pde


  ...
  frameRate(24);
  ...

23:40 | Put on a circular orbit

Master "Next time!"

Learning.pde


...
void draw() {
  ...
  //updateObject3();                                      // <=====Comment out=====
  updateObject4();                                        // <=====Postscript=====
  
}

...

// (4)Rectangle drawing(circular motion)                                  // <=====Added after this ↓=====
void updateObject4() {
  final float R     =  500;     //Revolution radius
  final float SPEED =   60;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)
  float x  = R * cos(dr);       //X coordinate
  float y  = R * sin(dr);       //Y coordinate
  
  fill(255, 255, 255);          //Fill color(R,G,B)
  stroke(0, 0, 255);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness

  beginShape();
  vertex(x-30, y, -30);
  vertex(x+30, y, -30);
  vertex(x+30, y,  30);
  vertex(x-30, y,  30);
  endShape(CLOSE);
}

Master "explain"

Master "The rest is trigonometric function calculation ..."

Padawan "Gee !!!" Padawan (I was not good at trigonometric functions ...) Padawan (I thought I'd do my best when it became a square function) Padawan (Initiate didn't tell me ...)

Radian (arc degree method)

Master "Then I reviewed it easily" Master "First of all, it's from'Radian'"

Master "Radian is a unit of angle" Master "The length of the arc on the circumference" Master "The angle equal to the radius of the circle is 1 radian" image.png Master "In terms of degrees, it's about 57.3 degrees."

Padawan "Why are these odd numbers!" Padawan "1 radian = 60 degrees is fine!"

Master "Well, don't say that ..." Master "In the Galactic System of Units (Footnote: International System of Units SI)" Master "It's a fixed unit"

Master "If you multiply this by about 3.14, you'll get 180 °!" Padawan "It's a pie (π)!" image.png Padawan "But I can't remember this!" Master "You don't have to remember this to use Processing"

Master "But the Processing method is" Master "Because the angle needs to be specified in radians" Master "Need to use radians () to convert frequencies to radians" Master "I just remember this"

Padawan "I see ..." Padawan "Anyway, the angle is" Padawan "Wrap it in radians () and hand it over!"

Master "Also defined constants related to special angles"

constant meaning frequency
(degree)
Radian
(radian)
PI π 180° 3.1415927
TWO_PI 360° 6.2831855
HALF_PI 1/2π 90° 1.5707964
QUARTER_PI 1/4π 45° 0.7853982

Master "You should keep this in mind as well."

Padawan "Gee! I just said" this is all "..."

Sine (sin), cosine (cos), tangent (tan)

Master "Next is trigonometric function"

Master "Do you remember sine, cosine and tangent?" Padawan "Oh! I've heard that name!"

Master "That's trigonometric function" Padawan (Huh? Was that so ...)

Master "Regardless of how you learned it, in general CG" Master "From a length and a angle `` Master "often used to find a `other length`

Master "I only use sine and cosine now," Master "Tangent is also often used, so let's explain it together."

Master "For now, these are all." Master "To find ``` another length `from` `length` and `angle` Master "Remember when it's used"

Master "First, it's a sine. It's a right triangle." Master "Can be used to find the height `` from the `hypotenuse length` image.png

Master "Next is the cosine. This is a right triangle." Master "Can be used to find the width `` from the ``` length of the hypotenuse` `` image.png

Master "Next is tangent, but there are two ways to use it."

Master "The first is a right triangle" Master "Used to find width `` from `height``, " image.png

Master "The other is a right triangle" Master "Can be used to find height `` from width `" image.png

Padawan "Well ..." Padawan "When you want to know straight from an angle" Padawan "Sine and cosine ..."

Padawan "When you want to know straight from straight" Padawan "In Tangent ..."

Master "And back to sine and cosine ..."

Master "Expand your thinking a little" Master "Centered on the origin (0, 0) on the XY plane" Paster "Let's consider a circle with radius R"

Master "Look at the``upper left graph` `` in the figure below. " image.png

Master "If you apply the sine and cosine" Master "The X and Y coordinates of the point P on the circumference" Master "Do you know what you can ask for?"

Padawan "Oh! Right triangle !!!" Padawan "Same as the previous figure"

Master "Yes, and as the remaining three figures show," Master "This is over 90 °, over 180 °, over 270 °" Master "You can ask for it in the same way"

Padawan "What if it gets bigger than 360 °?"

Master "In that case, you can ask for it in the same way!" Master "For example, 375 ° gives the same result as 15 °."

Padawan "Oh, that's right! If you pull 360, it will be 15!"

Master "However," Master "Note that the angle is ``` counterclockwise `` `.

Padawan "Is the reverse rotation negative?" Master "Yes. It's a minus if it's clockwise."

Master "Once you understand this,"

Master "Now, of an object that makes a circular motion" Master "Keep in mind that you are trying to know the coordinates after a certain amount of time" Master "Look at Saver again"

Master "Don't forget that the Y axis is pointing down" Master "If facing down, the positive direction of rotation will be clockwise` ``

Master "Okay, don't think with your head, capture the space with your body!"

image.png

updateObject4.gif

Padawan "Oh! I understand !!!!" Padawan "I don't feel like ..."

Midnight | 3D objects and coordinate transformations

00:00 | 3D object (stationary)

Master "Next is a 3D object" Master "Enter the following"

Learning.pde


...
void draw() {
  ...
  //updateObject4();                                      // <=====Comment out=====
  updateObject5();                                        // <=====Postscript=====
}

...

// (5)Drawing 3D objects(Rest)                        // <=====Added after this ↓=====
void updateObject5() {
  noFill();            //No fill
  strokeWeight(2);     //Border thickness

  stroke(255, 0, 255); //Border color(R,G,B)
  box(150);
}

Master "explain"

Padawan "Oh! It's too easy to cry" Padawan "It's much easier than specifying vertices with Vertex!"

Padawan (I wish I had told you earlier ...) Padawan (Why do you start because the master is always difficult?)

updateObject5.gif

Master "Next ..." Master "Add the following two lines"

Learning.pde


// (5)Drawing 3D objects(Rest)
void updateObject5() {
  noFill();            //No fill
  strokeWeight(2);     //Border thickness

  stroke(255, 0, 255); //Border color(R,G,B)
  box(150);

  stroke(0, 255, 255); //Border color(R,G,B)                 // <=====Postscript=====
  sphere(60);                                            // <=====Postscript=====
}

Master "explain"

updateObject5-2.gif

Padawan "That ??? noFill ()" Padawan "It's painted" None "but it's painted ..."

Master "This is not filled" Master "It's made of fine mesh"

Master "Try adding setCameraOrbitalRadius (150);` `` to setup ()"

Learning.pde


void setup() {
  size(1200, 800, P3D);

  setCameraOrbitalRadius(150); // <=====Postscript=====

  frameRate(24);
}
...

Master "This is a utility feature that I copied and pasted into the DevUtils tab." Master "It changes the radius of the orbit of the camera."

Master "If you set the value to 150, you can get pretty close to the origin (0,0,0)." image.png Padawan "Oh, really. I'm crazy." Master "Don't forget to comment out when you're done"

Learning.pde


void setup() {
  size(1200, 800, P3D);
  //setCameraOrbitalRadius(150);
  frameRate(24);
}
...

Master "By the way, I will explain the function of the utility here." Master "Now, just take a quick look"

Master "After that, it's hard to see the object during development," Master "I wish the camera turned more slowly" Master "The cube is in the way" Master "If you want to increase the number of cubes on the contrary" Master "You should see the details at that time"

Master "Also, because this is not a standard feature of Processing." Master "Please pay attention to that point"


Utility description

This utility was created for this article and is intended to save you the trouble of early development in 3DCG production with Processing. It has a function to display the development room (cube and coordinate axes) and automatically control the camera.


Method list
Method name Where to use Overview
setupDevRoom() setup() Development room setup. Set the size and number of cubes, camera conditions, etc.
setDevRoomAutoCameraEnabled() setup() Set whether to automatically control the camera.
setDevRoomVisible() setup() Set whether to display cubes and axes.
If you click the screen during operation, this method will be called and the display will be on./You can toggle off.
setCameraOrbitalRadius() setup() origin(0,0,0)The orbital radius of the camera that revolves around(ZX plane)To set.
setCameraMaxDepth() setup() Vertical direction of camera position(Y-axis direction)Set the maximum depth of.
setCameraOrbitalPeriod() setup() Set the revolution cycle (seconds) of the camera.
updateDevRoom() draw() Draw a development room (cube or axes).

Method details

(1) void setupDevRoom(float len, int hnum, int vnum) Development room setup (camera settings are automatically adjusted). It is supposed to be called from within the setup () method. If you do not call this method, the default value will be used.

Parameters Default value Description
len 200 The length of one side of the cube to be placed in the room.
len==0 :No cubes, floors, or axes are displayed.
hnum 4 Horizontal direction of the cube(X,Z-axis direction)Number of.
hnum<=0 :I don't see the cube, but vnum>If it is 0, the coordinate axes are displayed.
vnum 2 Vertical direction of the cube(Y-axis direction)Number of.
vnum<=0 :The cube is not visible, but hnum>If 0, the axes and floor are displayed.

(2) void setupDevRoom(float len, int hnum, int vnum, float radius, float depth, int period) Development room setup (including camera settings). It is supposed to be called from within the setup () method. If you do not call this method, the default value will be used.

Parameters Default value Description
len 200 The length of one side of the cube to be placed in the room.
len==0 :No cubes, floors, or axes are displayed.
hnum 4 Horizontal direction of the cube(X,Z-axis direction)Number of.
hnum<=0 :I don't see the cube, but vnum>If it is 0, the coordinate axes are displayed.
vnum 2 Vertical direction of the cube(Y-axis direction)Number of.
vnum<=0 :The cube is not visible, but hnum>If 0, the axes and floor are displayed.
radius Room width 1.25 times origin(0,0,0)The orbital radius of the camera that revolves around(ZX plane)。
radius==0.0 : radius==0.Same as 1.
radius< 0.0 :Operation is indefinite. Probably abs(radius)Same as.
depth Half the height of the room Vertical direction of camera position(Y-axis direction)Maximum depth of.
-depth ~ +Move in the range of depth
depth==0.0 :Vertical movement(Y-axis directionの移動)None.
depth< 0.0 :The vertical direction is reversed (the phase is shifted by half a circumference).
period 16 seconds Camera revolution cycle(Seconds)。
period==0 : period==Same as 1.
period< 0 :The direction of revolution of the camera is reversed

(3) void setDevRoomAutoCameraEnabled(boolean isEnabled) Specifies whether to automatically control the camera. It is supposed to be called from within the setup () method.

Parameters Default value Description
isEnabled true true:Automatically control the camera.
false:Do not control the camera automatically.

(4) void setDevRoomVisible(boolean isVisible) Specifies whether to display the development room (cube, axes, etc.). It is supposed to be called from within the setup () method, but it may be called from within draw ().

Parameters Default value Description
isVisible true true:Display the development room.
false:Do not show development room.

(5) void setCameraOrbitalRadius(float radius) Set the orbital radius (ZX plane) of the camera that revolves around the origin (0,0,0). It is supposed to be called from within the setup () method.

Parameters Default value Description
radius Room width 1.25 times origin(0,0,0)The orbital radius of the camera that revolves around(ZX plane)。
radius==0.0 : radius==0.Same as 1.
radius< 0.0 :Operation is indefinite. Probably abs(radius)Same as.

(6) void setCameraMaxDepth(float depth) Set the maximum depth of the camera position in the vertical direction (Y-axis direction). It is supposed to be called from within the setup () method.

Parameters Default value Description
depth Half the height of the room Vertical direction of camera position(Y-axis direction)Maximum depth of.
-depth ~ +Move in the range of depth
depth==0.0 :Vertical movement(Y-axis directionの移動)None.
depth< 0.0 :Vertical movementの向きが逆になる(位相が半周分ずれる)。

(7) void setCameraOrbitalPeriod(int period) Set the revolution cycle of the camera. It is supposed to be called from within the setup () method.

Parameters Default value Description
period 16 seconds Camera revolution cycle(Seconds)。
period==0 : period==Same as 1.
period< 0 :The direction of revolution of the camera is reversed

(8) void updateDevRoom() Update the development room. Update the camera position and draw the development room. It is supposed to be called from within the draw () method.


0:20 ~ | Constant velocity linear motion

Padawan "3D objects are too easy to laugh at, but ..."

Padawan "But ..." Padawan "The fact that the position cannot be specified" Padawan "I can't move ???"

Padawan "Sorry, it's too dull ..."

Master "Gahaha! Don't worry because you can move it properly" Padawan "What? Really ?!"

Master "Enter the following!"

Learning.pde


...
void draw() {
  ...
  //updateObject5();                                      // <=====Comment out=====
  updateObject6();                                        // <=====Postscript=====
}

...

// (6)3D object(Constant velocity linear motion with coordinate transformation)              // <=====Added after this ↓=====
// (3)Achieve a movement similar to
void drawEarth() {
  fill(224, 224, 255);          //Fill color(R,G,B)
  stroke(0, 0, 255);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  
  box(80);
}
void updateObject6() {
  final float START = -600;   //Position at the start
  final float SPEED =  200;   //per second

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float d = ms * SPEED / 1000;  //Moving distance
  float p = START + d;          //present location

  pushMatrix();
  translate(p, -100, 50);
  drawEarth();
  popMatrix();
}

Master "explain"

updateObject6.gif

Padawan "Oh! It worked! It moved!" Padawan "The earth is a blue and square star, isn't it ?!"

Master "..."

Local coordinate system

Padawan "But now" Padawan "The order of translate () -> drawEarth ()` `` is ,,"

Padawan "Um ..." Padawan "When I move it, I don't have the one I drew ..." Padawan "Why does the one I drew move ???"

Master "You noticed a good point!" Master "Let's explain ``` translate () `` in a little more detail."

Master "This isn't moving what you draw ..." Master "I'm moving the'stage'that I draw."

Padawan "He ???"

Master "Easy to understand, let's think only on the ZX plane" Master "Look at the next figure!" image.png Master "I used to draw directly in the world coordinate system, but ..." Master "Actually, there is a local coordinate system."

Master "Well, think of it as a coordinate system dedicated to an object."

Master "The left side of the figure is the world I have drawn so far." Master "Is the two axes overlapping?" Master "The larger one is the world coordinate system and the smaller one is the local coordinate system."

Master "And ..." Master "The right side of the figure is the world I'm drawing this time."

Padawan "Oh! The batten is off ..." Master "Yes"

Master "It is translate ()` `` that shifts it. "

Master "that is, by translate ()` `` Master "It means that the local coordinate system is translating." Master "And the drawing of the object is done to the local coordinate system."

Padawan "Really" Padawan "If you look only at the small batten, both right and left" Padawan "The squares drawn with vertex ()` `` are in the same place."

Master "And the local coordinate system was the last time" Master "I said it was a coordinate system dedicated to an object, but" Master "For example, if you draw three objects after translate ()" Master "All three objects use the same local coordinate system."

Master "Also, if you execute translate () twice in a row" Master "The first translate () moves the local coordinate system," Master "In the second call," Master "I'm going to move further from where I moved the first time." image.png

Master "So you have to declare the start and end of the stage you draw," Master "It is ``` pushMatrix () and popMatrix () `` that are responsible for it. "

Matrix and stack

Master "Matrix is a local coordinate system and a world coordinate system for the time being" Master "Think of it as the'current state'that indicates the relationship."

Master "And it's only one in the saver" Master "I share and use one of them from various places in the saver."

Master "So, for example, a method" Master "Once I change the Matrix to draw" Master "I have to put it back after using it" Master "I'm having trouble with the next method"

Master "But every time" Master " translate (5, 0, 10) `` followed by translate (-5, 0, -10) `" Master "Wouldn't it be hard if I wrote it back?"

Master "So in Processing, the current state of the Matrix" Master "It has a function to save it to the stack."

Master "Did you learn the stack?" Padawan "Yeah. First in, then out!" Padawan "Dishwasher !!!"

Master "Yes, that is,"

Master "pushMatrix () pushes the current Matrix onto the stack," Master "popMatrix () pulls the last saved Matrix off the stack" Master "Revert to the current Matrix"

Master "The following figure shows the coordinates when transforming and drawing." Master "It's a representation of how the state of the stack and Matrix changes."

Master "For clarity, we're only targeting the ZX plane." Master "Time series flows from left to right" image.png Master "Put this image in your head"

0:40 | Rotation

Master "Enter the following!"

Learning.pde


...
void draw() {
  ...
  //updateObject6();                                      // <=====Comment out=====
  updateObject7();                                        // <=====Postscript=====
}

...

// (7)3D object(Rotation by coordinate conversion)                     // <=====Added after this ↓=====
void updateObject7() {
  final float SPEED =  60;      //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  rotateY(dr);
  drawEarth();
  popMatrix();
}

Master "explain"

updateObject7.gif

Padawan "Hmm ???" Padawan "I'm turning ..."

Padawan "Do I have to use trigonometric functions?"

Master "Oh, no need"

Padawan "Gee !, is there such an easy thing !!!" Padawan (I wish I had told you earlier ...) Padawan (Why do you start because the master is always difficult?)

Master "The state transitions of the stack and matrix are as follows." image.png

1 am | Combine conversions

1:00 | Revolution (constant velocity circular motion)

Master "Let's try a transformation that combines translation and rotation" Master "Enter the following!"

Learning.pde


...
void draw() {
  ...
  //updateObject7();                                      // <=====Comment out=====
  updateObject8();                                        // <=====Postscript=====
}

...

// (8)3D object(Revolve by coordinate conversion)                     // <=====Added after this ↓=====
// (4)Achieve a movement similar to
void updateObject8() {
  final float R     =  300;     //Revolution radius
  final float SPEED =  150;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  rotateY(dr);
  translate(R, 0, 0);
  drawEarth();
  popMatrix();
}

Master "explain"

Padawan "Oh, I turned! I turned!" updateObject8.gif

Master "The state transitions of the stack and matrix are as follows" image.png

1:20 | Rotation at a distance

Master "Then, I will change the order of conversion in the future." Master "Enter the following!"

Learning.pde


...
void draw() {
  ...
  //updateObject8();                                      // <=====Comment out=====
  updateObject9();                                        // <=====Postscript=====
}

...

// (9)3D object(Rotating at a distant position by coordinate transformation)          // <=====Added after this ↓=====
// (8)Pay attention to the difference with
void updateObject9() {
  final float R     =  300;     //Revolution radius
  final float SPEED =  150;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  translate(R, 0, 0);  //I just changed the order
  rotateY(dr);         //I just changed the order
  drawEarth();
  popMatrix();
}

Master "This needs no explanation" Master "I just changed the order of rotateY () and translate ()` ``

Padawan "Oh, I'm spinning while stopped ..."

updateObject9.gif

Master "Because the camera is also rotating, you may not understand the movement of the rotation." Master "In that case, use the utility function setCameraOrbitalPeriod ()" Master "It would be good to lengthen the revolution cycle of the camera"

Learning.pde


...
void setup() {
  size(1200, 800, P3D);
  //setCameraOrbitalRadius(150);

  setCameraOrbitalPeriod(120);     // <=====Postscript=====

  frameRate(24);
}
...

Master "Don't forget to comment out when you're done"

Learning.pde


...
void setup() {
  size(1200, 800, P3D);
  //setCameraOrbitalRadius(150);
  //setCameraOrbitalPeriod(120);
  frameRate(24);
}
...

Master "The state transitions of the stack and matrix are as follows" image.png

Master "Be careful because the behavior changes greatly depending on the order of coordinate conversion."

1:40 | Revolution around the body

Master "Then, I'll move objects that look like the sun, the earth, and the moon." Master "Enter the following!"

Learning.pde


...
void draw() {
  ...
  //updateObject9();                                      // <=====Comment out=====
  updateObject10();                                       // <=====Postscript=====
}

...

// (10)3D object(Revolve around the revolving body by coordinate transformation)       // <=====Added after this ↓=====
void drawSun() {
  noFill();                     //No fill
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  sphere(60);
}
void drawMoon() {
  fill(255, 255, 128);          //Fill color(R,G,B)
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  beginShape();
  vertex(-20, -20, 0);
  vertex( 20, -20, 0);
  vertex( 20,  20, 0);
  vertex(-20,  20, 0);
  endShape(CLOSE);
}
void updateObject10() {
  float ms  = millis();            //Milliseconds elapsed from the start of the program

  final float E_R     =  400;      //Earth's orbital radius
  final float E_SPEED =   80;      //Earth angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of the earth(Degree)
  float edr = radians(edd);        //Movement angle of the earth(Radian)

  final float M_R     =  100;      //Revolution radius of the moon
  final float M_SPEED =  200;      //Moon angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon movement angle(Degree)
  float mdr = radians(mdd);        //Moon movement angle(Radian)

  drawSun();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);
    drawEarth();

    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, 0, 0);
      drawMoon();
    }
    popMatrix();

  }
  popMatrix();
}

Master "explain"

Master "The important thing here is the drawing of the moon." Master "After transforming the coordinates to draw the earth" Master "At the time of drawing the moon" Master "The matrix has not been restored by popMatrix () yet"

Master "So what is the local coordinate system of the moon?" Master "For rotation and translation for the earth" Master "Rotation and translation for the moon are combined"

Note that here, to make it easier to understand that pushMatrix () is used twice, it is enclosed in blocks ``` {}` `` and indented, but this is not necessary.

Padawan "Oh! I'm spinning around!"

updateObject10.gif

Master "This saver's stack and matrix state transitions," Master "This time, it starts with the sun already drawn."

Master "First, draw the Earth and run pushmatrix () for the moon." image.png

Master "And from drawing the moon to the end" image.png

Master "Can you understand?"

Padawan "Yeah! Easy victory!" Padawan "Because this is ..."

Padawan "While going around the corner with a pod racer" Padawan "It looks like your eyes are turning!"

Master (Wow ...)

Master (well, I think I understand it with my body) Master (although I'm a little worried ...)

2:00 am | Texture mapping and camera

2:00 | The leading role appears

Master "I don't know. It's time like this ..."

Master "Padawan" Master "Implementation in 3D objects may be difficult by morning"

Master "So to a 2D object" Master "Teach me how to do texture mapping"

Padawan "Texture ???"

Master "Yes, this is called'Billboard'" Master "It's an ancient technique that was once often used."

Master "That is, on a three-dimensional space" Master "Place objects like'signboards'" Master "It's a pseudo 3D"

Padawan "Oh, does that mean" writing "?"

Padawan "Then, in the start era" Padawan "I did it in a fun party play!"

Padawan "At that time, I got the role of" grass "that was my dream!"

Padawan "I don't know why," Padawan "The role of'grass', which was very popular in Tatooine in the desert" Padawan "It wasn't very popular in Coruscant, right?"

Padawan "That's why I won the role easily." Padawan "I was happy"

Then Gopher appeared there.

Padawan "What! Gopher-kun!" Padawan "It's too late !!!"

Padawan "I'm in trouble!" Padawan "Because it's the leading role" Padawan "You have to keep the entry time tightly!"

Master "Don't say so" Master "Gopher is also busy"

Master "Come to the right place" Master "Gopher, can you take a portrait?"

That said, Master released the Holocam shutter.

Master "Because I output in PNG mode" Master "in sketch folder" Master "Create a directory named data```, " Master "Copy this there" Master "Save as gopher.png " gopher.png

Character "Gopher-kun" is based on the Go mascot designed by Renée French. It is licensed for CC BY 3.0.

Master "Sketch folder is" Master "Can be opened with [Sketch] [Open Sketch Folder]" image.png

any-dir
    Learning
    ├── Learning.pde
    ├── DevUtils.pde
    └── data              <---Create
        └── gopher.png    <---copy

Master "Once you copy the PNG, type:"

Learning.pde


...
void draw() {
  ...
  //updateObject10();                                     // <=====Comment out=====
  updateObject11();                                       // <=====Postscript=====
}

...

// (11)Texture mapping(Rest)                          // <=====Added after this ↓=====
void drawGopher() {
  PImage img = loadImage("gopher.png ");
  int    h   = img.height;
  int    w   = img.width;

  noStroke();          //Do not draw border

  beginShape();
  texture(img);
  vertex(-150, -150, 0, 0, 0);
  vertex( 150, -150, 0, w, 0);
  vertex( 150,  150, 0, w, h);
  vertex(-150,  150, 0, 0, h);
  endShape();
}
void updateObject11() {
  drawGopher();
}

Master "explain"

Master "How to specify vertices is as follows" image.png Master "If the size does not match on the shape side and the image side" Master "The image is scaled to fit the shape side." Master "And if the shape side and the image side are not similar figures" Master "Be careful because the aspect ratio collapses."

Master "When you display an image including transparent parts in Processing" Master "despite being transparent" Master "The objects behind it can be hidden" Master "In that case, add the following line to the setup () method"

Learning.pde


...
void setup() {
  size(1200, 800, P3D);

  hint(ENABLE_DEPTH_SORT);             // <=====Postscript=====

  //setCameraOrbitalRadius(150);
  //setCameraOrbitalPeriod(120);
  frameRate(24);
}
...

Padawan "Ah, Pettanko Gopher-kun (laughs)" updateObject11.gif

Master "Then let's modify this method so that it can be sized"

Learning.pde


...
// (11)Texture mapping(Rest)                        // <=====Corrected after this ↓=====
void drawGopher(float len) {                            // <=====Fix=====
  PImage img = loadImage("gopher.png ");
  int    h   = img.height;
  int    w   = img.width;

  noStroke();          //Do not draw border

  beginShape();
  texture(img);
  vertex(-len/2, -len/2, 0, 0, 0);                      // <=====Fix=====
  vertex( len/2, -len/2, 0, w, 0);                      // <=====Fix=====
  vertex( len/2,  len/2, 0, w, h);                      // <=====Fix=====
  vertex(-len/2,  len/2, 0, 0, h);                      // <=====Fix=====
  endShape();
}
void updateObject11() {
  drawGopher(100);                                      // <=====Fix=====
}

Master "Simply explain"

Padawan "Oh, Pettanko has become tiny (laughs)"

2:10 | Revolve around the revolving body

Master "Enter the following"

Learning.pde


...
void draw() {
  ...
  //updateObject11();                                     // <=====Comment out=====
  updateObject12();                                       // <=====Postscript=====
}

...

// (12)Texture mapping(Revolve around the revolving body by coordinate transformation)    // <=====Added after this ↓=====
//The movement is(10)Almost the same as
void updateObject12() {
  float ms  = millis();            //Milliseconds elapsed from the start of the program

  final float S_LEN   =  200;      //The length of one side of the Sun Gopher

  final float E_LEN   =  100;      //The length of one side of the Earth Gopher
  final float E_R     =  400;      //Earth Gopher revolution radius
  final float E_SPEED =   80;      //Earth Gopher angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of Earth Gopher(Degree)
  float edr = radians(edd);        //Movement angle of Earth Gopher(Radian)

  final float M_LEN   =   50;      //The length of one side of the moon Gopher
  final float M_R     =  100;      //Moon Gopher Revolution Radius
  final float M_SPEED =  200;      //Moon Gopher angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon Gopher movement angle(Degree)
  float mdr = radians(mdd);        //Moon Gopher movement angle(Radian)

  pushMatrix();
  {
    translate(0, -S_LEN / 2, 0);
    drawGopher(S_LEN);             //Sun Gopher
  }
  popMatrix();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);

    pushMatrix();
    {
      translate(0, -E_LEN / 2, 0);
      drawGopher(E_LEN);           //Earth Gopher
    }
    popMatrix();
    
    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, -M_LEN / 2, 0);
      drawGopher(M_LEN);           //Moon gopher
    }
    popMatrix();

  }
  popMatrix();
}

Master "This is just before" Master "A method in which the earth and the moon revolve around the sun" Master "It's a little rewritten for Gopher"

Master "Although there is almost no difference ..." Master "I try to keep each Gopher's feet in contact with the ZX plane."

Master "For this reason, each Gopher is ``` translate () `` Master "Vertical (Y-axis) offset by half the length of one side of the rectangle" Master "But I don't want to affect other objects." Master "I'm evacuating and restoring the matrix before and after."

Sun Gopher's vertical translation


pushMatrix();                    //Evacuation of matrix
{
  //Coordinate transformations within this block do not affect the position or orientation of the Earth and the Moon
  translate(0, -S_LEN / 2, 0);   //Vertically offset by half the length of the sides of the rectangle
  drawGopher(S_LEN);             //Sun Gopher
}
popMatrix();                     //Matrix return

Master "And about Earth Gopher" Master "Separate the vertical (Y-axis) and horizontal (X-axis, Z-axis) movement components," Master "Only the rotational and horizontal movement components affect the Moon Gopher."

Earth Gopher's vertical translation


//Coordinate transformation for the revolution of the earth
//The following two lines (horizontal movement with rotation) affect the position and attitude of the moon
rotateY(edr);
translate(E_R, 0, 0);          //Does not include vertical movement components

pushMatrix();                  //Evacuation of matrix
{
  //Coordinate transformations within this block do not affect the moon
  translate(0, -E_LEN / 2, 0); //Vertical movement component
  drawGopher(E_LEN);           //Earth Gopher
}
popMatrix();                   //Matrix return

//After that, the coordinate transformation and drawing of the moon

With that said, Padawan clicked the Run button.

Padawan "Oh!" Padawan "Wow !!!"

Padawan "Ina Bauer !!!" updateObject12.gif

2:20 | Billboard

Master "But this is a problem" Padawan "Pettanko is going to get caught (laughs)"

Master "Yes, that's why." Master "From now on, I'll make sure it doesn't come out!" Master "Enter the following"

Learning.pde


...
void draw() {
  ...
  //updateObject12();                               // <=====Comment out=====
  updateObject13();                                 // <=====Postscript=====
}

...

// (13)Billboard(Revolve around the revolving body by coordinate transformation)       // <=====Added after this ↓=====
//The movement is(12)Almost the same as
void turnToCamera() {                              // <== +
  PMatrix3D m = (PMatrix3D)g.getMatrix();          // <== +
                                                   // <== +
  //column 0   //column 1   //column 2             // <== +
  m.m00 = 1;   m.m01 = 0;   m.m02 = 0;   // row 0  // <== +
  m.m10 = 0;   m.m11 = 1;   m.m12 = 0;   // row 1  // <== +
  m.m20 = 0;   m.m21 = 0;   m.m22 = 1;   // row 2  // <== +
                                                   // <== +
  resetMatrix();                                   // <== +
  applyMatrix(m);                                  // <== +
}                                                  // <== +
void updateObject13() {                            // <== +
  float ms  = millis();            //Milliseconds elapsed from the start of the program

  final float S_LEN   =  200;      //The length of one side of the Sun Gopher

  final float E_LEN   =  100;      //The length of one side of the Earth Gopher
  final float E_R     =  400;      //Earth Gopher revolution radius
  final float E_SPEED =   80;      //Earth Gopher angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of Earth Gopher(Degree)
  float edr = radians(edd);        //Movement angle of Earth Gopher(Radian)

  final float M_LEN   =   50;      //The length of one side of the moon Gopher
  final float M_R     =  100;      //Moon Gopher Revolution Radius
  final float M_SPEED =  200;      //Moon Gopher angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon Gopher movement angle(Degree)
  float mdr = radians(mdd);        //Moon Gopher movement angle(Radian)

  pushMatrix();
  {
    translate(0, -S_LEN / 2, 0);
    turnToCamera();                // <== +
    drawGopher(S_LEN);             //Sun Gopher
  }
  popMatrix();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);

    pushMatrix();
    {
      translate(0, -E_LEN / 2, 0);
      turnToCamera();              // <== +
      drawGopher(E_LEN);           //Earth Gopher
    }
    popMatrix();
    
    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, -M_LEN / 2, 0);
      turnToCamera();              // <== +
      drawGopher(M_LEN);           //Moon gopher
    }
    popMatrix();

  }
  popMatrix();
}

Master "Almost the same as the previous one," Master "I added // <== +` `` to the added part "

Master "briefly explain"

Master "By the way, if you think only in the ZX plane" Master "The left side of the figure below is" Strict conversion of billboard " Master "The conversion of method turnToCamera ()` `` is on the right" image.png

Padawan "Anything is fine if you don't get it!" With that said, Padawan clicked the Run button.

Padawan "Oh, I don't understand Pettanko!"

updateObject13.gif

Master "Whether the circular motion is as expected" Master "If you want to check from a higher or lower perspective" Master "Use the utility to do the following:"

Learning.pde


...
void setup() {
  size(1200, 800, P3D);
  hint(ENABLE_DEPTH_SORT);
  //setCameraOrbitalRadius(150);
  //setCameraOrbitalPeriod(120);

  setCameraMaxDepth(1500);             // <=====Postscript=====

  frameRate(24);
}
...

2:30 | Control the camera (stationary)

Master "so far" Master "The camera that was left to the automatic control of the utility," Master "Teaching how to control yourself"

Master "Enter the following"

Learning.pde


...
void setup() {
  size(1200, 800, P3D);
  hint(ENABLE_DEPTH_SORT);
  //setCameraOrbitalRadius(150);
  //setCameraOrbitalPeriod(120);
  //setCameraMaxDepth(1500);

  setDevRoomAutoCameraEnabled(false);                     // <=====Postscript=====

  frameRate(24);
}
...
void draw() {
  background(255, 255, 255);

  updateCamera1();                                        // <=====Postscript=====

  updateDevRoom();

  //updateObject1();
  //updateObject2();
  //updateObject3();
  //updateObject4();
  //updateObject5();
  //updateObject6();
  //updateObject7();
  //updateObject8();
  //updateObject9();
  //updateObject10()
  //updateObject11();
  //updateObject12();
  updateObject13();
}

...

// (14)Camera control(Rest)                                  // <=====Added after this ↓=====
void updateCamera1() {
  float x =  25;
  float y = -70;
  float z =  800;
  camera(x, y, z, 0, 0, 0, 0, 1, 0);
}

Master "explain"

Master "That is, this camera setting is" Master "Take the camera to coordinates (25, -75, 800)," Master "Point the lens at the coordinates (0, 0, 0)," Master "Aim the camera head toward the dark side of the Y axis (negative infinity)" Master "means"

Master "Looking at the next figure again" Master "Imagine the coordinates where the camera is placed and the image on the screen." image.png

Padawan clicked the Run button, envisioning what he would draw on the screen. updateCamera1.gif

Master "How is it? Did you follow the image?" Padawan "Yeah. There are three Gophers !!!"

2:40 | Move the camera straight (constant velocity linear motion)

Master "Let's move the camera" Master "Enter the following"

Learning.pde


...
void draw() {
  ...
  //updateCamera1();                                      // <=====Comment out=====
  updateCamera2();                                        // <=====Postscript=====
 ...
}

...

// (15)Camera control(Constant velocity linear motion)                             // <=====Added after this ↓=====
void updateCamera2() {
  final float START_Z =  1500;  //Z coordinate at the start
  final float SPEED   = -300;   //per second-300
  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dz = ms * SPEED / 1000; //Moving distance(Y coordinate) 

  float x = 100;
  float y = -50;
  float z = START_Z + dz;       //present location(Y coordinate)

  camera(x, y, z, x, y, z-1, 0, 1, 0);  
  //camera(x, y, z, 0, 0, 0, 0, 1, 0);  
}

Master "explain"

Padawan clicked the Run button.

updateCamera2.gif

Padawan "Oh! I thought I'd hit the sun Gopher!"

Master "If you can confirm it, try the camera control of the commented out person."

Learning.pde


...
  //camera(x, y, z, x, y, z-1, 0, 1, 0);  
  camera(x, y, z, 0, 0, 0, 0, 1, 0);  
...

2:50 | Revolve the camera (constant velocity circular motion)

Master "Next is the revolution of the camera"

Learning.pde


...
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white

  //updateCamera1();
  //updateCamera2();                                      // <=====Comment out=====
  updateCamera3();                                        // <=====Postscript=====

  updateDevRoom();

  updateObject1();                                        // <=====Uncomment=====
  updateObject2();                                        // <=====Uncomment=====
  updateObject3();                                        // <=====Uncomment=====
  updateObject4();                                        // <=====Uncomment=====
  //updateObject5();
  //updateObject6();
  //updateObject7();
  //updateObject8();
  //updateObject9();
  //updateObject10()
  //updateObject11();
  //updateObject12();
  //updateObject13();                                     // <=====Comment out=====
}

...

// (16)Camera control(revolution)                                  // <=====Added after this ↓=====
void updateCamera3() {
  final float R     =  1500;    //Revolution radius
  final float SPEED =   15;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)
  float x  = R * cos(dr);       //X coordinate
  float z  = R * sin(dr);       //Z coordinate
  float y  = -50;
  
  camera(x, y, z, 0, 0, 0, 0, 1, 0); 
}

Master "explain"

updateCamera3.gif

Padawan "Oh! Gopher-kun !!!" Padawan "Getting off ...?"

3:00 am | Model transformation and view transformation

3:00 | What is the matrix?

Master "Well, so far" Master "using translate () `` and ``` rotate () `` Master "Arrange objects freely,"

Master "Using camera ()` `` " Master "Where to put the viewpoint and how to see the world" Master "I've learned how to do that."

Master "Actually, what used to be called a coordinate system is" Master "Representing a point in space as a set of three numbers (x, y, z)" Master "It's called the Cartesian coordinate system` `` "

Master "and" Master "In many CG libraries, including Processing, etc." Master "When converting coordinates" Master "Representing points in space as a set of four numbers" Master "A thing called homogeneous coordinate system` `` is used. "

Padawan "Unknown !!!" Padawan "Why is it so difficult?"

Master "Gaha! Do you think so?" Master "But if you use this homogeneous coordinate system" Master "Coordinate transformation such as translation and rotation" Master "You will be able to express it very simply."

Master "Many knights practiced in the history of the galaxy," Master "It's a great technique that was created as a result of accumulating it."

Master "Open a new sketch with [File] [New]" image.png

Master "When you open a new sketch, go to [File] [Save As ...]" Master "Save it with a suitable name such as" Matrix "" image.png

Master "Once you save the sketch, type:"

Matrix.pde


size(500,500,P3D);

//Check the matrix
println("----------------------------------");
resetMatrix();         println("resetMatrix();");
printMatrix();

translate(-3, 0, -3);  println("translate(-3, 0, -3);");
printMatrix();

rotateY(radians(30));  println("rotateY(radians(30));");
printMatrix();

After entering this, when Padawan clicked the [Execute] button, the following was output to the console.

image.pnt

Padawan "What is this ???" Master "The true identity of the matrix!"

Padawan "What ???"

Master "I used to evacuate and restore" Master "What is the matrix ?" Master "Actually a collection of 16 numbers" Master "You can print its contents with printMatrix ()` `` "

Master "And coordinate transformations such as`` translate () ``and rotateY ()` `` Master "All of that can be represented by a combination of these 16 values."

Padawan "..."

Master "Did you learn" matrix "at the beginning?"

Padawan "Yeah! I learned!" Padawan "I know it's different from the store line!"

Master "What is the first information output to the console?" Master "after initialization with resetMatrix ()` `` Master "The current state of the matrix"

console


resetMatrix();
 1.0000  0.0000  0.0000  0.0000
 0.0000  1.0000  0.0000  0.0000
 0.0000  0.0000  1.0000  0.0000
 0.0000  0.0000  0.0000  1.0000

Master "Coordinate transformation information is" Master "It can be represented by a 4 row x 4 column matrix, that is, a 4th order square matrix" Master "And when initialized with resetMatrix () `` Master "The current matrix becomes identity matrix `` "

Padawan "???"

Master "What is an identity matrix?" Master "The identity element` `` in matrix multiplication, " Master "Speaking in ordinary numbers" Master "It's a basic value like 0 for addition or 1 for multiplication."

Master "What number plus 0 will not change the value?" Master "What about multiplication?"

Padawan "Oh! No matter what number you multiply by 1, it doesn't change!" Padawan "I feel ..."

Master "Yes. Coordinate transformation is done by matrix multiplication." Master "And multiply by any (matrix) value" Master "It is the identity matrix` `` that does not change it"

Padawan "Well ..." Padawan "Is it like setting it to 0 when initializing the counter?" Master "Well, that's fine"

Master "And this is the matrix with translate (-3, 0, -3)` `` applied. "

console


translate(-3, 0, -3);
 1.0000  0.0000  0.0000 -3.0000
 0.0000  1.0000  0.0000  0.0000
 0.0000  0.0000  1.0000 -3.0000
 0.0000  0.0000  0.0000  1.0000

Master "Furthermore, this is the matrix to which rotateY (radians (30));` `` is applied. "

console


rotateY(radians(30));
 0.8660  0.0000  0.5000 -3.0000
 0.0000  1.0000  0.0000  0.0000
-0.5000  0.0000  0.8660 -3.0000
 0.0000  0.0000  0.0000  1.0000

Master "You don't have to worry about the meaning of each number now."

Master "But in the matrix above, not just roatateY ()" Master "Translate the previous translate ()" Master "Be careful that it is included"

Padawan "Well, translate ()" Padawan "If you enclose it in pushMatrix () and popMatrix ()" Padawan "Is it just rotation?"

Master "If you have any doubts, check it out."

Padawan "Well ..." Padawan "Push here ..."

Matrix.pde


size(500,500,P3D);

//Check the matrix
println("----------------------------------");
resetMatrix();         println("resetMatrix();");
printMatrix();

pushMatrix();                                              // <==Postscript
translate(-3, 0, -3);  println("translate(-3, 0, -3);");
printMatrix();
popMatrix();                                               // <==Postscript

rotateY(radians(30));  println("rotateY(radians(30));");
printMatrix();

Padawan "Oh, really" Padawan "I don't know the details, but" Padawan "-3.0000 on the far right has disappeared!"

console


...
rotateY(radians(30));
 0.8660  0.0000  0.5000  0.0000
 0.0000  1.0000  0.0000  0.0000
-0.5000  0.0000  0.8660  0.0000
 0.0000  0.0000  0.0000  1.0000

Matrix multiplication

Master "If you organize this far,"

Master "To convert the local coordinate system to the world coordinate system" Master "What is the matrix you have used?" Master "Made of a combination of 16 numbers" Master "This represents a 4 row x 4 column matrix"

Master "And with this combination of values" Master "I can express all the coordinate transformations I've done so far"

Master "Is it okay ?!"

Padawan "Yeah! Somehow I understand !!!" Padawan "It's not that I don't feel like ..."

Master "Then this matrix is in Processing" Master "Let's think a little about how it is calculated"

Master "First, let's review the matrix multiplication"

Master "The multiplication of the basic`` 4 rows 1 column ``and the`` 1 row 4 columns ``is as follows."

image.png

Master "And the multiplication of 4 rows 4 columns`` and ``4 rows 1 column` `` Master "Calculate by separating 4 rows and 4 columns one row at a time"

Master "for example" Master "`` resetMatrix () ``and" Master "after executing translate (-3, 0, -3) " Master "Run`Vertex (5, 0, 4)` to draw" Master "Vertex P (5, 0, 4) on local coordinates is"

Master "Add 1 after (5, 0, 4)" Master "After making a 4-by-1 matrix" Master "Calculating as follows," image.png Master "It's converted to the vertex P'(2, 0, 1) in world coordinates." image.png

Master "Also, in the case of rotateY (radians (30))` ``, as well. " Master "Can be calculated as follows," image.png Master "Converted to vertex P'(6.33, 0, 0.964) in world coordinates" image.png

Padawan "Oh! I remembered!" Padawan "'Matrix' repeats multiplication and addition like a demon" Padawan "Mendocchi guy !!!"

Padawan "I forgot the rest!"

Affine transformation

Master " rotate`` is a type of transformation called a linear transformation," Master "They have ```scale`` and ``shear` ``. "

Padawan "Shear ???" Master "When the knight candy (footnote: Kintaro candy) is cut diagonally" Master "Can you think of a cross section?"

Padawan "Oh! When my uncle made a mistake in cutting" Padawan "That crappy face guy! (Laughs)"

Master "Think of it as shear"

Master "But I won't scale and shear this time." Master "If you are interested, study for yourself"

Master "and" Master "Linear transformation plus translate" Master "say ``` affine transformation `` "

Padawan "Hmm ..."

Master "And this affine transformation" Master "Can be represented by a quaternary square matrix," Master "The components of the matrix associated with each transmutation are:" image.png

Master "Also on translation and rotation" Master "The correspondence between methods and matrices is as follows" image.png

Master "By the way, in the initiating era" Master "Any point P (x, y) on the quadric (XY plane)" Master "Rotated by an angle θ around the origin (0, 0)" Master "I think I learned the formula to find the point P'(x', y'), but ..."

Master "Do you remember?"

x' = x cosθ - y sinθ y' = x sinθ + y cosθ

Padawan "Yeah!" Padawan "Of course, I don't remember !!!"

Master "For example, in the case of 30 ° rotation, it should have been calculated as follows." image.png

Master "Calculating the matrix of rotation rotateZ () around the Z axis" Master "You will find that it matches the above formula" image.png

Padawan "I knew it would match, but ..." Padawan "Well, something has changed ..."

Padawan "Oh! The direction of the arrow is different from the previous one" Padawan "Why are you turning in the same direction ???"

Padawan was comparing the ZX plane and the XY plane in his head. image.png

Padawan "Because the arrows are reversed ..." Padawan "Well, if you turn it over, the direction of rotation should be reversed ..." Padawan "Well, that ???"

Padawan "I got a headache (laughs)"

Master "Padawan ..."

Padawan (Wow, are you angry ...)

Rotate orientation

Master "I noticed a good point!" Padawan "He?"

Master "What to put on the vertical and horizontal axes," Master "Which direction is the right side (positive infinity direction)?" Master "Because it changes the direction of rotation" Master "Let's see them together"

Master "Processing defaults with the vertical axis pointing down and the horizontal axis pointing to the right" Master "Let's look at each plane accordingly"

Master "Then all the rotations will be clockwise as follows:" image.png

Padawan "Ah, Zurii!" Padawan "X is vertical!"

Master "Yes. To see the ZX plane from the same perspective as the XY plane" Master "We need to have X on the vertical axis and Z on the horizontal axis."

Master "What is the ZX plane view so far?" Master "I think it's easier to grasp the image" Master "X was on the horizontal axis"

Master "Remember that Processing is left-handed."

Master "For example, if it is a ZX plane" Master "After pointing your index finger (Y-axis) toward you" Master "If you let the rest of your fingers point to the right and down,"

Master "The orientation of the thumb (X-axis) and middle finger (Z-axis) is naturally determined" Master "You will find that it matches this figure."

Padawan "Oh, really ..." Padawan "Thumb down and middle finger right!"

Master "and" Master "If you take a closer look at the processing of rotateX () rotateY () rotateZ ()" Master "sin is the vertical axis component, cos (cosine) is the horizontal axis component" Master "You will see that it is calculated"

Method Axis of rotation Impact
receive
Plane
Planeの
Horizontal axis
Planeの
Vertical axis
cosθ
(cosine)
sinθ
(sine)
rotateZ() Z axis XY plane X axis Y axis X component Y component
rotateY() Y axis ZX plane Z axis X axis Z component X component
rotateX() X axis YZ plane Y axis Z axis Y component Z component

Master "If you remember that cosθ is the X component and sinθ is the Y component" Master "Because you'll get confused in the ZX and YZ planes." Master "I remember that cosθ is the horizontal axis component (width) and sinθ is the vertical axis component (height)."

Master "In addition, the following is a summary of the rotation formula."

Method Axis of rotation Impact
receive
Plane
Rotation formula
rotateZ() Z axis XY plane x' = x cosθ - y sinθ
y' = x sinθ + y cosθ
rotateY() Y axis ZX plane z' = z cosθ - x sinθ
x' = z sinθ + x cosθ
rotateX() X axis YZ plane y' = y cosθ - z sinθ
z' = y sinθ + z cosθ

Padawan "Oh, my head ..." Padawan "Explode !!!!"

Master "gahaha" Master "Well, you don't have to remember the formula" Master "Because the conversion method calculates the matrix"

Master "However, it is better to keep in mind the direction of rotation of each axis."

Master "If you point the axis of rotation at yourself" Master "The positive direction in which the axis rotates is clockwise."

Master "For example, if you pass a positive number to rotateZ ()," Master "If you point the Z axis at yourself, the XY plane will rotate clockwise."

Master "And of course if you pass a negative number to rotateZ ()," Master "Needless to say, it's counterclockwise."

Master "The'positive direction'of rotation of each axis is as follows." Master "Let this soak into your body" image.gif

Synthetic conversion

Master "Next, when combining coordinate transformations" Master "Let's think about what the matrix is like"

Master "For example, when translateY () is followed by translate ()" Master "You can express a transformation that combines both in one matrix."

Padawan "Can you only do two?" Master "No, no matter how many transformations you stack, you can express them in one matrix."

Master "And if you apply it to an object," Master "The conversion is completed in one go"

Padawan "Oh! It's the same as the pocketbook!" Master "What ???"

Padawan "The pocketbook is also ..." Padawan "No matter how many times you shop" Padawan "You can express the" balance "of the month with one number!"

Padawan "So, just add that balance to your balance at the end of last month." Padawan "You can calculate this month's balance!"

Coordinate conversion Pocket money book
translate () pocket money 10 credit
rotateY () Ame -1 credit
translate () Knight Figure -6 credit
rotateZ () Gum -1 credit
rotateX () Kids Saver -4 credit
** Synthetic Matrix ** ** This Month's Balance -2 credit **

Master "It looks like a deficit this month (laughs)"

Master "Well, you can think so" Master "But in the case of coordinate transformation, it's multiplication, not addition."

Master "Because each transmutation is a 4th-order square matrix" Master "It's a multiplication of 4th-order square matrices"

Master "Add the following to the newly created sketch"

Matrix.pde


...
//Confirmation of synthetic conversion//Added after this
println("----------------------------------");
resetMatrix();
rotateY(radians(30));  println("rotateY(radians(30));");
printMatrix();

resetMatrix();
rotateX(radians(30));  println("rotateX(radians(30));");
printMatrix();

Master "RotateY () and RotateX () output to console" Master "Let's multiply two transformation matrices"

console


----------------------------------
rotateY(radians(30));
 0.8660  0.0000  0.5000  0.0000
 0.0000  1.0000  0.0000  0.0000
-0.5000  0.0000  0.8660  0.0000
 0.0000  0.0000  0.0000  1.0000

rotateX(radians(30));
 1.0000  0.0000  0.0000  0.0000
 0.0000  0.8660 -0.5000  0.0000
 0.0000  0.5000  0.8660  0.0000
 0.0000  0.0000  0.0000  1.0000

Master "The calculation method is as follows" Master "First, calculate the first line as follows," image.png

Master "The same calculation can be done for the second and subsequent lines." image.png Padawan "Wow!" Padawan "Mendokusei !!!"

Master "Add the following to the sketch," Master "Check if the calculation results are correct"

Matrix.pde


...
resetMatrix();                                           //Added after this
rotateY(radians(30));  println("rotateY(radians(30));");
rotateX(radians(30));  println("rotateX(radians(30));");
printMatrix();

console


rotateY(radians(30));
rotateX(radians(30));
 0.8660  0.2500  0.4330  0.0000
 0.0000  0.8660 -0.5000  0.0000
-0.5000  0.4330  0.7500  0.0000
 0.0000  0.0000  0.0000  1.0000

Padawan "Oh! It's right !!!" Padawan "Well, it's faster to write this saver ?!"

Master "Would you like to write !?"

Master "How to get the current matrix" Master "Do you know because I did it with turnToCamera () a while ago?"

Master "In the method get () of the acquired PMatrix instance," Master "If you pass a float array (one-dimensional array) with 16 elements" Master "You can get the matrix as an array"

Padawan "Well ..." Padawan added the following to Matrix.pde:

Matrix.pde


...
//Multiplication between matrices//Added after this
println("----------------------------------");
float[] m1 = new float[16];  // rotateY()Result of
float[] m2 = new float[16];  // rotateX()Result of
float[] m3 = new float[16];  // rotateY()And rotateX()Synthetic result of

resetMatrix();
rotateY(radians(30));
((PMatrix3D)g.getMatrix()).get(m1);  

resetMatrix();
rotateX(radians(30));
((PMatrix3D)g.getMatrix()).get(m2);  

for (int i = 0; i < 4; i++)
  for (int j = 0; j < 4; j++)
    for (int k = 0; k < 4; k++)
      m3[i * 4 + j] += m1[i * 4 + k] * m2[k * 4 + j];

println(m3);

Padawan "Huh, I wonder if this suits me ..."

console


----------------------------------
[0] 0.8660254
[1] 0.25
[2] 0.4330127
[3] 0.0
[4] 0.0
[5] 0.8660254
[6] -0.5
[7] 0.0
[8] -0.5
[9] 0.4330127
[10] 0.75
[11] 0.0
[12] 0.0
[13] 0.0
[14] 0.0
[15] 1.0

Padawan "Yeah! Looks like it fits!"

Padawan "Well, this is calculated by Processing." Padawan "What does it mean to write by yourself ???"

Master "No (laughs)"

Padawan "Gee! I was deceived again !!!" Padawan "What! Chiku Show!"

Master "Well, don't get so rough (laughs)"

Master "The behavior of the library" Master "I also want to check if it matches my expectations" Master "I'm sure it will come out in the future" Master "I think it's a practice for that time."

3:30 | Camera identity

Master "Then add the following to Matrix.pde"

Matrix.pde


...
//Camera behavior//Added after this
println("----------------------------------");
camera(50, 0, 100, 50, 0, 0, 0, 1, 0);
println("camera(50, 0, 100, 50, 0, 0, 0, 1, 0);");
printMatrix();

camera(0, 0, 0, 250, 0, -433, 0, 1, 0);
println("camera(0, 0, 0, 250, 0, -433, 0, 1, 0);");
printMatrix();

Master "In the above, the camera is placed in the world coordinate system (see the figure below)," Master "I'm checking the matrix right after that" image.png Master "For clarity" Master "Camera and target are placed on the ZX plane"

Master "And on the left, make your line of sight parallel to the Z axis," Master "Right tilts the line of sight 30 ° from the Z axis"

Padawan "But why do you check the matrix?"

Padawan "Oh!"

console


----------------------------------
camera(50, 0, 100, 50, 0, 0, 0, 1, 0);
 001.0000  000.0000  000.0000 -050.0000
 000.0000  001.0000  000.0000  000.0000
 000.0000  000.0000  001.0000 -100.0000
 000.0000  000.0000  000.0000  001.0000

camera(0, 0, 0, 250, 0, -433, 0, 1, 0);
 0.8660  -0.0000  0.5000  0.0000
 0.0000  1.0000  0.0000  0.0000
-0.5000  0.0000  0.8660  0.0000
 0.0000  0.0000  0.0000  1.0000

Padawan "There are a lot of familiar numbers!" Padawan "But what is -0.0000?"

Master "It was designated by the Galactic Standardization Agency as No. 754" Master "In a story related to the standard for floating point numbers (footnote: IEEE754)" Master "For now, just think of it as a normal 0."

Master "How about other things?"

Padawan "Yeah. 0.866 or 0.5?" Padawan "By repeating addition and multiplication like the demon" Padawan "I saw a lot of numbers."

Master "That's right" Master "Let's enter the following to confirm that"

Matrix.pde


...
//Comparison with coordinate transformation//Added after this
println("----------------------------------");
resetMatrix();
translate(-50, 0, -100);
println("translate(-50, 0, -100);");
printMatrix();

resetMatrix();
rotateY(radians(30));
println("rotateY(radians(30));");
printMatrix();

When Padawan clicked the Run button, the following was output to the console:

console


----------------------------------
translate(-50, 0, -100);
 001.0000  000.0000  000.0000 -050.0000
 000.0000  001.0000  000.0000  000.0000
 000.0000  000.0000  001.0000 -100.0000
 000.0000  000.0000  000.0000  001.0000

rotateY(radians(30));
 0.8660  0.0000  0.5000  0.0000
 0.0000  1.0000  0.0000  0.0000
-0.5000  0.0000  0.8660  0.0000
 0.0000  0.0000  0.0000  1.0000

Padawan "Gee! It's the same !!!"

Master "Well, let's compare it a little easier to understand." image.png

Master "Translating the camera" Master "Same as moving an object in the opposite direction,"

Master "Rotating the camera" Master "Rotating an object in the opposite direction ..."

Padawan "It's the same !!!"

Master "Yes, when you call the method camera ()" Master "The current matrix has a reverse transformation set."

Master "In other words, I've been thinking mainly about the world coordinate system." Master "Actually, the camera was the center of the world."

Master "The left side of the figure below is the apparent movement" Master "The right side is the actual movement" image.png

Master "And this is the case for rotation" image.png

Master "Calling camera () like this" Master "I'm coming back with the" stage "of the world moving." Master "And the coordinate transformation and drawing process after that" Master "Everything will be done on this stage"

Master "Also, even if you move the stage of the world" Master "A coordinate system that stays stationary and doesn't move" Master "`` Camera coordinate system ``, Master "The camera's point of view is always at its origin (0, 0, 0)," Master "Camera is always on the dark side of the Z axis (negative infinity)" Master "I'm setting my eyes"

Master "So, in the camera coordinate system," Master "The screen plane is always parallel to the XY plane."

Master "And executed by calling camera ()" Master "Coordinate transformation is called viewing transformation` `` "

Master "For that, translate (), rotateY (), etc." Master "Transforming coordinates from the local coordinate system to the world coordinate system" Master "` `` Modeling transformation ```,"

Master "These two are combined and called model view conversion` `` "

Padawan "Hmm?"

Padawan "Then, come on" Padawan "A little while ago, this crap ↓↓↓↓↓ ,,,"

Padawan "Oh, something is going around ..." updateObject1.gif Master "Actually, everything in this is stationary" Padawan "What ??? Because it's going around!" Master "It's the camera that's spinning"

Master "That's a lie (laughs)"

Padawan "What! I think I was right !!!!" Padawan (Why does the master always mess around (angry))

Master "But centered on the world coordinate system," Master "Thinking about placing objects and cameras there" Master "It doesn't hurt to write a saver" Master "That's the great thing about this method"

The theory of changing the posture of the billboard

Master "If you can understand this far" Master "I can explain the change in the posture of the billboard."

Master "Look at turnToCamera () again"

Learning.pde


...
void turnToCamera() {
  PMatrix3D m = (PMatrix3D)g.getMatrix();  

  //column 0   //column 1   //column 2
  m.m00 = 1;   m.m01 = 0;   m.m02 = 0;   // row 0
  m.m10 = 0;   m.m11 = 1;   m.m12 = 0;   // row 1
  m.m20 = 0;   m.m21 = 0;   m.m22 = 1;   // row 2
  
  resetMatrix();  
  applyMatrix(m);  
}
...

Master "After fetching the current matrix with g.getMatrix ()" Master "Are you setting values in the fields m00 to m22?" Master "Actually, this is an element of the matrix."

Master "Of which, the unit matrix is set for the elements related to posture change." image.png

Padawan "Oh, it doesn't change even if you hang it!"

Master "By doing this, in the process so far" Master "Viewing Transform (Call camera ()) and" Master "Transformed with a modeling transformation (call of rotateY () or translate ())" Master "Keep the position of the'stage'as it is" Master "You can make that attitude the only thing you didn't have."

Master "The matrix m``` modified in this way " Master "I'm resetting it as the current matrix."

Master "First with resetMatrix ()` `` " Master "Make the current matrix an identity matrix," image.png

Master "Finally, with applyMatrix (m)` ``," Master "I'm multiplying the current matrix by` `m "

Master "Let's check the actual operation again" Master "Create a new sketch and do the following:"

TurnToCameraTest


void setup() {
  size(1000, 300, P3D);
}

void draw() {
  background(255, 255, 255);
  stroke(0, 0, 255);
  fill(240,240,240);
  camera(0, 0, 0, 0, 0, -1, 0, 1, 0); //Place the camera's viewpoint at the origin and direct the line of sight toward the negative infinity of the Z axis
  drawBoard(300,  45);                //Tilt the local coordinate system 45 ° and move 300 along the X axis to draw the board
  drawBoard(300,  90);                //Tilt the local coordinate system 90 ° and move 300 along the X axis to draw the board
  drawBoard(300, 135);                //Tilt the local coordinate system 135 ° and move 300 in the X-axis direction to draw the board
}

void drawBoard(float xpos, float degree) {
  pushMatrix();
    rotateY(radians(degree)); //Rotate the local coordinate system by degree around the Y axis
    translate(xpos, 0, 0);    //Translate the local coordinate system in the x direction (of the local coordinate system) by xpos
    //turnToCamera();         //Make the XY plane of the local coordinate system parallel to the XY plane of the camera coordinate system
    beginShape();             //Draw a board parallel to the XY plane in local coordinates
      vertex(-50, -50, 0);
      vertex( 50, -50, 0);
      vertex( 50,  50, 0);
      vertex(-50,  50, 0);
    endShape(CLOSE);
  popMatrix();
}

void turnToCamera() {         //Make the XY plane of the local coordinate system parallel to the XY plane of the camera coordinate system
    PMatrix3D m = (PMatrix3D)g.getMatrix();  
    m.m00 = m.m11 = m.m22 = 1;
    m.m01 = m.m02 = m.m10 = m.m12 = m.m20 = m.m21 = 0;
    resetMatrix();  
    applyMatrix(m);  
}

Master "After running and checking" Master " // turnToCamera (); Uncomment the` `` part " Master "I'll try again" image.png

Master "Did you get the image?"

Padawan "Yeah! Perfect !!!" Padawan (I don't know, but if you call the method, he will turn around !!!)

Master "In addition, I will supplement only one"

Master "I haven't dealt with this time," Master "Ingredients such as scale () and shareX ()" Master "Because it is included in the blue part in the figure below" image.png Master "For example, with scaling" Master "turnToCamera () will behave unfavorably"

3:50 | Code so far

Master "I've got a break so far" Master "Look at Learning.pde and Matrix.pde again"

Extract all code from Learning.pde

Learning.pde


// setup()Is called only once immediately after starting the program
void setup() {
  size(1200, 800, P3D); //Specifying window size and 3DCG
  hint(ENABLE_DEPTH_SORT);
  //setCameraOrbitalRadius(150);
  //setCameraOrbitalPeriod(120);
  //setCameraMaxDepth(1500);
  setDevRoomAutoCameraEnabled(false);
  frameRate(24);        //frame rate(fps)
}

// draw()Is called many times until the end of the program
// (fps==If 24, it will be called 24 times per second)
void draw() {
  background(255, 255, 255); //Background color(R,G,B)Is white

  //updateCamera1();
  //updateCamera2();
  updateCamera3();

  updateDevRoom();

  updateObject1();
  updateObject2();
  updateObject3();
  updateObject4();
  //updateObject5();
  //updateObject6();
  //updateObject7();
  //updateObject8();
  //updateObject9();
  //updateObject10()
  //updateObject11();
  //updateObject12();
  //updateObject13();
}

// (1)Rectangle drawing(Rest)
void updateObject1() {
  fill(240, 240, 240); //Fill color(R,G,B)
  stroke(255, 0, 255); //Border color(R,G,B)
  strokeWeight(2);     //Border thickness

  beginShape();
  vertex(-50, -50, -500);
  vertex( 50, -50, -500);
  vertex( 50,  50, -500);
  vertex(-50,  50, -500);
  endShape(CLOSE);
}

// (2)Rectangle drawing(Pseudo constant velocity linear motion)
float gZ = -600;
void updateObject2() {
  gZ+=120;              //Update Z coordinate

  fill(255, 255, 255); //Fill color(R,G,B)
  stroke(0, 255, 255); //Border color(R,G,B)
  strokeWeight(2);     //Border thickness

  beginShape();
  vertex(-40, -40, gZ);
  vertex( 40, -40, gZ);
  vertex( 40,  40, gZ);
  vertex(-40,  40, gZ);
  endShape(CLOSE);
}

// (3)Rectangle drawing(Real constant velocity linear motion)
void updateObject3() {
  final float START_Y = -600;   //Y coordinate at the start
  final float SPEED   =  200;   //per second

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dy = ms * SPEED / 1000; //Moving distance(Y coordinate) 
  float y = START_Y + dy;       //present location(Y coordinate)

  noFill();                     //No fill
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness

  beginShape();
  vertex(-30, y, -30);
  vertex( 30, y, -30);
  vertex( 30, y,  30);
  vertex(-30, y,  30);
  endShape(CLOSE);
}

// (4)Rectangle drawing(circular motion)
void updateObject4() {
  final float R     =  500;     //Revolution radius
  final float SPEED =   60;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)
  float x  = R * cos(dr);       //X coordinate
  float y  = R * sin(dr);       //Y coordinate
  
  fill(255, 255, 255);          //Fill color(R,G,B)
  stroke(0, 0, 255);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness

  beginShape();
  vertex(x-30, y, -30);
  vertex(x+30, y, -30);
  vertex(x+30, y,  30);
  vertex(x-30, y,  30);
  endShape(CLOSE);
}

// (5)Drawing 3D objects(Rest)
void updateObject5() {
  noFill();            //No fill
  strokeWeight(2);     //Border thickness

  stroke(255, 0, 255); //Border color(R,G,B)
  box(150);

  stroke(0, 255, 255); //Border color(R,G,B)
  sphere(60);
}

// (6)3D object(Constant velocity linear motion with coordinate transformation)
// (3)Achieve a movement similar to
void drawEarth() {
  fill(224, 224, 255);          //Fill color(R,G,B)
  stroke(0, 0, 255);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  
  box(80);
}
void updateObject6() {
  final float START = -600;   //Position at the start
  final float SPEED =  200;   //per second

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float d = ms * SPEED / 1000;  //Moving distance
  float p = START + d;          //present location

  pushMatrix();
  translate(p, -100, 50);
  drawEarth();
  popMatrix();
}

// (7)3D object(Rotation by coordinate conversion)
void updateObject7() {
  final float SPEED =  60;      //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  rotateY(dr);
  drawEarth();
  popMatrix();
}

// (8)3D object(Revolve by coordinate conversion)
// (4)Achieve a movement similar to
void updateObject8() {
  final float R     =  300;     //Revolution radius
  final float SPEED =  150;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  rotateY(dr);
  translate(R, 0, 0);
  drawEarth();
  popMatrix();
}

// (9)3D object(Rotating at a distant position by coordinate transformation)
// (8)Pay attention to the difference with
void updateObject9() {
  final float R     =  300;     //Revolution radius
  final float SPEED =  150;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)

  pushMatrix();
  translate(R, 0, 0);  //I just changed the order
  rotateY(dr);         //I just changed the order
  drawEarth();
  popMatrix();
}

// (10)3D object(Revolve around the revolving body by coordinate transformation)
void drawSun() {
  noFill();                     //No fill
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  sphere(60);
}
void drawMoon() {
  fill(255, 255, 128);          //Fill color(R,G,B)
  stroke(255, 0, 0);            //Border color(R,G,B)
  strokeWeight(2);              //Border thickness
  beginShape();
  vertex(-20, -20, 0);
  vertex( 20, -20, 0);
  vertex( 20,  20, 0);
  vertex(-20,  20, 0);
  endShape(CLOSE);
}
void updateObject10() {
  float ms  = millis();            //Milliseconds elapsed from the start of the program

  final float E_R     =  400;      //Earth's orbital radius
  final float E_SPEED =   80;      //Earth angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of the earth(Degree)
  float edr = radians(edd);        //Movement angle of the earth(Radian)

  final float M_R     =  100;      //Revolution radius of the moon
  final float M_SPEED =  200;      //Moon angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon movement angle(Degree)
  float mdr = radians(mdd);        //Moon movement angle(Radian)

  drawSun();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);
    drawEarth();

    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, 0, 0);
      drawMoon();
    }
    popMatrix();

  }
  popMatrix();
}

// (11)Texture mapping(Rest)
void drawGopher(float len) {
  PImage img = loadImage("gopher.png ");
  int    h   = img.height;
  int    w   = img.width;

  noStroke();          //Do not draw border

  beginShape();
  texture(img);
  vertex(-len/2, -len/2, 0, 0, 0);
  vertex( len/2, -len/2, 0, w, 0);
  vertex( len/2,  len/2, 0, w, h);
  vertex(-len/2,  len/2, 0, 0, h);
  endShape();
}
void updateObject11() {
  drawGopher(500);
}

// (12)Texture mapping(Revolve around the revolving body by coordinate transformation)
//The movement is(10)Almost the same as
void updateObject12() {
  float ms  = millis();            //Milliseconds elapsed from the start of the program

  final float S_LEN   =  200;      //The length of one side of the Sun Gopher

  final float E_LEN   =  100;      //The length of one side of the Earth Gopher
  final float E_R     =  400;      //Earth Gopher revolution radius
  final float E_SPEED =   80;      //Earth Gopher angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of Earth Gopher(Degree)
  float edr = radians(edd);        //Movement angle of Earth Gopher(Radian)

  final float M_LEN   =   50;      //The length of one side of the moon Gopher
  final float M_R     =  100;      //Moon Gopher Revolution Radius
  final float M_SPEED =  200;      //Moon Gopher angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon Gopher movement angle(Degree)
  float mdr = radians(mdd);        //Moon Gopher movement angle(Radian)

  pushMatrix();
  {
    translate(0, -S_LEN / 2, 0);
    drawGopher(S_LEN);             //Sun Gopher
  }
  popMatrix();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);

    pushMatrix();
    {
      translate(0, -E_LEN / 2, 0);
      drawGopher(E_LEN);           //Earth Gopher
    }
    popMatrix();
    
    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, -M_LEN / 2, 0);
      drawGopher(M_LEN);           //Moon gopher
    }
    popMatrix();

  }
  popMatrix();
}

// (13)Billboard(Revolve around the revolving body by coordinate transformation)
//The movement is(12)Almost the same as
void turnToCamera() {
  PMatrix3D m = (PMatrix3D)g.getMatrix();  

  //column 0   //column 1   //column 2
  m.m00 = 1;   m.m01 = 0;   m.m02 = 0;   // row 0
  m.m10 = 0;   m.m11 = 1;   m.m12 = 0;   // row 1
  m.m20 = 0;   m.m21 = 0;   m.m22 = 1;   // row 2
  
  resetMatrix();  
  applyMatrix(m);  
}
void updateObject13() {
  float ms  = millis();            //Milliseconds elapsed from the start of the program


  final float S_LEN   =  200;      //The length of one side of the Sun Gopher

  final float E_LEN   =  100;      //The length of one side of the Earth Gopher
  final float E_R     =  400;      //Earth Gopher revolution radius
  final float E_SPEED =   80;      //Earth Gopher angle(Degree)/Seconds
  float edd = ms * E_SPEED / 1000; //Movement angle of Earth Gopher(Degree)
  float edr = radians(edd);        //Movement angle of Earth Gopher(Radian)

  final float M_LEN   =   50;      //The length of one side of the moon Gopher
  final float M_R     =  100;      //Moon Gopher Revolution Radius
  final float M_SPEED =  200;      //Moon Gopher angle(Degree)/Seconds
  float mdd = ms * M_SPEED / 1000; //Moon Gopher movement angle(Degree)
  float mdr = radians(mdd);        //Moon Gopher movement angle(Radian)

  pushMatrix();
  {
    translate(0, -S_LEN / 2, 0);
    turnToCamera();
    drawGopher(S_LEN);             //Sun Gopher
  }
  popMatrix();

  pushMatrix();
  {
    rotateY(edr);
    translate(E_R, 0, 0);

    pushMatrix();
    {
      translate(0, -E_LEN / 2, 0);
      turnToCamera();
      drawGopher(E_LEN);           //Earth Gopher
    }
    popMatrix();
    
    pushMatrix();
    {
      rotateY(mdr);
      translate(M_R, -M_LEN / 2, 0);
      turnToCamera();
      drawGopher(M_LEN);           //Moon gopher
    }
    popMatrix();

  }
  popMatrix();
}

// (14)Camera control(Rest)
void updateCamera1() {
  float x =  25;
  float y = -70;
  float z =  800;
  camera(x, y, z, 0, 0, 0, 0, 1, 0);
}

// (15)Camera control(Constant velocity linear motion)
void updateCamera2() {
  final float START_Z =  1500;  //Z coordinate at the start
  final float SPEED   = -300;   //per second-300

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dz = ms * SPEED / 1000; //Moving distance(Y coordinate) 

  float x = 100;
  float y = -50;
  float z = START_Z + dz;       //present location(Y coordinate)

  //camera(x, y, z, x, y, z-1, 0, 1, 0);  
  camera(x, y, z, 0, 0, 0, 0, 1, 0);  
}

// (16)Camera control(revolution)
void updateCamera3() {
  final float R     =  1500;    //Revolution radius
  final float SPEED =   15;     //angle(Degree)/Seconds

  float ms = millis();          //Milliseconds elapsed from the start of the program
  float dd = ms * SPEED / 1000; //Moving angle(Degree)
  float dr = radians(dd);       //Moving angle(Radian)
  float x  = R * cos(dr);       //X coordinate
  float z  = R * sin(dr);       //Z coordinate
  float y  = -50;
  
  camera(x, y, z, 0, 0, 0, 0, 1, 0); 
}
Expand all code in Matrix.pde

Matrix.pde


size(500,500,P3D);

//Check the matrix
println("----------------------------------");
resetMatrix();         println("resetMatrix();");
printMatrix();

pushMatrix();
translate(-3, 0, -3);  println("translate(-3, 0, -3);");
printMatrix();
popMatrix();

rotateY(radians(30));  println("rotateY(radians(30));");
printMatrix();

//Confirmation of synthetic conversion
println("----------------------------------");
resetMatrix();
rotateY(radians(30));  println("rotateY(radians(30));");
printMatrix();

resetMatrix();
rotateX(radians(30));  println("rotateX(radians(30));");
printMatrix();

resetMatrix();
rotateY(radians(30));  println("rotateY(radians(30));");
rotateX(radians(30));  println("rotateX(radians(30));");
printMatrix();

//Multiplication between matrices
println("----------------------------------");
float[] m1 = new float[16];  // rotateY()Result of
float[] m2 = new float[16];  // rotateX()Result of
float[] m3 = new float[16];  // rotateY()And rotateX()Synthetic result of

resetMatrix();
rotateY(radians(30));
((PMatrix3D)g.getMatrix()).get(m1);  

resetMatrix();
rotateX(radians(30));
((PMatrix3D)g.getMatrix()).get(m2);  

for (int i = 0; i < 4; i++)
  for (int j = 0; j < 4; j++)
    for (int k = 0; k < 4; k++)
      m3[i * 4 + j] += m1[i * 4 + k] * m2[k * 4 + j];

println(m3);

//Camera behavior
println("----------------------------------");
camera(50, 0, 100, 50, 0, 0, 0, 1, 0);
println("camera(50, 0, 100, 50, 0, 0, 0, 1, 0);");
printMatrix();

camera(0, 0, 0, 250, 0, -433, 0, 1, 0);
println("camera(0, 0, 0, 250, 0, -433, 0, 1, 0);");
printMatrix();

//Comparison with coordinate transformation
println("----------------------------------");
resetMatrix();
translate(-50, 0, -100);
println("translate(-50, 0, -100);");
printMatrix();

resetMatrix();
rotateY(radians(30));
println("rotateY(radians(30));");
printMatrix();

4am | Class Design and Implementation

4:00 | Preparation for implementation

Master "It's finally time to make a simulator from here" Padawan "Oh! Finally ... (laughs)"

Master "But before that, on the official Processing website" Master "Tell me the URL of the reference page"

Master "Because there are various methods I haven't taught yet." Master "Proceed with implementation while investigating"

Processing Official Site-Reference

Master "Then we will proceed with development," Master "First, open a new sketch with [File] [New]," Master "Save as Simurator```

Master "Next, in [▼] [New Tab], create a tab named DevUtils``` " Master "Paste the utility code"

Master "I did it a while ago, so I don't need a detailed explanation?" Padawan "Yeah. Easy victory!"

Then, a group of Gophers appeared there.

Padawan "That? If you think it's gone, before you know it ..." Padawan "And appeared in a flashy appearance (laughs)"

Sun Gopher Mercury Gopher Venus Gopher
gp_sun.png
gp_sun.png
gp_mercury.png
gp_mercury.png
gp_venus.png
gp_venus.png
Earth Gopher Moon Gopher Mars Gopher
gp_earth.png
gp_earth.png
gp_moon.png
gp_moon.png
gp_mars.png
gp_mars.png
Jupiter Gopher Saturn Gopher Uranus Gopher
gp_jupiter.png
gp_jupiter.png
gp_saturn.png
gp_saturn.png
gp_uranus.png
gp_uranus.png
Neptune Gopher Blue star Gopher Shiraboshi Gopher
gp_neptune.png
gp_neptune.png
gp_50_blue.png
gp_600_blue.png gp_50_blue.png
gp_50_white.png
gp_600_white.png gp_50_white.png
Gopher Gopher Orange star Gopher Akaboshi Gopher
gp_50_yellow.png
gp_600_yellow.png gp_50_yellow.png
gp_50_orange.png
gp_600_orange.png gp_50_orange.png
gp_50_red.png
gp_600_red.png gp_50_red.png

Master "Until detailed materials on the solar system are available" Master "Gopher will take the place of each celestial body."

Padawan "Ugh! Uranus Gopher-kun !!!!"

Padawan "What is Aoboshi or Akahoshi ???" Master "I had five types prepared for each surface temperature of the star."

Master "Because I changed Holocam to PNG" Master "Create a data folder in the sketch folder" Master "Copy this there"

Master "To save memory" Master "Five files from Blue Star to Akahoshi" Master "Copy the smaller one with a size of 50 x 50"

Master "The directory structure should look like this:"

Sketch folder structure


any-dir
    Simulator
    ├── Simulator.pde
    ├── DevUtils.pde
    └── data
        ├── gp_50_blue.png
        ├── gp_50_orange.png
        ├── gp_50_red.png
        ├── gp_50_white.png
        ├── gp_50_yellow.png
        ├── gp_earth.png
        ├── gp_jupiter.png
        ├── gp_mars.png
        ├── gp_mercury.png
        ├── gp_moon.png
        ├── gp_neptune.png
        ├── gp_saturn.png
        ├── gp_sun.png
        ├── gp_uranus.png
        └── gp_venus.png

Master "Then, the simulator" Master "Let's consider a rough design policy"

Master "The object to draw is" Master "The sun in the center," Master "Then planets and their satellites," Master "And the stars of the galaxy"

Padawan "Galaxy ???"

Master "Yes. In this request, the stars of the galaxy" Master "You can think of it as stationary in the world coordinate system"

Padawan "Oh, that's why there are blue Gophers!"

Master "Also, the sun is in the world coordinate system" Master "It would be easier to make it stationary at the origin (0, 0, 0)"

Master "The rest are planets and satellites that revolve around the mother star."

4:10 | Billboard class

Master "First of all, the basic billboard class," Master "Whenever you ever view a billboard" Master "What attributes did you specify?"

Padawan "The size of the signboard and the image to be pasted ..." Padawan "Oh! It's a place to display!"

Master "That's right." Master "Then the class definition would look like this:"

** Billboard class **

category item Description
class Billboard Implement basic billboard functions such as changing the attitude toward the camera.
field mImage Image to be pasted on the billboard.
field mWidth Billboard width.
field mHeight Billboard height.
field mX Billboard X coordinate.
field mY Billboard Y coordinate.
field mZ Billboard Z coordinate.
method update() Draw with coordinate conversion. Transform so that the inheritance destination is easy to override()And drawSelf()Separate.
method transform() Coordinate conversion.
method drawSelf() Draw yourself.

Master "OK, then let's implement it" Master "Create a tab named Billboard``` on [▼] [New Tab]" Master "Write there"

Padawan "Well, while copying from Learning.pde ..."

Padawan wrote the following saver:

Buillboard.pde


//Billboard class
public class Billboard {
  private PImage mImage;  //Image to paste on the billboard
  private int    mWidth;  //Billboard width
  private int    mHeight; //Billboard height
  private float  mX;      //Billboard X coordinate
  private float  mY;      //Billboard Y coordinate
  private float  mZ;      //Billboard Z coordinate

  //constructor
  // param imageName:File name of the image to be pasted
  // param w        :Billboard width
  // param x        :Billboard X coordinate
  // param y        :Billboard Y coordinate
  // param z        :Billboard Z coordinate
  public Billboard(String imageName, int w, float x, float y, float z) {
    this( loadImage(imageName), w, x, y, z);
  }
  
  //constructor
  // param image:Image to paste
  // param w    :Billboard width
  // param x    :Billboard X coordinate
  // param y    :Billboard Y coordinate
  // param z    :Billboard Z coordinate
  public Billboard(PImage image,  int w, float x, float y, float z) {
    mImage  = image;
    mWidth  = w;
    mHeight = w * mImage.height / mImage.width; //Height is calculated from the aspect ratio of the image
    mX      = x;
    mY      = y;
    mZ      = z;
  }

  //Coordinate conversion and drawing
  public void update() {
    pushMatrix();
      transform();
      turnToCamera();
      drawSelf();
    popMatrix();
  }

  //Coordinate transformation
  protected void transform() {
    translate(mX, mY, mZ);
  }

  //drawing
  protected void drawSelf() {
    float hw = mWidth  / 2;
    float hh = mHeight / 2;
    float iw = mImage.width;
    float ih = mImage.height;
    pushStyle();
      noStroke();
      beginShape();
        texture(mImage);
        vertex(-hw, -hh, 0,  0,  0);
        vertex( hw, -hh, 0, iw,  0);
        vertex( hw,  hh, 0, iw, ih);
        vertex(-hw,  hh, 0,  0, ih);
      endShape();
    popStyle();
  }
 
  //Change posture toward the camera
  protected void turnToCamera() {
    PMatrix3D m = (PMatrix3D)g.getMatrix();  
    m.m00 = m.m11 = m.m22 = 1;
    m.m01 = m.m02 = m.m10 = m.m12 = m.m20 = m.m21 = 0;
    resetMatrix();  
    applyMatrix(m);  
  }
}

Padawan "I have two constructors!" Padawan "The one who specifies the file name," Padawan "The one who specifies the image object"

Master "That's right. It's okay if you need it," Master "You can prepare those two first."

Padawan "And update () can be called by anyone" Padawan "Make it public" Padawan "Other than that, it can be used from subclasses" Padawan "I made it protected"

Master "Well, that's right"

Master "Actually, the class created by Processing is" Master "of a class generated inside Processing" Master "Because it is built as an inner class"

Master "Private members, etc." Master "I can see it from where I can see it." Master "Well, that's fine"

Master "Hmm? Did you use pushStyle () and popStyle ()?"

Padawan "Yeah. I saw it on the reference page earlier."

Processing Official Site --Reference --pushStyle

Padawan "Like the matrix" Padawan "If you push, the color and line thickness" Padawan "I thought I could get it, so I wrote it as a trial (laughs)"

Master "Yes, that's fine!" Master (After all, this child is an intuitive type)

Master "Then" Master "Let's draw using the Billboard class"

Master "Write it on the Simurator tab"

Padawan "Well ..." Padawan "Then, I'll use Blue Star and Akahoshi!"

Simulator.pde


Billboard gStarBlue;
Billboard gStarRed;

void setup() {
  gStarBlue = new Billboard("gp_50_blue.png ", 50, 400, -25, 400);
  gStarRed  = new Billboard("gp_50_red.png " , 30, 400, -15, 200);
  
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
  gStarBlue.update();
  gStarRed.update();
}

After writing the saver, Padawan clicked the Run button. test_billboard.gif

Master "How is it?"

Padawan "Yeah. It is displayed perfectly at the specified position." Padawan "It's too easy to win and I'm crying !!! (laughs)"

4:20 | Galaxy class

Master "OK, then use the Billboard class" Master "I will draw the stars of the galaxy"

Master "Because I need to draw at least 1000 ..." Padawan "Hey! 1000 ?!" Master "Oh, that's right"

Master "So let's use random numbers to specify the position" Master "The method ``` random () `` Master "It will return a random number, so let's explain a little."

Master "Given these things," Master "Galaxy class will look like this"

** Galaxy class **

category item Description
class Galaxy Galactic class. Display about 1000 galaxy stars. Each star is implemented in the Billboard class. Images and coordinates to be pasted on the billboard are determined by random numbers.
field mStars An array of Billboards.
method update Draw all the stars.

The specifications for drawing the stars are as follows.

Master "Then create a Galaxy in a new tab," Master "Implement it there"

Padawan "Well, 2π is 180 ° ..." Padawan "Aha! You may have remembered it (laughs)"

Galaxy.pde


//Stars that make up the galaxy
public class Galaxy {
  private Billboard[] mStars = new Billboard[1000]; //Billboard as many as the number of stars

  //constructor
  public Galaxy() {
    //Image array initialization
    PImage[] images = new PImage[] {
      loadImage("gp_50_blue.png "),
      loadImage("gp_50_white.png "),
      loadImage("gp_50_yellow.png "),
      loadImage("gp_50_orange.png "),
      loadImage("gp_50_red.png "),
    };

    //Loop by the number of stars
    for (int i = 0; i < mStars.length; i++) {
      float angle  = random(TWO_PI);      //The angle on the ZX plane is 0 to 360 °(2π)Randomly in the range of
      float radius = random(4000, 5000);  //The distance from the origin on the ZX plane is randomly in the range of 4000-5000
      float x      = sin(angle) * radius; //X coordinate of the star
      float z      = cos(angle) * radius; //Z coordinate of the star
      float y      = random(-3000, 3000); //The Y coordinate of the star is-Randomly in the range of 3000-3000

      int n = (int)random(5);             //Images to be pasted on the billboard are randomly selected from 5 types
      mStars[i]    = new Billboard(images[n], 50, x, y, z); //Generate a billboard and store it in an array
    }
  }
  
  //Draw all stars with coordinate transformation
  public void update() {
    for (Billboard star: mStars) {
      star.update();
    }
  }
}

Padawan "Well ..." Padawan "If you want to put 5 images in an array and select them randomly" Padawan "I have downcast to an int type, but ..."

Padawan (If it's a positive number, it's scary to truncate!) (Footnote: see Episode I)

Padawan "But is this okay?" Master "Then I'll actually move it and check it."

Padawan "Well, open the Simulator tab ..."

Padawan "Because this is just creating an object and calling it." Padawan "Easy victory! Easy victory! (Laughs)"

Simulator.pde


//Billboard gStarBlue;     // ---
//Billboard gStarRed;      // ---
Galaxy gGalaxy;            // +++

void setup() {
//gStarBlue = new Billboard("gp_50_blue.png " , 50, 400, -25, 400); // ---
//gStarRed  = new Billboard("gp_50_red.png "  , 30, 400, -15, 200); // ---  
  gGalaxy = new Galaxy();                                          // +++
  
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
//gStarBlue.update(); // ---
//gStarRed.update();  // ---
  gGalaxy.update();   // +++
}

Padawan "`` // --- ``was deleted," Padawan "`` // +++ ``was added!"

Padawan "Gege! Gopher, the colors are noisy (laughs)" image.png

Padawan "Oh, but all the colors are displayed." Padawan "I'm glad I was downcast!"

4:30 | CelestialObject class

Master "Then, what's next?" Master "Karugamo Billboard"

Padawan "Eh? Spot-billed ducks ???"

Master "Yes. Like a parent and child of a spot-billed duck." Master "It's a billboard that can draw children"

Padawan (Nice, spot-billed ducks ...) Padawan (I'm jealous because I don't have a dad or mom)

Master "When I made Learning.pde a while ago" Master "Do you remember reflecting the local coordinates of the earth on the moon?"

Padawan "Oh, the moon is thinking about only my place" Padawan "Isn't it the one who follows the earth without permission?"

Master "Yes. The sun that draws the planets," Master "Behavior common to planets that can lead satellites" Master "Implement it on the billboard"

Padawan "Do you want to add to the billboard?" Padawan "But the stars of the galaxy don't have children!"

Master "That's right" Master "Well, you can implement it directly in the Billboard class," Master "You can create a new class that inherits Billboard."

Padawan "Well, make a new one!"

Master "Then name it CelestialObject" Master "Let's implement the following functions"

** CelestialObject class **

category item Description
class CelestialObject Revolutionary parent class. You can have multiple children (bilboards) that are affected by your local coordinate system.
extends Billboard
field mChildren List of children.
method addChild() Add a child.
method update() override. Once you've done your own coordinate transformation and drawing, update all the children()To call.

Master "Create a CelestialObject in a new tab," Master "Try to implement it there"

Padawan "Well, reference, reference ..." Padawan "Oh! You can use ArrayList!"

Processing Official Site --Reference --ArrayList

Padawan "Rururu ~ ♪" Padawan "List and medicine are generic ~ ♪" Padawan "Speaker is Genelec ~ ♪" Padawan "That ..."

CelestialObject.pde


//Celestial class (draw together if there is a child)
public class CelestialObject extends Billboard {
  private ArrayList<Billboard> mChildren = null; //Children list

  //constructor
  //param imageName image file name
  //param w celestial body(Billboard)Width of
  //param x celestial body(Billboard)X coordinate
  //param y celestial body(Billboard)Y coordinate of
  //param z celestial body(Billboard)Z coordinate
  public CelestialObject(String imageName, int w, float x, float y, float z) {
    super(imageName, w, x, y, z);
  }

  //Add a child
  public void addChild(Billboard child) {
    if (mChildren == null) {
      mChildren = new ArrayList<Billboard>();
    }
    mChildren.add(child);
  }
  
  public void update() {
    pushMatrix();
      transform();
      turnToCamera();
      drawSelf();     //Draw yourself
      updateChildren(); //Draw all kids
    popMatrix();
  }

  private void updateChildren() {
    if (mChildren != null) {
      for (Billboard child : mChildren) {
        child.update();
      }
    }
  }  
}

Padawan "Well," Padawan "Don't make ArrayList in constructor," Padawan "Only when adding the first child with addChild ()" Padawan "I tried to make it"

Padawan "And override update ()," Padawan "Children before calling popMatrix ()" Padawan "Updated"

Padawan "And the kids cut it into updateChildren ()," Padawan "I made it private because I wouldn't use it elsewhere!"

Padawan "Ah, but before calling updateChildren ()" Padawan "turnToCamera () and drawSelf ()" Padawan "With pushMatrix () and popMatrix ()" Padawan "Is it better to tie it up?"

Master "Then" Master "Let's actually move it and check it"

Master "Add to Simulator.pde" Master "Make the sun and its child and test it."

Master "If only the sun is updated ()" Master "It's important that other planets are also drawn."

Padawan "Yeah. Then ..." Padawan "Let's solidify the front, back, left and right of the sun with the strongest lineup (laughs)"

Simulator.pde


Galaxy gGalaxy;
CelestialObject gSun; // +++

void setup() {
  gGalaxy = new Galaxy();
  gSun    = new CelestialObject("gp_sun.png ", 300, 0, 0, 0); // +++

  CelestialObject earth   = new CelestialObject("gp_earth.png ",   100, -200, 0,    0); // +++
  CelestialObject jupiter = new CelestialObject("gp_jupiter.png ", 100,  200, 0,    0); // +++
  CelestialObject saturn  = new CelestialObject("gp_saturn.png ",  100,    0, 0, -200); // +++
  CelestialObject uranus  = new CelestialObject("gp_uranus.png ",  100,    0, 0,  200); // +++
  
  gSun.addChild(earth);   // +++
  gSun.addChild(jupiter); // +++
  gSun.addChild(saturn);  // +++
  gSun.addChild(uranus);  // +++

  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(2);
}

void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
  gGalaxy.update();
  gSun.update();    // +++
}

Padawan "That ???" Padawan "Something strange ..."

Padawan "Are you stopped?" celestial_object.gif Padawan "Oh! That's stopping ..." Padawan "I'm working with the camera !!!"

Padawan "I can see the male figure of Uranus in front of the sun all the time (laughs)"

Padawan "Oh ..." Padawan "turnToCamera () ..."

Padawan rewrote CelestialObject.pde as follows:

CelestialObject.pde


...
  public void update() {
    pushMatrix();
      transform();
      pushMatrix();                             // +++
        turnToCamera();
        drawSelf();     //Draw yourself
      popMatrix();                              // +++
      updateChildren(); //Draw all kids
    popMatrix();
  }
...
celestial_object2.gif

Master "That's right. TurnToCamera () is." Master "Reset the rotating components of the local and world coordinate systems" Master "Because it matches the camera coordinate system"

Master "Thinking about the world coordinate system" Master "An object that should be stationary there" Master "It moves with the camera"

4:40 | OrbitalObject class

Master "OK, then" Master "The rest is to create a class that behaves like a planet and hygiene."

Master "What attributes do you need for a revolution?"

Padawan "Well, radius ..." Padawan "Oh! It's fast to turn !!!!"

Master "That's right. The specs will look like this:"

** OrbitalObject class **

category item Description
class OrbitalObject Revolution class. Make a circular motion around the parent celestial body. Draw the orbit of the celestial body.
extends CelestialObject
field mRadius Revolution radius
field mPeriod Revolution cycle
mehtod transform() override. Coordinates are converted according to the revolution radius and revolution period.

Padawan "Yeah! If you can do this, it's almost done!"

Master "That's right ..." Master "I don't have the data I need to simulate yet."

Master "So, from now on I'm at the Republic Knights Library in Temple" Master "Collecting information on the solar system"

Master "In the meantime, you should proceed with the implementation with Gopher" Master "And if possible, to display the orbit of the celestial body" Master "Try it alone"

Padawan "Yeah! Easy victory (laughs)"

Master "Then I'm going to the library!" Master "Send the collected information at any time"

Padawan (Why does the master always leave me alone ...) Padawan (I wonder if I hate me ...)

Padawan (But I'm not lonely because Gopher is with me today) Padawan (Well, Ikka)

Padawan "Well, ..." Padawan "It's okay to turn it because I did it earlier," Padawan "How can I draw a round orbit?"

Padawan "Oh! There is a method called circle ()!"

Processing Official Site --Reference --circle

Padawan "But you can only specify x and y ..." Padawan "What happens if I draw in P3D?"

Padawan added the following to Simulator.pde and executed it.

Simulator.pde


...
void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
  gGalaxy.update();
  gSun.update();
  
  fill(192, 192, 255);        // +++
  circle(0, 0, 500);          // +++
}

Padawan "Oh! I was able to draw (laughs)" image.png

Padawan "Then, I should defeat this Maru ..." Padawan "Well, my thumb is X and my index finger is Y ..."

Padawan "Oh! Just turn it with your thumb!"

Simulator.pde


...
void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
  gGalaxy.update();
  gSun.update();
  
  rotateX(HALF_PI);           // +++
  fill(192, 192, 255);
  circle(0, 0, 500);
}
image.png

Padawan "Ah! It's too easy to cry (laughs)" Padawan "Then all you have to do is make a class!"

Padawan "Well," Padawan "Create an OrbitalObject in a new tab, ..."

OrbitalObject.pde


//A celestial body that revolves in a circular orbit
public class OrbitalObject extends CelestialObject {
  private float mRadius; //Revolution radius
  private int   mPeriod; //Revolution cycle(millisecond)

  //constructor
  //param parent Revolving mother star
  //param imageName Image file name
  //param w Revolution(Billboard)Width of
  //param radius Revolution radius
  //param period Revolution period(Seconds)
  public OrbitalObject(CelestialObject parent, String imageName, int w, float radius, int period) {
    super(imageName, w, 0, 0, 0);
    mRadius = radius;
    mPeriod = period * 1000;
    parent.addChild(this); //Add yourself to your home planet
  }

  //Coordinate conversion and drawing
  public void update() {
    updateOrbit();
    super.update();
  }

  //Coordinate transformation
  protected void transform() {
    int   ms = millis();
    float rd = TWO_PI * ms / mPeriod;
    rotateY(rd);
    translate(mRadius, 0, 0);
  }
  
  //Draw orbit
  protected void updateOrbit() {
    pushMatrix();
      rotateX(HALF_PI);
      pushStyle();
        noFill();
        stroke(48, 48, 48);
        strokeWeight(1);
        circle(0, 0, mRadius * 2);
      popStyle();
    popMatrix();
  }

}

Padawan "Well,"

4:50 | SolarSystem class

Padawan "Then, it would be better to have a class for the Taiyo family ..." Padawan "Is it like this?"

** SolarSystem class **

category item Description
class SolarSystem Solar system class. Display the stars of the solar system. The sun is implemented by CelestialObject, and planets and satellites are implemented by OrbitalObject class.
method update Draw all the stars.

Padawan "Well," Padawan "Create a SolarSystem in a new tab,"

Padawan "I don't know the size of the stars and how they turn" Padawan "Parameters are appropriate for the time being ..."

SolarSystem.pde


//Solar system class
public class SolarSystem {
  private CelestialObject mSun; //Sun

  //constructor
  public SolarSystem() {
    mSun = new CelestialObject("gp_sun.png ", 200, 0, 0, 0);

    OrbitalObject earth =
      new OrbitalObject(mSun, "gp_earth.png ", 50, 333, 16); //Earth
      new OrbitalObject(earth,"gp_moon.png ",  25,  77,  7); //Month

    new OrbitalObject(mSun, "gp_mercury.png ", 30, 111,  8); //Mercury
    new OrbitalObject(mSun, "gp_venus.png ",   40, 222, 12); //Venus
    new OrbitalObject(mSun, "gp_mars.png ",    40, 444, 20); //Mars
    new OrbitalObject(mSun, "gp_jupiter.png ",170, 555, 24); //Jupiter
    new OrbitalObject(mSun, "gp_saturn.png ", 160, 666, 28); //Saturn
    new OrbitalObject(mSun, "gp_uranus.png ",  80, 777, 32); //Uranus
    new OrbitalObject(mSun, "gp_neptune.png ", 70, 888, 36); //Neptune
  }

  //Draw all stars with coordinate transformation
  public void update() {
    mSun.update();
  }
}

Padawan "Oh, is this all right ..." Padawan "I don't need variables from the moon down (laughs)"

Padawan "The rest is rewriting the Simulator tab ..."

Simulator.pde


Galaxy gGalaxy;
//CelestialObject gSun;     // ---
SolarSystem gSolarSystem;   // +++


void setup() {
  gGalaxy = new Galaxy();
  gSolarSystem = new SolarSystem();                          // +++
//gSun    = new CelestialObject("gp_sun.png ", 300, 0, 0, 0); // ---

//CelestialObject earth   = new CelestialObject("gp_earth.png ",   100, -200, 0,    0); // ---
//CelestialObject jupiter = new CelestialObject("gp_jupiter.png ", 100,  200, 0,    0); // ---
//CelestialObject saturn  = new CelestialObject("gp_saturn.png ",  100,    0, 0, -200); // ---
//CelestialObject uranus  = new CelestialObject("gp_uranus.png ",  100,    0, 0,  200); // ---

//gSun.addChild(earth);   // ---
//gSun.addChild(jupiter); // ---
//gSun.addChild(saturn);  // ---
//gSun.addChild(uranus);  // ---
  
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
  background(255, 255, 255);
  updateDevRoom();
  
  gGalaxy.update();
  gSolarSystem.update(); // +++
//gSun.update();         // ---
//rotateX(HALF_PI);      // ---
//fill(192, 192, 255);   // ---
//circle(0, 0, 500);     // ---
}

Padawan "Ah! It's too easy, goosebumps (laughs)"

orbital_object.gif

5 am | Implementation

5:00 | Organize information on planetary systems

Padawan "Oh! Data has arrived from the master!"

After looking at the information for a while, Padawan arranged 18 stars in order from the largest of the celestial bodies belonging to the solar system.

Celestial body Mother star Average diameter Average revolution radius Revolution cycle
Sun 1,392,000 km
Jupiter Sun 139,822 km 778,412,010 km 4,332.43 days
Saturn Sun 116,464 km 1,426,725,400 km 10,786.62 days
Uranus Sun 50,724 km 2,870,990,000 km 30,773.41 days
Neptune Sun 49,244 km 4,495,060,000 km 60,189.55 days
Earth Sun 12,742 km 149,597,871 km 365.25th
Venus Sun 12,104 km 108,208,930 km 224.70 days
Mars Sun 6,780 km 227,920,000 km 686.98 days
Ganymede Jupiter 5,262 km 1,070,400 km 7.16th
Titan Saturn 5,152 km 1,221,865 km 15.95 days
Mercury Sun 4,879 km 57,910,000 km 87.97 days
Callisto Jupiter 4,821 km 1,882,700 km 16.69 days
Io Jupiter 3,643 km 421,700 km 1.77 days
Month Earth 3,474 km 384,400 km 27.33 days
Europa Jupiter 3,122 km 671,100 km 3.55 days
Triton Neptune 2,707km 354,759km (Retrograde) 5.88 days
Pluto Sun 2,370 km 5,900,898,441 km 90,487.28th day
Ellis Sun 2,326 km 10,139,893,274 km 203,824.11th

Padawan "Gee! The number is so big that it doesn't come out at all ..."

Therefore, Padawan calculated the conversion value when the diameter of the earth is 50 px and the orbital period is 60 seconds, and tried to sort out the relationship between each celestial body and the mother star.

Star Planets, etc. satellite diameter Revolution radius Revolution cycle
Sun 5,462.25 px
Mercury 19.15 px 227,240.62 px 14.45 s
Venus 47.49 px 424,615.17 px 36.91 s
Earth 50.00 px 587,026.65 px 60.00 s
Month 13.63 px 1,508.40 px 4.49 s
Mars 26.60 px 894,365.09 px 112.85 s
Jupiter 548.67 px 3,054,512.67 px 711.69 s
Io 14.30 px 1,654.76 px 0.29 s
Europa 12.25 px 2,633.42 px 0.58 s
Ganymede 20.65 px 4,200.28 px 1.18 s
Callisto 18.92 px 7,387.77 px 2.74 s
Saturn 457.01 px 5,598,514.36 px 1,771.93 s
Titan 20.22 px 4,794.64 px 2.62 s
Uranus 199.04 px 11,265,853.08 px 5,055.18 s
Neptune 193.23 px 17,638,753.73 px 9,887.40 s
Triton 10.62 px 1,392.09 px (Retrograde) 0.97 s
Pluto 9.30 px 23,155,307.02 px 14,864.44 s
Ellis 9.13 px 39,789,253.15 px 33,482.40 s

Padawan "This is still too big ..."

Padawan "But as the master said" Padawan "Is the moon about four stars as big as the earth ..." Padawan "It's bigger than mom" Padawan (I also want to be big ...) Padawan (I want a mom ...)

Padawan "The rest ..." Padawan "Io is a very fast star."

Padawan "Is Triton a star in the opposite direction?" Padawan "Kake!"

5:10 | Fix bugs

When Padawan was worried about what to do with the parameters of the celestial body, an old gentleman appeared there.

Supreme Chair "Hi! Padawan!" Supreme Chancellor "I've heard your rumors from the Grand Master." Supreme Chair "How is it? Is it going well?"

Padawan "Ah? Who is your uncle ???"

Supreme Chancellor "Oh! I'm sorry I was late ..." Supreme Chancellor "I'm just an old man who is the Supreme Chancellor of the Senate (laughs)."

Padawan "Gee! Supreme Chair ???" Padawan "Isn't that a bigger person than the Grand Master ?!"

Padawan "Hmm? Uncle, isn't it a meeting of great people right now?" Supreme Chancellor "The Parliament just closed safely."

Padawan "I see ..." Padawan "Will the war begin?"

Supreme Chancellor "If possible, there should be no war" Supreme Chancellor "But sometimes" Supreme Chancellor "Sometimes we have to protect something more important than life." Supreme Chancellor "War is needed in such an era."

Padawan "Hmm ..." Padawan "I don't really understand (laughs)"

Supreme Chair "By the way, how is the progress of the simulator?" Padawan "I can afford it! I wonder if I can replace the image ..."

Supreme Chancellor "Oh! Great!" Supreme Chair "Then Padawan's homemade saver" Supreme Chair "Can you show me?"

Padawan "Cheap!" Padawan "But can't you sword uncle ???"

The Supreme Chancellor slowly opened his mouth after looking at the Saver for a while.

Supreme Chair "I see, I can write well, but ..." Supreme Chancellor "It seems better to fix about two"

Padawan "Huh? Did you find a bug? Uncle awesome!"

Supreme Chancellor "One is the coordinates of each planet or satellite at the start." Supreme Chair "Because everyone starts from an angle of 0" Supreme Chair "It starts from the state of planetary series" Supreme Chancellor "Because it's a little unnatural" Supreme Chair "It would be better to scatter the starting points with random numbers."

Padawan "I see ..."

Supreme Chancellor "Another problem is" Supreme Chair "It is a formula to determine the coordinates of the revolution body"

OrbitalObject.pde


...
float rd = TWO_PI * ms / mPeriod;
...

Padawan "Eh ???" Padawan "What's wrong with this?"

Padawan "Well ..." Padawan "mPeriod takes one lap (milliseconds)" Padawan "Because ms is the time passed (milliseconds)"

Padawan "For example, where it takes 100 to go around" Padawan "If it takes 50, it's just half a lap (0.5), so" Padawan "Half of the 360 ° (TWO_PI) around is 180 ° (PI), and it fits."

Padawan "A place that takes 100 laps" Padawan "If it takes 150, it will take one and a half laps (1.5), so" Padawan "One round 360 ° (TWO_PI) plus half, 540 ° ,,"

Padawan "It's right !!!"

Padawan "The master said that it's okay to exceed 360 ° ..." Padawan "Eh ?! It should be perfect ..."

Supreme Chair "Padawan-kun" Supreme Chair "The idea is not wrong with that." Supreme Chancellor "The problem is using floating point numbers."

Padawan "Eh ???" Padawan "But Processing uses float normally" Padawan "It's a big number than int!"

Supreme Chancellor "Sure, float has a wider range of handling," Supreme Chair "The accuracy will be sacrificed by that amount."

Supreme Chair "360 or 720, while the number is small" Supreme Chair "(As long as there are few significant figures) that's fine." Supreme Chair "But the mantissa can handle about 7 significant digits." Supreme Chair "I can't express more strictly than that."

Supreme Chair "In the formula to find the angle," Supreme Chair "In the end, the remainder when divided by 360 ° (or 2π)," Supreme Chair "In other words, accuracy is important."

Supreme Chancellor "And floating point numbers ..." Supreme Chair "Similar to the nation ..."

Supreme Chair "It's okay if the population is small ..." Supreme Chair "But if the population grows to some extent," Supreme Chancellor "A few sacrifices are unavoidable !!!"

Supreme Chair "Do you understand? Padawan ..."

Supreme Chair "Wow, ka, ru, ka, right ?!" Supreme Chair "Pa da Wa N Kim !!!!"

Padawan "Uncle ..." Padawan "A little scary ..."

Supreme Chair "Oh, I'm sorry, I'm sorry ..." Supreme Chancellor "The Parliament has just finished" Supreme Chair "It seems that the excitement has not cooled yet (laughs)"

Supreme Chancellor "Add the following to OrbitalObject.pde:"

OrbitalObject.pde


...
  protected void transform() {
  //int   ms = millis();               // ---Comment out
    int   ms = millis() + 1000000000;  // +++Postscript
    float rd = TWO_PI * ms / mPeriod;
    rotateY(rd);
    translate(mRadius, 0, 0);
  }
...

Supreme Chancellor "This is a billion milliseconds after launching Saver." Supreme Chancellor "That is, the state after about 11 and a half days" Supreme Chair "It is intentionally created"

Padawan clicked the run button.

Padawan "Gegege !!!!" Padawan "The movement is jerky !!!"

Supreme Chancellor "Open a new sketch and type:"

NewSketch


int period = 3600;      //Cycle is 3600 ms (advance 1 ° every 10 ms)
int[] startingTimes = { //An array that stores the starting millisecond value
           0, //Situation a.1st lap
    36000000, //Situation b.  10,001th lap
  1000000800, //Situation c. 277,779th lap
};
println("a.\tb.\tc.");
println("---\t---\t---");
//How the angle increases in 10 millisecond increments in three types of time passage
for (int n = 0; n < 300; n += 10) {
  for (int start: startingTimes) {
    int ms = start + n;
    int rd = round(degrees(TWO_PI * ms / period)) % 360;
    print(rd + "°\t");
  }
  println();
}

Supreme Chancellor "This is the current logic" Supreme Chair "When calculating the revolution body with a cycle of 3600 milliseconds,"

Supreme Chair "Situation a. → Immediately after the start of the saver (that is, the first lap)," Supreme Chancellor "Situation b. → Just lap 10,001," Supreme Chancellor "Situation c. → Just 277,779 laps"

Supreme Chancellor "When chopped 10 milliseconds in three different situations" Supreme Chancellor "It shows how the angle increases."

Padawan "Because it makes one lap in 3600 milliseconds" Padawan "It should increase by 1 ° every 10 milliseconds!"

Supreme Chancellor "Let's see the results"

Padawan "Wow, situation c. !!!"

console


a.   b.   c.
---  ---  ---
0°   0°   352°
1°   1°   0°
2°   2°   0°
3°   3°   0°
4°   4°   0°
5°   5°   0°
6°   6°   0°
7°   7°   8°
8°   8°   8°
9°   9°   8°
10°  10°  8°
11°  11°  8°
12°  12°  8°
13°  13°  8°
14°  14°  8°
15°  15°  8°
16°  16°  8°
17°  17°  8°
18°  18°  8°
19°  19°  8°
20°  20°  16°
21°  21°  16°
22°  22°  16°
23°  23°  16°
24°  24°  16°
25°  25°  16°
26°  26°  32°
27°  27°  32°
28°  28°  32°
29°  29°  32°

Padawan "The numbers are jumping!" Padawan "Gege! What's up ???"

Supreme Chancellor "Variable ms for ms / PERIOD" Supreme Chancellor "Do you know that quote `` and remainder `` are included? "

Padawan "Well, for example, when you go around 3 and a half Padawan "In the time it took the answer to divide 3 laps `" Padawan "The remainder of the division is the time it took to ``` half `..."

Supreme Chair "That's right" Supreme Chancellor "ms contains ``` 3 and a half `` `minutes of time"

Supreme Chair "But what is important when calculating the angle is" Supreme Chancellor "Not the time of " 3 laps `` minutes " Supreme Chair "It's the remaining half lap `minutes of time."

Supreme Chair "So, this `` half lap remainder Supreme Chair "Before precision is sacrificed in floating point arithmetic" Supreme Chair "It would be better to find it as an integer type that maintains accuracy."

Padawan "Oh! That's right!"

Padawan rewrote the saver as follows:

NewSketch


...
  //int rd = round(degrees(TWO_PI * ms / period)) % 360;      //Before correction
    int rd = round(degrees(TWO_PI * (ms % period) / period)); //Revised
...

Padawan "Oh! Perfect !!!"

console


a.   b.   c.
---  ---  ---
0°   0°   0°
1°   1°   1°
2°   2°   2°
3°   3°   3°
4°   4°   4°
5°   5°   5°
6°   6°   6°
7°   7°   7°
8°   8°   8°
9°   9°   9°
10°  10°  10°
11°  11°  11°
12°  12°  12°
13°  13°  13°
14°  14°  14°
15°  15°  15°
16°  16°  16°
17°  17°  17°
18°  18°  18°
19°  19°  19°
20°  20°  20°
21°  21°  21°
22°  22°  22°
23°  23°  23°
24°  24°  24°
25°  25°  25°
26°  26°  26°
27°  27°  27°
28°  28°  28°
29°  29°  29°

Supreme Chair "Because the return value of millis () is int type" Supreme Chancellor "2,147,483,648 milliseconds after the start of the saver" Supreme Chancellor "That is, after about 25 days" Supreme Chancellor "We can expect an overflow," Supreme Chair "You don't have to think so much this time!"

Padawan "Wow! Uncle-friendly !!!"

Padawan "Then fix the OrbitalObject," Padawan "To make it separate from the beginning" Padawan "I'll try not to get confused!"

OrbitalObject.pde


...
public class OrbitalObject extends CelestialObject {
  private float mRadius; //Revolution radius
  private int   mPeriod; //Revolution cycle(millisecond)
  private float mStart;                                    // +++Postscript
  ...
  public OrbitalObject(CelestialObject parent, String imageName, int w, float radius, int period) {
    ...
    mPeriod = period * 1000;
    mStart = random(TWO_PI);                                // +++Postscript
    parent.addChild(this); //Add yourself to your home planet
  }
  ...
  protected void transform() {
  //int   ms = millis();                                    //Return later
    int   ms = millis() + 1000000000;                       //Erase later
  //float rd = TWO_PI * ms / mPeriod;                       // ---Delete
    float rd = mStart + TWO_PI * (ms % mPeriod) / mPeriod;  // +++Postscript
    ...
  }
  ...
}

Padawan "It fell apart from the beginning" Padawan "I'm no longer crazy!"

Padawan finally finished the OrbitalObject sword fight by organizing the transform () method as follows:

OrbitalObject.pde


...
  //Coordinate transformation
  protected void transform() {
    int   ms = millis();
    float rd = mStart + TWO_PI * (ms % mPeriod) / mPeriod;
    rotateY(rd);
    translate(mRadius, 0, 0);
  }
...

Padawan "Uncle is amazing!" Padawan "Thank you!"

5:20 | Process the image

Padawan "Oh! Master sent me something!"

To Padawan Send images of celestial bodies in the solar system I'm going to talk to the Grand Master, so do the following by yourself -Galaxy stars use Gimp to create their own particles ・ The celestial bodies of the solar system are processed with Gimp after confirming the license of the image. ・ Import the completed image to the saver

Supreme Chancellor "I'm looking behind you, so don't worry, keep working."

Make particles with Gimp

Padawan launched Gimp to create particle images.

Gimp Official Website-Download Page

Padawan "Well, first make an image with a black background," Padawan "Let's try it with the light effect!"

Padawan "Choose Light Effect ,," particle_1.png

Padawan "Adjust the size with`` distance ``,," particle_2.png

Padawan "If you select the color , adjust the position , and press [OK] ,," particle_3.png

Padawan "It's done! particle_4.png

Padawan "Hmm? But this ..." Padawan "How about making the back transparent ???"

Supreme Chancellor "In that case," Supreme Chair "It would be better to process the color with transparency ...` ``

Supreme Chancellor "Choose from the menu ..." particle_5.png

Supreme Chancellor "However, if the image does not have an alpha channel" Supreme Chair "First, the menu item two above" Supreme Chair "You need to select Add Alpha Channel` ``

Supreme Chancellor "Then choose a transparent color (black this time) ..." particle_6.png

Supreme Chair "How about something like this?" particle_7.png

Padawan "Oh !!!" Padawan "Uncle is amazing !!!"

Padawan "Then, the remaining four colors" Padawan "Make it the same way ..."

Padawan "Because the galaxy is full of stars" Padawan "Small image size before saving" Padawan "Don't forget!

Watch out for licenses

Padawan "Well, next is a license ..."

Padawan "Eh ???" Padawan "Can't I use images without permission ???"

** Classification of licenses such as images **

symbol Claim Description
PDM public domain Public Domain Mark
A mark that clearly indicates that the original author has waived the right or the protection period has expired.
However, note the following points even in works that are in the public domain.
Moral rights of authorBecause of the existence of, it is prohibited to modify the work that defame the author's personality.
TrademarkAnything that exists can infringe on it.
・ For photos of people, etc.Portrait rightInfringementRight of publicityThere is a risk of infringement.
CC0 public domain A mark that declares that it does not hold any rights.
Difference from PDM
CC Some rights reserved Those that claim limited rights.
Creative Commons License
All rights reserved A copyright claim.

Padawan "I thought the public domain was easy to use, but ..." Padawan "I have to be careful ..."

Padawan "So, if you take a closer look at CC," Padawan "There are four types of conditions ..."

** CC license type **

Mark Meaning
BY Displaying work credits
SA Publishing under the same CC license as the original work
ND Do not modify the original work
NC Do not use for commercial purposes

Padawan "And there are 6 types of licenses that combine this ..." Padawan "Ugh! It's complicated !!!"

Padawan "Ah, but are these two types related this time?"

** CC license combination **

Mark Meaning
CC BY License that allows modification and secondary use for commercial purposes, provided that the credits of the original author are displayed. ..
CC BY-SA The original author's credit is displayed, and if modified, it must be published on CC BY-SA. In addition, a license that allows secondary use for commercial purposes.
Others CC BY-ND, CC BY-NC /4.0/deed.ja), CC BY-NC-SA, CC BY-NC-ND (: //creativecommons.org/licenses/by-nc-nd/4.0/deed.ja) and so on.

Padawan "And the license of the image sent by the master is ..."

** Image list before processing **

Celestial body image license Source
Sun Created by NASA
(public domain)
Wikimedia
Commons
Mercury Created by NASA
(public domain)
Wikimedia
Commons
Venus Created by NASA
(public domain)
Wikimedia
Commons
Earth Created by NASA
(public domain)
Wikimedia
Commons
Month Luc Viatour
(CC BY-SA 3.0)
Wikimedia
Commons
Mars ESA & MPS for OSIRIS Team
MPS/UPD/LAM/IAA/RSSD/
INTA/UPM/DASP/IDA
(CC BY-SA IGO 3.0)
Wikimedia
Commons
Jupiter Created by NASA
(public domain)
Wikimedia
Commons
Io Created by NASA
(public domain)
Wikimedia
Commons
Europa Created by NASA
(public domain)
Wikimedia
Commons
Ganymede Created by NASA
(public domain)
Wikimedia
Commons
Callisto Created by NASA
(public domain)
Wikimedia
Commons
Saturn Created by NASA
(public domain)
Wikimedia
Commons
Titan Created by NASA
(public domain)
Wikimedia
Commons
Uranus Created by NASA
(public domain)
Wikimedia
Commons
Neptune WolfmanSF
(CC BY 2.0)
Wikimedia
Commons
Triton Created by NASA
(public domain)
Wikimedia
Commons
Pluto Created by NASA
(public domain)
Wikimedia
Commons
Ellis Created by NASA
(public domain)
Wikimedia
Commons

Padawan "I see, I have to be careful!"

Make the background transparent with Gimp

Padawan "Then, I'll make the background of the stars transparent."

Padawan "Once you open the image, add an alpha channel ..." tp_1.png

Padawan "Choose the " ellipse selection` `` tool," Padawan "If you specify the range by dragging and dropping," tp_2.png

Padawan "Invert the selection, ..." tp_3.png

Padawan "Erase" Padawan "And this disappears with the DELETE key! tp_4.png

Padawan "After that, export with a name," Padawan "It's okay if you save the extension as .png! tp_6.png

Supreme Chancellor "Oh! I forgot to say one ..." Supreme Chancellor "As with the image of the particles earlier," Supreme Chancellor "When I try to open an image created in Gimp in Processing" Supreme Chancellor "In that case, it may cause an error." Supreme Chair "With Export Options" Supreme Chair "You should adjust the area around the red frame." tp_7.png

Padawan finally created the following image.

** Image list after processing **

Celestial body Processed image Original image
License
original
Image source
Sun Sun.png
Sun.png
Created by NASA
(public domain)
Wikimedia
Commons
Mercury Mercury.png
Mercury.png
Created by NASA
(public domain)
Wikimedia
Commons
Venus Venus.png
Venus.png
Created by NASA
(public domain)
Wikimedia
Commons
Earth Earth.png
Earth.png
Created by NASA
(public domain)
Wikimedia
Commons
Month Moon.png
Moon.png
Luc Viatour
(CC BY-SA 3.0)
Wikimedia
Commons
Mars Mars.png
Mars.png
ESA & MPS for OSIRIS Team
MPS/UPD/LAM/IAA/RSSD/
INTA/UPM/DASP/IDA
(CC BY-SA IGO 3.0)
Wikimedia
Commons
Jupiter Jupiter.png
Jupiter.png
Created by NASA
(public domain)
Wikimedia
Commons
Io Io.png
Io.png
Created by NASA
(public domain)
Wikimedia
Commons
Europa Europa.png
Europa.png
Created by NASA
(public domain)
Wikimedia
Commons
Ganymede Ganymede.png
Ganymede.png
Created by NASA
(public domain)
Wikimedia
Commons
Callisto Callisto.png
Callisto.png
Created by NASA
(public domain)
Wikimedia
Commons
Saturn Saturn.png
Saturn.png
Created by NASA
(public domain)
Wikimedia
Commons
Titan Titan.png
Titan.png
Created by NASA
(public domain)
Wikimedia
Commons
Uranus Uranus.png
Uranus.png
Created by NASA
(public domain)
Wikimedia
Commons
Neptune Neptune.png
Neptune.png
WolfmanSF
(CC BY 2.0)
Wikimedia
Commons
Triton Triton.png
Triton.png
Created by NASA
(public domain)
Wikimedia
Commons
Pluto Pluto.png
Pluto.png
Created by NASA
(public domain)
Wikimedia
Commons
Ellis Eris.png
Eris.png
Created by NASA
(public domain)
Wikimedia
Commons
White dwarf WhiteStar50.png
WhiteStar50.png
Created by y-bash This article
Blue giant BlueStar50.png
BlueStar50.png
Created by y-bash This article
Yellow star YellowStar50.png
YellowStar50.png
Created by y-bash This article
Orange star OrangeStar50.png
OrangeStar50.png
Created by y-bash This article
Red star RedStar50.png
RedStar50.png
Created by y-bash This article

The author does not claim any rights regarding the contribution part (image processing) of the images posted here. However, some original works before processing have conditions for secondary use including modification. For example, CC BY is obliged to display credits, and CC BY-SA is obliged to publish processed works with the same license. Please follow the conditions of the original work when using these. Also, it is not always guaranteed that the licensor of the original work, including those claiming the public domain, has all rights to the work. When using the images posted here, please take these points into consideration and do so at your own risk.

Padawan "Wow, I'm really focused!" Padawan "I'm tired ..."

6 am | Complete

6:00 | Incorporate processed images

Padawan took the processed image into the data folder and opened the IDE.

Padawan "Well, first of all, Galaxy-chan,"

Galaxy.pde


...
  public Galaxy() {
    //Image array initialization
    PImage[] images = new PImage[] {
    //loadImage("gp_50_blue.png "),   // ---
    //loadImage("gp_50_white.png "),  // ---
    //loadImage("gp_50_yellow.png "), // ---
    //loadImage("gp_50_orange.png "), // ---
    //loadImage("gp_50_red.png "),    // ---

      loadImage("BlueStar50.png "),   // +++
      loadImage("WhiteStar50.png "),  // +++
      loadImage("YellowStar50.png "), // +++
      loadImage("OrangeStar50.png "), // +++
      loadImage("RedStar50.png "),    // +++
    };
...

Padawan "Next is the Taiyo family ..."

SolarSystem.pde


  public SolarSystem() {
  //mSun = new CelestialObject("gp_sun.png ", 200, 0, 0, 0); //Sun// ---
  //OrbitalObject earth =                                             // ---
  //  new OrbitalObject(mSun, "gp_earth.png ", 50, 333, 16); //Earth// ---
  //  new OrbitalObject(earth,"gp_moon.png ",  25,  77,  7); //Month// ---
  //new OrbitalObject(mSun, "gp_mercury.png ", 30, 111,  8); //Mercury// ---
  //new OrbitalObject(mSun, "gp_venus.png ",   40, 222, 12); //Venus// ---
  //new OrbitalObject(mSun, "gp_mars.png ",    40, 444, 20); //Mars// ---
  //new OrbitalObject(mSun, "gp_jupiter.png ",170, 555, 24); //Jupiter// ---
  //new OrbitalObject(mSun, "gp_saturn.png ", 160, 666, 28); //Saturn// ---
  //new OrbitalObject(mSun, "gp_uranus.png ",  80, 777, 32); //Uranus// ---
  //new OrbitalObject(mSun, "gp_neptune.png ", 70, 888, 36); //Neptune// ---

    mSun = new CelestialObject("Sun.png ", 50, 0, 0, 0);                              // +++
    OrbitalObject mercury  = new OrbitalObject(mSun,    "Mercury.png ", 19, 227,  14); // +++
    OrbitalObject venus    = new OrbitalObject(mSun,    "Venus.png ",   47, 425,  37); // +++
    OrbitalObject earth    = new OrbitalObject(mSun,    "Earth.png ",   50, 587,  60); // +++
               /* moon     */new OrbitalObject(earth,   "Moon.png ",    13, 130,   4); // +++
    OrbitalObject mars     = new OrbitalObject(mSun,    "Mars.png ",    26, 894, 112); // +++
    OrbitalObject jupiter  = new OrbitalObject(mSun,    "Jupiter.png ",100,1527, 711); // +++
               /* io       */new OrbitalObject(jupiter, "Io.png ",      14, 165,   1); // +++
               /* europa   */new OrbitalObject(jupiter, "Europa.png ",  12, 263,   2); // +++
               /* ganymede */new OrbitalObject(jupiter, "Ganymede.png ",21, 420,   3); // +++
               /* callisto */new OrbitalObject(jupiter, "Callisto.png ",19, 590,   4); // +++
    OrbitalObject saturn   = new OrbitalObject(mSun,    "Saturn.png ", 100,2800, 886); // +++
               /* titan    */new OrbitalObject(saturn,  "Titan.png ",   20, 479,   3); // +++
    OrbitalObject uranus   = new OrbitalObject(mSun,    "Uranus.png ",  50,3755,1685); // +++
    OrbitalObject neptune  = new OrbitalObject(mSun,    "Neptune.png ", 50,4410,2472); // +++
               /* triton   */new OrbitalObject(neptune, "Triton.png ",  11, 139,  -1); // +++
    OrbitalObject pluto    = new OrbitalObject(mSun,    "Pluto.png ",    9,5789,3716); // +++
    OrbitalObject eris     = new OrbitalObject(mSun,    "Eris.png ",     9,6632,5580); // +++
  }

Padawan "Because the solar system is too wide" Padawan "I made the parameters appropriate (laughs)"

Padawan "After that ..." Padawan "Because it interferes with the utility, make it invisible,"

Padawan "Disable automatic camera" Padawan "I'll look down on myself from above ..."

Padawan "Oh! Don't forget to make it pitch black ..."

Simulator.pde


...
void setup() {
  gGalaxy = new Galaxy();
  gSolarSystem = new SolarSystem();

  setDevRoomAutoCameraEnabled(false);       // +++
  setDevRoomVisible(false);                 // +++
  
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
camera( 100, -4000, 100, 0, 0, 0, 0, 1, 0);
//background(255, 255, 255);                // ---
  background(0, 0, 0);                      // +++
  updateDevRoom();
  gGalaxy.update();
  gSolarSystem.update();
}

Padawan "Oh!" image.gif Padawan "Something is small, but ..."

Padawan "It looks like it's moving (laughs)"

6:10 | Control the camera

Padawan "But I'm lonely just looking at it ..."

Supreme Chancellor "Then ..." Supreme Chair "Why don't you try to operate it yourself?"

Padawan "Eh? Can't you !?"

Supreme Chancellor "Because it only captures key events" Supreme Chair "It's not difficult"

Padawan "Uncle is amazing !!!" Padawan "Master only teaches sober techniques"

Supreme Chair "Is that so?" Padawan "Yeah. The basics are important!"

Padawan "It's stingy!"

Supreme Chair "Hahaha" Supreme Chancellor "Will you come to me then?"

Supreme Chancellor "I am the richest man in the galaxy." Supreme Chancellor "You're likely to be an excellent secretary (laughs)"

Padawan "Eh ??? Really?" Padawan "Wow, uncle"

Padawan "Gentle and cool technique, will teach you" Padawan "And rich !!!"

Supreme Chair "Hey Padawan ..." Supreme Chancellor "You should express your emotions more straightforwardly!"

Padawan "But ..." Padawan "Master is always" Padawan "Suppress your emotions ..."

Supreme Chancellor "That's an old way of thinking ..." Supreme Chancellor "The times are about to change"

Supreme Chancellor "Cry when sad," Supreme Chancellor "When you want to get angry," Supreme Chancellor "You should explode your anger!"

Supreme Chair "Do you think that is more human ?!"

Padawan "Hmm" Padawan "I don't know what's difficult!"

Padawan "Oh! What's the key event?"

Supreme Chancellor "If you write a method called keyPressed ()" Supreme Chancellor "Calls you when a key is pressed." Supreme Chair "All you have to do is look at the variables key and keyCode."

Processing Official Site-Reference keyPressed key keyCode

Padawan "I see!" Padawan "When you press a letter, that letter comes into the key," Padawan "If you press , it will be in the keyCode!"

Padawan "Uh ..." Padawan "It's too easy to cry (laughs)"

Padawan "Then, make a new class!"

** CameraController class **

category item Description
class CameraController Camera control class. Control the position of the camera with the keyboard. The camera shall rotate about the Y axis of the world coordinate system on a plane parallel to the ZX plane and always the origin.(0,0,0)I will turn my gaze to.
field mRadius Semi-major axis of the current camera(A plane parallel to the ZX plane)
field mAngle Horizontal position of the current camera(Angle on the orbital plane:deg)
field mYCoord Vertical position of current camera(Y coordinate:px)
field mRadiusSpeed Velocity in the front-back direction as seen from the camera(Change in mRadius: px/sec)
field mRotationalSpeed Left-right speed as seen from the camera(Amount of change in mAngle:deg/sec)
field mVerticalSpeed Vertical speed as seen from the camera(Change in mYCoord: px/sec)
field mPrevMillis Last millis()Hold the value of
method left() When viewed from the camera perspective
・ If you are moving to the right, reduce the amount of change to the right.
・ If you are moving to the left, increase the amount of change to the left.
method right() When viewed from the camera perspective
・ If you are moving to the right, increase the amount of change to the right.
・ If you are moving to the left, reduce the amount of change to the left.
method up() When viewed from the camera perspective
・ If you are climbing, increase the climbing speed
・ If you are descending, reduce the descending speed.
method down() When viewed from the camera perspective
・ If you are climbing, slow down the climbing speed
・ If you are descending, increase the descending speed
method forward() When viewed from the camera perspective
・ If you are moving forward, increase the forward speed
・ If you are retreating, reduce the retreat speed.
method backward() When viewed from the camera perspective
・ If you are moving forward, reduce the forward speed and
・ If you are retreating, increase the retreat speed
method printStatus() Output the current state of the camera (current position and its change amount) to the console
method update() Update camera position

Padawan "Then, make a new tab (CameraController)," Padawan "I'll write a saver ..."

CameraController.pde


//Camera control class
public class CameraController {
  private float mRadius = 1000; //Semi-major axis of the current camera(A plane parallel to the ZX plane)
  private float mAngle  =    0; //Horizontal position of the current camera(Angle on the orbital plane:deg)
  private float mYCoord =    0; //Vertical position of current camera(Y coordinate:px)

  private int mRadiusSpeed     = 0; //Velocity in the front-back direction as seen from the camera(Change in mRadius: px/sec)
  private int mRotationalSpeed = 0; //Left-right speed as seen from the camera(Amount of change in mAngle:deg/sec)
  private int mVerticalSpeed   = 0; //Vertical speed as seen from the camera(Change in mYCoord: px/sec)

  private int mPrevMillis = 0; //Last elapsed time

  //Decrease the rotation speed of the camera
  //When viewed from the camera perspective
  //If you are moving to the right, reduce the amount of change to the right,
  //If you are moving to the left, increase the amount of change to the left
  public void left() {
    mRotationalSpeed -= 5;
    printStatus();
  }

  //Increase the rotation speed of the camera
  //When viewed from the camera perspective
  //If you are moving to the right, increase the amount of change to the right,
  //If you are moving to the left, reduce the amount of change to the left
  public void right() {
    mRotationalSpeed += 5;
    printStatus();
  }

  //Increase the climbing speed of the camera
  //When viewed from the camera perspective
  //If it is climbing, increase the climbing speed,
  //If you are descending, reduce the descending speed
  public void up() {
    mVerticalSpeed -= 25;
    printStatus();
  }
  
  //Decrease the ascending speed of the camera
  //When viewed from the camera perspective
  //If it is climbing, slow down the climbing speed,
  //If you are descending, increase the descending speed
  public void down() {
    mVerticalSpeed +=25;
    printStatus();
  }

  //Decrease the amount of change in the camera's orbital radius
  //When viewed from the camera perspective
  //If you are moving forward, increase your forward speed,
  //If you are retreating, reduce the retreat speed
  public void forward() {
    mRadiusSpeed -= 10;
    printStatus();
  }
  
  //Increase the amount of change in the camera's orbital radius
  //When viewed from the camera perspective
  //If you are moving forward, slow down the forward speed,
  //If you are retreating, increase the retreat speed
  public void backward() {
    mRadiusSpeed += 10;
    printStatus();
  }

  //Output the current state of the camera to the console
  public void printStatus() {
    print("(R,A,V)=(");
    print((int)mRadius + "px, " + (int)mAngle + "deg, " + (int)mYCoord + "px");
    print(") (dR,dA,dV)=(");
    print(mRadiusSpeed + "px/s, " + mRotationalSpeed + "deg/s, " + mVerticalSpeed + "px/s");
    println(")");
  }
  
  //Update camera position
  public void update() {
    int ms = millis();

    if (ms/1000 != mPrevMillis/1000) printStatus(); //Status display every second

    int dt = ms - mPrevMillis; //Amount of change in time
    mPrevMillis = ms;          //Save current time

    //Update of orbital radius
    mRadius += mRadiusSpeed * dt / 1000.0;
    mRadius = max(mRadius, 100.0);        //Stop when you're about to hit the sun
    if (mRadius==100.0) mRadiusSpeed = 0;

    //Rotation angle update
    mAngle += mRotationalSpeed * dt / 1000.0;
    mAngle = mAngle % 360;                //Normalized to fit between 0 and 360
    if (mAngle < 0) mAngle += 360;

    //Vertical position update
    mYCoord += mVerticalSpeed * dt / 1000.0;

    float z = mRadius * cos(radians(mAngle));
    float x = mRadius * sin(radians(mAngle));
    float y = mYCoord;
    camera(x, y, z, 0, 0, 0, 0, 1, 0);
  }
}

Padawan "Something was easier than I expected!"

Padawan "Oh! But which key should I press?" Padawan "I forgot to think about how it works (laughs)"

** Key assignment **

Key Turning right Turning left
Speed up Slow down
Slow down Speed up
Key Rising On the descent
Speed up Slow down
Slow down Speed up
Key Moving forward Retreating
PgUp Speed up Slow down
PgDn Slow down Speed up

Padawan "Oh! Key constants aren't available!"

Padawan " `` is RIGHT," Padawan " `is LEFT"

Padawan " `` is UP," Padawan " `is DOWN"

Padawan "Aha! It's too easy to cry ..." Padawan "Hmm ???"

Padawan "What? No matter how much you look at the reference" Padawan "I can't find the constants for PgUp and PgDn"

Supreme Chancellor "Unfortunately ..." Supreme Chancellor "In Processing" Supreme Chancellor "These constants are not available."

Padawan "Eh ???" Padawan "But a constant must be prepared" Padawan "I don't know what value will come in!"

Supreme Chancellor "Open a new sketch," Supreme Chancellor "Write as follows"

NewSketch


void setup() {
  size(100, 100, P3D);
}
void draw() {
}
void keyPressed() {
  println("key: " + key + ", keyCode: " + keyCode);
}

Supreme Chair "If you move it, try entering something!"

Padawan "Oh! Uncle genius ?!"

console


key: a, keyCode: 65   # 'a'Press the key
key: b, keyCode: 66   # 'b'Press the key
key: c, keyCode: 67   # 'c'Press the key
key: d, keyCode: 68   # 'd'Press the key
key: e, keyCode: 69   # 'e'Press the key
key: f, keyCode: 70   # 'f'Press the key
key: g, keyCode: 71   # 'g'Press the key
key: ?, keyCode: 37   # [←]Press the key
key: ?, keyCode: 39   # [→]Press the key
key: ?, keyCode: 38   # [↑]Press the key
key: ?, keyCode: 40   # [↓]Press the key
key: , keyCode: 16    # [PgUp]Press the key
key: , keyCode: 11    # [PgDn]Press the key
...

Padawan "16 is PgUp, 11 is PgDn!"

Padawan "Then let's rewrite the Simulator tab!"

Padawan "Then ..." Padawan "I don't need utilities anymore" Padawan "Erase Oops!"

Simulator.pde


Galaxy gGalaxy;
SolarSystem gSolarSystem;
CameraController gCameraController = new CameraController(); // +++

void setup() {
  gGalaxy = new Galaxy();
  gSolarSystem = new SolarSystem();
  //setDevRoomAutoCameraEnabled(false);                      // ---
  //setDevRoomVisible(false);                                // ---
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
//camera( 100, -4000, 100, 0, 0, 0, 0, 1, 0);               // ---
  background(0, 0, 0);
//updateDevRoom();                                          // ---
  gCameraController.update();                               // +++
  gGalaxy.update();
  gSolarSystem.update();
}

void keyPressed() {                                        // +++
  final int PAGE_UP   = 16;                                // +++
  final int PAGE_DOWN = 11;                                // +++
  switch (keyCode) {                                       // +++
    case LEFT      : gCameraController.left();    break;   // +++
    case RIGHT     : gCameraController.right();   break;   // +++
    case UP        : gCameraController.up();      break;   // +++
    case DOWN      : gCameraController.down();    break;   // +++
    case PAGE_UP   : gCameraController.forward(); break;   // +++
    case PAGE_DOWN : gCameraController.backward();break;   // +++
  }                                                        // +++
}

Padawan "OK! Let's move it!"

CameraController.gif

Padawan "Oh!"

Padawan "Is it completed ???"

Padawan "It's completed! ???"

Padawan "It's done! This is it !!!"

Supreme Chancellor "Congratulations. Padawan!" Supreme Chair "The rest seems to be good if you pass the test."

Supreme Chair "Oh! And ..."

Supreme Chair "I have one request, but ..."

Supreme Chair "Because I prepared a special Gopher-kun" Supreme Chancellor "Getting him in orbit around the moon" Supreme Chair "Can you test it?"

D.S.Gopher.png

Padawan "Oh! Kake !!!!"

Padawan "What happened to Gopher ?!" Padawan "Eyes, have you become engorged ?!"

Supreme Chancellor "Then, I have to go now ..."

Supreme Chancellor "D.S.Gopher is a secret to everyone." Supreme Chair "Uncle and Padawan, it's a secret only for two people!"

Padawan "Yeah! I understand (laughs)"

Supreme Chancellor "Oh, then ..." Supreme Chair "I invited you to me, but ..." Supreme Chair "Why don't you think seriously ?!"

Padawan "Oh !!!" Padawan "Thank you, Uncle!" Padawan "Uncle, I love you !!!"

Padawan "But stop now ..."

Padawan "With Master" Padawan "Become a saver in the galaxy" Padawan "Because I promised !!!"

Padawan "Well, uncle!" Padawan "Thank you for your kindness!"

Padawan "Also, tell me the tricks" Padawan "Thank you very much!"

6:50 | All simulator codes

After a while, the master returned to Padawan.

Master "Oh, did you fall asleep?" Master "But the simulator seems to have been completed successfully!"

Master "You did your best!"

Master "You must have been tired ..." Master "I'm sleeping slowly now"

With a gentle smile, Master began reviewing Saver.

** Folder structure **

Sketch folder structure


any-dir
    Simulator
    ├── Simulator.pde
    ├── Billboard.pde
    ├── CelestialObject.pde
    ├── OrbitalObject.pde
    ├── Galaxy.pde
    ├── SolarSystem.pde
    ├── CameraController.pde
    └── data
        ├── WhiteStar50.png
        ├── BlueStar50.png
        ├── YellowStar50.png
        ├── OrangeStar50.png
        ├── RedStar50.png
        ├── Sun.png
        ├── Mercury.png
        ├── Venus.png
        ├── Earth.png
        ├── Moon.png
        ├── Mars.png
        ├── Jupiter.png
        ├── Io.png
        ├── Europa.png
        ├── Ganymede.png
        ├── Callisto.png
        ├── Saturn.png
        ├── Titan.png
        ├── Uranus.png
        ├── Neptune.png
        ├── Triton.png
        ├── Pluto.png
        └── Eris.png

Source code

Extract all code from Simulator.pde

Simulator.pde


//Solar system simulator

Galaxy gGalaxy;                      //Galactic stars
SolarSystem gSolarSystem;            //Stars of the solar system
CameraController gCameraController = 
   new CameraController();           //Camera control

void setup() {
  gGalaxy = new Galaxy();
  gSolarSystem = new SolarSystem();
  size(1920, 1080, P3D);
  hint(ENABLE_DEPTH_SORT);
  frameRate(24);
}

void draw() {
  background(0, 0, 0);
  gCameraController.update();
  gGalaxy.update();
  gSolarSystem.update();
}

void keyPressed() {
  final int PAGE_UP   = 16; //PgUp key
  final int PAGE_DOWN = 11; //PgDn key

  switch (keyCode) {
    case LEFT      : gCameraController.left();    break;
    case RIGHT     : gCameraController.right();   break;
    case UP        : gCameraController.up();      break;
    case DOWN      : gCameraController.down();    break;
    case PAGE_UP   : gCameraController.forward(); break;
    case PAGE_DOWN : gCameraController.backward();break;
  }
}
Extract all code from Billboard.pde

Billboard.pde


//Billboard class
public class Billboard {
  private PImage mImage;  //Image to paste on the billboard
  private int    mWidth;  //Billboard width
  private int    mHeight; //Billboard height
  private float  mX;      //Billboard X coordinate
  private float  mY;      //Billboard Y coordinate
  private float  mZ;      //Billboard Z coordinate

  //constructor
  // param imageName:File name of the image to be pasted
  // param w        :Billboard width
  // param x        :Billboard X coordinate
  // param y        :Billboard Y coordinate
  // param z        :Billboard Z coordinate
  public Billboard(String imageName, int w, float x, float y, float z) {
    this( loadImage(imageName), w, x, y, z);
  }
  
  //constructor
  // param image:Image to paste
  // param w    :Billboard width
  // param x    :Billboard X coordinate
  // param y    :Billboard Y coordinate
  // param z    :Billboard Z coordinate
  public Billboard(PImage image,  int w, float x, float y, float z) {
    mImage  = image;
    mWidth  = w;
    mHeight = w * mImage.height / mImage.width; //Height is calculated from the aspect ratio of the image
    mX      = x;
    mY      = y;
    mZ      = z;
  }

  //Coordinate conversion and drawing
  public void update() {
    pushMatrix();
      transform();
      turnToCamera();
      drawSelf();
    popMatrix();
  }

  //Coordinate transformation
  protected void transform() {
    translate(mX, mY, mZ);
  }

  //drawing
  protected void drawSelf() {
    float hw = mWidth  / 2;
    float hh = mHeight / 2;
    float iw = mImage.width;
    float ih = mImage.height;
    pushStyle();
      noStroke();
      beginShape();
        texture(mImage);
        vertex(-hw, -hh, 0,  0,  0);
        vertex( hw, -hh, 0, iw,  0);
        vertex( hw,  hh, 0, iw, ih);
        vertex(-hw,  hh, 0,  0, ih);
      endShape();
    popStyle();
  }
 
  //Change posture toward the camera
  protected void turnToCamera() {
    PMatrix3D m = (PMatrix3D)g.getMatrix();  
    m.m00 = m.m11 = m.m22 = 1;
    m.m01 = m.m02 = m.m10 = m.m12 = m.m20 = m.m21 = 0;
    resetMatrix();  
    applyMatrix(m);  
  }
}
Extract all code from CelestialObject.pde

CelestialObject.pde


//Celestial class (draw together if there is a child)
public class CelestialObject extends Billboard {
  private ArrayList<Billboard> mChildren = null; //Children list

  //constructor
  //param imageName image file name
  //param w celestial body(Billboard)Width of
  //param x celestial body(Billboard)X coordinate
  //param y celestial body(Billboard)Y coordinate of
  //param z celestial body(Billboard)Z coordinate
  public CelestialObject(String imageName,
                         int w, float x, float y, float z) {
    super(imageName, w, x, y, z);
  }

  //Add a child
  public void addChild(Billboard child) {
    if (mChildren == null) {
      mChildren = new ArrayList<Billboard>();
    }
    mChildren.add(child);
  }

  //Coordinate conversion and drawing (override)
  public void update() {
    pushMatrix();
      transform();
      pushMatrix();
        turnToCamera();
        drawSelf();     //Draw yourself
      popMatrix();
      updateChildren(); //Draw all kids
    popMatrix();
  }

  //Draw all kids
  private void updateChildren() {
    if (mChildren != null) {
      for (Billboard child : mChildren) {
        child.update();
      }
    }
  } 
}
Expand all code in OrbitalObject.pde

OrbitalObject.pde


//A celestial body that revolves in a circular orbit
public class OrbitalObject extends CelestialObject {
  private float mRadius; //Revolution radius
  private int   mPeriod; //Revolution cycle(millisecond)
  private float mStart;  //Angle at the start(radians)

  //constructor
  //param parent Revolving mother star
  //param imageName Image file name
  //param w Revolution(Billboard)Width of
  //param radius Revolution radius
  //param period Revolution period(Seconds)
  public OrbitalObject(CelestialObject parent,
                       String imageName, int w,
                       float radius, int period) {
    super(imageName, w, 0, 0, 0);
    mRadius = radius;
    mPeriod = period * 1000;
    mStart = random(TWO_PI);
    parent.addChild(this); //Add yourself to your home planet
  }

  //Coordinate conversion and drawing (override)
  public void update() {
    updateOrbit();
    super.update();
  }

  //Coordinate transformation (override)
  protected void transform() {
    int   ms = millis();
    float rd = mStart + TWO_PI * (ms % mPeriod) / mPeriod;
    rotateY(rd);
    translate(mRadius, 0, 0);
  }
  
  //Draw orbit
  protected void updateOrbit() {
    pushMatrix();
      rotateX(HALF_PI);
      pushStyle();
        noFill();
        stroke(48, 48, 48);
        strokeWeight(1);
        circle(0, 0, mRadius*2);
      popStyle();
    popMatrix();
  }
}
Extract all code from Galaxy.pde

Galaxy.pde


//Stars that make up the galaxy
public class Galaxy {
  private Billboard[] mStars = new Billboard[1000]; //Billboard as many as the number of stars

  //constructor
  public Galaxy() {
    //Image array initialization
    PImage[] images = new PImage[] {
      loadImage("BlueStar50.png "),
      loadImage("WhiteStar50.png "),
      loadImage("YellowStar50.png "),
      loadImage("OrangeStar50.png "),
      loadImage("RedStar50.png "),
    };

    //Loop by the number of stars
    for (int i = 0; i < mStars.length; i++) {
      float angle  = random(TWO_PI);      //The angle on the ZX plane is 0 to 360 °(2π)Randomly in the range of
      float radius = random(4000, 5000);  //The distance from the origin on the ZX plane is randomly in the range of 4000-5000
      float x      = sin(angle) * radius; //X coordinate of the star
      float z      = cos(angle) * radius; //Z coordinate of the star
      float y      = random(-3000, 3000); //The Y coordinate of the star is-Randomly in the range of 3000-3000

      int n = (int)random(5);             //Images to be pasted on the billboard are randomly selected from 5 types
      mStars[i]    = new Billboard(images[n], 50, x, y, z); //Generate a billboard and store it in an array
    }
  }
  
  //Draw all stars with coordinate transformation
  public void update() {
    for (Billboard star: mStars) {
      star.update();
    }
  }
}
Extract all code from SolarSystem.pde

SolarSystem.pde


//Solar system class
public class SolarSystem {
  private CelestialObject mSun; //Sun

  //constructor
  public SolarSystem() {
    mSun = new CelestialObject("Sun.png ", 50, 0, 0, 0);
    OrbitalObject mercury  = new OrbitalObject(mSun,    "Mercury.png ", 19, 227,  14);
    OrbitalObject venus    = new OrbitalObject(mSun,    "Venus.png ",   47, 425,  37);
    OrbitalObject earth    = new OrbitalObject(mSun,    "Earth.png ",   50, 587,  60);
               /* moon     */new OrbitalObject(earth,   "Moon.png ",    13, 130,   4);
    OrbitalObject mars     = new OrbitalObject(mSun,    "Mars.png ",    26, 894, 112);
    OrbitalObject jupiter  = new OrbitalObject(mSun,    "Jupiter.png ",100,1527, 711);
               /* io       */new OrbitalObject(jupiter, "Io.png ",      14, 165,   1);
               /* europa   */new OrbitalObject(jupiter, "Europa.png ",  12, 263,   2);
               /* ganymede */new OrbitalObject(jupiter, "Ganymede.png ",21, 420,   3);
               /* callisto */new OrbitalObject(jupiter, "Callisto.png ",19, 590,   4);
    OrbitalObject saturn   = new OrbitalObject(mSun,    "Saturn.png ", 100,2800, 886);
               /* titan    */new OrbitalObject(saturn,  "Titan.png ",   20, 479,   3);
    OrbitalObject uranus   = new OrbitalObject(mSun,    "Uranus.png ",  50,3755,1685);
    OrbitalObject neptune  = new OrbitalObject(mSun,    "Neptune.png ", 50,4410,2472);
               /* triton   */new OrbitalObject(neptune, "Triton.png ",  11, 139,  -1);
    OrbitalObject pluto    = new OrbitalObject(mSun,    "Pluto.png ",    9,5789,3716);
    OrbitalObject eris     = new OrbitalObject(mSun,    "Eris.png ",     9,6632,5580);
  }

  //Draw all stars with coordinate transformation
  public void update() {
    mSun.update();
  }
}
Expand all code in CameraController.pde

CameraController.pde


//Camera control class
public class CameraController {
  private float mRadius = 1000; //Semi-major axis of the current camera(A plane parallel to the ZX plane)
  private float mAngle  =    0; //Horizontal position of the current camera(Angle on the orbital plane:deg)
  private float mYCoord =    0; //Vertical position of current camera(Y coordinate:px)

  private int mRadiusSpeed     = 0; //Velocity in the front-back direction as seen from the camera(Change in mRadius: px/sec)
  private int mRotationalSpeed = 0; //Left-right speed as seen from the camera(Amount of change in mAngle:deg/sec)
  private int mVerticalSpeed   = 0; //Vertical speed as seen from the camera(Change in mYCoord: px/sec)

  private int mPrevMillis = 0; //Last elapsed time

  //Decrease the rotation speed of the camera
  //When viewed from the camera perspective
  //If you are moving to the right, reduce the amount of change to the right,
  //If you are moving to the left, increase the amount of change to the left
  public void left() {
    mRotationalSpeed -= 5;
    printStatus();
  }

  //Increase the rotation speed of the camera
  //When viewed from the camera perspective
  //If you are moving to the right, increase the amount of change to the right,
  //If you are moving to the left, reduce the amount of change to the left
  public void right() {
    mRotationalSpeed += 5;
    printStatus();
  }

  //Increase the climbing speed of the camera
  //When viewed from the camera perspective
  //If it is climbing, increase the climbing speed,
  //If you are descending, reduce the descending speed
  public void up() {
    mVerticalSpeed -= 25;
    printStatus();
  }
  
  //Decrease the ascending speed of the camera
  //When viewed from the camera perspective
  //If you are climbing, slow down the climb speed
  //If you are descending, increase the descending speed
  public void down() {
    mVerticalSpeed +=25;
    printStatus();
  }

  //Decrease the amount of change in the camera's orbital radius
  //When viewed from the camera perspective
  //If you are moving forward, increase your forward speed,
  //If you are retreating, reduce the retreat speed
  public void forward() {
    mRadiusSpeed -= 10;
    printStatus();
  }
  
  //Increase the amount of change in the camera's orbital radius
  //When viewed from the camera perspective
  //If you are moving forward, slow down the forward speed,
  //If you are retreating, increase the retreat speed
  public void backward() {
    mRadiusSpeed += 10;
    printStatus();
  }

  //Output the current state of the camera to the console
  public void printStatus() {
    print("(R,A,V)=(");
    print((int)mRadius + "px, " + (int)mAngle + "deg, " + (int)mYCoord + "px");
    print(") (dR,dA,dV)=(");
    print(mRadiusSpeed + "px/s, " + mRotationalSpeed + "deg/s, " + mVerticalSpeed + "px/s");
    println(")");
  }
  
  //Update camera position
  public void update() {
    int ms = millis();

    if (ms/1000 != mPrevMillis/1000) printStatus(); //Status display every second

    int dt = ms - mPrevMillis; //Amount of change in time
    mPrevMillis = ms;          //Save current time

    //Update of orbital radius
    mRadius += mRadiusSpeed * dt / 1000.0;
    mRadius = max(mRadius, 100.0);        //Stop when you're about to hit the sun
    if (mRadius==100.0) mRadiusSpeed = 0;

    //Rotation angle update
    mAngle += mRotationalSpeed * dt / 1000.0;
    mAngle = mAngle % 360;                //Normalized to fit between 0 and 360
    if (mAngle < 0) mAngle += 360;

    //Vertical position update
    mYCoord += mVerticalSpeed * dt / 1000.0;

    float z = mRadius * cos(radians(mAngle));
    float x = mRadius * sin(radians(mAngle));
    float y = mYCoord;
    camera(x, y, z, 0, 0, 0, 0, 1, 0);
  }
}

7am | Epilogue

On the roof of the Planet Coruscant / Republic Knight Temple ...

Young Knight "Finally, the army is founded." Grand Master "Oh, it's finally time"

Young Night "I was at the Senate Congress last night" Young Knight "I'm worried that the Supreme Chancellor has gained executive privilege."

Grand Master "Because the citizens of the Republic have a lot of support for him ..." Grand Master "This is also democracy."

Young Night "Actually from the Supreme Chancellor's office last night ..." Young Night "Where D.S. Mark's Gopher comes out" Young night "I have seen it"

Grand Master "What ?!"

Young Night "Grand Master!"

Young Night "D.S. is ..." Young Night "Isn't it an abbreviation for Dark Side !?"

Grand Master"…"

Grand Master "It's not ..." Grand Master "What if"

Grand Master "Even if he has some ambitions" Grand Master "Everyone will notice" Grand Master "Such a mess ..."

Young Night "Master ..." Young Knight "Do you think it will be a war?"

Grand Master "Umu," Grand Master "Reading the future ..."

Grand Master "Difficult ..."

When he looked at him, the buildings in the megacity illuminated by the morning sun were even more sparkling.

Afterword

How was it?

Even those who have experienced CG programming for the first time may have felt that it was surprisingly easy.

If you find it a little unsatisfactory, you may want to try the following improvements.

Solar system clock

It is a clock that regards the sun as "hours", the earth as "minutes", and the moon as "seconds". SolarSystemClock.jpg You can make such an expression by doing the following. · Write text on the billboard -Set the blending mode to "additive synthesis" ・ Control the camera so that the sun, earth, and moon are always in the angle of view.

Spacecraft simulator

It is a spacecraft simulator style game. SpaceProbeSimulator.jpg You can make such an expression by doing the following. ・ Control the camera more freely ・ Always place a billboard that looks like a control panel in front of the camera.

The billboard technique may be out of date, but depending on your ideas, you can still make something interesting.

Also, a little high school mathematics is required, but if you have children and have not yet decided on a free research theme for summer vacation, it would be fun to propose it as a subject. Oh, please be careful about the license of image materials.

Well then

May the Force be with you! (May the Force be with you!)

A certain scene after the end roll

Planet Coruscant At the Galactic Republic Supreme Chancellor's Office ...

Supreme Chairman "Guhahahaha!"

Supreme Chair "What is a citizen?"

Supreme Chancellor "Fools ..." Supreme Chancellor "I handed over the authority very easily!"

Supreme Chair "Republican Knights,"

Supreme Chancellor "D.S. seems to misunderstand that it is the dark side."

Supreme Chair "I also got a planetary simulator ..."

Supreme Chancellor "To seize this galaxy" Supreme Chancellor "Even if it took decades ..."

Supreme Chancellor "I will make this D.S.!"

DeathStar.gif The artificial celestial body in the center of the screen used as the billboard material for this image is the work of adnylangager, CC BY-NC 2.0. Is licensed. (Source: fiickr)

Recommended Posts

Gopher-kun's Go Episode II-A solar system simulator that even Daphnia can make overnight, and the dark side