_
BIN
desktop app/Understanding 4D.zip
Normal file
BIN
images/0.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
images/1.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
images/1d.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/2.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
images/3.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
images/3d.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
images/3d.png~
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
images/4.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
images/4d.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
images/4d.png~
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
images/5.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
images/anglesToRotate.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
images/basicRotations.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
images/colorVisualizationFor2D.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
images/colorVisualizationFor2D.png~
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
images/colorVisualizationForW.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/colorVisualizationForW.png~
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
images/directionalLightAndAmbientLightGradient.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
images/halfDonutVisualizedIn2D.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
images/heightmap.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
images/images from desktop app/0.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
images/images from desktop app/1.png
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
images/images from desktop app/2.png
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
images/images from desktop app/3.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
images/images from desktop app/3_.png
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
images/images from desktop app/4.png
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
images/images from desktop app/5.png
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
images/images from desktop app/5.png~
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
images/images from desktop app/main0.png
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
images/images from desktop app/main1.png
Normal file
After Width: | Height: | Size: 168 KiB |
BIN
images/images from desktop app/main1_.png
Normal file
After Width: | Height: | Size: 226 KiB |
BIN
images/known and unknown rotations.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
images/knownRotations2D.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
images/main.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
images/newRotations.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
images/projected3Ddonut.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
images/projectingTwiceFrom3D.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
images/projectingTwiceFrom4D.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
images/unknownRotationOnDonut.png
Normal file
After Width: | Height: | Size: 136 KiB |
BIN
images/unknownRotationsUsedForCreatingObjects.png
Normal file
After Width: | Height: | Size: 139 KiB |
315
index.html
Normal file
@ -0,0 +1,315 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="styles/style.css"/>
|
||||
<script src="libraries/jquery-3.6.0.min.js"></script>
|
||||
<title>Understanding 4D</title>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<nav></nav>
|
||||
</header>
|
||||
|
||||
<p class="title"><strong>Understanding 4D</strong></p>
|
||||
|
||||
<div class="a">
|
||||
<span class="highlight_text">0. Introduction</span> <br/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Hello, I am Tucan. <br/>
|
||||
In this course I will be explaining some ways of how to
|
||||
think about 4D and then explain rotations of a 4D object that kinda looks like a donut. There will be a lot of interactive stuff so look forward to that. <br/>
|
||||
Intuition is all you'll need.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="a">
|
||||
<p class="normal_text">
|
||||
Also please download
|
||||
<a href="./desktop app/Understanding 4D.zip" class="normal_text" download>this application.</a>
|
||||
(<a href="https://drive.google.com/file/d/1iRUxC5VLrMRLLMBHvf7_ZTHKjQovYyPa/view?usp=sharing" class="normal_text" download>source code</a>)<br/>
|
||||
It contains several scenes that will be useful in our explanation. <br/>
|
||||
You can continue without the app if you want to. <br/>
|
||||
There will be screenshots of the scenes, but they won't be interactive.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="a">
|
||||
<span class="highlight_text">1. What are we going to see?</span>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Before we look at 4D and try understanding it, we need to know what are we going to be seeing and how. <br/>
|
||||
To answer that, first let's look at what person in 1D would see.
|
||||
</p>
|
||||
|
||||
<img src="./images/1d.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Person in 1D would see 1 piece of information or 0D. <br/>
|
||||
Now let's look what happens in 2D. (use slider to move the points around)
|
||||
</p>
|
||||
|
||||
<canvas class="c" width=1100px height=360px></canvas>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
As we saw above person in 2D would see a line or section of 1D. <br/>
|
||||
Let's continue to 3D.
|
||||
</p>
|
||||
|
||||
<img src="./images/3d.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
In 3D we see section of 2D. As shown on the image, by projecting onto 2D surface we get rid of z coordinates. <br/>
|
||||
Now let's look what would a person in 4D see.
|
||||
</p>
|
||||
|
||||
<img src="./images/4d.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Every time we had person in some dimension what he saw was section of lower dimension. <br/>
|
||||
For example we live in 3D but see 2D. Similarly, a person in 4D would see 3D. <br/>
|
||||
But we can't see 3D space like person in 4D. <br/>
|
||||
For us, we need to project again, 3D => 2D. <br/>
|
||||
Then we can see 2D section that we end up with.<br/>
|
||||
Let me give you example of projecting twice. 3D => 2D => 1D
|
||||
</p>
|
||||
|
||||
<img src="./images/projectingTwiceFrom3D.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now, let's move onto our case 4D => 3D => 2D.
|
||||
We'll ignore 4D person for less confusion.
|
||||
</p>
|
||||
|
||||
<img src="./images/projectingTwiceFrom4D.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
By projecting twice we get something that we can see. <br/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="a">
|
||||
<span class="highlight_text">2. Visualizing w axis using color</span>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Before we do w axis let's try visualizing z axis with color in 2D. <br/>
|
||||
To do that we can use heightmaps. In heightmaps color is used to indicate height.<br/>
|
||||
Below we have 3D surface on the left and its heightmap on the right. <br/>
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
<video width="854" height="480" controls class="normal_video">
|
||||
<source src="./videos/Terrain3D.mp4" type="video/mp4">
|
||||
</video>
|
||||
|
||||
<img src="./images/heightmap.png" class="normal_image"/>
|
||||
</div>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Using only black and white can be problematic with negative values. <br/>
|
||||
By using more colors we can get more information from looking at heightmaps. <br/>
|
||||
Let's use blue and green.
|
||||
</p>
|
||||
|
||||
<img src="./images/colorVisualizationFor2D.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
We can also use this to visualize the w axis.
|
||||
</p>
|
||||
|
||||
<img src="./images/colorVisualizationForW.png" class="normal_image"/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="a">
|
||||
<span class="highlight_text">3. Creating 4D object</span>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now it's going to start getting exciting. <br/>
|
||||
4D object that we're going to create is in some ways similar to donut. <br/>
|
||||
That's why we will look at how to create a donut first. <br/>
|
||||
We can create a donut by rotating circle around a line. <br/>
|
||||
Below is how it would look in 2D visualized by color. <br/>
|
||||
Note that object below is only half donut. (sigle color per circle used for simplicity) <br/>
|
||||
</p>
|
||||
|
||||
<img src="./images/halfDonutVisualizedIn2D.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
As we saw above 2D person would see a circle that's getting squashed and its color changes. <br/>
|
||||
We're going to create our 4D object similarly but use spheres instead and rotate into the 4th dimension. <br/>
|
||||
Before that let's look at what we need to do basic rotations. <br/>
|
||||
All we need for basic rotation are 2 variables forming a plane. <br/>
|
||||
Its nicely demonstrated on the image below.
|
||||
</p>
|
||||
|
||||
<img src="./images/basicRotations.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now we can start creating our 4D object. <br/>
|
||||
Were going to do something similar to making a donut from circle. <br/>
|
||||
But instead of circles were going to use spheres, and rotate into 4D using rotation with x and w. <br/>
|
||||
Explore 3D scene that's illustrating half of the rotation. (signle color per sphere used for simplicity)
|
||||
</p>
|
||||
|
||||
<iframe src="./spline scenes/4_d_donut_creation/index.html" frameborder=0 class="spline_scene"></iframe>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now let's go back to normal donut. <br/>
|
||||
What would a person in 2D see when we project the donut. <br/>
|
||||
We count that the donut was created using method above and not manipulated yet.
|
||||
</p>
|
||||
|
||||
<img src="./images/projected3Ddonut.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
When person that's in 2D saw that projected donut, <br/>
|
||||
it looked something like rectangle with rounded corners. <br/>
|
||||
Because we created our 4D object using similar method we can use this. <br/>
|
||||
If this scales nicely, we should see something like cuboid (stretched cube) with rounded corners. <br/>
|
||||
|
||||
Please open the desktop app mentioned at the begging. <br/>
|
||||
Then click on the button shown below to run projection of 4D object. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/0.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/0.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
As we saw, it looked like cuboid with rounded corners.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="a">
|
||||
<span class="highlight_text">4. Exploring 4D object</span>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
There are a lot of confusing things that can happen when we rotate higher dimensional objects. <br/>
|
||||
So to get a little less confused we're going to look at rotations and their behavior first. <br/>
|
||||
Below is table with dimensions and rotations that become possible in that dimension.
|
||||
</p>
|
||||
|
||||
<img src="./images/newRotations.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now let's split rotations into known and unknown. <br/>
|
||||
Known rotations will be those that exist in our dimension. <br/>
|
||||
And unknown rotations will be those that are in higher dimensions. <br/>
|
||||
The number of unknown rotations will always be infinite like the number of higher dimensions. <br/>
|
||||
For example, if we're in 2D we have 1 known rotation.
|
||||
</p>
|
||||
|
||||
<img src="./images/known and unknown rotations.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Using known rotations on higher dimensional objects doesn't change the behavior of known rotations. <br/>
|
||||
For example, if we're in 2D and use known rotation on 3D donut it would rotate like we would expect.
|
||||
</p>
|
||||
|
||||
<img src="./images/knownRotations2D.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Also in the first scene that we used app to run were only known rotations inplace. <br/>
|
||||
That's why you haven't seen any unusual motion. <br/>
|
||||
To create higher dimensional objects in some dimension we used unknown rotations. <br/>
|
||||
Let's look again at where we used them.
|
||||
</p>
|
||||
|
||||
<img src="./images/unknownRotationsUsedForCreatingObjects.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now we will use these unknown rotations to rotate the objects. <br/>
|
||||
We're going to start with normal donut. <br/>
|
||||
For person in 2D it looks as if the points are cycling through the object.
|
||||
</p>
|
||||
|
||||
<img src="./images/unknownRotationOnDonut.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Next we're going to do the same with our 4D object. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/5.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/5.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Another thing we can do is use reverse rendering. <br/>
|
||||
Here, that means seeing whats furthest away first. <br/>
|
||||
This way we can see more useful information. <br/>
|
||||
Let's start with rendering normal 3D donut with reverse. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/1.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/1.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Using reverse we could see the backside and partially see front side as well when they overlapped. <br/>
|
||||
Next were going to use reverse with our 4D object. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/2.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/2.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Next we'll change lighting. <br/>
|
||||
Instead of normal lighting we can use ambient light gradients (alg). <br/>
|
||||
With them we can get better sense of distance. <br/>
|
||||
Image below is showing difference between directional lighting and alg.
|
||||
</p>
|
||||
|
||||
<img src="./images/directionalLightAndAmbientLightGradient.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Actually alg that's used in the app is a little different to improve performance. <br/>
|
||||
But it still looks similar enough. <br/>
|
||||
Now we'll try alg with 3D donut. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/3.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/3.png" class="normal_image mleft"/>
|
||||
<img src="./images/images from desktop app/3_.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Let's continue with our 4D object. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/4.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/4.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
There's one more thing we will do in this explanation. <br/>
|
||||
We never combined known and unknown rotations together with our 4D object. <br/>
|
||||
Because of that we never got to see all states of our 4D object. <br/>
|
||||
To access all rotated states of 4D object we need 3 angles. <br/>
|
||||
Below image illustrates this.
|
||||
</p>
|
||||
|
||||
<img src="./images/anglesToRotate.png" class="normal_image"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
Now, let's try it with our 4D object. <br/>
|
||||
Click the button shown below. (in app)
|
||||
</p>
|
||||
|
||||
<img src="./images/main.png" class="normal_image"/>
|
||||
<img src="./images/images from desktop app/main0.png" class="normal_image mleft"/>
|
||||
<img src="./images/images from desktop app/main1.png" class="normal_image mleft"/>
|
||||
<img src="./images/images from desktop app/main1_.png" class="normal_image mleft"/>
|
||||
|
||||
<p class="normal_text mtop">
|
||||
And with that, here ends the explanation. <br/> <br/>
|
||||
<a href="https://github.com/Tucan444/Understanding-4D" class="normal_text">Github<a/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script src="scripts/2Dprojection.js"></script>
|
||||
</body>
|
||||
</html>
|
2
libraries/jquery-3.6.0.min.js
vendored
Normal file
333
scripts/2Dprojection.js
Normal file
@ -0,0 +1,333 @@
|
||||
function rgb_to_hex(r, g, b) {
|
||||
r = Math.round(r).toString(16);
|
||||
g = Math.round(g).toString(16);
|
||||
b = Math.round(b).toString(16);
|
||||
|
||||
if (r.length < 2) {
|
||||
r = "0" + r;
|
||||
}
|
||||
if (g.length < 2) {
|
||||
g = "0" + g;
|
||||
}
|
||||
if (b.length < 2) {
|
||||
b = "0" + b;
|
||||
}
|
||||
|
||||
return `#${r}${g}${b}`;
|
||||
}
|
||||
|
||||
|
||||
class RotatingPoint2D {
|
||||
constructor(x, y, theta, magnitude, size, color) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
// r as rotated
|
||||
this.rx = x;
|
||||
this.ry = y;
|
||||
this.theta = theta;
|
||||
this.magnitude = magnitude;
|
||||
this.size = size;
|
||||
this.color = color;
|
||||
this.shaded_color = [0, 0, 0];
|
||||
this.d = 0;
|
||||
|
||||
this.linewidth = 4;
|
||||
this.offset = [400, 180];
|
||||
this.TAU = Math.PI * 2;
|
||||
}
|
||||
|
||||
shade = function(light_x, light_y, light_intensity) {
|
||||
let differences = [this.rx - light_x, this.ry - light_y];
|
||||
let distance = Math.sqrt(Math.pow(differences[0], 2) + Math.pow(differences[1], 2));
|
||||
let alpha = Math.max(0, -(distance - light_intensity) / light_intensity);
|
||||
|
||||
this.shaded_color = [this.color[0] * alpha, this.color[1] * alpha, this.color[2] * alpha];
|
||||
}
|
||||
|
||||
rotate = function(alpha = 0) {
|
||||
let beta = alpha + this.theta;
|
||||
this.rx = Math.cos(beta) * this.magnitude;
|
||||
this.ry = Math.sin(beta) * this.magnitude;
|
||||
}
|
||||
|
||||
find_d = function(player_pos) {
|
||||
let offseted_player_pos = [player_pos[0] - this.offset[0], player_pos[1] - this.offset[1]];
|
||||
|
||||
let differences = [this.rx - offseted_player_pos[0], this.ry - offseted_player_pos[1]];
|
||||
|
||||
this.d = Math.pow(differences[0], 2) + Math.pow(differences[1], 2);
|
||||
}
|
||||
|
||||
draw_line_to_player = function(ctx, player_pos) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = rgb_to_hex(this.shaded_color[0], this.shaded_color[1], this.shaded_color[2]);
|
||||
ctx.lineWidth = this.linewidth;
|
||||
|
||||
ctx.moveTo(this.rx + this.offset[0], this.ry + this.offset[1])
|
||||
|
||||
ctx.lineTo(player_pos[0], player_pos[1]);
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
blit = function(ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.fillStyle = rgb_to_hex(this.shaded_color[0], this.shaded_color[1], this.shaded_color[2]);
|
||||
|
||||
ctx.arc(this.rx + this.offset[0], this.ry + this.offset[1], this.size, 0, this.TAU);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
get_projected_positions = function(player_pos, projection_size, canvas_height) {
|
||||
let player_pos_x = player_pos[0] - this.offset[0];
|
||||
|
||||
let projected_pos = this.ry * (projection_size[0] / (player_pos_x - this.rx)) * (canvas_height / projection_size[1]);
|
||||
|
||||
return projected_pos + player_pos[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class VerticalSliderPoint {
|
||||
constructor (x, y, r, colors, constrains) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.r = r;
|
||||
this.colors = colors; // 0 for idle 1 for hover 2 for active
|
||||
this.constrains = constrains;
|
||||
|
||||
this.TAU = Math.PI * 2;
|
||||
}
|
||||
|
||||
set_y = function(y) {
|
||||
if (y < this.constrains[0]) {
|
||||
this.y = this.constrains[0];
|
||||
} else if (y > this.constrains[1]) {
|
||||
this.y = this.constrains[1];
|
||||
} else {
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
collidepoint = function (x, y) {
|
||||
let differences = [this.x - x, this.y - y];
|
||||
let distance = Math.sqrt(Math.pow(differences[0], 2) + Math.pow(differences[1], 2));
|
||||
|
||||
return (distance <= this.r);
|
||||
}
|
||||
|
||||
get_progress = function() {
|
||||
let progress = this.y - this.constrains[0];
|
||||
progress /= this.constrains[1] - this.constrains[0];
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
blit = function(ctx, color_index) {
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.lineWidth = 1;
|
||||
ctx.fillStyle = this.colors[color_index];
|
||||
|
||||
ctx.arc(this.x, this.y, this.r, 0, this.TAU);
|
||||
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
console.log("a");
|
||||
$(document).ready(function(){
|
||||
console.log("b");
|
||||
let c = $(".c")[0];
|
||||
let ctx = c.getContext("2d");
|
||||
let TAU = Math.PI * 2;
|
||||
let canvas_size = [1100, 360];
|
||||
let view_width = 120;
|
||||
let thin_line_width = 6;
|
||||
let normal_line_width = 20;
|
||||
let alpha = 0;
|
||||
let mousedown = false;
|
||||
let on_slider = false;
|
||||
|
||||
let player_pos = [canvas_size[0] - 360, canvas_size[1] /2];
|
||||
let projection_size = [100, 120];
|
||||
|
||||
let slider_padding_top_bottom = 40;
|
||||
let slider_angle = TAU * 1.2;
|
||||
|
||||
let creamy_white = "#c3c3c3";
|
||||
let creamy_gray_light = "#a3a3a3"
|
||||
let creamy_gray = "#999999";
|
||||
let creamy_gray_dark = "#777777";
|
||||
let green = "#6de256";
|
||||
|
||||
let sliderMode = 0;
|
||||
|
||||
let sliderPoint = new VerticalSliderPoint(50, slider_padding_top_bottom, 16,
|
||||
[creamy_gray, creamy_gray_light, creamy_white],
|
||||
[slider_padding_top_bottom, canvas_size[1] - slider_padding_top_bottom]);
|
||||
|
||||
let points = [new RotatingPoint2D(60, 0, 0, 60, 20, [255, 100, 100]),
|
||||
new RotatingPoint2D(Math.cos((Math.PI / 3) * 2) * 80, Math.sin((Math.PI / 3) * 2) * 80, (Math.PI / 3) * 2, 80, 20, [255, 100, 100]),
|
||||
new RotatingPoint2D(Math.cos((Math.PI / 3) * 4) * 110, Math.sin((Math.PI / 3) * 4) * 110, (Math.PI / 3) * 4, 110, 20, [255, 100, 100])];
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
points[i].shade(100, 100, 400);
|
||||
points[i].find_d(player_pos);
|
||||
points[i].draw_line_to_player(ctx, player_pos);
|
||||
}
|
||||
|
||||
points.sort((a, b) => (a.d < b.d) ? 1 : -1);
|
||||
|
||||
draw_projected_view();
|
||||
|
||||
draw_static_objects();
|
||||
|
||||
sliderPoint.blit(ctx, 0);
|
||||
|
||||
for(let i = 0; i<points.length; i++) {
|
||||
points[i].blit(ctx);
|
||||
}
|
||||
|
||||
function draw_static_objects() {
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.strokeStyle = creamy_white;
|
||||
ctx.lineWidth = normal_line_width;
|
||||
|
||||
ctx.moveTo(canvas_size[0] - view_width, 0);
|
||||
ctx.lineTo(canvas_size[0] - view_width, canvas_size[1])
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.strokeStyle = creamy_gray_dark;
|
||||
ctx.lineWidth = thin_line_width;
|
||||
|
||||
ctx.moveTo(50, slider_padding_top_bottom);
|
||||
|
||||
ctx.lineTo(50, canvas_size[1] - slider_padding_top_bottom);
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.strokeStyle = creamy_white;
|
||||
|
||||
ctx.moveTo(player_pos[0], player_pos[1]);
|
||||
|
||||
ctx.lineTo(player_pos[0] - projection_size[0], player_pos[1] - (projection_size[1] / 2));
|
||||
ctx.lineTo(player_pos[0] - projection_size[0], player_pos[1] + (projection_size[1] / 2));
|
||||
ctx.lineTo(player_pos[0], player_pos[1]);
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.fillStyle = green;
|
||||
ctx.arc(player_pos[0], player_pos[1], 20, 0, TAU);
|
||||
|
||||
ctx.fill();
|
||||
|
||||
}
|
||||
|
||||
function draw_projected_view() {
|
||||
ctx.lineWidth = normal_line_width;
|
||||
|
||||
for (var i = 0; i < points.length; ++i) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = rgb_to_hex(points[i].shaded_color[0], points[i].shaded_color[1], points[i].shaded_color[2]);
|
||||
|
||||
let projected_pos = points[i].get_projected_positions(player_pos, projection_size, canvas_size[1]);
|
||||
|
||||
ctx.moveTo(canvas_size[0] - view_width, projected_pos);
|
||||
ctx.lineTo(canvas_size[0], projected_pos);
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function clear_canvas () {
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.fillStyle = "#282828";
|
||||
ctx.fillRect(0, 0, canvas_size[0], canvas_size[1]);
|
||||
}
|
||||
|
||||
function draw_all () {
|
||||
clear_canvas();
|
||||
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
points[i].rotate(alpha);
|
||||
points[i].shade(100, 100, 400);
|
||||
points[i].find_d(player_pos);
|
||||
points[i].draw_line_to_player(ctx, player_pos);
|
||||
}
|
||||
|
||||
points.sort((a, b) => (a.d < b.d) ? 1 : -1);
|
||||
|
||||
draw_projected_view();
|
||||
|
||||
draw_static_objects();
|
||||
|
||||
sliderPoint.blit(ctx, sliderMode);
|
||||
|
||||
for(let i = 0; i<points.length; i++) {
|
||||
points[i].blit(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
$(".c").mousemove(function(event){
|
||||
|
||||
let mouse_pos = get_mouse_pos(event);
|
||||
|
||||
if (mousedown && on_slider) {
|
||||
sliderMode = 2;
|
||||
sliderPoint.set_y(mouse_pos[1]);
|
||||
console.log(sliderPoint.y);
|
||||
alpha = slider_angle * sliderPoint.get_progress();
|
||||
} else if (sliderPoint.collidepoint(mouse_pos[0], mouse_pos[1])) {
|
||||
sliderMode = 1;
|
||||
} else {
|
||||
sliderMode = 0;
|
||||
}
|
||||
|
||||
draw_all();
|
||||
});
|
||||
|
||||
$(".c").mousedown(function(event){
|
||||
let mouse_pos = get_mouse_pos(event);
|
||||
|
||||
mousedown = true;
|
||||
|
||||
if (sliderPoint.collidepoint(mouse_pos[0], mouse_pos[1])) {
|
||||
on_slider = true;
|
||||
sliderMode = 2;
|
||||
|
||||
draw_all();
|
||||
}
|
||||
});
|
||||
|
||||
$("body").mouseup(function(event) {
|
||||
let mouse_pos = get_mouse_pos(event);
|
||||
mousedown = false;
|
||||
|
||||
if (on_slider) {
|
||||
on_slider = false;
|
||||
sliderMode = 1 * sliderPoint.collidepoint(mouse_pos[0], mouse_pos[1]);
|
||||
draw_all();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// other functions
|
||||
|
||||
function get_mouse_pos(event) {
|
||||
let rect = c.getBoundingClientRect();
|
||||
return [event.clientX - rect.left, event.clientY - rect.top];
|
||||
}
|
||||
|
||||
|
||||
});
|
57
spline scenes/4_d_donut_creation/index.html
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body { width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
background: rgba(25,25,25, 1) }
|
||||
canvas { width: 100%; height: 100%; outline: none; }
|
||||
#container { width: 100%; height: 100%; position: relative; }
|
||||
|
||||
|
||||
.spline-watermark {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.spline-watermark:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.spline-watermark img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>
|
||||
<title>4D donut creation</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="https://spline.design/_assets/_images/icon_favicon16x16.png" sizes="16x16">
|
||||
<link rel="icon" type="image/png" href="https://spline.design/_assets/_images/icon_favicon32x32.png" sizes="32x32">
|
||||
</head>
|
||||
<body>
|
||||
<div id='container'>
|
||||
<canvas id="canvas3d"></canvas>
|
||||
|
||||
<a class="spline-watermark" href="https://spline.design">
|
||||
<img src="https://spline.design/_assets/_images/icon_favicon32x32.png">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/three@0.131.3/build/three.min.js"></script>
|
||||
<script src="js/spline.runtime.min.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
4
spline scenes/4_d_donut_creation/js/main.js
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
const app = new SpeRuntime.Application();
|
||||
app.start('./scene.json');
|
||||
|
27
spline scenes/4_d_donut_creation/js/spline.runtime.min.js
vendored
Normal file
1
spline scenes/4_d_donut_creation/scene.json
Normal file
55
styles/_classes.sass
Normal file
@ -0,0 +1,55 @@
|
||||
@import ./_variables
|
||||
@import ./_mixins
|
||||
|
||||
.title
|
||||
text-align: center
|
||||
margin-top: 2%
|
||||
margin-bottom: 2%
|
||||
font-size: 60px
|
||||
width: 100%
|
||||
color: $text_color_0
|
||||
|
||||
.a
|
||||
margin: 0% 5% 5% 5%
|
||||
padding: 2%
|
||||
border-radius: 10px
|
||||
background-color: $primary_light
|
||||
box-shadow:: 5px 5px 12px #141414
|
||||
|
||||
.normal_text
|
||||
@include normal_text
|
||||
background-color: $primary_light
|
||||
|
||||
.highlight_text
|
||||
@include highlight_text
|
||||
background-color: $primary_light
|
||||
|
||||
.mtop
|
||||
margin-top: $mtop
|
||||
|
||||
.mleft
|
||||
margin-left: $mleft
|
||||
|
||||
.normal_image
|
||||
margin-top: $mtop + $image_margins_size
|
||||
margin-bottom: $image_margins_size
|
||||
box-shadow: 10px 10px 24px #111
|
||||
|
||||
.normal_video
|
||||
margin-top: $mtop + $video_margins_size
|
||||
margin-bottom: $video_margins_size
|
||||
box-shadow: 10px 10px 24px #111
|
||||
|
||||
.row
|
||||
margin-top: $mtop
|
||||
display: flex
|
||||
justify-content: space-around
|
||||
flex-direction: row
|
||||
border-radius: 10px
|
||||
|
||||
.spline_scene
|
||||
margin-top: $mtop + $spline_scene_margins_size
|
||||
margin-bottom: $spline_scene_margins_size
|
||||
box-shadow: 10px 10px 24px #111
|
||||
width: 1000px
|
||||
height: 600px
|
12
styles/_main_tags.sass
Normal file
@ -0,0 +1,12 @@
|
||||
@import ./_variables
|
||||
|
||||
nav
|
||||
width: 100%
|
||||
height: 30px
|
||||
box-shadow: 0px 0px 20px #000
|
||||
background-color: $primary_dark
|
||||
|
||||
canvas
|
||||
margin-top: $mtop + $canvas_margins_size
|
||||
margin-bottom: $canvas_margins_size
|
||||
box-shadow: 10px 10px 24px #111
|
21
styles/_mixins.sass
Normal file
@ -0,0 +1,21 @@
|
||||
@import ./_variables
|
||||
|
||||
|
||||
@mixin smaller_text
|
||||
font-size: $smaller_text_font_size
|
||||
color: text_color_0
|
||||
font-family: Arial, Helvetica, sans-ser
|
||||
letter-spacing: 0.6px
|
||||
|
||||
|
||||
@mixin normal_text
|
||||
font-size: $normal_text_font_size
|
||||
color: $text_color_0
|
||||
font-family: Arial, Helvetica, sans-ser
|
||||
letter-spacing: 2px
|
||||
|
||||
@mixin highlight_text
|
||||
font-size: $highlight_text_font_size
|
||||
color: $text_color_1
|
||||
font-family: Arial, Helvetica, sans-serif
|
||||
letter-spacing: 1px
|
19
styles/_variables.sass
Normal file
@ -0,0 +1,19 @@
|
||||
$primary: #282828
|
||||
$primary_dark: #895d5d
|
||||
$primary_light: #313131
|
||||
|
||||
$scrollbar_track_color: #373737
|
||||
$scrollbar_thumb_color: #4b4b4b
|
||||
|
||||
$text_color_0: #d2d2d2
|
||||
$text_color_1: #e3e3e3
|
||||
$small_text_font_size: 22px
|
||||
$normal_text_font_size: 26px
|
||||
$highlight_text_font_size: 34px
|
||||
$mtop: 1.2%
|
||||
$mleft: 1.2%
|
||||
|
||||
$image_margins_size: 1.2%
|
||||
$video_margins_size: 1.2%
|
||||
$canvas_margins_size: 1.2%
|
||||
$spline_scene_margins_size: 1.2%
|
117
styles/style.css
Normal file
@ -0,0 +1,117 @@
|
||||
nav {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
-webkit-box-shadow: 0px 0px 20px #000;
|
||||
box-shadow: 0px 0px 20px #000;
|
||||
background-color: #895d5d;
|
||||
}
|
||||
|
||||
canvas {
|
||||
margin-top: 2.4%;
|
||||
margin-bottom: 1.2%;
|
||||
-webkit-box-shadow: 10px 10px 24px #111;
|
||||
box-shadow: 10px 10px 24px #111;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
margin-top: 2%;
|
||||
margin-bottom: 2%;
|
||||
font-size: 60px;
|
||||
width: 100%;
|
||||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
.a {
|
||||
margin: 0% 5% 5% 5%;
|
||||
padding: 2%;
|
||||
border-radius: 10px;
|
||||
background-color: #313131;
|
||||
-webkit-box-shadow: 5px 5px 12px #141414;
|
||||
box-shadow: 5px 5px 12px #141414;
|
||||
}
|
||||
|
||||
.normal_text {
|
||||
font-size: 26px;
|
||||
color: #d2d2d2;
|
||||
font-family: Arial, Helvetica, sans-ser;
|
||||
letter-spacing: 2px;
|
||||
background-color: #313131;
|
||||
}
|
||||
|
||||
.highlight_text {
|
||||
font-size: 34px;
|
||||
color: #e3e3e3;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
letter-spacing: 1px;
|
||||
background-color: #313131;
|
||||
}
|
||||
|
||||
.mtop {
|
||||
margin-top: 1.2%;
|
||||
}
|
||||
|
||||
.mleft {
|
||||
margin-left: 1.2%;
|
||||
}
|
||||
|
||||
.normal_image {
|
||||
margin-top: 2.4%;
|
||||
margin-bottom: 1.2%;
|
||||
-webkit-box-shadow: 10px 10px 24px #111;
|
||||
box-shadow: 10px 10px 24px #111;
|
||||
}
|
||||
|
||||
.normal_video {
|
||||
margin-top: 2.4%;
|
||||
margin-bottom: 1.2%;
|
||||
-webkit-box-shadow: 10px 10px 24px #111;
|
||||
box-shadow: 10px 10px 24px #111;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-top: 1.2%;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-pack: distribute;
|
||||
justify-content: space-around;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.spline_scene {
|
||||
margin-top: 2.4%;
|
||||
margin-bottom: 1.2%;
|
||||
-webkit-box-shadow: 10px 10px 24px #111;
|
||||
box-shadow: 10px 10px 24px #111;
|
||||
width: 1000px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
* {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
background-color: #282828;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #373737;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #4b4b4b;
|
||||
}
|
||||
/*# sourceMappingURL=style.css.map */
|
18
styles/style.css.map
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": 3,
|
||||
"mappings": "ACEA,AAAA,GAAG,CAAC;EACA,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,iBAAiB;EAC7B,gBAAgB,ECLL,OAAO;CDKgB;;AAEtC,AAAA,MAAM,CAAC;EACH,UAAU,EAAE,IAA4B;EACxC,aAAa,ECOK,IAAI;EDNtB,UAAU,EAAE,mBAAmB;CAAG;;AERtC,AAAA,MAAM,CAAC;EACH,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,EAAE;EACd,aAAa,EAAE,EAAE;EACjB,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,IAAI;EACX,KAAK,EDFM,OAAO;CCEK;;AAE3B,AAAA,EAAE,CAAC;EACC,MAAM,EAAE,WAAW;EACnB,OAAO,EAAE,EAAE;EACX,aAAa,EAAE,IAAI;EACnB,gBAAgB,EDbJ,OAAO;ECcnB,UAAU,EAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO;CAAK;;AAE1C,AAAA,YAAY,CAAC;EEPT,SAAS,EHDW,IAAI;EGExB,KAAK,EHLM,OAAO;EGMlB,WAAW,EAAE,0BAA0B;EACvC,cAAc,EAAE,GAAG;EFMnB,gBAAgB,EDlBJ,OAAO;CCkBgB;;AAEvC,AAAA,eAAe,CAAC;EELZ,SAAS,EHNc,IAAI;EGO3B,KAAK,EHVM,OAAO;EGWlB,WAAW,EAAE,4BAA4B;EACzC,cAAc,EAAE,GAAG;EFInB,gBAAgB,EDtBJ,OAAO;CCsBgB;;AAEvC,AAAA,KAAK,CAAC;EACF,UAAU,EDfP,IAAI;CCea;;AAExB,AAAA,MAAM,CAAC;EACH,WAAW,EDjBP,IAAI;CCiBc;;AAE1B,AAAA,aAAa,CAAC;EACV,UAAU,EAAE,IAA2B;EACvC,aAAa,EDnBI,IAAI;ECoBrB,UAAU,EAAE,mBAAmB;CAAG;;AAEtC,AAAA,aAAa,CAAC;EACV,UAAU,EAAE,IAA2B;EACvC,aAAa,EDvBI,IAAI;ECwBrB,UAAU,EAAE,mBAAmB;CAAG;;AAEtC,AAAA,IAAI,CAAC;EACD,UAAU,ED/BP,IAAI;ECgCP,OAAO,EAAE,IAAI;EACb,eAAe,EAAE,YAAY;EAC7B,cAAc,EAAE,GAAG;EACnB,aAAa,EAAE,IAAI;CAAG;;AAE1B,AAAA,aAAa,CAAC;EACV,UAAU,EAAE,IAAkC;EAC9C,aAAa,EDjCW,IAAI;ECkC5B,UAAU,EAAE,mBAAmB;EAC/B,KAAK,EAAE,MAAM;EACb,MAAM,EAAE,KAAK;CAAG;;AHjDpB,AAAA,CAAC,CAAC;EACE,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,GAAG;EACX,WAAW,EAAE,IAAI;EACjB,gBAAgB,EETV,OAAO;EFUb,WAAW,EAAE,GAAG;CAAG;;AAEvB,AAAA,mBAAmB,CAAC;EAChB,KAAK,EAAE,IAAI;CAAG;;AAElB,AAAA,yBAAyB,CAAC;EACtB,gBAAgB,EEZI,OAAO;CFYgB;;AAE/C,AAAA,yBAAyB,CAAC;EACtB,gBAAgB,EEdI,OAAO;CFcgB",
|
||||
"sources": [
|
||||
"style.sass",
|
||||
"_main_tags.sass",
|
||||
"_variables.sass",
|
||||
"_classes.sass",
|
||||
"_variables.sass",
|
||||
"_mixins.sass",
|
||||
"_variables.sass",
|
||||
"_variables.sass",
|
||||
"_mixins.sass",
|
||||
"_variables.sass"
|
||||
],
|
||||
"names": [],
|
||||
"file": "style.css"
|
||||
}
|
20
styles/style.sass
Normal file
@ -0,0 +1,20 @@
|
||||
@import ./_main_tags
|
||||
@import ./_classes
|
||||
@import ./_variables
|
||||
@import ./_mixins
|
||||
|
||||
*
|
||||
padding: 0px
|
||||
margin: 0px
|
||||
user-select: none
|
||||
background-color: $primary
|
||||
line-height: 1.3
|
||||
|
||||
::-webkit-scrollbar
|
||||
width: 10px
|
||||
|
||||
::-webkit-scrollbar-track
|
||||
background-color: $scrollbar_track_color
|
||||
|
||||
::-webkit-scrollbar-thumb
|
||||
background-color: $scrollbar_thumb_color
|