From d98504fcc874d4ddc95604726089e59b0507d7d2 Mon Sep 17 00:00:00 2001 From: Daniil Mordanov <153565951+Daniiiil1@users.noreply.github.com> Date: Tue, 11 Aug 2026 18:46:40 +0700 Subject: [PATCH] Fix distance attenuation in lidar intensity Signed-off-by: Daniil Mordanov <153565951+Daniiiil1@users.noreply.github.com> --- docs/Usage.md | 2 +- include/rgl/api/core.h | 2 +- src/gpu/optixPrograms.cu | 6 +++++- test/src/graph/nodes/RaytraceNodeTest.cpp | 9 +++++++-- test/src/scene/reflectivityTest.cpp | 20 +++++++++----------- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/Usage.md b/docs/Usage.md index 70b8fc2c..21d45ab7 100644 --- a/docs/Usage.md +++ b/docs/Usage.md @@ -21,7 +21,7 @@ In order to create an Entity, it is required to provide a Mesh, which must be cr Entities can share the same Mesh. ### Texture -A Texture is a handle for the on-GPU data of a 2D image provided by the user. It is used to calculate the intensity of a hit point. It is expected to be a grayscale image in 8-bit red channel data. The intensity is calculated by sampling the Texture at the Mesh's Texture coordinates. If the Texture coordinates are not present, the Texture will not be sampled. +A Texture is a handle for the on-GPU data of a 2D image provided by the user. It is used to calculate the intensity of a hit point. It is expected to be a grayscale image in 8-bit red channel data. The intensity is calculated by sampling the Texture at the Mesh's Texture coordinates, applying the cosine of the incident angle and inverse-square attenuation with distance. If the Texture coordinates are not present, the Texture will not be sampled. The Texture coordinates are calculated by interpolating the Texture coordinates of the hitpoint's triangle vertices. The Texture coordinates of the triangle vertices are provided by the user when creating the Mesh and should be assigned via API call. The Texture coordinates are expected to be in the range [0, 1]. If the range is exceeded, then the Texture will be tiled. diff --git a/include/rgl/api/core.h b/include/rgl/api/core.h index 28d8a43c..4ca43074 100644 --- a/include/rgl/api/core.h +++ b/include/rgl/api/core.h @@ -354,7 +354,7 @@ typedef enum : int32_t /** * Strength of the returned signal captured by the LiDAR sensor. * It is simulated using intensity textures assigned to entities (see `rgl_entity_set_intensity_texture`). - * The final value also depends on the incident angle of the ray hit. + * The final value also depends on the incident angle and follows inverse-square attenuation with distance. */ RGL_FIELD_INTENSITY_F32, /** diff --git a/src/gpu/optixPrograms.cu b/src/gpu/optixPrograms.cu index bc442817..e5d567fe 100644 --- a/src/gpu/optixPrograms.cu +++ b/src/gpu/optixPrograms.cu @@ -187,7 +187,11 @@ extern "C" __global__ void __closesthit__() intensity = tex2D(entityData.texture, uv[0], uv[1]); } - intensity *= cosIncidentAngle; + // Approximate the geometric spreading of the reflected signal with the + // inverse-square law. A zero-distance hit is outside the physical operating + // range of a LiDAR and must not produce an infinite intensity. + const double distanceSquared = distance * distance; + intensity = distanceSquared > 0.0 ? intensity * cosIncidentAngle / static_cast(distanceSquared) : 0.0f; Vec3f absPointVelocity{NAN}; Vec3f relPointVelocity{NAN}; diff --git a/test/src/graph/nodes/RaytraceNodeTest.cpp b/test/src/graph/nodes/RaytraceNodeTest.cpp index d5d66e9b..23a27701 100644 --- a/test/src/graph/nodes/RaytraceNodeTest.cpp +++ b/test/src/graph/nodes/RaytraceNodeTest.cpp @@ -277,8 +277,9 @@ TEST_F(RaytraceNodeTest, config_default_intensity_should_correctly_change_output spawnCubeOnScene(Mat3x4f::TRS({0, 0, 0})); std::vector rays = { - Mat3x4f::TRS({0, 0, 0}, {0, 0, 0}).toRGL(), // hit point - Mat3x4f::TRS({CUBE_HALF_EDGE * 3, 0, 0}, {0, 0, 0}).toRGL(), // non-hit point + Mat3x4f::TRS({0, 0, 0}, {0, 0, 0}).toRGL(), // hit at distance 1 + Mat3x4f::TRS({CUBE_HALF_EDGE * 3, 0, 0}, {0, 0, 0}).toRGL(), // non-hit point + Mat3x4f::TRS({0, 0, -CUBE_HALF_EDGE * 3}, {0, 0, 0}).toRGL(), // hit at distance 2 }; float defaultIntensity = 100.0f; @@ -314,6 +315,10 @@ TEST_F(RaytraceNodeTest, config_default_intensity_should_correctly_change_output // Non-hit point EXPECT_EQ(outIsHits[1], 0); EXPECT_EQ(outIntensities[1], expectedIntensityForNonHit); + + // The same surface is four times weaker from twice the distance. + EXPECT_EQ(outIsHits[2], 1); + EXPECT_NEAR(outIntensities[2], defaultIntensity / 4.0f, EPSILON_F); }; validateOutput(); diff --git a/test/src/scene/reflectivityTest.cpp b/test/src/scene/reflectivityTest.cpp index c7455bfc..3ddd6695 100644 --- a/test/src/scene/reflectivityTest.cpp +++ b/test/src/scene/reflectivityTest.cpp @@ -9,10 +9,10 @@ struct ReflectivityTest : public RGLTestWithParam(0), static_cast(127), static_cast(255)), - testing::Values(0.012, 0.123, 1.23))); + testing::Combine(testing::Values(0.012f, 0.12f, 1.23f), + testing::Values(static_cast(0), static_cast(127), + static_cast(255)), + testing::Values(0.012, 0.123, 1.23))); TEST_P(ReflectivityTest, read_value) { @@ -80,14 +80,12 @@ TEST_P(ReflectivityTest, read_value) EXPECT_RGL_SUCCESS(rgl_graph_get_result_data(yieldNode, DISTANCE_F32, outDistance.data())); for (int i = 0; i < outCount; ++i) { - EXPECT_NEAR(((float) value), outIntensity.at(i), EPSILON_F); float outDistanceValue = outDistance.at(i); float intensity = outIntensity.at(i); - float reflectivityValue = alpha * outDistanceValue * outDistanceValue * intensity; + float expectedIntensity = static_cast(value) / (outDistanceValue * outDistanceValue); + float expectedReflectivity = alpha * static_cast(value); - // Reflectivity test is conducted with greater epsilon. - // This is due to lack of distance impact on intensity. - // As long as distance is not included into intensity calculations, reflectivity value will grow relatively fast with the distance. - EXPECT_NEAR(reflectivityValue, outReflectivity.at(i), 1e-3f); + EXPECT_NEAR(expectedIntensity, intensity, EPSILON_F * expectedIntensity); + EXPECT_NEAR(expectedReflectivity, outReflectivity.at(i), 1e-3f); } -} \ No newline at end of file +}