Jump to content

Recommended Posts

Posted (edited)

I need to take a 3d point in the world (eg. "The cow is at (12, 63, -19)") and project it to 2d screen coordinates (eg. "The cow is 243 pixels from the left of the screen, and 87 pixels from the top of the screen").

 

I found this: https://forums.minecraftforge.net/topic/75508-how-do-i-convert-a-3d-point-to-screen-coordinates/ but it is non-functional.  I tried figuring out the rotations on my own, but that also didn't work.  Both produce incorrect projections, that don't seem to correlate with the correct point in any noticable way.

 

My math (`MiscUtil.projectToPlayerView`):

public static Vector2f projectToPlayerView(Vector3d target) {
	double fov = 70;

	ActiveRenderInfo ari = Minecraft.getMinecraft().gameRenderer.getActiveRenderInfo();
	Vector3d camera_pos = ari.getProjectedView();
	double x = camera_pos.x, y = camera_pos.y, z = camera_pos.z;
	double yaw = Math.toRadians(ari.getYaw()), pitch = Math.toRadians(ari.getPitch());

	x = target.x - x;
	y = target.y - y;
	z = target.z - z;

	// my rotations (doesn't work)
	// rotate so camera is on yz-plane
	// x = (x * Math.cos(yaw) - z * Math.sin(yaw));
	// z = (x * Math.sin(yaw) + z * Math.cos(yaw));
	// rotate so camera is on z axis
	// y = (y * Math.cos(pitch) - z * Math.sin(pitch));
	// z = (y * Math.sin(pitch) + z * Math.cos(pitch));

	// rotations given in linked post
	z = z * Math.cos(yaw) * Math.cos(pitch);
	x = x * Math.sin(yaw);
	y = y * Math.sin(pitch);

	// apply fov
	x = x / z * fov;
	y = y / z * fov;

	return new Vector2f((float) x, (float) y);
}

 

Edited by Ravenwolf397
solved
Posted (edited)
5 hours ago, Ravenwolf397 said:

I need to take a 3d point in the world (eg. "The cow is at (12, 63, -19)") and project it to 2d screen coordinates (eg. "The cow is 243 pixels from the left of the screen, and 87 pixels from the top of the screen").

 

I found this: https://forums.minecraftforge.net/topic/75508-how-do-i-convert-a-3d-point-to-screen-coordinates/ but it is non-functional.  I tried figuring out the rotations on my own, but that also didn't work.  Both produce incorrect projections, that don't seem to correlate with the correct point in any noticable way.

 

My math (`MiscUtil.projectToPlayerView`):


public static Vector2f projectToPlayerView(Vector3d target) {
	double fov = 70;

	ActiveRenderInfo ari = Minecraft.getMinecraft().gameRenderer.getActiveRenderInfo();
	Vector3d camera_pos = ari.getProjectedView();
	double x = camera_pos.x, y = camera_pos.y, z = camera_pos.z;
	double yaw = Math.toRadians(ari.getYaw()), pitch = Math.toRadians(ari.getPitch());

	x = target.x - x;
	y = target.y - y;
	z = target.z - z;

	// my rotations (doesn't work)
	// rotate so camera is on yz-plane
	// x = (x * Math.cos(yaw) - z * Math.sin(yaw));
	// z = (x * Math.sin(yaw) + z * Math.cos(yaw));
	// rotate so camera is on z axis
	// y = (y * Math.cos(pitch) - z * Math.sin(pitch));
	// z = (y * Math.sin(pitch) + z * Math.cos(pitch));

	// rotations given in linked post
	z = z * Math.cos(yaw) * Math.cos(pitch);
	x = x * Math.sin(yaw);
	y = y * Math.sin(pitch);

	// apply fov
	x = x / z * fov;
	y = y / z * fov;

	return new Vector2f((float) x, (float) y);
}

 

Why would you even need that? You need to draw something near a cow? You may use RenderLivingEvent (Post subclass, if you need to draw over the cow).

 

About your own math - check if you're rotating your vector in correct directions. Actually, you need to turn -yaw and -pitch (I see, you did it ok), because initially your vector points target, but you need it to point your looking direction. Also your yaw and pitch should be actually a difference between camera yaw and entity relative yaw, I can't see you calculating it.

 

At last, you may use Quaternions to make you code more readable - they are at package net.minecraft.util.math.vector.Quaternion, and Vector3f has useful methods, such as rotation(float) gives you a Quternion to rotate around axis collinear to vector and transform(Quternion) to transform current vector with specified Quaternion.

Happy math-ing!

Edited by Dzuchun
  • Thanks 1

Everything said above may be absolutely wrong. No rights reserved.

Posted (edited)

Thank you!

 

Quaternions were the answer; I just apply the ActiveRenderInfo::getRotation() as a transformation to the relative position of the point and the camera, then scale by some factor `scale_factor` (180 works well at the default fov of 70).

 

Through a bit of finagling, I even managed to compensate for the effects of view bobbing.  

 

However, I now face a new but related conundrum: changing the fov away from 70 makes the calculated point become scaled incorrectly.  Specifically, if the fov is high then it is too far from the screen center, and if the fov is low then it is too close to the screen center.  

 

The problem seems pretty clearly to do with my scaling factor of 180 above.  I tried multiplying `scale_factor` by (70 / fov), but that didn't change it enough; the result was still too close to center at low fov, and too far from center at high fov.  It was closer to what it should be, but still not correct.

 

Since the function appeared to be trigonometric, I attempted multiplying `scale_factor` by `-1 / Math.tan(fov / 2)` (essentially treating it as focal length), but that produced very odd behavior with no discernable pattern.

 

How does Minecraft's fov affect this situation?  I would have though that `scaling_factor` was just the focal length, but the multiplier above involving tangent should have worked in that case, so I'm not sure.

 

Updated code:

    public static Vector2f projectToPlayerView(Vector3d target, float partialTicks) {
        /* The (centered) location on the screen of the given 3d point in the world. */
        float scale_factor = 180;

        ActiveRenderInfo ari = getActiveRenderInfo();
        Vector3d camera_pos = ari.getProjectedView();
        Quaternion camera_rotation_conj = ari.getRotation().copy();
        camera_rotation_conj.conjugate();

        Vector3f result3f = new Vector3f((float) (camera_pos.x - target.x),
                (float) (camera_pos.y - target.y),
                (float) (camera_pos.z - target.z));
        result3f.transform(camera_rotation_conj);

        // compensate for view bobbing (if active)
        // this isn't relevant to the question, I just put it here in case anyone wants it
        // the following code adapted from GameRenderer::applyBobbing (to invert it)
        Minecraft mc = getMinecraft();
        if (mc.gameSettings.viewBobbing) {
            Entity renderViewEntity = mc.getRenderViewEntity();
            if (renderViewEntity instanceof PlayerEntity) {
                PlayerEntity playerentity = (PlayerEntity) renderViewEntity;
                float distwalked_modified = playerentity.distanceWalkedModified;

                float f = distwalked_modified - playerentity.prevDistanceWalkedModified;
                float f1 = -(distwalked_modified + f * partialTicks);
                float f2 = MathHelper.lerp(partialTicks, playerentity.prevCameraYaw, playerentity.cameraYaw);
                Quaternion q2 = new Quaternion(Vector3f.XP, Math.abs(MathHelper.cos(f1 * (float) Math.PI - 0.2F) * f2) * 5.0F, true);
                q2.conjugate();
                result3f.transform(q2);

                Quaternion q1 = new Quaternion(Vector3f.ZP, MathHelper.sin(f1 * (float) Math.PI) * f2 * 3.0F, true);
                q1.conjugate();
                result3f.transform(q1);

                Vector3f bob_translation = new Vector3f((MathHelper.sin(f1 * (float) Math.PI) * f2 * 0.5F), (-Math.abs(MathHelper.cos(f1 * (float) Math.PI) * f2)), 0.0f);
                bob_translation.setY(-bob_translation.getY());  // this is weird but hey, if it works
                result3f.add(bob_translation);
            }
        }

        // handle alteration due to fov
        double fov = mc.gameSettings.fov;
        // neither of these are correct:
        // scale_factor *= (70 / fov);
        // scale_factor *= -1 / Math.tan(fov / 2);

        // todo include fov modifier from sprinting, speed, etc.

        Vector2f result = new Vector2f(-result3f.getX(), result3f.getY());
        result = new Vector2f(scale_factor * result.x / result3f.getZ(), scale_factor * result.y / result3f.getZ());

        return result;
    }

 

Edited by Ravenwolf397
Posted (edited)

Actually, I have no certain idea how FoV works in Minecraft. But I if we assume, that it works like an optical camera, I may help you.

Screenshot_2020-07-17_20-30-23.png.29a86007ac3937296d5cb50acecbfb28.pngHere you can see how world is projected to the screen (or matrix in camera).

So, to negate FoV deformations you should (using spherical trigonometry) calculate angle distance to center of the screen and take a tangent of it - now you have pure coordinate - distance to target in radius of some sphere. To find a pure coordinate of screen border, you may take tan(FoV/2). Then using screen resolution calculate distance in pixels on screen between center and target. Then again using spherical trigonometry calculate angle between Center-Target and, for example, horizon line, understand that it is unchanged after projection, and get your result vector by this angle and that distance.

But please,

don't do that!

I'm sure, more forge-like way exists to do what you want.

For example, this:

11 hours ago, Dzuchun said:

You may use RenderLivingEvent (Post subclass, if you need to draw over the cow).

or net.minecraftforge.client.event.RenderWorldLastEvent.

Edited by Dzuchun
  • Thanks 2

Everything said above may be absolutely wrong. No rights reserved.

Posted
7 minutes ago, Dzuchun said:

Actually, I have no certain idea how FoV works in Minecraft. But I if we assume, that it works like an optical camera, I may help you.

Screenshot_2020-07-17_20-30-23.png.29a86007ac3937296d5cb50acecbfb28.pngHere you can see how world is projected to the screen (or matrix in camera).

So, to negate FoV deformations you should (using spherical trigonometry) calculate angle distance to center of the screen and take a tangent of it - now you have pure coordinate - distance to target in radius of some sphere. To find a pure coordinate of screen border, you may take tan(FoV/2). Then using screen resolution calculate distance in pixels on screen between center and target. Then again using spherical trigonometry calculate angle between Center-Target and, for example, horizon line, understand that it is unchanged after projection, and get your result vector by this angle and that distance.

 

 

 

This actually helps me on a completely unrelated project. The (builtin) WorldToScreen method I have doesn't (seem to) generate useful values when the position isn't inside the view frustum (so something that was off-screen-leftish would show a direction of off-screen-upish).

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
2 minutes ago, Draco18s said:

 

This actually helps me on a completely unrelated project. The (builtin) WorldToScreen method I have doesn't (seem to) generate useful values when the position isn't inside the view frustum (so something that was off-screen-leftish would show a direction of off-screen-upish).

Please, double-check everything writen in my post (because of my signachure).

Everything said above may be absolutely wrong. No rights reserved.

Posted (edited)
57 minutes ago, Dzuchun said:

Please, double-check everything writen in my post (because of my signachure).

👍

Sure, I was just saying that because the builtin was being bad, that gave me something to work with to try and write the function myself. A starting point as it were.

 

And by bad, I mean this object is in the lower left and the coordinate popping out is in the upper right.

image.thumb.png.d768016fb34f965c0ab2b3bff563c532.png:

But I move it over here:

image.thumb.png.582ecf8e46b8951fd8cb8140fc6c6643.png

Suddenly its correct again.

 

Could be related to absolute distance from the camera (I can get values of about -20,000,000 before it goes positive), but when I've tried mathing the world coordinates down towards the camera (this being very easy, the stuff in the center is at (0,0,0), so dividing by a fixed value should work) I still get nonsense.

 

Success! Calculating the angle myself (ok, I used a builtin) based on the object's position and the camera's position (with the same height to avoid some oddities with things being directly ahead/behind) works perfectly.

Edited by Draco18s

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Okay, I got it working 100%.  Compensates for screen resolution, view bobbing, fov changes, and even dynamic fov like from sprinting and speed potions.

 

public static FinalTriple<Float, Float, Boolean> projectToPlayerView(double target_x, double target_y, double target_z, float partialTicks) {
        /* The (centered) location on the screen of the given 3d point in the world.
         * Result is <dist right of center screen, dist up from center screen, is target in front of viewing plane> */
        ActiveRenderInfo ari = getActiveRenderInfo();
        Vector3d camera_pos = ari.getProjectedView();
        Quaternion camera_rotation_conj = ari.getRotation().copy();
        camera_rotation_conj.conjugate();

        Vector3f result3f = new Vector3f((float) (camera_pos.x - target_x),
                (float) (camera_pos.y - target_y),
                (float) (camera_pos.z - target_z));
        result3f.transform(camera_rotation_conj);

        // ----- compensate for view bobbing (if active) -----
        // the following code adapted from GameRenderer::applyBobbing (to invert it)
        Minecraft mc = getMinecraft();
        if (mc.gameSettings.viewBobbing) {
            Entity renderViewEntity = mc.getRenderViewEntity();
            if (renderViewEntity instanceof PlayerEntity) {
                PlayerEntity playerentity = (PlayerEntity) renderViewEntity;
                float distwalked_modified = playerentity.distanceWalkedModified;

                float f = distwalked_modified - playerentity.prevDistanceWalkedModified;
                float f1 = -(distwalked_modified + f * partialTicks);
                float f2 = MathHelper.lerp(partialTicks, playerentity.prevCameraYaw, playerentity.cameraYaw);
                Quaternion q2 = new Quaternion(Vector3f.XP, Math.abs(MathHelper.cos(f1 * (float) Math.PI - 0.2F) * f2) * 5.0F, true);
                q2.conjugate();
                result3f.transform(q2);

                Quaternion q1 = new Quaternion(Vector3f.ZP, MathHelper.sin(f1 * (float) Math.PI) * f2 * 3.0F, true);
                q1.conjugate();
                result3f.transform(q1);

                Vector3f bob_translation = new Vector3f((MathHelper.sin(f1 * (float) Math.PI) * f2 * 0.5F), (-Math.abs(MathHelper.cos(f1 * (float) Math.PI) * f2)), 0.0f);
                bob_translation.setY(-bob_translation.getY());  // this is weird but hey, if it works
                result3f.add(bob_translation);
            }
        }

        // ----- adjust for fov -----
        Method m;
        float fov;
        GameRenderer gameRenderer = mc.gameRenderer;
        try {
            m = gameRenderer.getClass().getDeclaredMethod("getFOVModifier", ActiveRenderInfo.class, float.class, boolean.class);
        } catch (NoSuchMethodException e) {
            LOGGER.error(e);
            throw new Error("getFOVModifier method not present on GameRenderer class; cannot project to player screen.", e);
        }
        m.setAccessible(true);
        try {
            fov = ((Double) m.invoke(gameRenderer, ari, partialTicks, true)).floatValue();
        } catch (IllegalAccessException | InvocationTargetException e) {
            LOGGER.error(e);
            throw new Error("getFOVModifier invocation caused error.", e);
        }

        float half_height = (float) mc.getMainWindow().getScaledHeight() / 2;
        float scale_factor = half_height / (result3f.getZ() * (float) Math.tan(Math.toRadians(fov / 2)));
        return new FinalTriple<>(-result3f.getX() * scale_factor, result3f.getY() * scale_factor, result3f.getZ() < 0);
    }

 

There are couple of self-explanatory methods (getActiveRenderInfo, getMinecraft) and a class (FinalTriple) that should be obvious to implement yourself.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • When I first heard about Bitcoin back in 2018, I was skeptical. The idea of a decentralized, digital currency seemed too good to be true. But I was intrigued as I learned more about the technology behind it and its potential. I started small, investing just a few hundred dollars, dipping my toes into the cryptocurrency waters. At first, it was exhilarating to watch the value of my investment grow exponentially. I felt like I was part of the future, an early adopter of this revolutionary new asset. But that euphoria was short-lived. One day, I logged into my digital wallet only to find it empty - my Bitcoin had vanished without a trace. It turned out that the online exchange I had trusted had been hacked, and my funds were stolen. I was devastated, both financially and emotionally. All the potential I had seen in Bitcoin was tainted by the harsh reality that with decentralization came a lack of regulation and oversight. My hard-earned money was gone, lost to the ether of the digital world. This experience taught me a painful lesson about the price of trust in the uncharted territory of cryptocurrency. While the technology holds incredible promise, the risks can be catastrophic if you don't approach it with extreme caution. My Bitcoin investment gamble had failed, and I was left to pick up the pieces, wiser but poorer for having placed my faith in the wrong hands. My sincere appreciation goes to MUYERN TRUST HACKER. You are my hero in recovering my lost funds. Send a direct m a i l ( muyerntrusted ( @ ) mail-me ( . )c o m ) or message on whats app : + 1 ( 4-4-0 ) ( 3 -3 -5 ) ( 0-2-0-5 )
    • You could try posting a log (if there is no log at all, it may be the launcher you are using, the FAQ may have info on how to enable the log) as described in the FAQ, however this will probably need to be reported to/remedied by the mod author.
    • So me and a couple of friends are playing with a shitpost mod pack and one of the mods in the pack is corail tombstone and for some reason there is a problem with it, where on death to fire the player will get kicked out of the server and the tombstone will not spawn basically deleting an entire inventory, it doesn't matter what type of fire it is, whether it's from vanilla fire/lava, or from modded fire like ice&fire/lycanites and it's common enough to where everyone on the server has experienced at least once or twice and it doesn't give any crash log. a solution to this would be much appreciated thank you!
    • It is 1.12.2 - I have no idea if there is a 1.12 pack
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.