LWJGL BlockWorld

Picking faces in 3d - Part 1 - Maths Theory

I’m not sure if this is a standard approach, this is just how I figured it out.

A ray is traced from the camera position along its direction Vector.

In a voxel world a test can be made at unit intervals on X,Y,Z axis to see if a collision with a
face has occurred. The distance of 3 possible collisions is compared. The closes is the hit face.
(this method can be adapted to work with non-axis aligned boxes too)

This example shows how to use parametric equations to make these tests. These are the equations we will use

This example will be shown in 2d for clarity, but unlike equations of line, this method will work exactly the same in 3d.

The camera is located at (1,2.5) has a Vector of (1,-0.25)
That means for each moment of 1 in X, there will be -0.25 movement in Y

We will use the parameter t, which could be visualised as time. After a given time, we will be further along the line. We know where we want to be in x. We are checking all the x planes moving away from the camera in + direction(in this case).

For this example we will be checking x= 6. So x(t) = 6.
Now we have x(t) we can solve for t.

Now we can calculate the y value y(t) where the line will be on x=6. If the value is >box min and <box max position then the face has been hit.

In 3d the Z and Y values have to be checked, both must be within the in and max bounds of the box for there to be a hit.

We then calculate the distance to that point - in 3d Distance = Math.sqrt ( X^2, Y^2,Z^2)

Now test all the Z planes, then all the Y planes. The one with the shortest Distance is the one you hit.

Part 2 coming soon - Java code

Picking faces in 3d - Part 1 - Maths Theory

I’m not sure if this is a standard approach, this is just how I figured it out.

A ray is traced from the camera position along its direction Vector.

In a voxel world a test can be made at unit intervals on X,Y,Z axis to see if a collision with a
face has occurred. The distance of 3 possible collisions is compared. The closes is the hit face.
(this method can be adapted to work with non-axis aligned boxes too)

This example shows how to use parametric equations to make these tests. These are the equations we will use

This example will be shown in 2d for clarity, but unlike equations of line, this method will work exactly the same in 3d.

The camera is located at (1,2.5) has a Vector of (1,-0.25)
That means for each moment of 1 in X, there will be -0.25 movement in Y

We will use the parameter t, which could be visualised as time. After a given time, we will be further along the line. We know where we want to be in x. We are checking all the x planes moving away from the camera in + direction(in this case).

For this example we will be checking x= 6. So x(t) = 6.
Now we have x(t) we can solve for t.

Now we can calculate the y value y(t) where the line will be on x=6. If the value is >box min and <box max position then the face has been hit.

In 3d the Z and Y values have to be checked, both must be within the in and max bounds of the box for there to be a hit.

We then calculate the distance to that point - in 3d Distance = Math.sqrt ( X^2, Y^2,Z^2)

Now test all the Z planes, then all the Y planes. The one with the shortest Distance is the one you hit.

Part 2 coming soon - Java code

Face Picking part 2 - Java Code

This is my cumbersome implementation. Its not optimised, or well coded, but it should be clear how it works.

The update loop gets the camera vector…using the horizontal rotation (rot) and vertical rotation (lookupdown) angles in degrees

public void getNormalisedCamVector(){
			camVector.y =  (float) Math.sin(lookupdown * piover180) * 1f;
			float v = (float) Math.cos(lookupdown * piover180) * 1f;
			camVector.x = (float) Math.sin(yrot * piover180) * v;
			camVector.z= (float) Math.cos(yrot * piover180) * v;
			
		}

Next a test is done in X, if facing right x>0… so


		//do right X sweep
			if(camVector.x>0){
				
				for(int distance=1;distance<10;distance++){
				//solve for t
				t =   (((int)xpos -( distance+0.5f) )-xpos) / camVector.x;
				Xh = (int)xpos -(distance + 1);
				
				//solve for Yh
				Yh = -camHieght + t*camVector.y;
				Zh = zpos + t  * camVector.z;
				Xd = xpos - Xh;
				Yd = Math.abs(-camHieght - Yh);
				Zd =Math.abs(zpos - Zh);
				
				
				Yh = (int) (Yh+0.5f);
				Zh = (int)( Zh+0.5f);
				helperX=Xh;
				helperY=Yh;
				helperZ=Zh;
				//System.out.println("Xh="+Xh+ "   Yh="+ Yh +  "  Zh=" + Zh);
				if(isHelperOnSoildBlock()){
					helperFace = 5;
					
					XDist = (float)Math.sqrt(Xd*Xd + Yd* Yd + Zd*Zd);
					xx = Xh; xy = Yh; xz = Zh;
					//System.out.println("XDist =" + XDist );
					break;
				}
				}
				
			}


some floats are used to hold temp values. The isHelperOnSoildBlock method uses the helperBlock position and returns true if the block is soild (not water or air).
The distance is saved.

Y and Z axis tests are just the same. (as well as facing left x<=0)

After all the tests:


if (XDist < ZDist && XDist < YDist){
			
				if(camVector.x>0){
				helperFace = 5;	
				}else{
				helperFace = 4;	
				}
				
				
				Xh = xx; Yh = xy; Zh=xz;
			}

In this example if the X distance was the shortest, the faces and block position are saved. The blocks render method will only render the
face with that helperFace ID.

one thing to note:
when a block is removed , its the block at Xh, Yh, Zh

but if a block is added
then if HelperFace =4, then Xh-=1 just before the block is placed.
So we use the helperface ID to determine how the selected face alters where we place a block - but not where a block is removed.

Face Picking part 2 - Java Code

This is my cumbersome implementation. Its not optimised, or well coded, but it should be clear how it works.

The update loop gets the camera vector…using the horizontal rotation (rot) and vertical rotation (lookupdown) angles in degrees

public void getNormalisedCamVector(){
			camVector.y =  (float) Math.sin(lookupdown * piover180) * 1f;
			float v = (float) Math.cos(lookupdown * piover180) * 1f;
			camVector.x = (float) Math.sin(yrot * piover180) * v;
			camVector.z= (float) Math.cos(yrot * piover180) * v;
			
		}

Next a test is done in X, if facing right x>0… so


		//do right X sweep
			if(camVector.x>0){
				
				for(int distance=1;distance<10;distance++){
				//solve for t
				t =   (((int)xpos -( distance+0.5f) )-xpos) / camVector.x;
				Xh = (int)xpos -(distance + 1);
				
				//solve for Yh
				Yh = -camHieght + t*camVector.y;
				Zh = zpos + t  * camVector.z;
				Xd = xpos - Xh;
				Yd = Math.abs(-camHieght - Yh);
				Zd =Math.abs(zpos - Zh);
				
				
				Yh = (int) (Yh+0.5f);
				Zh = (int)( Zh+0.5f);
				helperX=Xh;
				helperY=Yh;
				helperZ=Zh;
				//System.out.println("Xh="+Xh+ "   Yh="+ Yh +  "  Zh=" + Zh);
				if(isHelperOnSoildBlock()){
					helperFace = 5;
					
					XDist = (float)Math.sqrt(Xd*Xd + Yd* Yd + Zd*Zd);
					xx = Xh; xy = Yh; xz = Zh;
					//System.out.println("XDist =" + XDist );
					break;
				}
				}
				
			}


some floats are used to hold temp values. The isHelperOnSoildBlock method uses the helperBlock position and returns true if the block is soild (not water or air).
The distance is saved.

Y and Z axis tests are just the same. (as well as facing left x<=0)

After all the tests:


if (XDist < ZDist && XDist < YDist){
			
				if(camVector.x>0){
				helperFace = 5;	
				}else{
				helperFace = 4;	
				}
				
				
				Xh = xx; Yh = xy; Zh=xz;
			}

In this example if the X distance was the shortest, the faces and block position are saved. The blocks render method will only render the
face with that helperFace ID.

one thing to note:
when a block is removed , its the block at Xh, Yh, Zh

but if a block is added
then if HelperFace =4, then Xh-=1 just before the block is placed.
So we use the helperface ID to determine how the selected face alters where we place a block - but not where a block is removed.

Update

Added a 3d cloud. Modelled and textured in blender, and exported as .OBJ.
I have a also made a new animated water texture, and pass co-ordinates to the shader.

fFeFzTAbHgo

Update

Added a 3d cloud. Modelled and textured in blender, and exported as .OBJ.
I have a also made a new animated water texture, and pass co-ordinates to the shader.

fFeFzTAbHgo

Oh this is so inspiring, it looks beautiful, just for this I’m greatly inspired to learn java and enrole myself in a CS course.
Where can we play it? Is there any chance you show how goes your code so we all can learn from this good work too? Thank you keep the good work!

Oh this is so inspiring, it looks beautiful, just for this I’m greatly inspired to learn java and enrole myself in a CS course.
Where can we play it? Is there any chance you show how goes your code so we all can learn from this good work too? Thank you keep the good work!

The project is coming along nicely, but that inventory popup/screen seems really clumsy to me, like it’s always blocking your view of the block hand. Obviously I saw the “x” button, but I think it would be a lot better to put the inventory somewhere less-intrusive.

The project is coming along nicely, but that inventory popup/screen seems really clumsy to me, like it’s always blocking your view of the block hand. Obviously I saw the “x” button, but I think it would be a lot better to put the inventory somewhere less-intrusive.

I will compile a runnable version, and also update the source code for download. I’ve cleaned the code up a bit and annotated some of it. Thank you for taking an interests, I’m doing this project to learn various things.

Yes, I see what you mean. I plan for the windows to be moveable, drag with mouse. I’ve got a a map window to put in, I might put the Inventory under that. Thank you for your suggestion, I’ll change that for the next update.

I will compile a runnable version, and also update the source code for download. I’ve cleaned the code up a bit and annotated some of it. Thank you for taking an interests, I’m doing this project to learn various things.

Yes, I see what you mean. I plan for the windows to be moveable, drag with mouse. I’ve got a a map window to put in, I might put the Inventory under that. Thank you for your suggestion, I’ll change that for the next update.

Have been busy lately with other things - I’m not sure at this point if I will work on this again, maybe - may be not.
Working on a small app atm…

Anyhow…I have uploaded the source code to my site:

Please feel free to use any of it. Its not perfect, or even good, but you might be able to use some of it if your learning LWJGL - especially to make a
block game.

I’ll still be around on forum so ask questions if you need to…

Have been busy lately with other things - I’m not sure at this point if I will work on this again, maybe - may be not.
Working on a small app atm…

Anyhow…I have uploaded the source code to my site:

Please feel free to use any of it. Its not perfect, or even good, but you might be able to use some of it if your learning LWJGL - especially to make a
block game.

I’ll still be around on forum so ask questions if you need to…

I have been lurking here for a couple of weeks reading on the progress you had made. Thank you for sharing all the source Vermeer!! I can’t wait to look at it. :slight_smile:

I have been lurking here for a couple of weeks reading on the progress you had made. Thank you for sharing all the source Vermeer!! I can’t wait to look at it. :slight_smile:

Hello i need some help with this.first of all maybe someone can explain how that tool is drawed?i looked on its code and played a litle bit but i cant figure out how to change that metal sides shape.for example hot to draw an axe.I have made stick but i am missing the metal part.
And my other question is how do i can enable infinite terrain back? And yea i am yust learning all this.Son i will make my own engine but at the beginig i want to understand how this code works.Thanks.

Hello i need some help with this.first of all maybe someone can explain how that tool is drawed?i looked on its code and played a litle bit but i cant figure out how to change that metal sides shape.for example hot to draw an axe.I have made stick but i am missing the metal part.
And my other question is how do i can enable infinite terrain back? And yea i am yust learning all this.Son i will make my own engine but at the beginig i want to understand how this code works.Thanks.

Enable infinite terrain? You have to generate the terrain yourself, per chunk, using an algorithm that you’ve implemented.

DreamHacker start at the basics. It sounds like you don’t know much about OpenGL yet because your first question is almost trivial to solve. What you need to understand is that no one will code your entire game for you, and if you think that’s going to happen then you need to revisit the basics of programming where people learn to be independent. You need to be a problem solver.