如何计算3D模型是否与地形表面相交 LWJGL

huangapple go评论36阅读模式
英文:

How to calculate if 3D model is intersecting terrain surface LWJGL

问题

I am currently working on a project using 3d simplex noise and the marching cubes algorithm in order to procedurally generated terrain. I am trying to implement collision detection between the player object and terrain mesh but I have no clue how to start. I have read some articles and posts about using JBullet and other libraries but they do not support complex meshes such as the ones generated by simplex noise. In order to simplify things for myself I decided to make it so that the player can only move in the direction I point meaning that I would only need to check if a singular point on the player is intersecting with the terrain. Are there any methods to implement such a process? (edit: I've already looked into barycentric coordinates but I have no idea how to implement into the game)

Current Player Code

package Entities;

import org.lwjgl.glfw.GLFW;

import Engine.Input;
import Maths.Vector3f;
import Models.TexturedModel;

public class Player extends Entity {
	
	public float xspeed = 0,zspeed = 0, yspeed = 0; 
	public Vector3f mousePos;
	public float yrotation = 0, zrotation = 0;
	public float maxYRotation = 75f;
	
	private double lastMousePosX = 600 , newMousePosX;
	private double lastMousePosY = 500 , newMousePosY;
	private float speed = 3;
	
	public Player(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, float scale) {
		super(model, position, rotX, rotY, rotZ, scale);
	}
	public void move(){
		checkInput();
		System.out.println("x = "+this.position.x+" y = "+this.position.y+" z = "+this.position.z);
		checkCollision();
	}
	public boolean checkCollision(){
		if(terrain != null){
			for(int i = 0; i<terrain.getVertices().length; i+=9){
				Vector3f vertex1 = new Vector3f(terrain.getVertices()[i],terrain.getVertices()[i+1],terrain.getVertices()[i+2]);
				Vector3f vertex2 = new Vector3f(terrain.getVertices()[i+3],terrain.getVertices()[i+4],terrain.getVertices()[i+5]);
				Vector3f vertex3 = new Vector3f(terrain.getVertices()[i+6],terrain.getVertices()[i+7],terrain.getVertices()[i+8]);
				
                //Check if point p is interseting triangle (vertex1, vertex2, vertex3)
                if(someCalculationFunction(position, vertex1, vertex2, vertex3)){
				    return true;
                }
			}
		}
		return false;
	}

	public void checkInput(){
		newMousePosX = Input.getMouseX();
		newMousePosY = Input.getMouseY();
		
		float dx = (float)(newMousePosX-lastMousePosX)*0.07f;
		float dy = (float)(newMousePosY-lastMousePosY)*0.07f;
		
		if(!Input.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_1)){

			this.rotY -= dx/2;
			this.rotX -= dy*0.8f;
		
		}
		
		if(Math.abs(rotX) > 50){
			this.rotX = Math.abs(rotX)/rotX*50;
		}
		
		if(this.rotY<0){
			this.rotY = 360;
		}
		
		float horizontalDistance = speed*(float)(Math.cos(Math.toRadians(rotX)));
		float verticleDistance = speed*(float)(Math.sin(Math.toRadians(rotX)));

		if(Input.isKeyDown(GLFW.GLFW_KEY_W)){
			this.position.x += horizontalDistance*Math.sin(Math.toRadians(-rotY));
			this.position.z -= horizontalDistance*Math.cos(Math.toRadians(-rotY));
			this.position.y += verticleDistance;
		}else if(Input.isKeyDown(GLFW.GLFW_KEY_S)){
			this.position.x -= horizontalDistance*Math.sin(Math.toRadians(-rotY));
			this.position.z += horizontalDistance*Math.cos(Math.toRadians(-rotY));
			this.position.y -= verticleDistance;	
		}
		
		lastMousePosX = newMousePosX;
		lastMousePosY = newMousePosY;		
		
	}

}

Please note that code comments and formatting have been retained for clarity.

英文:

I am currently working on a project using 3d simplex noise and the marching cubes algorithm in order to procedurally generated terrain. I am trying to implement collision detection between the player object and terrain mesh but I have no clue how to start. I have read some articles and posts about using JBullet and other libraries but they do not support complex meshes such as the ones generated by simplex noise. In order to simplify things for myself I decided to make it so that the player can only move in the direction I point meaning that I would only need to check if a singular point on the player is intersecting with the terrain. Are there any methods to implement such a process? (edit: I've already looked into barycentric coordinates but I have no idea how to implement into the game)

Current Player Code

package Entities;
import org.lwjgl.glfw.GLFW;
import Engine.Input;
import Maths.Vector3f;
import Models.TexturedModel;
public class Player extends Entity {
public float xspeed = 0,zspeed = 0, yspeed = 0; 
public Vector3f mousePos;
public float yrotation = 0, zrotation = 0;
public float maxYRotation = 75f;
private double lastMousePosX = 600 , newMousePosX;
private double lastMousePosY = 500 , newMousePosY;
private float speed = 3;
public Player(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, float scale) {
super(model, position, rotX, rotY, rotZ, scale);
}
public void move(){
checkInput();
System.out.println(&quot;x =&quot;+this.position.x+&quot; y =&quot;+this.position.y+&quot; z =&quot;+this.position.z);
checkCollision();
}
public boolean checkCollision(){
if(terrain != null){
for(int i = 0; i&lt;terrain.getVertices().length; i+=9){
Vector3f vertex1 = new Vector3f(terrain.getVertices()[i],terrain.getVertices()[i+1],terrain.getVertices()[i+2]);
Vector3f vertex2 = new Vector3f(terrain.getVertices()[i+3],terrain.getVertices()[i+4],terrain.getVertices()[i+5]);
Vector3f vertex3 = new Vector3f(terrain.getVertices()[i+6],terrain.getVertices()[i+7],terrain.getVertices()[i+8]);
//Check if point p is interseting triangle (vertex1, vertex2, vertex3)
if(someCalculationFunction(position, vertex1, vertex2, vertex3){
return true;
}
}
}
return false;
}
public void checkInput(){
newMousePosX = Input.getMouseX();
newMousePosY = Input.getMouseY();
float dx = (float)(newMousePosX-lastMousePosX)*0.07f;
float dy = (float)(newMousePosY-lastMousePosY)*0.07f;
if(!Input.isMouseDown(GLFW.GLFW_MOUSE_BUTTON_1)){
this.rotY -= dx/2;
this.rotX -= dy*0.8f;
}
if(Math.abs(rotX) &gt; 50){
this.rotX = Math.abs(rotX)/rotX*50;
}
if(this.rotY&lt;0){
this.rotY = 360;
}
float horizontalDistance = speed*(float)(Math.cos(Math.toRadians(rotX)));
float verticleDistance = speed*(float)(Math.sin(Math.toRadians(rotX)));
if(Input.isKeyDown(GLFW.GLFW_KEY_W)){
this.position.x += horizontalDistance*Math.sin(Math.toRadians(-rotY));
this.position.z -= horizontalDistance*Math.cos(Math.toRadians(-rotY));
this.position.y += verticleDistance;
}else if(Input.isKeyDown(GLFW.GLFW_KEY_S)){
this.position.x -= horizontalDistance*Math.sin(Math.toRadians(-rotY));
this.position.z += horizontalDistance*Math.cos(Math.toRadians(-rotY));
this.position.y -= verticleDistance;	
}
lastMousePosX = newMousePosX;
lastMousePosY = newMousePosY;		
}
}

答案1

得分: 1

我不确定是否正确理解了问题,但这个答案将解决确保玩家的高度与其所站立的地形高度相匹配的问题。

使用重心坐标,您可以通过使用构成该三角形的三个顶点的高度来计算玩家的高度应该是多少:

public static float baryCentric(Vector3f p1, Vector3f p2, Vector3f p3, Vector2f pos) {
    float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
    float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
    float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
    float l3 = 1.0f - l1 - l2;
    return l1 * p1.y + l2 * p2.y + l3 * p3.y;
}

为了获得这三个点,您可以使用玩家的世界坐标进行计算:

// 假设世界由相等高度和宽度的三角形构成
float gridSquareSize = SIZE_OF_TERRAIN_MESH / NUM_TRIANGLES_PER_ROW;
float xCoord = worldX % gridSquareSize / gridSquareSize;
float zCoord = worldZ % gridSquareSize / gridSquareSize;

有了xCoord和zCoord,您可以确定需要用于baryCentric计算的三个点。

英文:

I'm not positive if I understood the question right, but this answer will address the problem of ensuring the players height is that of the terrain that it is standing on

With barycentric coordinates you can calculate what the players height is supposed to be by using the heights of the three vertices that make up that triangle:

public static float baryCentric(Vector3f p1, Vector3f p2, Vector3f p3, Vector2f pos) {
float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z)) / det;
float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z)) / det;
float l3 = 1.0f - l1 - l2;
return l1 * p1.y + l2 * p2.y + l3 * p3.y;
}

In order to get these three points you can make a calculation using the world coordinates of your player:

    //Assuming the world is constructed of equal height and width sized triangles
float gridSquareSize = SIZE_OF_TERRAIN_MESH / NUM_TRIANGLES_PER_ROW;
float xCoord = worldX % gridSquareSize / gridSquareSize;
float zCoord = worldZ % gridSquareSize / gridSquareSize;

With the xCoord and zCoord you can determine the 3 points that you need to use for your baryCentric calculation

huangapple
  • 本文由 发表于 2020年7月30日 05:17:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63162549.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定