Skip to content
Draft
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
2 changes: 1 addition & 1 deletion docs/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion include/rgl/api/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/**
Expand Down
6 changes: 5 additions & 1 deletion src/gpu/optixPrograms.cu
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,11 @@ extern "C" __global__ void __closesthit__()

intensity = tex2D<TextureTexelFormat>(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<float>(distanceSquared) : 0.0f;

Vec3f absPointVelocity{NAN};
Vec3f relPointVelocity{NAN};
Expand Down
9 changes: 7 additions & 2 deletions test/src/graph/nodes/RaytraceNodeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,9 @@ TEST_F(RaytraceNodeTest, config_default_intensity_should_correctly_change_output
spawnCubeOnScene(Mat3x4f::TRS({0, 0, 0}));

std::vector<rgl_mat3x4f> 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;
Expand Down Expand Up @@ -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();
Expand Down
20 changes: 9 additions & 11 deletions test/src/scene/reflectivityTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ struct ReflectivityTest : public RGLTestWithParam<std::tuple<float, unsigned cha
{};

INSTANTIATE_TEST_SUITE_P(Parametrized, ReflectivityTest,
testing::Combine(
testing::Values(0.012f, 0.12f, 1.23f),
testing::Values(static_cast<unsigned char>(0), static_cast<unsigned char>(127), static_cast<unsigned char>(255)),
testing::Values(0.012, 0.123, 1.23)));
testing::Combine(testing::Values(0.012f, 0.12f, 1.23f),
testing::Values(static_cast<unsigned char>(0), static_cast<unsigned char>(127),
static_cast<unsigned char>(255)),
testing::Values(0.012, 0.123, 1.23)));

TEST_P(ReflectivityTest, read_value)
{
Expand Down Expand Up @@ -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<float>(value) / (outDistanceValue * outDistanceValue);
float expectedReflectivity = alpha * static_cast<float>(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);
}
}
}