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

Add intersects_ray() method to OpenXRCompositionLayer #90286

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions modules/openxr/doc_classes/OpenXRCompositionLayer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
<tutorials>
</tutorials>
<methods>
<method name="intersects_ray" qualifiers="const">
<return type="Vector2" />
<param index="0" name="origin" type="Vector3" />
<param index="1" name="direction" type="Vector3" />
<description>
Returns UV coordinates where the given ray intersects with the composition layer. [param origin] and [param direction] must be in global space.
Returns [code]Vector2(-1.0, -1.0)[/code] if the ray doesn't intersect.
</description>
</method>
<method name="is_natively_supported" qualifiers="const">
<return type="bool" />
<description>
Expand Down
6 changes: 6 additions & 0 deletions modules/openxr/scene/openxr_composition_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ void OpenXRCompositionLayer::_bind_methods() {

ClassDB::bind_method(D_METHOD("is_natively_supported"), &OpenXRCompositionLayer::is_natively_supported);

ClassDB::bind_method(D_METHOD("intersects_ray", "origin", "direction"), &OpenXRCompositionLayer::intersects_ray);

ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend");
Expand Down Expand Up @@ -199,6 +201,10 @@ bool OpenXRCompositionLayer::is_natively_supported() const {
return false;
}

Vector2 OpenXRCompositionLayer::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
return Vector2(-1.0, -1.0);
}

void OpenXRCompositionLayer::_reset_fallback_material() {
ERR_FAIL_NULL(fallback);

Expand Down
2 changes: 2 additions & 0 deletions modules/openxr/scene/openxr_composition_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class OpenXRCompositionLayer : public Node3D {

virtual PackedStringArray get_configuration_warnings() const override;

virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const;

OpenXRCompositionLayer();
~OpenXRCompositionLayer();
};
Expand Down
45 changes: 45 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_cylinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,48 @@ void OpenXRCompositionLayerCylinder::set_fallback_segments(uint32_t p_fallback_s
uint32_t OpenXRCompositionLayerCylinder::get_fallback_segments() const {
return fallback_segments;
}

Vector2 OpenXRCompositionLayerCylinder::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
Transform3D cylinder_transform = get_global_transform();
Vector3 cylinder_axis = cylinder_transform.basis.get_column(1);

Vector3 offset = p_origin - cylinder_transform.origin;
float a = p_direction.dot(p_direction - cylinder_axis * p_direction.dot(cylinder_axis));
float b = 2.0 * (p_direction.dot(offset - cylinder_axis * offset.dot(cylinder_axis)));
float c = offset.dot(offset - cylinder_axis * offset.dot(cylinder_axis)) - (radius * radius);

float discriminant = b * b - 4.0 * a * c;
if (discriminant < 0.0) {
return Vector2(-1.0, -1.0);
}

float t0 = (-b - Math::sqrt(discriminant)) / (2.0 * a);
float t1 = (-b + Math::sqrt(discriminant)) / (2.0 * a);
float t = MAX(t0, t1);

if (t < 0.0) {
return Vector2(-1.0, -1.0);
}
Vector3 intersection = p_origin + p_direction * t;

Basis correction = cylinder_transform.basis.inverse();
correction.rotate(Vector3(0.0, 1.0, 0.0), -Math_PI / 2.0);
Vector3 relative_point = correction.xform(intersection - cylinder_transform.origin);

Vector2 projected_point = Vector2(relative_point.x, relative_point.z);
float intersection_angle = Math::atan2(projected_point.y, projected_point.x);
if (Math::abs(intersection_angle) > central_angle / 2.0) {
return Vector2(-1.0, -1.0);
}

float arc_length = radius * central_angle;
float height = aspect_ratio * arc_length;
if (Math::abs(relative_point.y) > height / 2.0) {
return Vector2(-1.0, -1.0);
}

float u = 0.5 + (intersection_angle / central_angle);
float v = 1.0 - (0.5 + (relative_point.y / height));

return Vector2(u, v);
}
2 changes: 2 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_cylinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class OpenXRCompositionLayerCylinder : public OpenXRCompositionLayer {
void set_fallback_segments(uint32_t p_fallback_segments);
uint32_t get_fallback_segments() const;

virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const override;

OpenXRCompositionLayerCylinder();
~OpenXRCompositionLayerCylinder();
};
Expand Down
51 changes: 51 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_equirect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,54 @@ void OpenXRCompositionLayerEquirect::set_fallback_segments(uint32_t p_fallback_s
uint32_t OpenXRCompositionLayerEquirect::get_fallback_segments() const {
return fallback_segments;
}

Vector2 OpenXRCompositionLayerEquirect::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
Transform3D equirect_transform = get_global_transform();

Vector3 offset = p_origin - equirect_transform.origin;
float a = p_direction.dot(p_direction);
float b = 2.0 * offset.dot(p_direction);
float c = offset.dot(offset) - (radius * radius);

float discriminant = b * b - 4.0 * a * c;
if (discriminant < 0.0) {
return Vector2(-1.0, -1.0);
}

float t0 = (-b - Math::sqrt(discriminant)) / (2.0 * a);
float t1 = (-b + Math::sqrt(discriminant)) / (2.0 * a);
float t = MAX(t0, t1);

if (t < 0.0) {
return Vector2(-1.0, -1.0);
}
Vector3 intersection = p_origin + p_direction * t;

Basis correction = equirect_transform.basis.inverse();
correction.rotate(Vector3(0.0, 1.0, 0.0), -Math_PI / 2.0);
Vector3 relative_point = correction.xform(intersection - equirect_transform.origin);

float horizontal_intersection_angle = Math::atan2(relative_point.z, relative_point.x);
if (Math::abs(horizontal_intersection_angle) > central_horizontal_angle / 2.0) {
return Vector2(-1.0, -1.0);
}

float vertical_intersection_angle = Math::acos(relative_point.y / radius) - (Math_PI / 2.0);
if (vertical_intersection_angle < 0) {
if (Math::abs(vertical_intersection_angle) > upper_vertical_angle) {
return Vector2(-1.0, -1.0);
}
} else if (vertical_intersection_angle > lower_vertical_angle) {
return Vector2(-1.0, -1.0);
}

// Re-center the intersection angle if the vertical angle is uneven between upper and lower.
if (upper_vertical_angle != lower_vertical_angle) {
vertical_intersection_angle -= (-upper_vertical_angle + lower_vertical_angle) / 2.0;
}

float u = 0.5 + (horizontal_intersection_angle / central_horizontal_angle);
float v = 0.5 + (vertical_intersection_angle / (upper_vertical_angle + lower_vertical_angle));

return Vector2(u, v);
}
2 changes: 2 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_equirect.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class OpenXRCompositionLayerEquirect : public OpenXRCompositionLayer {
void set_fallback_segments(uint32_t p_fallback_segments);
uint32_t get_fallback_segments() const;

virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const override;

OpenXRCompositionLayerEquirect();
~OpenXRCompositionLayerEquirect();
};
Expand Down
33 changes: 33 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_quad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,36 @@ void OpenXRCompositionLayerQuad::set_quad_size(const Size2 &p_size) {
Size2 OpenXRCompositionLayerQuad::get_quad_size() const {
return quad_size;
}

Vector2 OpenXRCompositionLayerQuad::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
Transform3D quad_transform = get_global_transform();
Vector3 quad_normal = quad_transform.basis.get_column(2);

float denom = quad_normal.dot(p_direction);
if (Math::abs(denom) > 0.0001) {
Vector3 vector = quad_transform.origin - p_origin;
float t = vector.dot(quad_normal) / denom;
if (t < 0.0) {
return Vector2(-1.0, -1.0);
}
Vector3 intersection = p_origin + p_direction * t;

Vector3 relative_point = intersection - quad_transform.origin;
Vector2 projected_point = Vector2(
relative_point.dot(quad_transform.basis.get_column(0)),
relative_point.dot(quad_transform.basis.get_column(1)));
if (Math::abs(projected_point.x) > quad_size.x / 2.0) {
return Vector2(-1.0, -1.0);
}
if (Math::abs(projected_point.y) > quad_size.y / 2.0) {
return Vector2(-1.0, -1.0);
}

float u = 0.5 + (projected_point.x / quad_size.x);
float v = 1.0 - (0.5 + (projected_point.y / quad_size.y));

return Vector2(u, v);
}

return Vector2(-1.0, -1.0);
}
2 changes: 2 additions & 0 deletions modules/openxr/scene/openxr_composition_layer_quad.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class OpenXRCompositionLayerQuad : public OpenXRCompositionLayer {
void set_quad_size(const Size2 &p_size);
Size2 get_quad_size() const;

virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const override;

OpenXRCompositionLayerQuad();
~OpenXRCompositionLayerQuad();
};
Expand Down
Loading