겹치지 않는 엔티티를 무작위로 배치하는 방법은 무엇입니까?


11

개발중인 게임을 위해 무작위로 생성 된 환경을 만들고 있습니다. OpenGL에서 사용 하고 코딩하고 Java있습니다.

나는 세계에 나무를 무작위로 배치하려고 노력하고 있지만 (숲을 만들기 위해) 모델이 겹치지 않기를 원합니다 (두 개의 나무가 서로 너무 가까이있을 때 발생합니다). 다음은 내가 말하는 것에 대한 그림입니다.

여기에 이미지 설명을 입력하십시오

필요한 경우 더 많은 코드를 제공 할 수 있지만 다음은 필수 스 니펫입니다. 나는 내 객체를 포함하고 ArrayListList<Entity> entities = new ArrayList<Entity>();. 그런 다음 다음을 사용하여 해당 목록에 추가합니다.

Random random = new Random();
for (int i = 0; i < 500; i++) {
    entities.add(new Entity(tree, new Vector3f(random.nextFloat() * 800 - 400, 
    0, random.nextFloat() * -600), 0, random.nextFloat() * 360, 0, 3, 3, 3);
}

여기서 각각 Entity은 다음 구문을 따릅니다.

new Entity(modelName, positionVector(x, y, z), rotX, rotY, rotZ, scaleX, scaleY, scaleZ);

rotXx 축을 따른 회전이며 scaleXx 방향의 배율 등입니다.

당신은 내가 함께 무작위로이 나무를 배치하고 있음을 알 수 random.nextFloat()xz위치, 그리고 나무가 원하는 위치에 나타납니다 있도록 범위를 경계. 그러나 어떻게 든이 위치를 제어하고 싶습니다. 따라서 이전에 배치 된 나무에 너무 가까운 나무를 배치하려고하면 새로운 임의의 위치가 다시 계산됩니다. 나는 각 나무 Entity가과 같은 다른 필드를 가질 수 있다고 생각하고 있었고 treeTrunkGirth, 나무가 다른 나무의 위치와의 거리 사이에 treeTrunkGirth있으면 새로운 위치를 다시 계산할 것입니다. 이것을 달성 할 수있는 방법이 있습니까?

필요에 따라 더 많은 코드 스 니펫과 세부 정보를 추가하게되어 기쁩니다.


3
포아송 디스크 샘플링이 작업을 수행해야합니다. 이것이 최선인지, 실제로 구현 / 사용하지는 않았지만 적어도 좋은 출발으로 보입니다. 이 기사를 확인하십시오 : devmag.org.za/2009/05/03/poisson-disk-sampling
Mars

@Mars Wow, 그 링크는 매우 도움이됩니다. 감사합니다. 내가 할 수있는 일을보고 아마도 내 자신의 대답으로 돌아올 수도 있습니다.
wcarhart

@Pikalek 예, 당신이 연결 한 질문은 중복이라고 생각합니다. 다른 질문에서와 같이 xz 평면 을 "별표"의 영역으로 사용 하시겠습니까 ?
wcarhart

예, 귀하의 경우에 xz 평면을 사용하십시오. 또한 treeTrunkGirth상수 대신 트리를 사용하여 나무를 배치해야하는 최소 거리를 결정하십시오.
Pikalek

@Pikalek 답변에 모든 것을 추가하면 가장 좋은 것으로 선택하겠습니다. 도와 주셔서 감사합니다.
wcarhart

답변:


15

푸 아송 디스크 샘플링 분포는 당신이 떨어져 임의의 점을 최소 거리를 선택할 수 있습니다. 귀하의 상황은 이 질문 과 비슷 하지만 나무가 이상적인 점이 아니기 때문에 다음과 같이 거리 확인을 변경해야합니다. 잠재적 인 새 나무와 기존 나무 사이의 거리는 반경의 합보다 작아야합니다 .

Bridson의 알고리즘 은 O (n)의 문제를 효율적으로 해결할 수 있지만 가변 거리에 대해 약간 조정하는 것이 약간 어려울 수 있습니다. 매개 변수가 낮거나 지형을 사전 계산하는 경우 무차별 대입 솔루션도 함께 사용할 수 있습니다. 다음은 이전에 배치 된 모든 트리에 대해 잠재적 인 새 트리 배치를 모두 확인하여 문제를 강제로 처리하는 샘플 코드입니다.

public static class SimpleTree{
    float x;
    float z;
    float r;

    public SimpleTree(Random rng, float xMax, float zMax, float rMin, float rMax){
        x = rng.nextFloat() * xMax;
        z = rng.nextFloat() * zMax;
        r = rng.nextFloat() * (rMax-rMin) + rMin;
    }
}

private static ArrayList<SimpleTree> buildTreeList(float xMax, float zMax, 
        float rMin, float rMax, int maxAttempts, Random rng) {
    ArrayList<SimpleTree> result = new ArrayList<>();

    SimpleTree currentTree = new SimpleTree(rng, xMax, zMax, rMin, rMax);
    result.add(currentTree);

    boolean done = false;
    while(!done){
        int attemptCount = 0;
        boolean placedTree = false;
        Point nextPoint = new Point();
        SimpleTree nextTree = null;
        while(attemptCount < maxAttempts && !placedTree){
            attemptCount++;
            nextTree = new SimpleTree(rng, xMax, zMax, rMin, rMax);
            if(!tooClose(nextTree, result)){
                placedTree = true;
            }
        }
        if(placedTree){
            result.add(nextTree);
        }
        else{
            done = true;
        }
    }

    return result;
}

private static boolean tooClose(SimpleTree tree, ArrayList<SimpleTree> treeList) {
    for(SimpleTree otherTree : treeList) {
        float xDiff = tree.x - otherTree.x;
        float zDiff = tree.z - otherTree.z;

        float dist = (float)Math.sqrt((xDiff * xDiff) + (zDiff * zDiff));
        if(dist < tree.r + otherTree.r){
            return true;
        }
    }        
    return false;
}

다음 매개 변수를 사용하십시오.

 maxAttempts = 500;
 width = 300;
 height = 200;
 minSize = 2;
 maxSize = 15;

400-450 그루의 나무를 1 초 안에 무작위로 배치하고 렌더링 할 수있었습니다. 예를 들면 다음과 같습니다. 여기에 이미지 설명을 입력하십시오


포아송 디스크 샘플링을 사용합니까?
wcarhart

예, 나는 그것을 명시 적으로 편집했습니다.
Pikalek

math.sqrt tree.r + other tree.r대신, 2에서 math.pow를 사용하십시오 . sqrt는 보통 pow보다 느립니다.
Ferrybig

1
@Ferrybig 제곱 거리를 비교하는 것이 더 빠르지 만 그것이 무차별 대입 알고리즘이며 여전히 O (n ^ 2)라는 사실을 바꾸지는 않습니다. 더 빠른 솔루션이 필요한 경우 Bridson의 알고리즘을 사용하십시오. 또한, 여기에 설명 된 대로 Math.pow(x,2)사용 x*x하는 것보다 반드시 사용하는 것이 더 나을 수도 있습니다 .
Pikalek

1
지형과 비슷한 문제가 있었으며 적절한 퍼짐과 겹침이 없음을 보장했습니다. 실제로 변형을 했으므로 버전에서는 머릿단 / 브러쉬가 지형 영역에 무작위로 퍼져 있습니다. 그런 다음 함수 게시물을 실행하여 모든 항목의 거리를 서로 비교하여 너무 가깝게 밀었습니다. 그러나이 지역의 다른 나무에 영향을 줄 수 있습니다. 나는 충돌이 없을 때까지 이것을 반복했다. 그것은 느리지 만 보너스로 가지고있는 것은 개간 (모든 곳에서 다루지는 않습니다!)과 같은 것들이었고 나무 밀도는 더 "흥미로운"것 같았습니다.
ErnieDingo 2019
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.