clouds: Added edge density
This commit is contained in:
parent
359c6b5902
commit
330ac54ac9
8 changed files with 147 additions and 6 deletions
|
@ -87,6 +87,8 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
|
||||||
curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0);
|
curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0);
|
||||||
noiseAddLevelsSimple(definition->_shape_noise, 7, 1.0, 0.0, 1.0, 0.5);
|
noiseAddLevelsSimple(definition->_shape_noise, 7, 1.0, 0.0, 1.0, 0.5);
|
||||||
noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.4, 0.0);
|
noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.4, 0.0);
|
||||||
|
noiseAddLevelsSimple(definition->_edge_noise, 2, 1.0, -0.5, 0.5, 0.5);
|
||||||
|
noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.8, 0.0);
|
||||||
break;
|
break;
|
||||||
case CLOUDS_TYPE_STRATOCUMULUS:
|
case CLOUDS_TYPE_STRATOCUMULUS:
|
||||||
curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0);
|
curveQuickAddPoint(definition->_coverage_by_altitude, 0.0, 0.0);
|
||||||
|
@ -95,7 +97,7 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
|
||||||
curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0);
|
curveQuickAddPoint(definition->_coverage_by_altitude, 1.0, 0.0);
|
||||||
noiseAddLevelsSimple(definition->_shape_noise, 2, 1.0, 0.0, 1.0, 0.5);
|
noiseAddLevelsSimple(definition->_shape_noise, 2, 1.0, 0.0, 1.0, 0.5);
|
||||||
noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.3, 0.0);
|
noiseSetFunctionParams(definition->_shape_noise, NOISE_FUNCTION_SIMPLEX, 0.3, 0.0);
|
||||||
noiseAddLevelsSimple(definition->_edge_noise, 8, 1.0, -0.5, 0.5, 0.5);
|
noiseAddLevelsSimple(definition->_edge_noise, 6, 1.0, -0.5, 0.5, 0.5);
|
||||||
noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.5, 0.0);
|
noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.5, 0.0);
|
||||||
break;
|
break;
|
||||||
case CLOUDS_TYPE_STRATUS:
|
case CLOUDS_TYPE_STRATUS:
|
||||||
|
@ -114,6 +116,7 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
|
||||||
|
|
||||||
noiseNormalizeAmplitude(definition->_coverage_noise, -1.0, 3.0, 0);
|
noiseNormalizeAmplitude(definition->_coverage_noise, -1.0, 3.0, 0);
|
||||||
noiseNormalizeAmplitude(definition->_shape_noise, -0.5, 0.5, 0);
|
noiseNormalizeAmplitude(definition->_shape_noise, -0.5, 0.5, 0);
|
||||||
|
noiseNormalizeAmplitude(definition->_edge_noise, -0.5, 0.5, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CloudsLayerDefinition* cloudsLayerCreateDefinition()
|
CloudsLayerDefinition* cloudsLayerCreateDefinition()
|
||||||
|
|
|
@ -37,6 +37,24 @@ double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, dou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cloudsGetEdgeDensity(CloudsLayerDefinition* layer, Vector3 location, double layer_density)
|
||||||
|
{
|
||||||
|
if (layer_density == 0.0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
else if (layer_density == 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double density = noiseGet3DTotal(layer->_edge_noise, location.x / layer->edge_scaling, location.y / layer->edge_scaling, location.z / layer->edge_scaling);
|
||||||
|
density -= (0.5 - layer_density);
|
||||||
|
return (density <= 0.0) ? 0.0 : density;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static double _fakeGetDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
|
static double _fakeGetDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
|
||||||
{
|
{
|
||||||
UNUSED(layer);
|
UNUSED(layer);
|
||||||
|
@ -46,9 +64,20 @@ static double _fakeGetDensity(Renderer* renderer, CloudsLayerDefinition* layer,
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double _fakeGetEdgeDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location, double layer_density)
|
||||||
|
{
|
||||||
|
UNUSED(layer);
|
||||||
|
UNUSED(renderer);
|
||||||
|
UNUSED(location);
|
||||||
|
UNUSED(layer_density);
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer)
|
void cloudsBindFakeDensityToRenderer(CloudsRenderer* renderer)
|
||||||
{
|
{
|
||||||
renderer->getLayerDensity = _fakeGetDensity;
|
renderer->getLayerDensity = _fakeGetDensity;
|
||||||
|
renderer->getEdgeDensity = _fakeGetEdgeDensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double _realGetDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
|
static double _realGetDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
|
||||||
|
@ -60,7 +89,15 @@ static double _realGetDensity(Renderer* renderer, CloudsLayerDefinition* layer,
|
||||||
return cloudsGetLayerDensity(layer, location, coverage);
|
return cloudsGetLayerDensity(layer, location, coverage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double _realGetEdgeDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location, double layer_density)
|
||||||
|
{
|
||||||
|
UNUSED(renderer);
|
||||||
|
|
||||||
|
return cloudsGetEdgeDensity(layer, location, layer_density);
|
||||||
|
}
|
||||||
|
|
||||||
void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer)
|
void cloudsBindRealDensityToRenderer(CloudsRenderer* renderer)
|
||||||
{
|
{
|
||||||
renderer->getLayerDensity = _realGetDensity;
|
renderer->getLayerDensity = _realGetDensity;
|
||||||
|
renderer->getEdgeDensity = _realGetEdgeDensity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the local coverage of a cloud layer [0.0;1.0]
|
* Get the coverage of a cloud layer [0.0;1.0]
|
||||||
*
|
*
|
||||||
* 0.0 means no cloud is present.
|
* 0.0 means no cloud is present.
|
||||||
* 1.0 means full layer.
|
* 1.0 means full layer.
|
||||||
|
@ -21,13 +21,18 @@ extern "C"
|
||||||
double cloudsGetLayerCoverage(CloudsLayerDefinition* layer, Vector3 location);
|
double cloudsGetLayerCoverage(CloudsLayerDefinition* layer, Vector3 location);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the local density of a cloud layer at a given point [0.0;1.0].
|
* Get the global density of a cloud layer at a given point [0.0;1.0].
|
||||||
*
|
*
|
||||||
* 0.0 means no cloud is present.
|
* 0.0 means no cloud is present.
|
||||||
* 1.0 means full density (deep inside cloud).
|
* 1.0 means full density (deep inside cloud).
|
||||||
*/
|
*/
|
||||||
double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, double coverage);
|
double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, double coverage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the local density of a cloud layer at a given point inside an edge [0.0;1.0].
|
||||||
|
*/
|
||||||
|
double cloudsGetEdgeDensity(CloudsLayerDefinition* layer, Vector3 location, double layer_density);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind fake density functions to a renderer.
|
* Bind fake density functions to a renderer.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -125,7 +125,20 @@ static void _walkerMaterialCallback(CloudsWalker* walker)
|
||||||
|
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
double density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
double density_integral;
|
||||||
|
if (segment->subdivided)
|
||||||
|
{
|
||||||
|
density_integral = segment->length * (segment->start.local_density + segment->end.local_density) / 2.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((segment->start.global_density > 0.0 || segment->end.global_density > 0.0) && (segment->start.global_density < 1.0 || segment->end.global_density < 1.0))
|
||||||
|
{
|
||||||
|
cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
data->out_scattering += 0.5 * density_integral;
|
data->out_scattering += 0.5 * density_integral;
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct CloudsWalker
|
||||||
double max_length;
|
double max_length;
|
||||||
double step_size;
|
double step_size;
|
||||||
int skip_void;
|
int skip_void;
|
||||||
|
int local_density;
|
||||||
|
|
||||||
int started;
|
int started;
|
||||||
CloudWalkerStepInfo last_segment;
|
CloudWalkerStepInfo last_segment;
|
||||||
|
@ -113,6 +114,7 @@ CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* laye
|
||||||
result->cursor = 0.0;
|
result->cursor = 0.0;
|
||||||
result->step_size = 1.0;
|
result->step_size = 1.0;
|
||||||
result->skip_void = 0;
|
result->skip_void = 0;
|
||||||
|
result->local_density = -1;
|
||||||
|
|
||||||
result->started = 0;
|
result->started = 0;
|
||||||
result->subdivision_count = 0;
|
result->subdivision_count = 0;
|
||||||
|
@ -138,10 +140,15 @@ void cloudsWalkerSetStepSize(CloudsWalker* walker, double step)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* TODO Automatic settings (using rendering quality and cloud feature size) */
|
/* TODO Automatic settings (using rendering quality and cloud feature size) */
|
||||||
walker->step_size = 1.0;
|
walker->step_size = 5.0 / (double)walker->last_segment.renderer->render_quality;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled)
|
||||||
|
{
|
||||||
|
walker->local_density = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled)
|
void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled)
|
||||||
{
|
{
|
||||||
walker->skip_void = enabled;
|
walker->skip_void = enabled;
|
||||||
|
@ -155,6 +162,15 @@ static void _getPoint(CloudsWalker* walker, double cursor, CloudWalkerPoint* out
|
||||||
Renderer* renderer = walker->last_segment.renderer;
|
Renderer* renderer = walker->last_segment.renderer;
|
||||||
CloudsLayerDefinition* layer = walker->last_segment.layer;
|
CloudsLayerDefinition* layer = walker->last_segment.layer;
|
||||||
out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
|
out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
|
||||||
|
|
||||||
|
if (walker->local_density > 0 || (walker->local_density < 0 && walker->subdivision_count > 0))
|
||||||
|
{
|
||||||
|
out_point->local_density = renderer->clouds->getEdgeDensity(renderer, layer, out_point->location, out_point->global_density);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out_point->local_density = 0.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
|
static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
|
||||||
|
|
|
@ -18,6 +18,7 @@ typedef struct
|
||||||
double distance_from_start;
|
double distance_from_start;
|
||||||
Vector3 location;
|
Vector3 location;
|
||||||
double global_density;
|
double global_density;
|
||||||
|
double local_density;
|
||||||
} CloudWalkerPoint;
|
} CloudWalkerPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,6 +87,16 @@ void cloudsWalkerSetStepSize(CloudsWalker* walker, double step);
|
||||||
*/
|
*/
|
||||||
void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled);
|
void cloudsWalkerSetVoidSkipping(CloudsWalker* walker, int enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle the local density computing.
|
||||||
|
*
|
||||||
|
* When this option is set, the CloudWalkerStepInfo will contain information about local density.
|
||||||
|
* The automatic setting will set to 1 on subdivided steps, and 0 elsewhere.
|
||||||
|
* @param walker The walker to configure
|
||||||
|
* @param enabled 1 to enable local density, 0 to disable it, -1 for automatic setting.
|
||||||
|
*/
|
||||||
|
void cloudsWalkerToggleLocalDensity(CloudsWalker* walker, int enabled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a single step.
|
* Perform a single step.
|
||||||
*
|
*
|
||||||
|
|
|
@ -61,6 +61,7 @@ typedef struct
|
||||||
|
|
||||||
typedef Color (*FuncCloudsGetColor)(Renderer* renderer, Color base, Vector3 start, Vector3 end);
|
typedef Color (*FuncCloudsGetColor)(Renderer* renderer, Color base, Vector3 start, Vector3 end);
|
||||||
typedef double (*FuncCloudsGetLayerDensity)(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location);
|
typedef double (*FuncCloudsGetLayerDensity)(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location);
|
||||||
|
typedef double (*FuncCloudsGetEdgeDensity)(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location, double layer_density);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -69,6 +70,7 @@ typedef struct
|
||||||
FuncCloudsGetColor getColor;
|
FuncCloudsGetColor getColor;
|
||||||
FuncLightingAlterLight alterLight;
|
FuncLightingAlterLight alterLight;
|
||||||
FuncCloudsGetLayerDensity getLayerDensity;
|
FuncCloudsGetLayerDensity getLayerDensity;
|
||||||
|
FuncCloudsGetEdgeDensity getEdgeDensity;
|
||||||
} CloudsRenderer;
|
} CloudsRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -200,6 +200,15 @@ static double _getLayerDensitySinX(Renderer* renderer, CloudsLayerDefinition* la
|
||||||
return (density > 0.0) ? density : 0.0;
|
return (density > 0.0) ? density : 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double _getEdgeDensitySquared(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location, double edge_density)
|
||||||
|
{
|
||||||
|
UNUSED(renderer);
|
||||||
|
UNUSED(layer);
|
||||||
|
UNUSED(location);
|
||||||
|
return edge_density * edge_density;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
START_TEST(test_clouds_walking)
|
START_TEST(test_clouds_walking)
|
||||||
{
|
{
|
||||||
/* Init */
|
/* Init */
|
||||||
|
@ -414,7 +423,52 @@ START_TEST(test_clouds_walking)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_clouds_walking_local)
|
||||||
|
{
|
||||||
|
/* Init */
|
||||||
|
CloudsLayerDefinition* layer;
|
||||||
|
layer = cloudsGetLayerType().callback_create();
|
||||||
|
layer->lower_altitude = -1.0;
|
||||||
|
layer->thickness = 2.0;
|
||||||
|
cloudsGetLayerType().callback_validate(layer);
|
||||||
|
|
||||||
|
Renderer* renderer;
|
||||||
|
renderer = rendererCreate();
|
||||||
|
|
||||||
|
renderer->render_quality = 8;
|
||||||
|
renderer->clouds->getLayerDensity = _getLayerDensitySinX;
|
||||||
|
renderer->clouds->getEdgeDensity = _getEdgeDensitySquared;
|
||||||
|
|
||||||
|
CloudsWalker* walker = cloudsCreateWalker(renderer, layer, v3(0.0, 0.0, 0.0), v3(1.0, 0.0, 0.0));
|
||||||
|
CloudWalkerStepInfo* segment;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Test that local density is off by default */
|
||||||
|
cloudsWalkerSetStepSize(walker, 0.3);
|
||||||
|
result = cloudsWalkerPerformStep(walker);
|
||||||
|
segment = cloudsWalkerGetLastSegment(walker);
|
||||||
|
ck_assert_int_eq(result, 1);
|
||||||
|
ck_assert_double_eq(segment->length, 0.3);
|
||||||
|
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||||
|
ck_assert_double_eq(segment->start.local_density, 0.0);
|
||||||
|
ck_assert_double_eq(segment->end.global_density, 0.951056516295);
|
||||||
|
ck_assert_double_eq(segment->end.local_density, 0.0);
|
||||||
|
|
||||||
|
/* Test it's automatically enabled on subdivision */
|
||||||
|
cloudsWalkerOrderSubdivide(walker, 2);
|
||||||
|
result = cloudsWalkerPerformStep(walker);
|
||||||
|
segment = cloudsWalkerGetLastSegment(walker);
|
||||||
|
ck_assert_int_eq(result, 1);
|
||||||
|
ck_assert_double_eq(segment->length, 0.15);
|
||||||
|
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||||
|
ck_assert_double_eq(segment->start.local_density, 0.0);
|
||||||
|
ck_assert_double_eq(segment->end.global_density, 0.809016994375);
|
||||||
|
ck_assert_double_eq(segment->end.local_density, 0.654508497187);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
TEST_CASE(clouds,
|
TEST_CASE(clouds,
|
||||||
test_clouds_density,
|
test_clouds_density,
|
||||||
|
test_clouds_walking,
|
||||||
test_clouds_walking_boundaries,
|
test_clouds_walking_boundaries,
|
||||||
test_clouds_walking)
|
test_clouds_walking_local)
|
||||||
|
|
Loading…
Reference in a new issue