Merge pull request #90286 from dsnopek/openxr-composition-layers-intersects-ray
Add `intersects_ray()` method to `OpenXRCompositionLayer`
This commit is contained in:
commit
ad1993455a
9 changed files with 152 additions and 0 deletions
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -89,6 +89,8 @@ public:
|
|||
|
||||
virtual PackedStringArray get_configuration_warnings() const override;
|
||||
|
||||
virtual Vector2 intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const;
|
||||
|
||||
OpenXRCompositionLayer();
|
||||
~OpenXRCompositionLayer();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ public:
|
|||
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();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue