Rotating object around camera

Hello everyone, I am trying to make an accurate sky simulation in the voxel game I am working on, as an update. So far, I have day and night working, with clouds (though they are kind of buggy). However, I want to make a sun that rotates around the camera. I store this in a pshape. However, I was to make it rotateX() (rotate vertically). However, it just spins in tiny circle. How would I make the arc bigger and make it rotate around the camera?

Source:

import processing.core.PApplet;
import processing.core.PImage;
import processing.core.PVector;
import processing.core.PShape;
import processing.core.PConstants;
public class Sky {
  PImage clouds;
  PApplet app;
  int r = 0, g = 0, b = 0;
  public PVector pos = new PVector(0, 0, 0);
  public PVector pos2 = new PVector(0, 0, 0);
  public PVector pos3 = new PVector(0, 0, 0);
  public PVector pos4 = new PVector(0, 0, 0);
  public PVector pos5 = new PVector(0, 0, 0);
  PShape skyShape;
  boolean day;
  boolean night;
  int dayTime = 60000;
  int sunsetColor = 0xFFFD5E53;
  int dayColor = 0xFF82E6FF;
  int nightColor = 0xFF1E1E1E;
  int sunsetAnimTime = 10000;
  boolean startTimer = false;
  int inc = 0;
  PShape c, c2, c3;
  PShape sun;
  int timer = (sunsetAnimTime/1000) * 60;
  public Sky(PApplet p) {
	  app = p;
	  clouds = Minecraft.clouds;
	  pos = new PVector(0 * Minecraft.size, 256 * Minecraft.size, 0 * Minecraft.size);
	  pos2 = new PVector(0 * Minecraft.size, 256 * Minecraft.size, -128 * Minecraft.size);
	  pos3 = new PVector(0 * Minecraft.size, 256 * Minecraft.size, -256 * Minecraft.size);
	  pos4 = new PVector(0 * Minecraft.size, 256 * Minecraft.size, -128 * Minecraft.size);
	  pos5 = new PVector(0 * Minecraft.size, 256 * Minecraft.size, -256 * Minecraft.size);
	  float x1 = -5000;
	  float y1 = -5000;
	  float z1 = -5000;
	  float x2 = 5000;
	  float y2 = 5000;
	  float z2 = 5000;
	  sun = app.createShape();
      sun.setTexture(Minecraft.sunImage);
      sun.beginShape(PConstants.QUADS);
      sun.noFill();
      sun.noStroke();
      sun.vertex(x1, y1, z1, 0f, 0f);
      sun.vertex(x2, y1, z1, 1f, 0f);
      sun.vertex(x2, y2, z1, 1f, 1f);
      sun.vertex(x1, y2, z1, 0f, 1f);
      sun.endShape();
	  x1 = -6400;
	  y1 = -6400;
	  z1 = -6400;
	  x2 = 6400;
	  y2 = 6400;
	  z2 = 6400;
	  c = app.createShape();
      c.setTexture(Minecraft.clouds);
	  c.beginShape(PConstants.QUADS);
	  c.noFill();
	  c.noStroke();
	  c.vertex(x1, y1, z2, 0, 0);
	  c.vertex(x2, y1, z2, 1, 0);
	  c.vertex(x2, y1, z1, 1, 1);
	  c.vertex(x1, y1, z1, 0, 1);
	  c.endShape();
	  z1 -= 128 * Minecraft.size;
	  z2 -= 128 * Minecraft.size;
	  c2 = app.createShape();
      c2.setTexture(Minecraft.clouds);
	  c2.beginShape(PConstants.QUADS);
	  c2.noFill();
	  c2.noStroke();
	  c2.vertex(x1, y1, z2, 0, 0);
	  c2.vertex(x2, y1, z2, 1, 0);
	  c2.vertex(x2, y1, z1, 1, 1);
	  c2.vertex(x1, y1, z1, 0, 1);
	  c2.endShape();
	  z1 -= 128 * Minecraft.size;
	  z2 -= 128 * Minecraft.size;
	  c3 = app.createShape();
      c3.setTexture(Minecraft.clouds);
	  c3.beginShape(PConstants.QUADS);
	  c3.noFill();
	  c3.noStroke();
	  c3.vertex(x1, y1, z2, 0, 0);
	  c3.vertex(x2, y1, z2, 1, 0);
	  c3.vertex(x2, y1, z1, 1, 1);
	  c3.vertex(x1, y1, z1, 0, 1);
	  c3.endShape();
	  c3 = app.createShape();
      c3.setTexture(Minecraft.clouds);
	  c3.beginShape(PConstants.QUADS);
	  c3.noFill();
	  c3.noStroke();
	  c3.vertex(x1, y1, z2, 0, 0);
	  c3.vertex(x2, y1, z2, 1, 0);
	  c3.vertex(x2, y1, z1, 1, 1);
	  c3.vertex(x1, y1, z1, 0, 1);
	  c3.endShape();
  }
  public void setColor(int x, int y, int z) {
	  r = x;
	  g = y;
	  b = z;
  }
  public void draw() {
	 if (((app.millis() / dayTime) & 1) == 0) {
		 if((((app.millis() + sunsetAnimTime) / dayTime) & 1) != 0) {
			float a = PApplet.constrain(timer, 1, 100);
		    animateSky(a, sunsetColor, dayColor);
		 } else {
			 if((((app.millis() - sunsetAnimTime) / dayTime) & 1) != 0) {
					float a = PApplet.constrain(timer, 1, 100);
				    animateSky(a, dayColor, sunsetColor);
				 } else {
			 app.background(dayColor);
				 }
		 }
	 } else {
		 if((((app.millis() + sunsetAnimTime) / dayTime) & 1) == 0) {
			float a = PApplet.constrain(timer, 1, 100);
		    animateSky(a, sunsetColor, nightColor);
		 } else {
			 if((((app.millis() - sunsetAnimTime) / dayTime) & 1) == 0) {
					float a = PApplet.constrain(timer, 1, 100);
				    animateSky(a, nightColor, sunsetColor);
				 } else {
			 app.background(nightColor);
				 }
		 }
	 }
	 if(startTimer) {
		 timer--;
	 }
	  if(timer < 1) {
		  startTimer = false;
		  timer = (sunsetAnimTime/1000) * 60;
	  }
	  PVector chunkPos = Minecraft.camera.chunkPos;
	  PVector p = Minecraft.camera.position;
	  /*
	  pos.z = chunkPos.z * (Chunk.w * Minecraft.size);
	  pos2.z = chunkPos.z * (Chunk.w * Minecraft.size);
	  pos3.z = chunkPos.z * (Chunk.w * Minecraft.size);
	  */
	  pos.x = chunkPos.x * (Chunk.w * Minecraft.size);
	  pos2.x = chunkPos.x * (Chunk.w * Minecraft.size);
	  pos3.x = chunkPos.x * (Chunk.w * Minecraft.size);
	  app.pushMatrix();
	  app.translate(pos.x, pos.y, pos.z);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x, pos2.y, pos2.z);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x, pos3.y, pos3.z);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(pos.x + 12800, pos.y, pos.z);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x + 12800, pos2.y, pos2.z);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x + 12800, pos3.y, pos3.z);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(pos.x - 12800, pos.y, pos.z);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x - 12800, pos2.y, pos2.z);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x - 12800, pos3.y, pos3.z);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(pos.x, pos.y, pos.z + 12800);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x, pos2.y, pos2.z + 12800);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x, pos3.y, pos3.z + 12800);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(pos.x + 12800, pos.y, pos.z + 12800);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x + 12800, pos2.y, pos2.z + 12800);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x + 12800, pos3.y, pos3.z + 12800);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(pos.x - 12800, pos.y, pos.z + 12800);
	  app.shape(c);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos2.x - 12800, pos2.y, pos2.z + 12800);
	  app.shape(c2);
	  app.popMatrix();
	  app.pushMatrix();
	  app.translate(pos3.x - 12800, pos3.y, pos3.z + 12800);
	  app.shape(c3);
	  app.popMatrix();
	  
	  app.pushMatrix();
	  app.translate(p.x, p.y, p.z + 12800);
	  app.rotateX(PApplet.radians(-inc));
	  app.shape(sun);
	  app.popMatrix();
	  
	  if(pos.z >= (128 * Minecraft.size) + chunkPos.z * (Chunk.w * Minecraft.size)) {
		  pos.z = chunkPos.z * (Chunk.w * Minecraft.size) - (640 * Minecraft.size);
	  }
	  if(pos2.z >= (128 * Minecraft.size) + chunkPos.z * (Chunk.w * Minecraft.size) + 6400) {
		  pos2.z = chunkPos.z * (Chunk.w * Minecraft.size) - (512 * Minecraft.size);
	  }
	  if(pos3.z >= (128 * Minecraft.size) + chunkPos.z * (Chunk.w * Minecraft.size) + 12800) {
		  pos3.z = chunkPos.z * (Chunk.w * Minecraft.size) - (384 * Minecraft.size);
	  }
	  if(pos4.z >= (128 * Minecraft.size) + chunkPos.z * (Chunk.w * Minecraft.size) + 6400) {
		  pos4.z = chunkPos.z * (Chunk.w * Minecraft.size) - (256 * Minecraft.size);
	  }
	  if(pos5.z >= (128 * Minecraft.size) + chunkPos.z * (Chunk.w * Minecraft.size) + 12800) {
		  pos5.z = chunkPos.z * (Chunk.w * Minecraft.size) - (128 * Minecraft.size);
	  }
	  pos.z += 16;
	  pos2.z += 16;
	  pos3.z += 16;
	  pos4.z += 16;
	  pos5.z += 16;
	  inc++;
  }
  public void animateSky(float x, int col1, int col2) {
	  startTimer = true;
	  app.background(app.lerpColor(col1, col2, x / 100));
  }
}

Minecraft is the class that holds data that this class uses, such as cube size and PImages. I am not showing it here.

Hey buddy, could you make a simple (simplified) version of the problem in the shape of a sketch we can run and take a look at, without any of the sky and dependent classes? You just want a sphere to rotate around the camera?

2 Likes

For a simplified version I would make a camera by using the QueasyCam library, and then get information from the camera to determine its position, and draw the sphere accordingly.

in a simple sketch like this:

import queasycam.*;
QueasyCam camera;
void setup() {
 size(1000, 800, P3D);
 camera = new QueasyCam(this);
}
void draw() {
  background(0);
pushMatrix();
translate(0, 0, 0);
 sphere(100); 
popMatrix();
}

How would I get the sphere to rotate on the x axis, around the camera?

You can make an object rotate around a point by using basic trig:

float rad = 1000; // radius
float angle = frameCount / 100.f; // arbitrary value that determines the rotation speed

float x = rad * cos(angle);
float z = rad * sin(angle); // x, z is the horizontal plane

Add the camera.position to these values, translate to this position before you draw the sphere and you should be done?

2 Likes

Whats the difference between QueasyCam and PeasyCam?
http://mrfeinberg.com/peasycam/#about

It says in the description… (I wondered the same…) he named it in honour of Peasy; it’s a FPS adaptation, allowing you to move the camera with WASD.

2 Likes

Thank you for the solution. However, I have 1 more question.

  1. Would I use tan() to make the sphere rotate on the y-axis?

Well, yes and no. You can look up spherical coordinates on wiki to understand how coordinates around a sphere work, but in this case it’d probably be easier to rotate your orbit using rotateX/Y/Z or rotation matrices. Like I suggested in my example, the combination of cos for one, and sin for the other makes a circle - to which components you connect them; x, y or z, determines how the circle is oriented.

x = cos(angle)
y = sin(angle)

makes the circle go vertical, aligned with the camera plane (you see a circle)

z = cos(angle)
x = sin(angle)

creates a horizontal circle

z = cos(angle)
y = sin(angle)

creates a vertical circle that’s perpendicular to the camera plane (you see the circle from the side: a line)