Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix world positions on rotated or scaled terrain #153

Conversation

Dgzt
Copy link
Collaborator

@Dgzt Dgzt commented Apr 23, 2023

Currently the isOnTerrain, getNormalAtWordCoordinate and getHeightAtWorldCoord methods on Terrain are only check translation and don't check rotation and scaling.

You can test them with these temporary codes in FreeCamController in editor:

isOnTerrain:

override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
    if (camera == null) {
        return false
    }

    val currentProject = projectManager.current()
    val currentScene = currentProject.currScene
    val ray = currentScene.viewport.getPickRay(screenX.toFloat(), screenY.toFloat())

    for (terrain in currentScene.terrains) {
        val wordPos = getWorldPos(ray)
        val result = terrain.isOnTerrain(wordPos.x, wordPos.z)
       // You will see true value if the mouse is on terrain otherwise false
        println("wordPos: $wordPos, result: $result")
    }

    return true
}

private fun getWorldPos(ray: Ray): Vector3 {
    tmp.set(ray.origin)

    var round = 0
    var distance = 1f;

    while (tmp.y >= 1 && round < 5000) {
        ray.getEndPoint(tmp, distance)
        ++round
        ++distance
    }

    return tmp
}

getNormalAtWordCoordinate:

override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
    if (camera == null) {
        return false
    }

    val currentProject = projectManager.current()
    val currentScene = currentProject.currScene
    val ray = currentScene.viewport.getPickRay(screenX.toFloat(), screenY.toFloat())

    for (terrain in currentScene.terrains) {
        val wordPos = getWorldPos(ray)
        val result = terrain.terrainAsset.terrain.getNormalAtWordCoordinate(Vector3(), wordPos.x, wordPos.z, terrain.modelInstance.transform)
// You will see the normal vector if the mouse  is  on a hill, otherwise you will see (0,1,0) vector
        println("wordPos: $wordPos, result: $result")
    }

    return true
}

private fun getWorldPos(ray: Ray): Vector3 {
    tmp.set(ray.origin)

    var round = 0
    var distance = 1f;

    while (tmp.y >= 1 && round < 5000) {
        ray.getEndPoint(tmp, distance)
        ++round
        ++distance
    }

    return tmp
}

getHeightAtWorldCoord:

override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
    if (camera == null) {
        return false
    }

    val currentProject = projectManager.current()
    val currentScene = currentProject.currScene
    val ray = currentScene.viewport.getPickRay(screenX.toFloat(), screenY.toFloat())

    for (terrain in currentScene.terrains) {
        val wordPos = getWorldPos(ray)
        val result = terrain.getHeightAtWorldCoord(wordPos.x, wordPos.z)
        // You will see non 0 value if the mouse  is  on a hill, otherwise you will se 0 value
        println("wordPos: $wordPos, result: $result")
    }

    return true
}

private fun getWorldPos(ray: Ray): Vector3 {
    tmp.set(ray.origin)

    var round = 0
    var distance = 1f;

    while (tmp.y >= 1 && round < 5000) {
        ray.getEndPoint(tmp, distance)
        ++round
        ++distance
    }

    return tmp
}

Just you need add currentProject constructor parameter and add this parameter in Mundus.kt.

@Dgzt Dgzt added the bug Something isn't working label Apr 23, 2023
@Dgzt Dgzt changed the title Fix word positions on rotated or scaled terrain Fix world positions on rotated or scaled terrain Apr 23, 2023
@antzGames
Copy link
Collaborator

antzGames commented Apr 24, 2023

So this bug affected my Mundus integration into ode4j. I am not blocked, but I am glad you are fixing.

adding this code so that I am reminded/remember where to fix it once fixed in this PR.

    private double heightfield_callback( Object pUserData, int x, int z ) {
        float fx = x/2f; // because we have 40 samples on a 20x20 mesh, we divide by 2
        float fz = z/2f; // because we have 40 samples on a 20x20 mesh, we divide by 2

        double h = ((TerrainComponent) scene.sceneGraph.getGameObjects().get(0).findComponentByType(Component.Type.TERRAIN)).
            getHeightAtWorldCoord(fx, fz);

        return h*3f + 0.2f; // x3 because I scaled the Y terrain x3 in the Mundus editor (issue#153), +0.2f to increase thickness of mesh
        //Mundus PR >>> https://github.com/JamesTKhan/Mundus/pull/153  remove *3f once fixed
    }

Copy link
Owner

@JamesTKhan JamesTKhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you.

@JamesTKhan JamesTKhan merged commit 99a7923 into JamesTKhan:master Apr 24, 2023
@Dgzt Dgzt deleted the fix-word-positions-on-terrain-for-rotated-and-scaling branch April 24, 2023 13:56
@antzGames
Copy link
Collaborator

I got the latest code because I see:

    public float getHeightAtWorldCoord(float worldX, float worldZ, Matrix4 terrainTransform) {
        // Translates world coordinates to local coordinates
        tmp.set(worldX, 0f, worldZ).mul(tmpMatrix.set(terrainTransform).inv());

But the height is still calculated without the Y Scale = 3

image

@Dgzt
Copy link
Collaborator Author

Dgzt commented Apr 24, 2023

I got the latest code because I see:

    public float getHeightAtWorldCoord(float worldX, float worldZ, Matrix4 terrainTransform) {
        // Translates world coordinates to local coordinates
        tmp.set(worldX, 0f, worldZ).mul(tmpMatrix.set(terrainTransform).inv());

But the height is still calculated without the Y Scale = 3

image

Ohh, I think I know why. I will check it and fix it today.

@antzGames
Copy link
Collaborator

antzGames commented Apr 24, 2023

@Dgzt @JamesTKhan Sorry for the stupid question but is it possible to point to a specific forked branch in your gradle.build. What is the easiest way for me to test another person's PR change prior to merge, not from source but from maven library? Is it possible?

dependencies {
  api "com.github.jamestkhan.mundus:gdx-runtime:master-SNAPSHOT"

@JamesTKhan
Copy link
Owner

JamesTKhan commented Apr 24, 2023

@antzGames I normally just check out the Mundus PR, then build it if I need to using Maven Publish to my local. But you may be able to use jitpack to point straight to Dgzt's branches, however the branch for this PR was deleted already from what I can tell

https://jitpack.io/#DGZT/Mundus

@Dgzt
Copy link
Collaborator Author

Dgzt commented Apr 24, 2023

@antzGames I usually check out the PR with this git command:

git fetch origin pull/ID/head:BRANCH_NAME
git checkout BRANCH_NAME

and build the project and copy common and runtime jars into my project's libs directory and rewrite dependency lines in build.gradle to:

implementation(files('../libs/gdx-runtime-0.4.2.jar'))
implementation(files('../libs/commons-0.4.2.jar'))

@antzGames
Copy link
Collaborator

Thanks guys. This is exactly what I was looking for. Now I can test people PRs from a runtime perspective as testing the editor is easy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants