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

Camera3D.project_position(point,z_depth) return wrong value when z_depth==far #95786

Closed
waci11 opened this issue Aug 19, 2024 · 1 comment · Fixed by #98489
Closed

Camera3D.project_position(point,z_depth) return wrong value when z_depth==far #95786

waci11 opened this issue Aug 19, 2024 · 1 comment · Fixed by #98489
Milestone

Comments

@waci11
Copy link

waci11 commented Aug 19, 2024

Tested versions

v4.3.stable.official [77dcf97]

System information

macOS 10.15.7

Issue description

Camera3D.project_position(point,z_depth) return wrong value when z_depth==far

Steps to reproduce

add this script to a Camera3D:

extends Camera3D
func _ready() -> void:
	far=2000
	print(project_position(Vector2.ONE,999))
	print(project_position(Vector2.ONE,1000))
	print(project_position(Vector2.ONE,1001))
	print("---")
	far=1000
	print(project_position(Vector2.ONE,999))
	print(project_position(Vector2.ONE,1000))
	print(project_position(Vector2.ONE,1001))

the log:

(-1360.407, 764.1937, -999)
(-1361.769, 764.9588, -1000)
(-1363.13, 765.7237, -1001)
---
(-1360.407, 764.1937, -999)
(-0.998264, 0.996914, -1000)
(-1363.13, 765.7237, -1001)

Minimal reproduction project (MRP)

empty project with camera3D

@waci11
Copy link
Author

waci11 commented Sep 2, 2024

I think maybe the problem is because cm return a identity Projection .
p_near can not as same as _far
i think it is beter to change the line 304 to cm.set_perspective(fov, viewport_size.aspect(), 0 , p_near, keep_aspect == KEEP_WIDTH);
But the content of the set_perspective needs to be changed, I don't know if this is feasible.

godot/core/math/projection.cpp

void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
	if (p_flip_fov) {
		p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
	}

	real_t sine, cotangent, deltaZ;
	real_t radians = Math::deg_to_rad(p_fovy_degrees / 2.0);

	deltaZ = p_z_far - p_z_near; // line 264
	sine = Math::sin(radians);

	if ((deltaZ == 0) || (sine == 0) || (p_aspect == 0)) {
		return;// line 260
	}
	cotangent = Math::cos(radians) / sine;

	set_identity();

	columns[0][0] = cotangent / p_aspect;
	columns[1][1] = cotangent;
	columns[2][2] = -(p_z_far + p_z_near) / deltaZ;
	columns[2][3] = -1;
	columns[3][2] = -2 * p_z_near * p_z_far / deltaZ;
	columns[3][3] = 0;
}

godot/scene/3d/camera_3d.cpp

Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) const {
	ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene.");

	if (p_z_depth == 0 && mode != PROJECTION_ORTHOGONAL) {
		return get_global_transform().origin;
	}
	Size2 viewport_size = get_viewport()->get_visible_rect().size;

	Projection cm = _get_camera_projection(p_z_depth);// line 531

	Vector2 vp_he = cm.get_viewport_half_extents();

	Vector2 point;
	point.x = (p_point.x / viewport_size.x) * 2.0 - 1.0;
	point.y = (1.0 - (p_point.y / viewport_size.y)) * 2.0 - 1.0;
	point *= vp_he;

	Vector3 p(point.x, point.y, -p_z_depth);

	return get_camera_transform().xform(p);
}

Projection Camera3D::_get_camera_projection(real_t p_near) const {
	Size2 viewport_size = get_viewport()->get_visible_rect().size;
	Projection cm;

	switch (mode) {
		case PROJECTION_PERSPECTIVE: {
			cm.set_perspective(fov, viewport_size.aspect(), p_near, _far, keep_aspect == KEEP_WIDTH);// line 304
		} break;
		case PROJECTION_ORTHOGONAL: {
			cm.set_orthogonal(size, viewport_size.aspect(), p_near, _far, keep_aspect == KEEP_WIDTH);
		} break;
		case PROJECTION_FRUSTUM: {
			cm.set_frustum(size, viewport_size.aspect(), frustum_offset, p_near, _far);
		} break;
	}

	return cm;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants