summaryrefslogtreecommitdiff
path: root/src/mbgl/programs
diff options
context:
space:
mode:
authorAnsis Brammanis <brammanis@gmail.com>2017-06-16 10:42:33 -0400
committerAnsis Brammanis <brammanis@gmail.com>2017-07-10 13:09:34 -0400
commit9034544932c81201d71e3043be785bc2b251042a (patch)
tree35cedb587e7874f517e09c1573c71f354a269828 /src/mbgl/programs
parent5cfa15e1143aea8d2a6a25625350399c483f10b9 (diff)
downloadqtlocation-mapboxgl-9034544932c81201d71e3043be785bc2b251042a.tar.gz
[core] improve legibility of labels that follow lines
port https://github.com/mapbox/mapbox-gl-js/pull/4781 This improves legibility of labels that follow lines in pitched views. The previous approach used the limited information in the shader to calculate put the glyph in approximatelyright place. The new approach does this more accurately by doing it on the cpu where we have access to the entire line geometry.
Diffstat (limited to 'src/mbgl/programs')
-rw-r--r--src/mbgl/programs/attributes.hpp1
-rw-r--r--src/mbgl/programs/symbol_program.cpp39
-rw-r--r--src/mbgl/programs/symbol_program.hpp203
-rw-r--r--src/mbgl/programs/uniforms.hpp1
4 files changed, 107 insertions, 137 deletions
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index f39af2deec..684d9d6099 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -23,6 +23,7 @@ inline uint16_t packUint8Pair(T a, T b) {
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset);
+MBGL_DEFINE_ATTRIBUTE(float, 3, a_projected_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_label_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos);
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index bd43237b8f..8790adcc63 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -2,6 +2,7 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/layout/symbol_projection.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/math/clamp.hpp>
@@ -10,7 +11,7 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(SymbolLayoutVertex) == 20, "expected SymbolLayoutVertex size");
+static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size");
std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom,
const style::DataDrivenPropertyValue<float>& sizeProperty,
@@ -33,6 +34,7 @@ Values makeValues(const bool isText,
const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
+ const bool alongLine,
const RenderTile& tile,
const TransformState& state,
Args&&... args) {
@@ -46,21 +48,41 @@ Values makeValues(const bool isText,
pixelsToGLUnits[1] * state.getCameraToCenterDistance()
}};
}
+
+ const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom());
+ const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map;
+ const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map;
+
+ mat4 labelPlaneMatrix;
+ if (alongLine) {
+ // For labels that follow lines the first part of the projection is handled on the cpu.
+ // Pass an identity matrix because no transformation needs to be done in the vertex shader.
+ matrix::identity(labelPlaneMatrix);
+ } else {
+ labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
+ }
+
+ mat4 glCoordMatrix = getGlCoordMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
return Values {
uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate,
values.translateAnchor,
state) },
+ uniforms::u_label_plane_matrix::Value{labelPlaneMatrix},
+ uniforms::u_gl_coord_matrix::Value{ tile.translateVtxMatrix(glCoordMatrix,
+ values.translate,
+ values.translateAnchor,
+ state,
+ true) },
uniforms::u_extrude_scale::Value{ extrudeScale },
uniforms::u_texsize::Value{ texsize },
- uniforms::u_zoom::Value{ float(state.getZoom()) },
- uniforms::u_rotate_with_map::Value{ values.rotationAlignment == AlignmentType::Map },
uniforms::u_texture::Value{ 0 },
uniforms::u_fadetexture::Value{ 1 },
uniforms::u_is_text::Value{ isText },
uniforms::u_collision_y_stretch::Value{ tile.tile.yStretch() },
uniforms::u_camera_to_center_distance::Value{ state.getCameraToCenterDistance() },
uniforms::u_pitch::Value{ state.getPitch() },
+ uniforms::u_pitch_with_map::Value{ pitchWithMap },
uniforms::u_max_camera_distance::Value{ values.maxCameraDistance },
std::forward<Args>(args)...
};
@@ -71,6 +93,7 @@ SymbolIconProgram::uniformValues(const bool isText,
const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
+ const bool alongLine,
const RenderTile& tile,
const TransformState& state)
{
@@ -79,6 +102,7 @@ SymbolIconProgram::uniformValues(const bool isText,
values,
texsize,
pixelsToGLUnits,
+ alongLine,
tile,
state
);
@@ -90,25 +114,24 @@ typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<Paint
const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
+ const bool alongLine,
const RenderTile& tile,
const TransformState& state,
const SymbolSDFPart part)
{
const float gammaScale = (values.pitchAlignment == AlignmentType::Map
- ? std::cos(state.getPitch())
- : 1.0) * state.getCameraToCenterDistance();
+ ? std::cos(state.getPitch()) * state.getCameraToCenterDistance()
+ : 1.0);
return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>(
isText,
values,
texsize,
pixelsToGLUnits,
+ alongLine,
tile,
state,
uniforms::u_gamma_scale::Value{ gammaScale },
- uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
- uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
- uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map },
uniforms::u_is_halo::Value{ part == SymbolSDFPart::Halo }
);
}
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index 130e556b46..79a961ad21 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -29,9 +29,9 @@ class RenderTile;
class TransformState;
namespace uniforms {
-MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map);
+MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_gl_coord_matrix);
+MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_label_plane_matrix);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
@@ -40,57 +40,58 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_size);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_layout_size);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance);
} // namespace uniforms
struct SymbolLayoutAttributes : gl::Attributes<
attributes::a_pos_offset,
- attributes::a_label_pos,
attributes::a_data<uint16_t, 4>>
{
- static Vertex vertex(Point<float> a,
+ static Vertex vertex(Point<float> labelAnchor,
Point<float> o,
- Point<float> labelAnchor,
+ float glyphOffsetY,
uint16_t tx,
uint16_t ty,
- float minzoom,
- float maxzoom,
- float labelminzoom,
- uint8_t labelangle) {
+ const Range<float>& sizeData) {
return Vertex {
// combining pos and offset to reduce number of vertex attributes passed to shader (8 max for some devices)
{{
- static_cast<int16_t>(a.x),
- static_cast<int16_t>(a.y),
- static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement
- static_cast<int16_t>(::round(o.y * 64))
- }},
- {{
static_cast<int16_t>(labelAnchor.x),
- static_cast<int16_t>(labelAnchor.y)
+ static_cast<int16_t>(labelAnchor.y),
+ static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement
+ static_cast<int16_t>(::round((o.y + glyphOffsetY) * 64))
}},
{{
tx,
ty,
- mbgl::attributes::packUint8Pair(
- static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
- static_cast<uint8_t>(labelangle)
- ),
- mbgl::attributes::packUint8Pair(
- static_cast<uint8_t>(minzoom * 10),
- static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
- )
+ static_cast<uint16_t>(sizeData.min * 10),
+ static_cast<uint16_t>(sizeData.max * 10)
}}
};
}
};
+
+struct SymbolDynamicLayoutAttributes : gl::Attributes<attributes::a_projected_pos> {
+ static Vertex vertex(Point<float> anchorPoint, float labelAngle, float labelminzoom) {
+ return Vertex {
+ {{
+ anchorPoint.x,
+ anchorPoint.y,
+ static_cast<float>(mbgl::attributes::packUint8Pair(
+ static_cast<uint8_t>(std::fmod(labelAngle + 2 * M_PI, 2 * M_PI) / (2 * M_PI) * 255),
+ static_cast<uint8_t>(labelminzoom * 10)))
+ }}
+ };
+ }
+};
-class SymbolSizeAttributes : public gl::Attributes<attributes::a_size> {
-public:
- using Attribute = attributes::a_size::Type;
+struct ZoomEvaluatedSize {
+ bool isZoomConstant;
+ bool isFeatureConstant;
+ float sizeT;
+ float size;
+ float layoutSize;
};
-
// Mimic the PaintPropertyBinder technique specifically for the {text,icon}-size layout properties
// in order to provide a 'custom' scheme for encoding the necessary attribute data. As with
// PaintPropertyBinder, SymbolSizeBinder is an abstract class whose implementations handle the
@@ -103,18 +104,25 @@ public:
uniforms::u_is_size_zoom_constant,
uniforms::u_is_size_feature_constant,
uniforms::u_size_t,
- uniforms::u_size,
- uniforms::u_layout_size>;
+ uniforms::u_size>;
using UniformValues = Uniforms::Values;
static std::unique_ptr<SymbolSizeBinder> create(const float tileZoom,
const style::DataDrivenPropertyValue<float>& sizeProperty,
const float defaultValue);
- virtual SymbolSizeAttributes::Bindings attributeBindings() const = 0;
- virtual void populateVertexVector(const GeometryTileFeature& feature) = 0;
- virtual UniformValues uniformValues(float currentZoom) const = 0;
- virtual void upload(gl::Context&) = 0;
+ virtual Range<float> getVertexSizeData(const GeometryTileFeature& feature) = 0;
+ virtual ZoomEvaluatedSize evaluateForZoom(float currentZoom) const = 0;
+
+ UniformValues uniformValues(float currentZoom) const {
+ const ZoomEvaluatedSize u = evaluateForZoom(currentZoom);
+ return UniformValues {
+ uniforms::u_is_size_zoom_constant::Value{ u.isZoomConstant },
+ uniforms::u_is_size_feature_constant::Value{ u.isFeatureConstant},
+ uniforms::u_size_t::Value{ u.sizeT },
+ uniforms::u_size::Value{ u.size }
+ };
+ }
};
// Return the smallest range of stops that covers the interval [lowerZoom, upperZoom]
@@ -160,14 +168,9 @@ public:
);
}
- SymbolSizeAttributes::Bindings attributeBindings() const override {
- return SymbolSizeAttributes::Bindings { gl::DisabledAttribute() };
- }
-
- void upload(gl::Context&) override {}
- void populateVertexVector(const GeometryTileFeature&) override {};
+ Range<float> getVertexSizeData(const GeometryTileFeature&) override { return { 0.0f, 0.0f }; };
- UniformValues uniformValues(float currentZoom) const override {
+ ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override {
float size = layoutSize;
bool isZoomConstant = !(coveringRanges || function);
if (coveringRanges) {
@@ -186,14 +189,9 @@ public:
} else if (function) {
size = function->evaluate(currentZoom);
}
-
- return UniformValues {
- uniforms::u_is_size_zoom_constant::Value{ isZoomConstant },
- uniforms::u_is_size_feature_constant::Value{ true },
- uniforms::u_size_t::Value{ 0.0f }, // unused
- uniforms::u_size::Value{ size },
- uniforms::u_layout_size::Value{ layoutSize }
- };
+
+ const float unused = 0.0f;
+ return { isZoomConstant, true, unused, size, layoutSize };
}
float layoutSize;
@@ -215,49 +213,22 @@ public:
defaultValue(defaultValue_) {
}
- SymbolSizeAttributes::Bindings attributeBindings() const override {
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0, 1) };
- }
-
- void populateVertexVector(const GeometryTileFeature& feature) override {
- const auto sizeVertex = Vertex {
- {{
- static_cast<uint16_t>(function.evaluate(feature, defaultValue) * 10)
- }}
- };
-
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
+ Range<float> getVertexSizeData(const GeometryTileFeature& feature) override {
+ const float size = function.evaluate(feature, defaultValue);
+ return { size, size };
};
- UniformValues uniformValues(float) const override {
- return UniformValues {
- uniforms::u_is_size_zoom_constant::Value{ true },
- uniforms::u_is_size_feature_constant::Value{ false },
- uniforms::u_size_t::Value{ 0.0f }, // unused
- uniforms::u_size::Value{ 0.0f }, // unused
- uniforms::u_layout_size::Value{ 0.0f } // unused
- };
- }
-
- void upload(gl::Context& context) override {
- buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) };
+ ZoomEvaluatedSize evaluateForZoom(float) const override {
+ const float unused = 0.0f;
+ return { true, false, unused, unused, unused };
}
const style::SourceFunction<float>& function;
const float defaultValue;
-
- VertexVector vertices;
- optional<VertexBuffer> buffer;
};
class CompositeFunctionSymbolSizeBinder final : public SymbolSizeBinder {
public:
- using Vertex = SymbolSizeAttributes::Vertex;
- using VertexVector = gl::VertexVector<Vertex>;
- using VertexBuffer = gl::VertexBuffer<Vertex>;
CompositeFunctionSymbolSizeBinder(const float tileZoom, const style::CompositeFunction<float>& function_, const float defaultValue_)
: function(function_),
@@ -268,51 +239,27 @@ public:
return getCoveringStops(stops, tileZoom, tileZoom + 1); }))
{}
- SymbolSizeAttributes::Bindings attributeBindings() const override {
- return SymbolSizeAttributes::Bindings { SymbolSizeAttributes::Attribute::binding(*buffer, 0) };
- }
-
- void populateVertexVector(const GeometryTileFeature& feature) override {
- const auto sizeVertex = Vertex {
- {{
- static_cast<uint16_t>(function.evaluate(coveringZoomStops.min, feature, defaultValue) * 10),
- static_cast<uint16_t>(function.evaluate(coveringZoomStops.max, feature, defaultValue) * 10),
- static_cast<uint16_t>(function.evaluate(layoutZoom, feature, defaultValue) * 10)
- }}
+ Range<float> getVertexSizeData(const GeometryTileFeature& feature) override {
+ return {
+ function.evaluate(coveringZoomStops.min, feature, defaultValue),
+ function.evaluate(coveringZoomStops.max, feature, defaultValue)
};
-
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
- vertices.emplace_back(sizeVertex);
};
- UniformValues uniformValues(float currentZoom) const override {
+ ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override {
float sizeInterpolationT = util::clamp(
util::interpolationFactor(1.0f, coveringZoomStops, currentZoom),
0.0f, 1.0f
);
- return UniformValues {
- uniforms::u_is_size_zoom_constant::Value{ false },
- uniforms::u_is_size_feature_constant::Value{ false },
- uniforms::u_size_t::Value{ sizeInterpolationT },
- uniforms::u_size::Value{ 0.0f }, // unused
- uniforms::u_layout_size::Value{ 0.0f } // unused
- };
- }
-
- void upload(gl::Context& context) override {
- buffer = VertexBuffer { context.createVertexBuffer(std::move(vertices)) };
+ const float unused = 0.0f;
+ return { false, false, sizeInterpolationT, unused, unused };
}
const style::CompositeFunction<float>& function;
const float defaultValue;
float layoutZoom;
Range<float> coveringZoomStops;
-
- VertexVector vertices;
- optional<VertexBuffer> buffer;
};
@@ -326,7 +273,7 @@ public:
using LayoutAttributes = LayoutAttrs;
using LayoutVertex = typename LayoutAttributes::Vertex;
- using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, SymbolSizeAttributes>;
+ using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, SymbolDynamicLayoutAttributes>;
using PaintProperties = PaintProps;
using PaintPropertyBinders = typename PaintProperties::Binders;
@@ -359,6 +306,7 @@ public:
gl::ColorMode colorMode,
UniformValues&& uniformValues,
const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer,
const SymbolSizeBinder& symbolSizeBinder,
const gl::IndexBuffer<DrawMode>& indexBuffer,
const gl::SegmentVector<Attributes>& segments,
@@ -375,7 +323,7 @@ public:
.concat(symbolSizeBinder.uniformValues(currentZoom))
.concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties)),
LayoutAttributes::bindings(layoutVertexBuffer)
- .concat(symbolSizeBinder.attributeBindings())
+ .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer))
.concat(paintPropertyBinders.attributeBindings(currentProperties)),
indexBuffer,
segments
@@ -389,16 +337,17 @@ class SymbolIconProgram : public SymbolProgram<
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
+ uniforms::u_label_plane_matrix,
+ uniforms::u_gl_coord_matrix,
uniforms::u_extrude_scale,
uniforms::u_texsize,
- uniforms::u_zoom,
- uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
uniforms::u_is_text,
uniforms::u_collision_y_stretch,
uniforms::u_camera_to_center_distance,
uniforms::u_pitch,
+ uniforms::u_pitch_with_map,
uniforms::u_max_camera_distance>,
style::IconPaintProperties>
{
@@ -409,6 +358,7 @@ public:
const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
+ const bool alongLine,
const RenderTile&,
const TransformState&);
};
@@ -425,21 +375,19 @@ class SymbolSDFProgram : public SymbolProgram<
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
+ uniforms::u_label_plane_matrix,
+ uniforms::u_gl_coord_matrix,
uniforms::u_extrude_scale,
uniforms::u_texsize,
- uniforms::u_zoom,
- uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
uniforms::u_is_text,
uniforms::u_collision_y_stretch,
uniforms::u_camera_to_center_distance,
uniforms::u_pitch,
+ uniforms::u_pitch_with_map,
uniforms::u_max_camera_distance,
uniforms::u_gamma_scale,
- uniforms::u_bearing,
- uniforms::u_aspect_ratio,
- uniforms::u_pitch_with_map,
uniforms::u_is_halo>,
PaintProperties>
{
@@ -449,21 +397,19 @@ public:
SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
+ uniforms::u_label_plane_matrix,
+ uniforms::u_gl_coord_matrix,
uniforms::u_extrude_scale,
uniforms::u_texsize,
- uniforms::u_zoom,
- uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
uniforms::u_is_text,
uniforms::u_collision_y_stretch,
uniforms::u_camera_to_center_distance,
uniforms::u_pitch,
+ uniforms::u_pitch_with_map,
uniforms::u_max_camera_distance,
uniforms::u_gamma_scale,
- uniforms::u_bearing,
- uniforms::u_aspect_ratio,
- uniforms::u_pitch_with_map,
uniforms::u_is_halo>,
PaintProperties>;
@@ -477,6 +423,7 @@ public:
const style::SymbolPropertyValues&,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
+ const bool alongLine,
const RenderTile&,
const TransformState&,
const SymbolSDFPart);
diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp
index 861f3271c9..285d243251 100644
--- a/src/mbgl/programs/uniforms.hpp
+++ b/src/mbgl/programs/uniforms.hpp
@@ -15,7 +15,6 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_collision_y_stretch);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius);