Cubes | #Game Engine | simple voxel game featuring single player

 by   ictrobot Java Updated: 8 months ago - v0.0.6 License: MIT

Download this library from

Build Applications

kandi X-RAY | Cubes REVIEW AND RATINGS

A simple voxel game featuring single player, multiplayer and endless procedurally generated terrain

kandi-support
Support

  • Cubes has a low active ecosystem.
  • It has 22 star(s) with 5 fork(s).
  • It had no major release in the last 12 months.
  • It has a neutral sentiment in the developer community.

quality kandi
Quality

  • Cubes has no issues reported.

security
Security

  • Cubes has no vulnerabilities reported, and its dependent libraries have no vulnerabilities reported.

license
License

  • Cubes is licensed under the MIT License. This license is Permissive.
  • Permissive licenses have the least restrictions, and you can use them in most projects.

build
Reuse

  • Cubes releases are available to install and integrate.
  • Build file is available. You can build the component from source.
Top functions reviewed by kandi - BETA

kandi has reviewed Cubes and discovered the below as its top functions. This is intended to give you an instant insight into Cubes implemented functionality, and help decide if they suit your requirements.

  • Returns the value of the given x - axis .
  • Writes the specified font to the output file .
  • Calculates the intersection of two blocks .
  • Initialize the block area map .
  • Gets the globals .
  • Render the icons of the Cubes
  • Generate random rooms .
  • Parses the command line arguments .
  • Add a new block .
  • Generate a tree

Cubes Key Features

A simple voxel game featuring single player, multiplayer and endless procedurally generated terrain

Cubes examples and code snippets

  • default
  • Optimize c++ Monte Carlo simulation with long dynamic arrays
  • Vector attraction when mouse pressed
  • Three.js: Cannot display mesh created with texture array
  • How to limit the number of total animated drop cubes and make them animate by their added order?
  • Are OpenGL ordered as viewed by an internal or external viewer?
  • How can I rotate the capsule to look at the next position while reaching the current position?
  • What decides the calling order of OnCollisionEnter(other) in Unity?
  • 3D Rotation warps cube
  • Python voxelfuse can only concatenate str (not "int") to str
  • How can I move a cube between other targets in different ways between each one?

default

![Screenshot 1](/screenshots/screenshot1.png)
![Screenshot 2](/screenshots/screenshot2.png)

Mods
--------
For sample json and lua mods, see mod_sample/json and mod_sample/lua respectively. [CubesSampleMod](https://github.com/ictrobot/CubesSampleMod) is a sample java mod, which uses [CubesModPlugin](https://github.com/ictrobot/CubesModPlugin), a gradle plugin to build .cm files automatically. [CubesEquationTerrainGenerator](https://github.com/ictrobot/CubesEquationTerrainGenerator) is an example of a mod that actually does something (add terrain generators based off mathematical expressions).


Launcher

Optimize c++ Monte Carlo simulation with long dynamic arrays

  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);
-----------------------
  mt19937 rng(127386261); //I want a deterministic seed
#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat
if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}
double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}
 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){
const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){
const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;
if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}
const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}
cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);

Vector attraction when mouse pressed

let cubes = [];

function setup() {
  /* max(...) here is just for rendering with minimum size in the snippet */
  createCanvas(max(windowWidth, 800), max(windowHeight, 600), WEBGL);
  backCol = color(243, 243, 243);
 
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      let xPos = map(i, 0, 9, 50, width - 50);
      let yPos = map(j, 0, 9, 50, height - 50);
      cubes.push(new Cubes(xPos, yPos));
    }
  }
}

function draw() {
  background(backCol);
  noFill();
  for (let cube of cubes) {
    cube.update();
  } 
  attracting();
}

function attracting() {
  /* changed to check for mouse pressed once for all cubes */
  if (mouseIsPressed) {
    /* generating mouse position vector once for all cubes */
    const mousePosVect = new p5.Vector(mouseX, mouseY);
    for (let a = 0; a < cubes.length; a++) {
      cubes[a].attraction(mousePosVect);
    }
  }
}

class Cubes {

  constructor(x, y) {
    /* Removed useless and confusing this.x, this.y */
    this.size = 30;
    this.stroke = 70;
    this.gap = 150;
    this.shift1 = color(96);
    this.shift2 = color(244);
 
    //vector variables
    this.pos = createVector(x, y);
    this.vel = createVector(); 
    this.acc = createVector();
  }

  update() {
    this.test_Color();
    
    //attraction values
    this.vel.add(this.acc);
    this.vel.limit(5);
    this.pos.add(this.vel);
    this.acc.mult(0);
    this.shape();
  }
  
  shape() {
    push();
    stroke(this.stroke);
    this.test_Color();
    /* Used this.pos instead of this.x, this.y for positioning */
    translate(this.pos.x - width / 2, this.pos.y - height / 2, 0);
    this.test_rotation();
    box(this.size);
    pop();
  }

  test_Color() {
    fill(this.shift1);
  }

  test_rotation() {               
    rotateX(frameCount / 60);
    rotateY(frameCount / 60);
  }
  
  attraction(targetVector) {
    //all cubes supposed to attract towards the mouse when pressed

    /* Set target argument to vector,
     * moved the `if (mouseIsPressed)` condition outside */
    let force = p5.Vector.sub(targetVector,this.pos);
    let d = force.mag();
    d = constrain(d, 1, 25);
    var G = 50;
    var strength = G / (d * d);
    force.setMag(strength);
    if (d < 20) {
      force.mult(10);
    }
    /* changed to add force to acceleration
     * instead of velocity (physically accurate) */
    this.acc.add(force);  
  }
}
<!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">
        <title>P5 cube attractor</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js" integrity="sha512-gQVBYBvfC+uyor5Teonjr9nmY1bN+DlOCezkhzg4ShpC5q81ogvFsr5IV4xXAj6HEtG7M1Pb2JCha97tVFItYQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    </head>
    <body>
        <!--h1>P5 test</h1-->
    </body>
</html>
-----------------------
let cubes = [];

function setup() {
  /* max(...) here is just for rendering with minimum size in the snippet */
  createCanvas(max(windowWidth, 800), max(windowHeight, 600), WEBGL);
  backCol = color(243, 243, 243);
 
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      let xPos = map(i, 0, 9, 50, width - 50);
      let yPos = map(j, 0, 9, 50, height - 50);
      cubes.push(new Cubes(xPos, yPos));
    }
  }
}

function draw() {
  background(backCol);
  noFill();
  for (let cube of cubes) {
    cube.update();
  } 
  attracting();
}

function attracting() {
  /* changed to check for mouse pressed once for all cubes */
  if (mouseIsPressed) {
    /* generating mouse position vector once for all cubes */
    const mousePosVect = new p5.Vector(mouseX, mouseY);
    for (let a = 0; a < cubes.length; a++) {
      cubes[a].attraction(mousePosVect);
    }
  }
}

class Cubes {

  constructor(x, y) {
    /* Removed useless and confusing this.x, this.y */
    this.size = 30;
    this.stroke = 70;
    this.gap = 150;
    this.shift1 = color(96);
    this.shift2 = color(244);
 
    //vector variables
    this.pos = createVector(x, y);
    this.vel = createVector(); 
    this.acc = createVector();
  }

  update() {
    this.test_Color();
    
    //attraction values
    this.vel.add(this.acc);
    this.vel.limit(5);
    this.pos.add(this.vel);
    this.acc.mult(0);
    this.shape();
  }
  
  shape() {
    push();
    stroke(this.stroke);
    this.test_Color();
    /* Used this.pos instead of this.x, this.y for positioning */
    translate(this.pos.x - width / 2, this.pos.y - height / 2, 0);
    this.test_rotation();
    box(this.size);
    pop();
  }

  test_Color() {
    fill(this.shift1);
  }

  test_rotation() {               
    rotateX(frameCount / 60);
    rotateY(frameCount / 60);
  }
  
  attraction(targetVector) {
    //all cubes supposed to attract towards the mouse when pressed

    /* Set target argument to vector,
     * moved the `if (mouseIsPressed)` condition outside */
    let force = p5.Vector.sub(targetVector,this.pos);
    let d = force.mag();
    d = constrain(d, 1, 25);
    var G = 50;
    var strength = G / (d * d);
    force.setMag(strength);
    if (d < 20) {
      force.mult(10);
    }
    /* changed to add force to acceleration
     * instead of velocity (physically accurate) */
    this.acc.add(force);  
  }
}
<!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">
        <title>P5 cube attractor</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js" integrity="sha512-gQVBYBvfC+uyor5Teonjr9nmY1bN+DlOCezkhzg4ShpC5q81ogvFsr5IV4xXAj6HEtG7M1Pb2JCha97tVFItYQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    </head>
    <body>
        <!--h1>P5 test</h1-->
    </body>
</html>

Three.js: Cannot display mesh created with texture array

uv_bottom: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_side: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_top: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
if (this.blockEmpty(x, z+1, y))
{
    this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
    this.uv.push(this.structure[x][z][y].uv_side);
}
public generateTerrain (): THREE.Mesh
{
    this.terrain = new Array<THREE.BufferGeometry>();

    for (let x = 0; x < Chunk.base; x++)
        for (let z = 0; z < Chunk.base; z++)
            for (let y = 0; y < Chunk.build_height; y++)
                if (!this.structure[x][z][y].attrs.empty)
                    this.generateBlockFaces(x, z, y);

    const geometry = BufferGeometryUtils.mergeBufferGeometries(this.terrain);
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv.flat()), 2));

    return new THREE.Mesh(geometry, Textures.material);
}
import * as THREE from 'three';

export default class Textures
{
    private static readonly loader = new THREE.TextureLoader();

    public static readonly rows = 3;
    public static readonly cols = 2;

    public static readonly atlas    = Textures.loader.load("/tex/atlas.png");
    public static readonly material = new THREE.MeshBasicMaterial({map: Textures.atlas});
}

Textures.atlas.magFilter = THREE.NearestFilter;
Textures.atlas.minFilter = THREE.NearestFilter;
-----------------------
uv_bottom: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_side: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_top: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
if (this.blockEmpty(x, z+1, y))
{
    this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
    this.uv.push(this.structure[x][z][y].uv_side);
}
public generateTerrain (): THREE.Mesh
{
    this.terrain = new Array<THREE.BufferGeometry>();

    for (let x = 0; x < Chunk.base; x++)
        for (let z = 0; z < Chunk.base; z++)
            for (let y = 0; y < Chunk.build_height; y++)
                if (!this.structure[x][z][y].attrs.empty)
                    this.generateBlockFaces(x, z, y);

    const geometry = BufferGeometryUtils.mergeBufferGeometries(this.terrain);
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv.flat()), 2));

    return new THREE.Mesh(geometry, Textures.material);
}
import * as THREE from 'three';

export default class Textures
{
    private static readonly loader = new THREE.TextureLoader();

    public static readonly rows = 3;
    public static readonly cols = 2;

    public static readonly atlas    = Textures.loader.load("/tex/atlas.png");
    public static readonly material = new THREE.MeshBasicMaterial({map: Textures.atlas});
}

Textures.atlas.magFilter = THREE.NearestFilter;
Textures.atlas.minFilter = THREE.NearestFilter;
-----------------------
uv_bottom: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_side: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_top: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
if (this.blockEmpty(x, z+1, y))
{
    this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
    this.uv.push(this.structure[x][z][y].uv_side);
}
public generateTerrain (): THREE.Mesh
{
    this.terrain = new Array<THREE.BufferGeometry>();

    for (let x = 0; x < Chunk.base; x++)
        for (let z = 0; z < Chunk.base; z++)
            for (let y = 0; y < Chunk.build_height; y++)
                if (!this.structure[x][z][y].attrs.empty)
                    this.generateBlockFaces(x, z, y);

    const geometry = BufferGeometryUtils.mergeBufferGeometries(this.terrain);
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv.flat()), 2));

    return new THREE.Mesh(geometry, Textures.material);
}
import * as THREE from 'three';

export default class Textures
{
    private static readonly loader = new THREE.TextureLoader();

    public static readonly rows = 3;
    public static readonly cols = 2;

    public static readonly atlas    = Textures.loader.load("/tex/atlas.png");
    public static readonly material = new THREE.MeshBasicMaterial({map: Textures.atlas});
}

Textures.atlas.magFilter = THREE.NearestFilter;
Textures.atlas.minFilter = THREE.NearestFilter;
-----------------------
uv_bottom: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_side: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_top: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
if (this.blockEmpty(x, z+1, y))
{
    this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
    this.uv.push(this.structure[x][z][y].uv_side);
}
public generateTerrain (): THREE.Mesh
{
    this.terrain = new Array<THREE.BufferGeometry>();

    for (let x = 0; x < Chunk.base; x++)
        for (let z = 0; z < Chunk.base; z++)
            for (let y = 0; y < Chunk.build_height; y++)
                if (!this.structure[x][z][y].attrs.empty)
                    this.generateBlockFaces(x, z, y);

    const geometry = BufferGeometryUtils.mergeBufferGeometries(this.terrain);
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv.flat()), 2));

    return new THREE.Mesh(geometry, Textures.material);
}
import * as THREE from 'three';

export default class Textures
{
    private static readonly loader = new THREE.TextureLoader();

    public static readonly rows = 3;
    public static readonly cols = 2;

    public static readonly atlas    = Textures.loader.load("/tex/atlas.png");
    public static readonly material = new THREE.MeshBasicMaterial({map: Textures.atlas});
}

Textures.atlas.magFilter = THREE.NearestFilter;
Textures.atlas.minFilter = THREE.NearestFilter;
-----------------------
const materials = [
  new THREE.MeshBasicMaterial( { color: 'red' } ),
  new THREE.MeshBasicMaterial( { color: 'blue' } )
];

const geometries = [
  new THREE.PlaneGeometry( 1, 1 ),
  new THREE.PlaneGeometry( 1, 1 )
];
geometries[ 1 ].rotateX( Math.PI * -0.5 );

// Add groups that set the materialIndex of each vertex in a group
// For this code all the vertices in each geometry have the same material. 
// If you load in a model that already has multiple textures you don't need to do this.
geometries[ 0 ].addGroup( 0, geometries[0].attributes.position.count, 0 ); 
geometries[ 1 ].addGroup( 0, geometries[1].attributes.position.count, 1 );

// Setting true on the second argument enables groups for the merged geometry.
const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries( geometries, true );

const multiMaterialMesh = new THREE.Mesh( mergedGeometry, materials );
scene.add( multiMaterialMesh );

How to limit the number of total animated drop cubes and make them animate by their added order?

$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>
-----------------------
$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>
-----------------------
$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>
-----------------------
$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>
-----------------------
$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>
-----------------------
$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>

Are OpenGL ordered as viewed by an internal or external viewer?

    0
y    +
^    | \
|    |   \
|    +-----+
    1       2

      ----> x
        0
       +
     / |
   /   |
 +-----+
2       1
-----------------------
    0
y    +
^    | \
|    |   \
|    +-----+
    1       2

      ----> x
        0
       +
     / |
   /   |
 +-----+
2       1

How can I rotate the capsule to look at the next position while reaching the current position?

Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);

newDirection.z = 0f;

capsule.rotation = Quaternion.LookRotation(newDirection, capsule.Up);

What decides the calling order of OnCollisionEnter(other) in Unity?

// Does nothing on its own but holding and providing the state
public class Obstacle : MonoBehaviour
{
    // I would use an enum (or even bool) State instead of tags!
    public enum State
    {
        Unhitted,
        Hitted
    }

    public State state;
}
public class Mover : MonoBehaviour
{
    private int hits = 0;

    private void OnCollisionEnter(Collision collision) 
    {
        Debug.Log("Mover has collision.");
        if (other.TryGetComponent<Obstacle>(out var obstacle) && obstacle.state == Obstacle.State.Unhitted)
        {
            Debug.Log($"The mover has had {++hits} times collision", this);
            obstacle.state = Obstacle.State.Hitted;
        }
    }
}
public class Obstacle : MonoBehaviour
{
    // Just as an example this time I use the bool instead of the enum 
    // again how exactly you check the state is up to you
    // but in my eyes tags is not the best solution
    [SerializeField] private bool hitted;

    private void OnCollisionEnter (Collision collision)
    {
        if(!hitted && other.TryGetComponent<Mover>(out var mover))
        {
            Debug.Log($"The mover has had {++mover.hits} times collision", this);

            hitted = true;
        }
    }
}
// Mover does nothing itself but holding and providing the hit counter
public class Mover : MonoBehaviour
{
    public int hits = 0;
}
-----------------------
// Does nothing on its own but holding and providing the state
public class Obstacle : MonoBehaviour
{
    // I would use an enum (or even bool) State instead of tags!
    public enum State
    {
        Unhitted,
        Hitted
    }

    public State state;
}
public class Mover : MonoBehaviour
{
    private int hits = 0;

    private void OnCollisionEnter(Collision collision) 
    {
        Debug.Log("Mover has collision.");
        if (other.TryGetComponent<Obstacle>(out var obstacle) && obstacle.state == Obstacle.State.Unhitted)
        {
            Debug.Log($"The mover has had {++hits} times collision", this);
            obstacle.state = Obstacle.State.Hitted;
        }
    }
}
public class Obstacle : MonoBehaviour
{
    // Just as an example this time I use the bool instead of the enum 
    // again how exactly you check the state is up to you
    // but in my eyes tags is not the best solution
    [SerializeField] private bool hitted;

    private void OnCollisionEnter (Collision collision)
    {
        if(!hitted && other.TryGetComponent<Mover>(out var mover))
        {
            Debug.Log($"The mover has had {++mover.hits} times collision", this);

            hitted = true;
        }
    }
}
// Mover does nothing itself but holding and providing the hit counter
public class Mover : MonoBehaviour
{
    public int hits = 0;
}
-----------------------
// Does nothing on its own but holding and providing the state
public class Obstacle : MonoBehaviour
{
    // I would use an enum (or even bool) State instead of tags!
    public enum State
    {
        Unhitted,
        Hitted
    }

    public State state;
}
public class Mover : MonoBehaviour
{
    private int hits = 0;

    private void OnCollisionEnter(Collision collision) 
    {
        Debug.Log("Mover has collision.");
        if (other.TryGetComponent<Obstacle>(out var obstacle) && obstacle.state == Obstacle.State.Unhitted)
        {
            Debug.Log($"The mover has had {++hits} times collision", this);
            obstacle.state = Obstacle.State.Hitted;
        }
    }
}
public class Obstacle : MonoBehaviour
{
    // Just as an example this time I use the bool instead of the enum 
    // again how exactly you check the state is up to you
    // but in my eyes tags is not the best solution
    [SerializeField] private bool hitted;

    private void OnCollisionEnter (Collision collision)
    {
        if(!hitted && other.TryGetComponent<Mover>(out var mover))
        {
            Debug.Log($"The mover has had {++mover.hits} times collision", this);

            hitted = true;
        }
    }
}
// Mover does nothing itself but holding and providing the hit counter
public class Mover : MonoBehaviour
{
    public int hits = 0;
}
-----------------------
// Does nothing on its own but holding and providing the state
public class Obstacle : MonoBehaviour
{
    // I would use an enum (or even bool) State instead of tags!
    public enum State
    {
        Unhitted,
        Hitted
    }

    public State state;
}
public class Mover : MonoBehaviour
{
    private int hits = 0;

    private void OnCollisionEnter(Collision collision) 
    {
        Debug.Log("Mover has collision.");
        if (other.TryGetComponent<Obstacle>(out var obstacle) && obstacle.state == Obstacle.State.Unhitted)
        {
            Debug.Log($"The mover has had {++hits} times collision", this);
            obstacle.state = Obstacle.State.Hitted;
        }
    }
}
public class Obstacle : MonoBehaviour
{
    // Just as an example this time I use the bool instead of the enum 
    // again how exactly you check the state is up to you
    // but in my eyes tags is not the best solution
    [SerializeField] private bool hitted;

    private void OnCollisionEnter (Collision collision)
    {
        if(!hitted && other.TryGetComponent<Mover>(out var mover))
        {
            Debug.Log($"The mover has had {++mover.hits} times collision", this);

            hitted = true;
        }
    }
}
// Mover does nothing itself but holding and providing the hit counter
public class Mover : MonoBehaviour
{
    public int hits = 0;
}

3D Rotation warps cube

    x = v.x * cosZ - v.y * sinZ;
    y = v.y * cosZ + v.x * sinZ;

    v.x = x;
    v.y = y;

Python voxelfuse can only concatenate str (not &quot;int&quot;) to str

for tile in tiles:
    cubes.append(cuboid((6,18,6),(int(tile['x']),1,int(tile['y'])),2))

How can I move a cube between other targets in different ways between each one?

targetPosition = targets[targetIndex]; 
if (targetIndex == 0) // do lerp or in a switch case
private Vector3 startingPosition = Vector3.zero;
private int targetIndex = 0;
private float lerpT = 0;

void Start()
{
    targetIndex = -1;
    SetNextTarget();
}
void Update()
{
    switch (targetIndex)
    {
        case 0: UpdateLerp(); break;
        case 1: UpdateMoveTowards(); break;
        case 2: UpdateSmoothDamp(); break;
    }
}
void UpdateLerp()
{
    lerpT += Time.deltaTime * speed;

    if (lerpT > 1)
        lerpT = 1;

    transform.position = Vector3.Lerp(startingPosition, target, lerpT);
    
    if (lerpT == 1)
    {
        SetNextTarget();
    }
}
void UpdateMoveTowards()
{
    transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

    if (Vector3.Distance(transform.position, target) <= Mathf.Epsilon)
    {
        SetNextTarget();
    }
}
void UpdateSmoothDamp()
{
    // Using the examples, fill in this one with the smooth damp version of movement
}
void SetNextTarget()
{
    targetIndex++;
    target = targets[targetIndex];
    startingPosition = transform.position;
}
-----------------------
targetPosition = targets[targetIndex]; 
if (targetIndex == 0) // do lerp or in a switch case
private Vector3 startingPosition = Vector3.zero;
private int targetIndex = 0;
private float lerpT = 0;

void Start()
{
    targetIndex = -1;
    SetNextTarget();
}
void Update()
{
    switch (targetIndex)
    {
        case 0: UpdateLerp(); break;
        case 1: UpdateMoveTowards(); break;
        case 2: UpdateSmoothDamp(); break;
    }
}
void UpdateLerp()
{
    lerpT += Time.deltaTime * speed;

    if (lerpT > 1)
        lerpT = 1;

    transform.position = Vector3.Lerp(startingPosition, target, lerpT);
    
    if (lerpT == 1)
    {
        SetNextTarget();
    }
}
void UpdateMoveTowards()
{
    transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

    if (Vector3.Distance(transform.position, target) <= Mathf.Epsilon)
    {
        SetNextTarget();
    }
}
void UpdateSmoothDamp()
{
    // Using the examples, fill in this one with the smooth damp version of movement
}
void SetNextTarget()
{
    targetIndex++;
    target = targets[targetIndex];
    startingPosition = transform.position;
}
-----------------------
targetPosition = targets[targetIndex]; 
if (targetIndex == 0) // do lerp or in a switch case
private Vector3 startingPosition = Vector3.zero;
private int targetIndex = 0;
private float lerpT = 0;

void Start()
{
    targetIndex = -1;
    SetNextTarget();
}
void Update()
{
    switch (targetIndex)
    {
        case 0: UpdateLerp(); break;
        case 1: UpdateMoveTowards(); break;
        case 2: UpdateSmoothDamp(); break;
    }
}
void UpdateLerp()
{
    lerpT += Time.deltaTime * speed;

    if (lerpT > 1)
        lerpT = 1;

    transform.position = Vector3.Lerp(startingPosition, target, lerpT);
    
    if (lerpT == 1)
    {
        SetNextTarget();
    }
}
void UpdateMoveTowards()
{
    transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

    if (Vector3.Distance(transform.position, target) <= Mathf.Epsilon)
    {
        SetNextTarget();
    }
}
void UpdateSmoothDamp()
{
    // Using the examples, fill in this one with the smooth damp version of movement
}
void SetNextTarget()
{
    targetIndex++;
    target = targets[targetIndex];
    startingPosition = transform.position;
}

COMMUNITY DISCUSSIONS

Top Trending Discussions on Cubes
  • Bind 2 different OLAP Cube results
  • Optimize c++ Monte Carlo simulation with long dynamic arrays
  • Vector attraction when mouse pressed
  • Three.js: Cannot display mesh created with texture array
  • C++ OpenGL stb_image.h errors
  • How to limit the number of total animated drop cubes and make them animate by their added order?
  • Issue with FirstPersonController in Ursina
  • Are OpenGL ordered as viewed by an internal or external viewer?
  • How can I rotate the capsule to look at the next position while reaching the current position?
  • Polygon Z Ordering
Top Trending Discussions on Cubes

QUESTION

Bind 2 different OLAP Cube results

Asked 2021-Jun-11 at 16:08

is there a way to bind 2 OLAP Cubes with the same structure into one? As for now I have big Datasets for past 10 years (20-50 milion records each cube) that is every day processed. For optimalization purposes I want to separate it. For exaple the data for past 8 years will be processed once and the new data will process daily. For it it would need 2 Cubes but can I merge results from it?

Edit. Im reading on blogs and forums about partitioning the data but how does it really work? Would I be able to process only the new data so I dont need to process all 30+ mil rows?

ANSWER

Answered 2021-Jun-11 at 16:08

Processing these partitions is done separately from the cube design. One way to deal with this is by scripting out the commands and running them in a sql agent job:

1- Connect to the ssas instance, browse to the dimensions folder and hit F7 to open the object explorer details window.
2- Highlight all the dimensions, right click and select process enter image description here

3- In the dialogue, select the script button and choose script action to new query window or script action to clipboard and save it someplace. This will be the xmla command to update all the dimensions.

enter image description here

4- Next, navigate to the measure group in which you made the partitions and select the last partition in the group which you want to refresh daily. Right click, select process and use the script option to create an xmla command

enter image description here

5- Next, select the measure group folder and select all the measure groups in the object explorer detail window, except for the partitioned group. Right click, select process and script out the command as in step 3.

6- Now that you have all the commands, add them to a SQL Agent job with 3 xmla command steps, one to process the dimensions and the next two to process the measure groups and most recent partition. Note that if this is running under the sql agent service account, that account will need to have permissions to process the cube.

tip add another job to run on the weekends which does a process full over the whole cube. This is a little cleanup step to make sure everything stays in sync.

Source https://stackoverflow.com/questions/67919938

QUESTION

Optimize c++ Monte Carlo simulation with long dynamic arrays

Asked 2021-Jun-10 at 13:17

This is my first post here and I am not that experienced, so please excuse my ignorance.

I am building a Monte Carlo simulation in C++ for my PhD and I need help in optimizing its computational time and performance. I have a 3d cube repeated in each coordinate as a simulation volume and inside every cube magnetic particles are generated in clusters. Then, in the central cube a loop of protons are created and move and at each step calculate the total magnetic field from all the particles (among other things) that they feel.

At this moment I define everything inside the main function and because I need the position of the particles for my calculations (I calculate the distance between the particles during their placement and also during the proton movement), I store them in dynamic arrays. I haven't used any class or function,yet. This makes my simulations really slow because I have to use eventually millions of particles and thousands of protons. Even with hundreds it needs days. Also I use a lot of for and while loops and reading/writing to .dat files.

I really need your help. I have spent weeks trying to optimize my code and my project is behind schedule. Do you have any suggestion? I need the arrays to store the position of the particles .Do you think classes or functions would be more efficient? Any advice in general is helpful. Sorry if that was too long but I am desperate...

Ok, I edited my original post and I share my full script. I hope this will give you some insight regarding my simulation. Thank you.

Additionally I add the two input files

parametersDiffusion_spher_shel.txt

parametersIONP_spher_shel.txt

#include <stdio.h> 
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <math.h>
#include <iomanip> //precision to output
//#include <time.h>
#include <ctime>
#include <cstdlib>
#include <algorithm>
#include <string>
//#include <complex>
#include <chrono> //random generator
#include <random>

using namespace std;

#define PI 3.14159265
#define tN 500000 //# of timepoints (steps) to define the arrays ONLY
#define D_const 3.0E-9 //diffusion constant (m^2/s)
#define Beq 0.16 // Tesla
#define gI 2.6752218744E8 //(sT)^-1

int main(){

  //Mersenne Twister random engine
  mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  //uniform_int_distribution<int> intDist(0,1);
  uniform_real_distribution<double> realDist(0.,1.);

  //for(int i=1; i<100; i++){
    //cout<<"R max: "<<Ragg-Rspm<<" r_spm: "<<(Ragg-Rspm)*sqrt(realDist(rng))<<endl;
  //}

  /////////////////////////////////////////////////////////////////////////////////////////////////////////
  //input files
  double Rionp=1.0E-8, Ragg=2.0E-7, t_tot=2.0E-2, l_tot = 3.0E-4;
  int ionpN=10, aggN=10,cubAxN=10, parN=1E5;
  int temp_ionpN, temp_aggN, temp_cubAxN, temp_parN;

  ifstream inIONP;

  inIONP.open("parametersIONP_spher_shel.txt");
  if(!inIONP){
    cout << "Unable to open IONP parameters file";
    exit(1); // terminate with error
  }

  while (inIONP>>Rionp>>Ragg>>temp_ionpN>>temp_aggN>>l_tot>>temp_cubAxN) {

  ionpN = (int)temp_ionpN;
  aggN = (int)temp_aggN;
  cubAxN = (int)temp_cubAxN;

  }

  inIONP.close();

  cout<<"Rionp: "<<Rionp<<" ionpN: "<<ionpN <<" aggN: "<<aggN<<endl;
  cout<<"l_tot: "<<l_tot<<" cubAxN: "<<cubAxN<<endl;

  ifstream indiff;

  indiff.open("parametersDiffusion_spher_shel.txt");
  if(!indiff){
    cout << "Unable to open diffusion parameters file";
    exit(1); // terminate with error
  }

  while (indiff>>temp_parN>>t_tot) {

    parN = (int)temp_parN;

  }
  indiff.close();

  cout<<"parN: "<<parN<<" t_tot: "<<t_tot<<endl;

  /////////////////////////////////////////////////////////////////////////////////////////////////
  int cubN = pow(cubAxN,3.); // total cubes
  int Nionp_tot = ionpN*aggN*cubN; //total IONP
  double f_tot = (double)Nionp_tot*(4.*PI*pow(Rionp,3.)/3.)/pow(l_tot,3.);//volume density

  //central cube
  double l_c = l_tot/(double)cubAxN;
  int Nionp_c = ionpN*aggN; //SPM in central cube
  double f_c = (double)Nionp_c*(4.*PI*pow(Rionp,3.)/3.)/pow(l_c,3.);

  cout<<"f_tot: "<<f_tot<<" Nionp_tot: "<<Nionp_tot<<" l_tot "<<l_tot<<endl;
  cout<<"f_c: "<<f_c<<" Nionp_c: "<<Nionp_c<<" l_c "<<l_c<<endl;
  cout<<"Now IONP are generated..."<<endl;

  //position of aggregate (spherical distribution IONP)
  double *x1_ionp, *x2_ionp, *x3_ionp, *theta_ionp, *phi_ionp, *r_ionp, *x1_agg, *x2_agg, *x3_agg;
  x1_ionp = new double [Nionp_tot];
  x2_ionp = new double [Nionp_tot];
  x3_ionp = new double [Nionp_tot];
  theta_ionp = new double [Nionp_tot];
  phi_ionp = new double [Nionp_tot];
  r_ionp = new double [Nionp_tot];
  x1_agg = new double [Nionp_tot];
  x2_agg = new double [Nionp_tot];
  x3_agg = new double [Nionp_tot];

  int ionpCounter = 0;
  int aggCounter = 0;
  double x1_aggTemp=0., x2_aggTemp=0., x3_aggTemp=0.;
  double ionpDist = 0.; //distance SPM-SPM

  for(int a=0; a<cubAxN; a++){ //x1-filling cubes
    for(int b=0; b<cubAxN; b++){ //x2-
      for(int c=0; c<cubAxN; c++){ //x3-

        bool far_ionp = true;

        cout<<"cube: (a, b, c): ("<<a<<", "<<b<<", "<<c<<")"<<endl;

        for(int i=0; i<aggN; i++){ //aggregate iterations
          x1_aggTemp=realDist(rng)*l_c + l_c*a - l_tot/2.; //from neg to pos filling
          x2_aggTemp=realDist(rng)*l_c + l_c*b - l_tot/2.;
          x3_aggTemp=realDist(rng)*l_c + l_c*c - l_tot/2.;

          for(int j=0; j<ionpN; j++){ //SPM iterations
          //  cout<<"SPM: "<<j<<" aggregate: "<<i<<" cube: (a, b, c): ("<<a<<", "<<b<<", "<<c<<")"<<endl;
            x1_agg[ionpCounter]=x1_aggTemp;
            x2_agg[ionpCounter]=x2_aggTemp;
            x3_agg[ionpCounter]=x3_aggTemp;

            //uniform 4pi distribution in sphere
            while(true){
              far_ionp = true; //must be updated!
              theta_ionp[ionpCounter] = 2.*PI*realDist(rng);
              phi_ionp[ionpCounter] = acos(1. - 2.*realDist(rng));
              r_ionp[ionpCounter] = (Ragg-Rionp)*sqrt(realDist(rng)); // to have uniform distribution sqrt
              x1_ionp[ionpCounter] = sin(phi_ionp[ionpCounter])*cos(theta_ionp[ionpCounter])*r_ionp[ionpCounter] + x1_agg[ionpCounter];
              x2_ionp[ionpCounter] = sin(phi_ionp[ionpCounter])*sin(theta_ionp[ionpCounter])*r_ionp[ionpCounter] + x2_agg[ionpCounter];
              x3_ionp[ionpCounter] = cos(phi_ionp[ionpCounter])*r_ionp[ionpCounter] + x3_agg[ionpCounter];

              for(int m=0; m<ionpCounter; m++){ //impenetrable IONP to each other
                ionpDist = sqrt(pow(x1_ionp[m]-x1_ionp[ionpCounter],2.)+pow(x2_ionp[m]-x2_ionp[ionpCounter],2.)+pow(x3_ionp[m]-x3_ionp[ionpCounter],2.));
          //cout<<"spmDist: "<<spmDist<<endl;
                if((j>0) && (ionpDist <= 2*Rionp)){
                  far_ionp = false;
                  cout<<"CLOSE ionp-ionp! Distanse ionp-ionp: "<<ionpDist<<endl;
                }
              }
             if(far_ionp){
               cout<<"IONP can break now! ionpCounter: "<<ionpCounter<<endl;
              break;
             }
           }

           cout<<"r_ionp: "<<r_ionp[ionpCounter]<<" x1_ionp: "<<x1_ionp[ionpCounter]<<" x2_ionp: "<<x2_ionp[ionpCounter]<<" x3_ionp: "<<x3_ionp[ionpCounter]<<endl;
           cout<<"x1_agg: "<<x1_agg[ionpCounter]<<" x2_agg: "<<x2_agg[ionpCounter]<<" x3_agg: "<<x3_agg[ionpCounter]<<endl;

           ionpCounter++;

          }
          aggCounter++;
        }
      }
    }
  }
  cout<<"ionpCounter: "<<ionpCounter<<" aggCounter: "<<aggCounter<<endl;

  //=====proton diffusion=============//

  //outfile
  //proton diffusion time-positionSPM_uniform
  FILE *outP_tPos;
  outP_tPos = fopen("V3_MAT_positionProtons_spherical.dat","wb+");
  if(!outP_tPos){// file couldn't be opened
    cerr << "Error: file could not be opened" << endl;
    exit(1);
  }

  //proton diffusion time-positionSPM_uniform
  FILE *outP_tB;
  outP_tB = fopen("V3_MAT_positionB_spherical.dat","wb+");
  if(!outP_tB){// file couldn't be opened
      cerr << "Error: file could not be opened" << endl;
      exit(1);
    }


  double *cosPhase_S, *sinPhase_S, *m_tot;
  cosPhase_S = new double [tN];
  sinPhase_S = new double [tN];
  m_tot = new double [tN];

  double tstep = 0.; // time of each step
  int stepCounter = 0; // counter for the steps for each proton
  int cnt_stpMin=0; //, cnt_stpMax=0; //counters for the step length conditions


  for (int i=0; i<parN; i++){// repetition for all the protons in the sample
    stepCounter = 0; //reset

    cout<<"Now diffusion calculated for proton: "<<i<<endl;

    double x0[3]={0.}, xt[3]={0.}, vt[3]={0.};
    double tt=0.;
    double stepL_min = Rionp/8.; //min step length
    double stepL_max = Rionp; //max step length
    double stepL = 0.;
    double extraL = 0.; //extra length beyond central cube
    bool hit_ionp = false;
    double pIONPDist = 0.; // proton-IONP Distance (vector ||)
    double pIONPCosTheta = 0.; //proton_IONP vector cosTheta with Z axis
    double Bloc = 0.; //B 1 IONP
    double Btot = 0.; //SUM B all IONP
    double Dphase = 0.; //Delta phase for step 1p
    double phase = 0.; //phase 1p
    double theta_p=0., phi_p=0.;

    //randomized initial position of the particle;
    x0[0] = realDist(rng)*l_c - l_c/2.;
    x0[1] = realDist(rng)*l_c - l_c/2.;
    x0[2] = realDist(rng)*l_c - l_c/2.;

    //for (int j=0; j<tN; j++){ //steps
    bool diffTime = true; // flag protons are allowed to diffuse (tt<10ms)
    while(diffTime){ // steps loop

     //unit vector for 4p direction
     theta_p = 2.*PI*realDist(rng);
     phi_p = acos(1. - 2.*realDist(rng));

     vt[0] = sin(phi_p)*cos(theta_p);
     vt[1] = sin(phi_p)*sin(theta_p);
     vt[2] = cos(phi_p);;

     //determine length of step
     for(int k=0; k<ionpCounter; k++){
      if(abs(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.))-Rionp) <= 8*Rionp){
        //spm closer than 8R
        stepL = Rionp/8;
        cnt_stpMin ++;
        break;
      }
      else if(abs(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.))-Rionp) > 8*Rionp){
        stepL = Rionp;
      }
      else{
        cout<<"sth wrong with the proton-IONP distance!"<<endl;
      }
    }

    //determine Dt step duration
    tstep = pow(stepL,2.)/(6.*D_const);
    tt += tstep;
    if(tt>t_tot){
      diffTime = false; //proton is not allowed to diffuse any longer
      cout<<"Proton id: "<<i<<" has reached diffusion time! -> Move to next one!"<<endl;
      cout<<"stepCounter: "<<stepCounter<<" cnt_stpMin: "<<cnt_stpMin<<endl;
    }

    while(true){
      xt[0]=x0[0]+vt[0]*stepL;
      xt[1]=x0[1]+vt[1]*stepL;
      xt[2]=x0[2]+vt[2]*stepL;
      for(int m=0; m<3; m++){
        if(abs(xt[m]) > l_c/2.){ //particle outside central cube,// reflected, elastic collision(no!)
          //particle enters fron the other way, periodicity
        //  hit_cx[m] = true; //I don't need it yet
          extraL = abs(xt[m]) - l_c/2.;
        //  xt[m]=-x0[m];
          cout<<"proton outside! xt[m]: "<<xt[m]<<" extra lenght: "<<extraL<<endl;
          xt[m] = xt[m]-l_c;
          cout<<"Relocating => new x[t]: "<<xt[m]<<endl;
        }
      }
      for(int k=0; k<ionpCounter; k++){//check if proton inside SPM
        pIONPDist = sqrt(pow((x1_ionp[k]-xt[0]),2.)+pow((x2_ionp[k]-xt[1]),2.)+pow((x3_ionp[k]-xt[2]),2.)) - Rionp;
        if(pIONPDist <= 0.){
          cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
          hit_ionp = true;
        }
        else if(pIONPDist > 0.){
          hit_ionp=false; //with this I don't have to reset flag in the end
          //calculations of Bloc for this position
          pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
          Bloc = pow(Rionp,3.)*Beq*(3.*pIONPCosTheta - 1.)/pow(pIONPDist,3.);
          Btot += Bloc;
          //cout<<"pSPMDist: "<<pSPMDist<<" pSPMCosTheta: "<<pSPMCosTheta<<" Bloc: "<<Bloc<<" Btot: "<<Btot<<endl;
        }
        else{
          cout<<"Something wrong with the calculation of pIONPDist! "<<pIONPDist<<endl;
          hit_ionp = true;
        }
      }

      if(!hit_ionp){
      //  hit_spm=false; //reset flag (unnessesary alreaty false)
        break;
      }
    }// end of while for new position -> the new position is determined, Btot calculated

    // Dphase, phase
    Dphase = gI*Btot*tstep;
    phase += Dphase;

    //store phase for this step
    //filled for each proton at this timepoint (step)

    cosPhase_S[stepCounter] += cos(phase);
    sinPhase_S[stepCounter] += sin(phase);

    //reset Btot
    Btot = 0.;
    stepCounter++;

   } //end of for loop step
  } //end of for loop particles

  //-----calculate the <m> the total magnetization
for(int t=0; t<tN; t++){
  m_tot[t] = sqrt(pow(cosPhase_S[t],2.) + pow(sinPhase_S[t],2.))/(double)parN;
  //cout<<"m_tot[t]: "<<m_tot[t]<<endl;
}
fclose(outP_tPos); //proton time-position
fclose(outP_tB); //proton time-B

//====== outfile data=============//

  //----- output data of SPM position---------//
  FILE *outP_S;
  outP_S = fopen("V3_MAT_positionSPM_spherical.dat","wb+");
  if(!outP_S){// file couldn't be opened
    cerr << "Error: file could not be opened" << endl;
    exit(1);
  }
  for (int i=0; i<ionpCounter; ++i){
    fprintf(outP_S,"%.10f \t %.10f \t %.10f\n",x1_ionp[i],x2_ionp[i],x3_ionp[i]);
  }
  fclose(outP_S);

  FILE *outP_agg;
  outP_agg = fopen("V3_MAT_positionAggreg_spherical.dat","wb+");
  if(!outP_agg){// file couldn't be opened
    cerr << "Error: file could not be opened" << endl;
    exit(1);
  }
  for (int j=0; j<ionpCounter; ++j){
    fprintf(outP_agg,"%.10f \t %.10f \t %.10f\n",x1_agg[j],x2_agg[j],x3_agg[j]);
  }
  fclose(outP_agg);

  FILE *outSngl;
  outSngl = fopen("V3_MAT_positionSingle_spherical.dat","wb+");
  if(!outSngl){// file couldn't be opened
    cerr << "Error: file could not be opened" << endl;
    exit(1);
  }
  int findAgg = (int)(realDist(rng)*aggN);
  int idxMin = findAgg*ionpN;
  int idxMax = idxMin + ionpN;
  for (int k=idxMin; k<idxMax; ++k){
    fprintf(outSngl,"%.10f\t%.10f\t%.10f\t%.10f\t%.10f\t%.10f\n",x1_agg[k],x2_agg[k],x3_agg[k],x1_ionp[k],x2_ionp[k],x3_ionp[k]);
  }
  fclose(outSngl);

  //delete new arrays
  delete[] x1_ionp;
  delete[] x2_ionp;
  delete[] x3_ionp;
  delete[] theta_ionp;
  delete[] phi_ionp;
  delete[] r_ionp;
  delete[] x1_agg;
  delete[] x2_agg;
  delete[] x3_agg;

  delete[] cosPhase_S;
  delete[] sinPhase_S;
  delete[] m_tot;



}

ANSWER

Answered 2021-Jun-10 at 13:17

I talked the problem in more steps, first thing I made the run reproducible:

  mt19937 rng(127386261); //I want a deterministic seed

Then I create a script to compare the three output files generated by the program:

#!/bin/bash

diff V3_MAT_positionAggreg_spherical.dat V3_MAT_positionAggreg_spherical2.dat
diff V3_MAT_positionSingle_spherical.dat V3_MAT_positionSingle_spherical2.dat
diff V3_MAT_positionSPM_spherical.dat V3_MAT_positionSPM_spherical2.dat

Where the files ending in two is created by the optimized code and the other by your version.

I run your version compiling with O3 flag and marked the time (for 20 magnetic particles and 10 protons it is taking 79 seconds on my box, my architecture is not that important because we are just going to compare the differences).

Then I start refactoring steps by steps, running every small changes comparing the output files and the time, here are all the iterations:

Remove redundant else if gain 5 seconds (total run 74.0 s)

if(sqrt(pow(x1_ionp[k]-x0[0],2.)+pow(x2_ionp[k]-x0[1],2.)+pow(x3_ionp[k]-x0[2],2.)) <= 7*Rionp){
  //spm closer than 8R
  stepL = Rionp/8;
  cnt_stpMin ++;
  break;
}
else { //this was an else if and an else for error that will never happen
  stepL = Rionp;
}

At this point, I run it under the profiler and pow function stood out.

Replacing pow with square and cube gain 61 seconds (total run 13.2 s)

Simply replacing pow(x,2.) with square(x) and pow(x,3.) with cube(x) will reduce the run time by about 600%

double square(double d)
{
  return d*d;
}
double cube(double d)
{
  return d*d*d;
}

Now the gain is reduced quite a lot for each improvement, but still.

Remove redundant sqrt gain (total run 12.9 s)

 double ionpDist = square(x1_ionp[m]-x1_ionp[ionpCounter])+square(x2_ionp[m]-x2_ionp[ionpCounter])+square(x3_ionp[m]-x3_ionp[ionpCounter]);
 //cout<<"spmDist: "<<spmDist<<endl;
 if((j>0) && (ionpDist <= 4*square_Rionp)){

Introducing const variable square_Rionp and cube_Rionp (total run 12.7 s)

const double square_Rionp = square(Rionp);
const double cube_Rionp = cube(Rionp);
//replaced in the code like this
if((j>0) && (ionpDist <= 4*square_Rionp)){

Introducing variable for pi (total run 12.6 s)

const double Two_PI = PI*2.0;
const double FourThird_PI = PI*4.0/3.0;

Remove a (another) redundant else if (total run 11.9s)

if(pIONPDist <= 0.){
  cout<<"proton inside IONP => reposition! Distance: "<<pIONPDist<<" Rionp: "<<Rionp<<endl;
  hit_ionp = true;
}
else { //this was an else if without any reason
  hit_ionp=false; //with this I don't have to reset flag in the end
  //calculations of Bloc for this position
  pIONPCosTheta = (x3_ionp[k]-xt[2])/pIONPDist;
...
}

Remove another redundant sqrare root (total run 11.2 s)

const double Seven_Rionp_squared =square(7*Rionp);
...
for(int k=0; k<ionpCounter; k++){
  if(square(x1_ionp[k]-x0[0])+square(x2_ionp[k]-x0[1])+square(x3_ionp[k]-x0[2]) <= Seven_Rionp_squared){
  //spm closer than 8R
  stepL = stepL_min;
  cnt_stpMin ++;
  break;
}

I don't see many more things obvious to squeeze more performance out of it. Further optimization may require some thinking.

I did another comparison run with 50 magnetic particles and 10 protons and I have found that my version is 7 times faster then the yours and it is producing the exact same files.

I would do this exercise with the help of source control.

Your code is trivially parallelizable, but I will go that route just when you have optimized the single thread version.

EDIT

Change += with = operator (total run 6.23 s)

I have noticed that += operator is used for no reason, the substitution to operator = is a substanzial gain:

cosPhase_S[stepCounter] = cos(phase);
sinPhase_S[stepCounter] = sin(phase);

Source https://stackoverflow.com/questions/67905839

QUESTION

Vector attraction when mouse pressed

Asked 2021-Jun-08 at 11:29

Currently trying to create attraction effect on 3D cubes using createVector function. The attraction designed to trigger when mouse pressed but currently it's stating the error:

Uncaught TypeError: Cannot read property 'copy' of undefined

The code:

let cubes = [];

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  backCol = color(243, 243, 243);
 
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      let xPos = map(i, 0, 9, 50, width - 50);
      let yPos = map(j, 0, 9, 50, height - 50);
      cubes.push(new Cubes(xPos, yPos));
    }
  }
}

function draw() {
  background(backCol);
  noFill();
  for (let cube of cubes) {
    cube.update();
  } 
  attracting();
}

function attracting() {
  for (let a = 0; a < cubes.length; a++) {
    cubes[a].attraction(mouseX,mouseY);
  }
}

class Cubes {

  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.size = 30;
    this.stroke = 70;
    this.gap = 150;
    this.shift1 = color(96);
    this.shift2 = color(244);
 
    //vector variables
    this.pos = createVector(x, y);
    this.vel = createVector(); 
    this.acc = createVector();
  }

  update() {
    this.shape();
    this.test_Color();
    
    //attraction values
    this.vel.add(this.acc);
    this.vel.limit(5);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }
  
  shape() {
    push();
    stroke(this.stroke);
    this.test_Color();
    translate(this.x - width / 2, this.y - height / 2, 0);
    this.test_rotation()
    box(this.size);
    pop();
  }

  test_Color() {
    fill(this.shift1);
  }

  test_rotation() {               
    rotateX(frameCount / 60);
    rotateY(frameCount / 60);
  }
  
  attraction(target) {
    
    //all cubes supposed to attract towards the mouse when pressed

    if (mouseIsPressed) {
      let force = p5.Vector.sub(target.pos,this.pos);
      let d = force.mag();
      d = constrain(d, 1, 25);
      var G = 50;
      var strength = G / (d * d);
      force.setMag(strength);
      if (d < 20) {
        force.mult(10);
      }
      this.vel.add(force);  
    }
  }
}

unsure what detail to add further. Unsure what detail to add further. Unsure what detail to add further. Unsure what detail to add further. Unsure what detail to add further. Unsure what detail to add further. Unsure what detail to add further.

ANSWER

Answered 2021-Jun-08 at 11:29
  • You're using index a for argument of Cubes.attraction which is expecting an object with a pos vector field (a Cubes ?)
  • You're trying to position your cubes using this.x / this.y, which aren't changed by update. Use the this.pos vector instead
  • You can optimize by checking for mouse pressed only once, and only then calling attraction on every cube with mouse coordinates as vector argument
  • In physics, force drives acceleration, not velocity. I changed that but maybe it was deliberate of you.
  • You should change your class name to Cube rather than Cubes

let cubes = [];

function setup() {
  /* max(...) here is just for rendering with minimum size in the snippet */
  createCanvas(max(windowWidth, 800), max(windowHeight, 600), WEBGL);
  backCol = color(243, 243, 243);
 
  for (let i = 0; i < 10; i++) {
    for (let j = 0; j < 10; j++) {
      let xPos = map(i, 0, 9, 50, width - 50);
      let yPos = map(j, 0, 9, 50, height - 50);
      cubes.push(new Cubes(xPos, yPos));
    }
  }
}

function draw() {
  background(backCol);
  noFill();
  for (let cube of cubes) {
    cube.update();
  } 
  attracting();
}

function attracting() {
  /* changed to check for mouse pressed once for all cubes */
  if (mouseIsPressed) {
    /* generating mouse position vector once for all cubes */
    const mousePosVect = new p5.Vector(mouseX, mouseY);
    for (let a = 0; a < cubes.length; a++) {
      cubes[a].attraction(mousePosVect);
    }
  }
}

class Cubes {

  constructor(x, y) {
    /* Removed useless and confusing this.x, this.y */
    this.size = 30;
    this.stroke = 70;
    this.gap = 150;
    this.shift1 = color(96);
    this.shift2 = color(244);
 
    //vector variables
    this.pos = createVector(x, y);
    this.vel = createVector(); 
    this.acc = createVector();
  }

  update() {
    this.test_Color();
    
    //attraction values
    this.vel.add(this.acc);
    this.vel.limit(5);
    this.pos.add(this.vel);
    this.acc.mult(0);
    this.shape();
  }
  
  shape() {
    push();
    stroke(this.stroke);
    this.test_Color();
    /* Used this.pos instead of this.x, this.y for positioning */
    translate(this.pos.x - width / 2, this.pos.y - height / 2, 0);
    this.test_rotation();
    box(this.size);
    pop();
  }

  test_Color() {
    fill(this.shift1);
  }

  test_rotation() {               
    rotateX(frameCount / 60);
    rotateY(frameCount / 60);
  }
  
  attraction(targetVector) {
    //all cubes supposed to attract towards the mouse when pressed

    /* Set target argument to vector,
     * moved the `if (mouseIsPressed)` condition outside */
    let force = p5.Vector.sub(targetVector,this.pos);
    let d = force.mag();
    d = constrain(d, 1, 25);
    var G = 50;
    var strength = G / (d * d);
    force.setMag(strength);
    if (d < 20) {
      force.mult(10);
    }
    /* changed to add force to acceleration
     * instead of velocity (physically accurate) */
    this.acc.add(force);  
  }
}
<!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">
        <title>P5 cube attractor</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js" integrity="sha512-gQVBYBvfC+uyor5Teonjr9nmY1bN+DlOCezkhzg4ShpC5q81ogvFsr5IV4xXAj6HEtG7M1Pb2JCha97tVFItYQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    </head>
    <body>
        <!--h1>P5 test</h1-->
    </body>
</html>

Source https://stackoverflow.com/questions/67884977

QUESTION

Three.js: Cannot display mesh created with texture array

Asked 2021-Jun-07 at 19:33

I'm building a very original game based in cubes you place in a sandbox world (a totally unique concept that will revolutionize gaming as we know it) and I'm working with the chunk generation. Here's what I have so far:

My blocks are defined in an object literal:

import * as THREE from 'three';

const loader = new THREE.TextureLoader();

interface BlockAttrs
{
    breakable: boolean;
    empty:     boolean;
}

export interface Block
{
    attrs:       BlockAttrs;
    mat_bottom?: THREE.MeshBasicMaterial;
    mat_side?:   THREE.MeshBasicMaterial;
    mat_top?:    THREE.MeshBasicMaterial;
}

interface BlockList
{
    [key: string]: Block;
}

export const Blocks: BlockList = {
    air:
    {
        attrs:
        {
            breakable: false,
            empty: true,
        },
    },
    grass:
    {
        attrs:
        {
            breakable: true,
            empty: false,
        },
        mat_bottom: new THREE.MeshBasicMaterial({map: loader.load("/tex/dirt.png")}),
        mat_side: new THREE.MeshBasicMaterial({map: loader.load("/tex/grass-side.png")}),
        mat_top: new THREE.MeshBasicMaterial({map: loader.load("/tex/grass-top.png")}),
    },
};

Here is my Chunk class:

import * as THREE from 'three';
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils';

import { Block, Blocks } from './blocks';

const px = 0; const nx = 1; const py = 2;
const ny = 3; const pz = 4; const nz = 5;

export default class Chunk
{
    private static readonly faces = [
        new THREE.PlaneGeometry(1,1)
            .rotateY(Math.PI / 2)
            .translate(0.5, 0, 0),

        new THREE.PlaneGeometry(1,1)
            .rotateY(-Math.PI / 2)
            .translate(-0.5, 0, 0),

        new THREE.PlaneGeometry(1,1)
            .rotateX(-Math.PI / 2)
            .translate(0, 0.5, 0),

        new THREE.PlaneGeometry(1,1)
            .rotateX(Math.PI / 2)
            .translate(0, -0.5, 0),

        new THREE.PlaneGeometry(1,1)
            .translate(0, 0, 0.5),

        new THREE.PlaneGeometry(1,1)
            .rotateY(Math.PI)
            .translate(0, 0, -0.5)
    ];
    private structure: Array<Array<Array<Block>>>;
    public static readonly size = 16;
    private materials = Array<THREE.MeshBasicMaterial>();
    private terrain = Array<THREE.BufferGeometry>();

    constructor ()
    {
        this.structure = new Array<Array<Array<Block>>>(Chunk.size);

        for (let x = 0; x < Chunk.size; x++)
        {
            this.structure[x] = new Array<Array<Block>>(Chunk.size);

            for (let y = 0; y < Chunk.size; y++)
            {
                this.structure[x][y] = new Array<Block>(Chunk.size);

                for (let z = 0; z < Chunk.size; z++)
                    if ((x+y+z) % 2)
                        this.structure[x][y][z] = Blocks.grass;
                    else
                        this.structure[x][y][z] = Blocks.air;
            }
        }
    }

    private blockEmpty (x: number, y: number, z: number): boolean
    {
        let empty = true;

        if (
            x >= 0 && x < Chunk.size &&
            y >= 0 && y < Chunk.size &&
            z >= 0 && z < Chunk.size
        ) {
            empty = this.structure[x][y][z].attrs.empty;
        }

        return empty;
    }

    private generateBlockFaces (x: number, y: number, z: number): void
    {
        if (this.blockEmpty(x+1, y, z))
        {
            this.terrain.push(Chunk.faces[px].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_side);
        }

        if (this.blockEmpty(x, y, z+1))
        {
            this.terrain.push(Chunk.faces[nx].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_side);
        }

        if (this.blockEmpty(x, y-1, z))
        {
            this.terrain.push(Chunk.faces[py].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_bottom);
        }

        if (this.blockEmpty(x, y+1, z))
        {
            this.terrain.push(Chunk.faces[ny].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_top);
        }

        if (this.blockEmpty(x, y, z-1))
        {
            this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_side);
        }

        if (this.blockEmpty(x-1, y, z))
        {
            this.terrain.push(Chunk.faces[nz].clone().translate(x, y, z));
            this.materials.push(this.structure[x][y][z].mat_side);
        }
    }

    public generateTerrain (): THREE.Mesh
    {
        this.terrain   = new Array<THREE.BufferGeometry>();
        this.materials = new Array<THREE.MeshBasicMaterial>();

        for (let x = 0; x < Chunk.size; x++)
            for (let y = 0; y < Chunk.size; y++)
                for (let z = 0; z < Chunk.size; z++)
                    if (!this.structure[x][y][z].attrs.empty)
                        this.generateBlockFaces(x, y, z);

        return new THREE.Mesh(
            BufferGeometryUtils.mergeBufferGeometries(this.terrain),
            this.materials
        );
    }
}

I know the mesh creator should be decoupled from the model, but right now I'm experimenting. The class works like this:

First, constructor() creates a 3D matrix of Block. I've set it to create it in a chess board pattern of air and grass, so every other block is empty.

Next, I call generateTerrain() from my Scene:

this.chunk = new Chunk();
this.add(this.chunk.generateTerrain());

When this method is called, it enters generateBlockFaces for every non-empty block and pushes the appropiate PlaneGeometrys into the terrain array as well as the appropriate THREE.MeshBasicMaterial into the materials array. I then merge the geometries using BufferGeometryUtils.mergeBufferGeometries and create the mesh passing the merged geometry and the materials array.

The problem I have is that creating the mesh works perfectly well when passing new THREE.MeshNormalMaterial, or any other material for that matter, but not when I pass the materials array. Passing the array creates the object (and console.loging it shows that it was created without errors), but it isn't drawn with the scene.

Am I mistaken in believing that the materials array will assign a material to each of the faces? What am I doing wrong?

ANSWER

Answered 2021-Jun-01 at 10:32

I solved it after finding a reference to THREE.UVMapping in the docs. When sending the geometry to the GPU, textures coordinates need to be a biyection from the vertices coordinates. To achieve this, I defined the following three attributes in my blocks:

uv_bottom: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_side: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],
uv_top: [
    stone_row     / Textures.rows, (stone_col+1) / Textures.cols,
    (stone_row+1) / Textures.rows, (stone_col+1) / Textures.cols,
    stone_row     / Textures.rows, stone_col     / Textures.cols,
    (stone_row+1) / Textures.rows, stone_col     / Textures.cols,
],

Textures.rows and Textures.cols references the number of colums and rows my textures atlas (the file where all the textures are stored in a png grid) has and every block has their own row and col file that references its position. Then, I created a private uv = Array<Array<number>>(); in my Chunk class and modified the terrain generator to push the blocks' uv arrays to it. For example, this is how it is done for positive z faces (note that I have swapped y and z for efficiency purposes):

if (this.blockEmpty(x, z+1, y))
{
    this.terrain.push(Chunk.faces[pz].clone().translate(x, y, z));
    this.uv.push(this.structure[x][z][y].uv_side);
}

Now, BufferGeometry only accepts 'uv' arrays as typed (Float32Array in this case), so I had to construct one from a flattened version of this.uv. This is how the terrain generator function looks like now:

public generateTerrain (): THREE.Mesh
{
    this.terrain = new Array<THREE.BufferGeometry>();

    for (let x = 0; x < Chunk.base; x++)
        for (let z = 0; z < Chunk.base; z++)
            for (let y = 0; y < Chunk.build_height; y++)
                if (!this.structure[x][z][y].attrs.empty)
                    this.generateBlockFaces(x, z, y);

    const geometry = BufferGeometryUtils.mergeBufferGeometries(this.terrain);
    geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uv.flat()), 2));

    return new THREE.Mesh(geometry, Textures.material);
}

As you can see, the material I'm using comes from the Textures class. Here's the whole imported file:

import * as THREE from 'three';

export default class Textures
{
    private static readonly loader = new THREE.TextureLoader();

    public static readonly rows = 3;
    public static readonly cols = 2;

    public static readonly atlas    = Textures.loader.load("/tex/atlas.png");
    public static readonly material = new THREE.MeshBasicMaterial({map: Textures.atlas});
}

Textures.atlas.magFilter = THREE.NearestFilter;
Textures.atlas.minFilter = THREE.NearestFilter;

And that's it! The terrain now generates rendering every single block's texture and I can't be happier about it :D

Source https://stackoverflow.com/questions/67764263

QUESTION

C++ OpenGL stb_image.h errors

Asked 2021-May-31 at 19:12

I am following an OpenGL tutorial from https://learnopengl.com/ (specifically https://learnopengl.com/Advanced-OpenGL/Depth-testing) and I have many errors to do with stbi. Error Log image here (Below I have also attached the complete Output tab). I have added the "#define STB_IMAGE_IMPLEMENTATION" at the top of the main.cpp file (and not in a header). If I don't use any stb_image functionalities, the project compiles and runs. I have had projects where stb_image worked fine, but all those projects that worked were x86 (or 32-bit). It seems that I can not get stb_image with x64 (or 64-bit). I know that x64 itself works since other projects without stb_image that were x64 have compiled. I have also looked back to where I downloaded the header file for stb_image and there was no option for x64 vs x86 as there was only one universal option. Here is an image of how the files are organized: File hierarchy. I will also include my main.cpp file but if you want to see a specific file let me know. I am very new to c++ since I come from java and python so any help is appreciated.

#define STB_IMAGE_IMPLEMENTATION

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <stb_image.h>

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <Shader.h>
#include <Camera.h>
#include <Model.h>

#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);
unsigned int loadTexture(const char* path);

// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;

// camera
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
float lastX = (float)SCR_WIDTH / 2.0;
float lastY = (float)SCR_HEIGHT / 2.0;
bool firstMouse = true;

// timing
float deltaTime = 0.0f;
float lastFrame = 0.0f;

int main()
{
    // glfw: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // glfw window creation
    // --------------------
    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window, scroll_callback);

    // tell GLFW to capture our mouse
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

    // glad: load all OpenGL function pointers
    // ---------------------------------------
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // configure global opengl state
    // -----------------------------
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_ALWAYS); // always pass the depth test (same effect as glDisable(GL_DEPTH_TEST))

    // build and compile shaders
    // -------------------------
    Shader shader("depth_testing.vs", "depth_testing.fs");

    // set up vertex data (and buffer(s)) and configure vertex attributes
    // ------------------------------------------------------------------
    float cubeVertices[] = {
        // positions          // texture Coords
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
         0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
         0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
         0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
         0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
         0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
    };
    float planeVertices[] = {
        // positions          // texture Coords (note we set these higher than 1 (together with GL_REPEAT as texture wrapping mode). this will cause the floor texture to repeat)
         5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,

         5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
         5.0f, -0.5f, -5.0f,  2.0f, 2.0f
    };
    // cube VAO
    unsigned int cubeVAO, cubeVBO;
    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    glBindVertexArray(cubeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glBindVertexArray(0);
    // plane VAO
    unsigned int planeVAO, planeVBO;
    glGenVertexArrays(1, &planeVAO);
    glGenBuffers(1, &planeVBO);
    glBindVertexArray(planeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glBindVertexArray(0);

    // load textures
    // -------------
    unsigned int cubeTexture = loadTexture("resources/textures/container.jpg");
    unsigned int floorTexture = loadTexture("resources/textures/awesomeface.png");

    // shader configuration
    // --------------------
    shader.use();
    shader.setInt("texture1", 0);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(window))
    {
        // per-frame time logic
        // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        shader.use();
        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = camera.GetViewMatrix();
        glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
        shader.setMat4("view", view);
        shader.setMat4("projection", projection);
        // cubes
        glBindVertexArray(cubeVAO);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, cubeTexture);
        model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
        shader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        model = glm::mat4(1.0f);
        model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
        shader.setMat4("model", model);
        glDrawArrays(GL_TRIANGLES, 0, 36);
        // floor
        glBindVertexArray(planeVAO);
        glBindTexture(GL_TEXTURE_2D, floorTexture);
        shader.setMat4("model", glm::mat4(1.0f));
        glDrawArrays(GL_TRIANGLES, 0, 6);
        glBindVertexArray(0);

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // optional: de-allocate all resources once they've outlived their purpose:
    // ------------------------------------------------------------------------
    glDeleteVertexArrays(1, &cubeVAO);
    glDeleteVertexArrays(1, &planeVAO);
    glDeleteBuffers(1, &cubeVBO);
    glDeleteBuffers(1, &planeVBO);

    glfwTerminate();
    return 0;
}

// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
        camera.ProcessKeyboard(FORWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
        camera.ProcessKeyboard(BACKWARD, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
        camera.ProcessKeyboard(LEFT, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
        camera.ProcessKeyboard(RIGHT, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
        camera.ProcessKeyboard(UP, deltaTime);
    if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
        camera.ProcessKeyboard(DOWN, deltaTime);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    // make sure the viewport matches the new window dimensions; note that width and 
    // height will be significantly larger than specified on retina displays.
    glViewport(0, 0, width, height);
}

// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
    if (firstMouse)
    {
        lastX = xpos;
        lastY = ypos;
        firstMouse = false;
    }

    float xoffset = xpos - lastX;
    float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top

    lastX = xpos;
    lastY = ypos;

    camera.ProcessMouseMovement(xoffset, yoffset);
}

// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    camera.ProcessMouseScroll(yoffset);
}

// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const* path)
{
    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char* data = stbi_load(path, &width, &height, &nrComponents, 0);
    if (data)
    {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    }
    else
    {
        std::cout << "Texture failed to load at path: " << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}
Build started...
1>------ Build started: Project: DepthTesting, Configuration: Debug x64 ------
1>main.cpp
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\Shader.h(56,40): warning C4101: 'e': unreferenced local variable
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(677,12): error C2084: function 'int stbi__cpuid3(void)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(677): message : see previous definition of 'stbi__cpuid3'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(699,12): error C2084: function 'int stbi__sse2_available(void)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(699): message : see previous definition of 'stbi__sse2_available'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(701,17): error C2065: 'stbi__cpuid3': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(701,31): error C2440: 'initializing': cannot convert from 'int (__cdecl *)(void)' to 'int'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(701,15): message : There is no context in which this conversion is possible
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(762,3): error C2371: 'stbi__context': redefinition; different basic types
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(762): message : see declaration of 'stbi__context'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(768,13): error C2084: function 'void stbi__start_mem(stbi__context *,const stbi_uc *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(768): message : see previous definition of 'stbi__start_mem'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(778,13): error C2084: function 'void stbi__start_callbacks(stbi__context *,stbi_io_callbacks *,void *)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(778): message : see previous definition of 'stbi__start_callbacks'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(792,12): error C2084: function 'int stbi__stdio_read(void *,char *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(792): message : see previous definition of 'stbi__stdio_read'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(797,13): error C2084: function 'void stbi__stdio_skip(void *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(797): message : see previous definition of 'stbi__stdio_skip'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(807,12): error C2084: function 'int stbi__stdio_eof(void *)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(807): message : see previous definition of 'stbi__stdio_eof'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(812,26): error C2374: 'stbi__stdio_callbacks': redefinition; multiple initialization
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(812): message : see declaration of 'stbi__stdio_callbacks'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(819,13): error C2084: function 'void stbi__start_file(stbi__context *,FILE *)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(819): message : see previous definition of 'stbi__start_file'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(821,5): error C2065: 'stbi__start_callbacks': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(828,13): error C2084: function 'void stbi__rewind(stbi__context *)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(828): message : see previous definition of 'stbi__rewind'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(839,5): error C2365: 'STBI_ORDER_RGB': redefinition; previous definition was 'enumerator'
...
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1286,13): message : There is no context in which this conversion is possible
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1288,20): error C2065: 'stbi__err': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1294,18): error C2084: function 'stbi_uc *stbi_load_from_file(FILE *,int *,int *,int *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1294): message : see previous definition of 'stbi_load_from_file'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1298,5): error C2065: 'stbi__start_file': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1299,14): error C2065: 'stbi__load_and_postprocess_8bit': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1299,71): error C2568: '=': unable to resolve function overload
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1299,71): message : could be 'unsigned char *stbi__load_and_postprocess_8bit(stbi__context *,int *,int *,int *,int)'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1307,23): error C2084: function 'stbi_us *stbi_load_from_file_16(FILE *,int *,int *,int *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1307): message : see previous definition of 'stbi_load_from_file_16'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1311,5): error C2065: 'stbi__start_file': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1312,14): error C2065: 'stbi__load_and_postprocess_16bit': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1312,72): error C2568: '=': unable to resolve function overload
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1312,72): message : could be 'stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *,int *,int *,int *,int)'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1320,18): error C2084: function 'stbi_us *stbi_load_16(const char *,int *,int *,int *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1320): message : see previous definition of 'stbi_load_16'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1322,15): error C2065: 'stbi__fopen': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1322,42): error C2440: 'initializing': cannot convert from 'FILE *(__cdecl *)(const char *,const char *)' to 'FILE *'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1322,13): message : There is no context in which this conversion is possible
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1324,30): error C2065: 'stbi__err': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1325,14): error C2065: 'stbi_load_from_file_16': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1325,61): error C2568: '=': unable to resolve function overload
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1325,61): message : could be 'stbi_us *stbi_load_from_file_16(FILE *,int *,int *,int *,int)'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1333,18): error C2084: function 'stbi_us *stbi_load_16_from_memory(const stbi_uc *,int,int *,int *,int *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1333): message : see previous definition of 'stbi_load_16_from_memory'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1336,5): error C2065: 'stbi__start_mem': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1337,12): error C2065: 'stbi__load_and_postprocess_16bit': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1340,18): error C2084: function 'stbi_us *stbi_load_16_from_callbacks(const stbi_io_callbacks *,void *,int *,int *,int *,int)' already has a body
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1340): message : see previous definition of 'stbi_load_16_from_callbacks'
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1343,5): error C2065: 'stbi__start_callbacks': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1344,12): error C2065: 'stbi__load_and_postprocess_16bit': undeclared identifier
1>C:\Users\caleb\Documents\OpenGL\AdvancedOpenGL\DepthTesting\include\stb_image.h(1344,89): fatal error C1003: error count exceeds 100; stopping compilation
1>Done building project "DepthTesting.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

ANSWER

Answered 2021-May-31 at 19:12

As mentioned by Retired Ninja in the comments, all you do to fix it is to put the #define STB_IMAGE_IMPLEMENTATION and #include stb_image.h after all the headers that also include the stb_image.h file. Once this was fixed, the program runs but I am getting a frame not found error but I think that is a separate issue from this.

Source https://stackoverflow.com/questions/67777769

QUESTION

How to limit the number of total animated drop cubes and make them animate by their added order?

Asked 2021-May-28 at 17:28

When we click this add button we will add a new cube which will drop immediately, but if we click it very quickly, there will be too many cubes dropping. I want to limit the number of the total animated dropping cube.

For example, even if we click the button very quickly and 10 cubes are added to the page, only two cubes are dropping, and others must wait until they finished.

For example, the 3rd and 4th cubes will start to drop when cube 1 and cube 2 finished.

I was thinking maybe we can have a global variable of the total animated cubes count, ++ and -- it when a new cube is starting and finishing animation, use setInterval to check if the variable is less than 2, but this can't make the animation based on the cubes created order. May I know how to solve this? Thank you so much!

var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";

    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)


}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
}
<button id="add">add new</button>
<div id="cubes-container">
</div>

ANSWER

Answered 2021-May-28 at 17:28

Consider the following example. It is using jQuery versus JavaScript. It could be similarly scripted.

$(function() {
  function addCube(target) {
    var i = $(".cube").length;
    var container = $("<div>", {
      class: "cube-container"
    }).appendTo(target);
    $("<div>", {
      class: "cube",
      id: "cube-" + i
    }).html(i).appendTo(container);
    return container;
  }

  function dropCube(cube) {
    $(cube).addClass("falling").animate({
      top: "200px"
    }, 2000, function() {
      $(cube).removeClass("falling");
      if (cubes.length && $(".falling").length < 2) {
        dropCube(cubes.shift());
      }
    });
  }

  var cubes = [];

  $("#add").click(function() {
    cubes.push(addCube("#cubes-container"));
    if ($(".falling").length < 2) {
      dropCube(cubes.shift());
    }
  });
});
/*
var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubeId = 0;
btn.addEventListener('click', addCube);

var currentAnimateCount = 0;

function dropCube(cube) {
  var pos = 0;
  let intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);

}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = cubeId;
  cube.innerHTML = cube.id;
  cubeId++;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  let pos = 0;
  dropCube(cube)
}
*/
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">add new</button>
<div id="cubes-container"></div>

Using an Array, you cna .shift() the first item of the array. Also adding a Class to the falling items allows you to keep a count of which ones are falling. I like to use Animate since it allows for a callback when the animation is done, so you can check for the next item.

Update for JavaScript

var btn = document.getElementById('add');
var container = document.getElementById('cubes-container');
var cubes = [];
btn.addEventListener('click', function(event) {
  cubes.push(addCube());
  if (document.getElementsByClassName("falling").length < 2) {
    dropCube(cubes.shift());
  }
});

function dropCube(cube) {
  var pos = 0;
  cube.classList.add("falling");
  var intervalId = setInterval(function() {
    if (pos == 200) {
      clearInterval(intervalId);
      cube.classList.remove("falling");
      if (document.getElementsByClassName("falling").length < 2 && cubes.length) {
        dropCube(cubes.shift());
      }
    } else {
      pos++;
      cube.style.top = pos + "px";
    }
  }, 1);
}

function addCube() {
  let cube = document.createElement('div');
  let cubeContainer = document.createElement('div');
  cube.className = 'cube';
  cube.id = document.getElementsByClassName("cube").length;
  cube.innerHTML = cube.id;
  cubeContainer.className = 'cube-container';
  cubeContainer.append(cube);
  container.append(cubeContainer);
  return cubeContainer;
}
#cubes-container {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}

.cube-container {
  position: relative;
  height: 30px;
}

.cube {
  width: 30px;
  height: 30px;
  background-color: orange;
  text-align: center;
  display: grid;
  align-items: center;
  justify-items: center;
  position: absolute;
  top: 0;
}
<button id="add">add new</button>
<div id="cubes-container"></div>

Source https://stackoverflow.com/questions/67742464

QUESTION

Issue with FirstPersonController in Ursina

Asked 2021-May-24 at 07:46

I'm using the Ursina engine to create a 3D game. However, when i try to load the FirstPersonCharacter, all I got is a grey background (normal) and a very small magenta square, in the center, tilted at 45°. What is that ?

I was first trying to make my own mechanics for a first person character, move the camera according to the mouse position (I have this), and I was playing with math and stuff for movements... I was looking at this video (https://www.youtube.com/watch?v=DHSRaVeQxIk) for totally something else, and I found out about the FirstPersonController.

But, with the (almost) same code as him, it doesn't work ! What's that issue, has someone already ran into it ? Is FirstPersonController broken ? Or is my brain broken ?

Edit : found out in the ursina cheatsheet that the small magenta tilted square is the cursor. But I still can't move, can't have gravity or anything ? And I can't see my floor.

Second edit : using some piece of code the ursina cheatsheet provided, arranged, I can now see my floor. But I can only move the camera on 1 axis (up and down), I can't move, no gravity, nothing...

Here is my code :

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController

app = Ursina()

window.title = 'The lab'
window.borderless = False
window.fullscreen = True
window.exit_button.visible = False
window.fps_counter.enabled = True

floorcubes = []
for i in range(-20, 20, 2):
    for j in range(-20, 20, 2):
        floorcubes.append(Entity(model='cube', color=color.white, scale=(2,2,2), position = (i, 0, j)))
player = FirstPersonController()
app.run()

Here is the code provided in the ursina cheatsheet, arranged a bit :

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
app = Ursina()
ground = Entity(model='plane', scale=(100,1,100), color=color.yellow.tint(-.2), texture='white_cube', texture_scale=(100,100), collider='box', position = (0, -2, 0), grounded = True)
e = Entity(model='cube', scale=(1,5,10), x=2, y=.01, rotation_y=45, collider='box', texture='white_cube')
e.texture_scale = (e.scale_z, e.scale_y)
e = Entity(model='cube', scale=(1,5,10), x=-2, y=.01, collider='box', texture='white_cube')
e.texture_scale = (e.scale_z, e.scale_y)

player = FirstPersonController(model='cube', y=2, origin_y=-.5, gravity = 1)
player.gun = None

gun = Button(parent=scene, model='cube', color=color.blue, origin_y=-.5, position=(3,0,3), collider='box')
gun.on_click = Sequence(Func(setattr, gun, 'parent', camera), Func(setattr, player, 'gun', gun))

gun_2 = duplicate(gun, z=7, x=8)
slope = Entity(model='cube', collider='box', position=(0,0,8), scale=6, rotation=(45,0,0), texture='brick', texture_scale=(8,8))
slope = Entity(model='cube', collider='box', position=(5,0,10), scale=6, rotation=(80,0,0), texture='brick', texture_scale=(8,8))

def input(key):
    if key == 'left mouse down' and player.gun:
        gun.blink(color.orange)
        bullet = Entity(parent=gun, model='cube', scale=.1, color=color.black)
        bullet.world_parent = scene
        bullet.animate_position(bullet.position+(bullet.forward*50), curve=curve.linear, duration=1)
        destroy(bullet, delay=1)
app.run()

Thanks to the answer, I have now :

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
import pyautogui
import random
import math

app = Ursina()

is_fullscreen = True
window.title = 'The lab'
window.borderless = False
window.fullscreen = is_fullscreen
window.exit_button.visible = False
window.fps_counter.enabled = True

latest_mouse_pos = pyautogui.position()
pyautogui.FAILSAFE = False
sensibility = 2.5
mouse.visible = True


floorcube = Entity(model="cube", color = color.white, scale=(20, 1, 20), collider="box", position=(0, -100, 0))


def update():
    global latest_mouse_pos
    if held_keys['f']:
        camera.fov += 1
    if held_keys['r']:
        camera.fov -= 1

player = FirstPersonController()

app.run()

ANSWER

Answered 2021-May-22 at 07:57

There is gravity and it has the effect of letting the player fall into infinity. When you move the mouse around to look up, you will see the cubes disappearing into the distance.

The solution is to add collider='box' to your floor cubes to stop the player from falling through. Note that the starting point seems to be inside one of the cubes so you have to jump out of it (using the space bar) or slightly lower your floor cubes' position.

Source https://stackoverflow.com/questions/67588962

QUESTION

Are OpenGL ordered as viewed by an internal or external viewer?

Asked 2021-May-23 at 07:38

I have written a WebGL program which displays a rotating cube. The indices are in counter-clockwise order as viewed from the outside. However, when I decide to enable cull faces, the faces that I understand to be "front" are culled, and the cube appears to be hollowed-out. I can fix this issue by telling WebGL to cull "front" faces instead.

I declared the cube's vertex positions, texture coordinates, and indices as follows: image or text.

My question is: am I supposed to declare points in counter-clockwise order as viewed from within the shape? If not, why are the indices I am using backwards?

This program (which is already the minimum reproducible example) is below.

const cubeVertexPositions = [
  // Front
  -1, 1, -1,
  -1, -1, -1,
  1, -1, -1,
  1, 1, -1,

  // Back
  1, 1, 1,
  1, -1, 1,
  -1, -1, 1,
  -1, 1, 1,

  // Left
  -1, 1, 1,
  -1, -1, 1,
  -1, -1, -1,
  -1, 1, -1,

  // Right
  1, 1, -1,
  1, -1, -1,
  1, -1, 1,
  1, 1, 1,

  // Top
  -1, 1, 1,
  -1, 1, -1,
  1, 1, -1,
  1, 1, 1,

  // Bottom
  -1, -1, -1,
  -1, -1, 1,
  1, -1, 1,
  1, -1, -1
];

const cubeTextureCoordinates = [
  // Front
  0, 1,
  0, 0,
  1, 0,
  1, 1,

  // Back
  0, 1,
  0, 0,
  1, 0,
  1, 1,

  // Left
  0, 1,
  0, 0,
  1, 0,
  1, 1,

  // Right
  0, 1,
  0, 0,
  1, 0,
  1, 1,

  // Bottom
  0, 1,
  0, 0,
  1, 0,
  1, 1,

  // Top
  0, 1,
  0, 0,
  1, 0,
  1, 1
];

const cubeIndices = [
  // Front
  0, 1, 2,
  2, 3, 0,

  // Back
  4, 5, 6,
  6, 7, 4,

  // Left
  8, 9, 10,
  10, 11, 8,

  // Right
  12, 13, 14,
  14, 15, 12,

  // Top
  16, 17, 18,
  18, 19, 16,

  // Bottom
  20, 21, 22,
  22, 23, 20
];

// Vertex shader source code.
const vertexShaderSrc = `#version 300 es
in vec4 a_position;
in vec2 a_texcoord;

out vec2 v_texcoord;

uniform mat4 u_matrix;

void main() {
    gl_Position = u_matrix * a_position;

    v_texcoord = a_texcoord;
}`;

// Fragment shader source code.
const fragmentShaderSrc = `#version 300 es
precision highp float;

in vec2 v_texcoord;

uniform sampler2D u_texture;

out vec4 outColor;

void main() {
    outColor = texture(u_texture, v_texcoord);
}`;

// Variables for controlling the cube.
let cubeTranslation = new Vector(0, 0, 0);
let cubeRotation = new Vector(0, 0, 0);
let cubeAngularVelocity = new Vector(0, 1, 0);
let cubeScale = new Vector(1, 1, 1);
let cubeHue = new Vector(1, 1, 1, 1);
let fov = 60;
let near = 1;
let far = 200;
let lookAt = cubeTranslation;
let cameraTranslaton = new Vector(0, 0, 5);

// Initialization instructions.
onload = () => {
  // Find the canvas and WebGL2 context.
  const canvas = document.querySelector('#canvas');
  const gl = canvas.getContext('webgl2');

  // Create a WebGL2 program using the vertex and fragment shader source code above.
  const programInfo = new ProgramInfo(gl, new ShaderInfo(gl, gl.VERTEX_SHADER, vertexShaderSrc), new ShaderInfo(gl, gl.FRAGMENT_SHADER, fragmentShaderSrc));

  // Cube vertex positions buffer.
  const cubeVerticesBufferInfo = new BufferInfo(gl, new Float32Array(cubeVertexPositions));

  // Cube texture coordinates buffer.
  const cubeTexcoordsBufferInfo = new BufferInfo(gl, new Float32Array(cubeTextureCoordinates));

  // Vertex Array Object for the cube.
  const vao = new VAOInfo(gl, programInfo);
  vao.addAttribute(new AttributeInfo('a_position', cubeVerticesBufferInfo));
  vao.addAttribute(new AttributeInfo('a_texcoord', cubeTexcoordsBufferInfo, 2));
  vao.setIndices(new Uint8Array(cubeIndices));

  // A simple texture to show the edges of the cube.
  const outlineTextureInfo = new TextureInfo(gl);
  outlineTextureInfo.setColor(new Uint8Array([255, 0, 255, 255])); // Temporary color while image is loading.
  outlineTextureInfo.loadImage(imageBase64);

  // Render time instructions.
  const render = (time) => {
    requestAnimationFrame(render);

    // Set global state.
    UmbraGL.resizeCanvasToDisplaySize(canvas);
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST);
    gl.enable(gl.CULL_FACE);
    // gl.cullFace(gl.FRONT); // Uncomment this line to fix the cube.

    // Animate.
    cubeRotation.operate(cubeAngularVelocity);

    // Draw.
    gl.useProgram(programInfo.program);
    programInfo.uniforms['u_matrix'].setter([...new Matrix()
      .perspective(fov, gl.canvas.clientWidth / gl.canvas.clientHeight, near, far)
      .multiply(new Matrix().lookAt(cameraTranslaton, lookAt).invert())
      .translate(...cubeTranslation)
      .rotate(...cubeRotation)
    ]);
    programInfo.uniforms['u_texture'].setter(outlineTextureInfo.texture);
    vao.draw();
  };
  requestAnimationFrame(render);
};

// Base64 version of the image. This is at the bottom so that it doesn't get in the way of the rest of the code.
const imageBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zUAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0VaRFpExCFDdbIgKuIoVSyChdJWaNXB5NIvaNKQtLg4Cq4FBz8Wqw4uzro6uAqC4AeIm5uToouU+L+k0CLGg+N+vLv3uHsHCM0KU82eCUDVakYqHhOzuVXR/wofQhjAIIISM/VEejED1/F1Dw9f76I8y/3cnyOo5E0GeETiOaYbNeIN4pnNms55nzjMSpJCfE48btAFiR+5Ljv8xrlos8Azw0YmNU8cJhaLXSx3MSsZKvE0cURRNcoXsg4rnLc4q5U6a9+TvzCQ11bSXKc5gjiWkEASImTUUUYFNURp1UgxkaL9mIt/2PYnySWTqwxGjgVUoUKy/eB/8LtbszA16SQFYoDvxbI+RgH/LtBqWNb3sWW1TgDvM3CldfzVJjD7SXqjo0WOgP5t4OK6o8l7wOUOMPSkS4ZkS16aQqEAvJ/RN+WA0C3Qt+b01t7H6QOQoa6Wb4CDQ2CsSNnrLu/u7e7t3zPt/n4ASt1ylxIM+ngAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQflBRMRGRZyIYKeAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAEaJJREFUeNrt2bERwDAIBMHHZUvF4yIU2CN2S/iIGxIAAGCMStLdhgAAgOvtvR8rAADAHAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQACYAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAACAc5Wkuw0BAAD3X/9VPgAAADCIAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAASACQAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAMA3AbDWsgIAAEwJABMAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAJgAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAAAAAAPAfLyiBENdcBN3eAAAAAElFTkSuQmCC';
body {
  margin: 0;
}

canvas#canvas {
  width: 100%;
  height: 100%;
}
<script src="https://unpkg.com/umbra-math@1.0.0/index.js"></script>
<script src="https://unpkg.com/umbra-gl@1.0.0/index.js"></script>

<canvas id="canvas"></canvas>

ANSWER

Answered 2021-May-23 at 07:01

You said "The indices are in counter-clockwise order as viewed from the outside."

No they are not. The indices of the 1st triangle are 0, 1, 2 and the vertices are (-1, 1, -1), (-1, -1, -1), (1, -1, -1).

    0
y    +
^    | \
|    |   \
|    +-----+
    1       2

      ----> x

In a right handed system (Right-hand rule), the z-axis points against the view. Hence this is a triangle on the back.

When you look at the triangle from the back you can clearly see that the winding order is clock wise

        0
       +
     / |
   /   |
 +-----+
2       1

Source https://stackoverflow.com/questions/67656919

QUESTION

How can I rotate the capsule to look at the next position while reaching the current position?

Asked 2021-May-20 at 23:43
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class WaypointsFollower : MonoBehaviour
{
    public float speed;
    public Waypoints waypoints;
    public Transform capsule;
    public bool go;
    public bool goForward;
    public float rotationSpeed;

    private int index = 0;
    private int counter = 0;
    private int c = 0;
    private List<GameObject> curvedLinePoints = new List<GameObject>();

    public int numofposbetweenpoints;

    private bool getonce;
    private bool getBackwardIndexOnce = true;

    private void Start()
    {
        waypoints = GameObject.Find("Waypoints").GetComponent<Waypoints>();

        curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();

        if(waypoints.moveInReverse == false)
        {
            goForward = true;
        }
        else
        {
            goForward = false;
        }

        if(goForward)
        {
            index = 0;
        }
    }

    private void Update()
    {
        if (getonce == false)
        {
            numofposbetweenpoints = curvedLinePoints.Count;

            getonce = true;
        }

        if (go == true && waypoints.lineRendererPositions.Count > 0)
        {
            if(goForward == false && getBackwardIndexOnce)
            {
                index = waypoints.lineRendererPositions.Count - 1;

                getBackwardIndexOnce = false;
            }

            Move();
        }
    }

    private void Move()
    {
        Vector3 newPos = transform.position;
        float distanceToTravel = speed * Time.deltaTime;

        bool stillTraveling = true;
        while (stillTraveling)
        {
            Vector3 oldPos = newPos;

            // error exception out of bound on line 55 to check !!!!!
            newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);

            distanceToTravel -= Vector3.Distance(newPos, oldPos);

            if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
            {
                // when you hit a waypoint:
                if (goForward)
                {
                    bool atLastOne = index >= waypoints.lineRendererPositions.Count - 1;
                    if (!atLastOne)
                    {
                        index++;
                        counter++;
                        if (counter == numofposbetweenpoints)
                        {
                            c++;

                            counter = 0;
                        }
                        if (c == curvedLinePoints.Count - 1)
                        {
                            c = 0;
                        }
                    }
                    else { index--; goForward = false; }
                }
                else
                { // going backwards:
                    bool atFirstOne = index <= 0;
                    if (!atFirstOne)
                    {
                        index--;

                        counter++;
                        if (counter == numofposbetweenpoints)
                        {
                            c++;

                            counter = 0;
                        }
                        if (c == curvedLinePoints.Count - 1)
                        {
                            c = 0;
                        }
                    }
                    else { index++; goForward = true; }
                }
            }
            else
            {
                stillTraveling = false;
            }
        }

        transform.position = newPos;
    }

    private void RotateTo()
    {
        // Determine which direction to rotate towards
        Vector3 targetDirection = -capsule.position;

        // The step size is equal to speed times frame time.
        float singleStep = rotationSpeed * Time.deltaTime;

        // Rotate the forward vector towards the target direction by one step
        Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);

        // Draw a ray pointing at our target in
        Debug.DrawRay(capsule.position, newDirection, Color.red);

        // Calculate a rotation a step closer to the target and applies rotation to this object
        capsule.rotation = Quaternion.LookRotation(newDirection);
    }
}

The transform is moving along the waypoints but I want that the capsule to rotate facing each numofposbetweenpoints.

There are a lot of waypoints over 4000 more or less but there are only 10 numofposbetweenpoints. This screenshot will clear it. The waypoints are the linerenderer positions and the numofposbetweenpoints are the cubes that connect each line of the line renderer lines.

Clear image

In the screenshot, the big cube is the transform in the script the transform is moving along the ping lines that are the linerenderer positions. The small cubes in the background are the points where the linerenderer lines are connected at.

I want the capsule to rotate smoothly looking at the numofposbetweenpoints(Small Cubes) each time the transform is moving the capsule should rotate smoothly looking at the next numofposbetweenpoints. there are only 10 of numofposbetweenpoints.

This is the rotation part at the bottom :

private void RotateTo()
        {
            // Determine which direction to rotate towards
            Vector3 targetDirection = -capsule.position;
    
            // The step size is equal to speed times frame time.
            float singleStep = rotationSpeed * Time.deltaTime;
    
            // Rotate the forward vector towards the target direction by one step
            Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);
    
            // Draw a ray pointing at our target in
            Debug.DrawRay(capsule.position, newDirection, Color.red);
    
            // Calculate a rotation a step closer to the target and applies rotation to this object
            capsule.rotation = Quaternion.LookRotation(newDirection);
        }

At this line it's missing the next small cube each time :

Vector3 targetDirection = -capsule.position;

I have the number of small cubes numofposbetweenpoints but how do I get a reference to each small cube and make the numofposbetweenpoints index increase each time?

At line 50 I'm doing :

numofposbetweenpoints = curvedLinePoints.Count;

curvedLinePoints is a List but I'm not sure how to do the rotation to the GameObjects in the List.

This is what I did so far I think the rotation is working but not as I wanted :

At the top I added :

private int rotationIndex = 0;

Then in the RotateTo I change it to :

private void RotateTo()
    {
        var distance = Vector3.Distance(capsule.position, curvedLinePoints[rotationIndex].transform.position);
        if(distance < 0.1f)
        {
            rotationIndex++;
        }

        // Determine which direction to rotate towards
        Vector3 targetDirection = curvedLinePoints[rotationIndex].transform.position -capsule.position;

        // The step size is equal to speed times frame time.
        float singleStep = rotationSpeed * Time.deltaTime;

        // Rotate the forward vector towards the target direction by one step
        Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);

        // Draw a ray pointing at our target in
        Debug.DrawRay(capsule.position, newDirection, Color.red);

        // Calculate a rotation a step closer to the target and applies rotation to this object
        capsule.rotation = Quaternion.LookRotation(newDirection);
    }

Two problems :

  1. Even if I set the rotationSpeed to 30 it's still rotating kind of slow. Why 30 is so slow ?

  2. The rotation is on all the axis like in this screenshot but I want it to rotate only on the Y but because to make the capsule stand I have to set the X to -90 when rotating on the Y it's changing the capsule-like scaling it. I want the capsule to like spin around itself.

Rotation

This is how the capsule looks like in the original when running the game before it starts rotating :

Rotation at start

ANSWER

Answered 2021-May-20 at 23:43

To answer your two newly added questions:

  1. Even if I set the rotationSpeed to 30 it's still rotating kind of slow. Why 30 is so slow?

Your current timestep is set to rotationSpeed * Time.deltaTime. As you mentioned, rotationSpeed is now 30, but what is Time.deltaTime? Time.deltaTime is the amount of seconds between frames, meaning it is 1 / framesPerSecond. Generally framerate is ~60, so for the example we'll call it 1/60 or 0.016666667. When multiplied by your constant of 30, we get 30/60 or 0.5.

The parameter you are using in RotateTowards is maxRadiansDelta. From the wiki, this parameter is:

The maximum angle in radians allowed for this rotation.

As to why your rotation could be defined as slow, is you are moving at roughly 0.5 radians per second. If you increase this value from 30 to something like 60, you then move to 1.0 radians per second and so on.

  1. The rotation is on all the axis like in this screenshot but I want it to rotate only on the Y but because to make the capsule stand I have to set the X to -90 when rotating on the Y it's changing the capsule-like scaling it. I want the capsule to like spin around itself.

The issue here is that RotateTowards will orient your object on all axes to directly take the forward direction and point it at your goal transform. I believe something like this could work?

Vector3 newDirection = Vector3.RotateTowards(capsule.forward, targetDirection, singleStep, 0.0f);

newDirection.z = 0f;

capsule.rotation = Quaternion.LookRotation(newDirection, capsule.Up);

I believe that the above snippet should only rotate the object around the Y-axis. Let me know how it goes.

Source https://stackoverflow.com/questions/67627909

QUESTION

Polygon Z Ordering

Asked 2021-May-20 at 07:40

I am currently trying to write a 2D only 3D "renderer" that uses polygons only.

Before rendering, I order the polygons by calculating one Z value as following:

double z = (v1.getZ()+v2.getZ()+v3.getZ());

My polygons consist of each three vectors (X,Y,Z)

Then I sort the polygons so I then can use the painters algorithm approach:

int i = 0;
for (Poly polygon : polyZSort) {
    if(polygon.getRealZ()>z) {
        break;
    }
    i++;
}
polyZSort.add(i, polygon);

The rendering then is as simple as:

for (Poly poly : polyZSort) {
    OVector v1 = poly.getV1();
    v1 = form.doTransform(v1);
    OVector v2 = poly.getV2();
    v2 = form.doTransform(v2);
    OVector v3 = poly.getV3();
    v3 = form.doTransform(v3);
                
    g2d.setColor(poly.getColor());

    Polygon pl = new Polygon();
    pl.addPoint(getX(v1.getX()),getY(v1.getY()));   
    pl.addPoint(getX(v2.getX()),getY(v2.getY()));   
    pl.addPoint(getX(v3.getX()),getY(v3.getY()));
                

    g2d.fillPolygon(pl);    

    // black border line
    g2d.setColor(Color.BLACK);
    g2d.drawLine(
        getX(v1.getX()), 
        getY(v1.getY()), 
        getX(v2.getX()), 
        getY(v2.getY())
    );
                
    g2d.drawLine(
        getX(v2.getX()), 
        getY(v2.getY()), 
        getX(v3.getX()), 
        getY(v3.getY())
    );
                
    g2d.drawLine(
        getX(v3.getX()), 
        getY(v3.getY()), 
        getX(v1.getX()), 
        getY(v1.getY())
    );                          
}

This works, even with multiple cubes (but only most of the time): works

However in certain positions, the ordering seems to be wrong: enter image description here

Does anybody know where the problem may be? Here a video of the "glitch" https://vimeo.com/552355610

ANSWER

Answered 2021-May-20 at 07:40

You are missing important steps ... This is how it should be done:

  1. input is list of 3D triangles, output is list of 3D triangles

    The output list is empty at start

  2. "2D" screen project each processed triangle and leave it with original z values

    so its still 3D , but x,y are screen positions and z is "original" z value in camera coordinate system.

  3. check each processed triangle after projection if it intersects any triangle already in output list.

    If no intersection occurs then simply add this triangle to output list as is.

    if it does intersect you need to re-triangulate all intersected and new triangle so no intersections occur. And add these new triangle(s) to output list (while removing the original intersecting triangles from output list).

    Here exampel of 2 overlaping triangles:

    retriangulation

    as you can see it can create quite a lot of new triangles and usually new triangle intersects more than just one triangle so you need to do this recursively for each triangle of the overlapped parts or create a list of all intersecting triangles first and retriangulate them at once ...

  4. after whole scene is processed Z sort the output list by mid point z value

    this step you already got.

  5. render the sorted output list using 2D triangle rendering

    this step you already got.

As you can see you need a buffer of size depending on number of triangles in scene and overlaps. Also this method is very complicated (and not very good choice for rookie programmers) and usable only for very simple scenes. For more complex ones is much easier and faster to use Z buffer. However that one require along with the buffer itself also 3D rendering of triangle (so one more interpolation and per pixel condition). As you can see its O(1) instead of the O(n.log(n)) for z sort.

Source https://stackoverflow.com/questions/67602347

Community Discussions, Code Snippets contain sources that include Stack Exchange Network

VULNERABILITIES

No vulnerabilities reported

INSTALL Cubes

You can use Cubes like any standard Java library. Please include the the jar files in your classpath. You can also use any IDE and you can run and debug the Cubes component as you would do with any other Java program. Best practice is to use a build tool that supports dependency management such as Maven or Gradle. For Maven installation, please refer maven.apache.org. For Gradle installation, please refer gradle.org .

SUPPORT

For any new features, suggestions and bugs create an issue on GitHub. If you have any questions check and ask questions on community page Stack Overflow .

Implement Cubes faster with kandi.

  • Use the support, quality, security, license, reuse scores and reviewed functions to confirm the fit for your project.
  • Use the, Q & A, Installation and Support guides to implement faster.

Discover Millions of Libraries and
Pre-built Use Cases on kandi