clouds: Precision fixes
This commit is contained in:
parent
330ac54ac9
commit
24a9145bb3
3 changed files with 72 additions and 23 deletions
|
@ -87,7 +87,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, 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);
|
noiseAddLevelsSimple(definition->_edge_noise, 4, 1.0, -0.5, 0.5, 0.5);
|
||||||
noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.8, 0.0);
|
noiseSetFunctionParams(definition->_edge_noise, NOISE_FUNCTION_SIMPLEX, 0.8, 0.0);
|
||||||
break;
|
break;
|
||||||
case CLOUDS_TYPE_STRATOCUMULUS:
|
case CLOUDS_TYPE_STRATOCUMULUS:
|
||||||
|
@ -95,7 +95,7 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
|
||||||
curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0);
|
curveQuickAddPoint(definition->_coverage_by_altitude, 0.2, 1.0);
|
||||||
curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0);
|
curveQuickAddPoint(definition->_coverage_by_altitude, 0.5, 1.0);
|
||||||
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, 4, 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, 6, 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);
|
||||||
|
|
|
@ -4,28 +4,39 @@
|
||||||
|
|
||||||
double cloudsGetLayerCoverage(CloudsLayerDefinition* layer, Vector3 location)
|
double cloudsGetLayerCoverage(CloudsLayerDefinition* layer, Vector3 location)
|
||||||
{
|
{
|
||||||
if (layer->base_coverage == 0.0)
|
if (layer->base_coverage <= 0.0)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
double coverage = noiseGet2DTotal(layer->_coverage_noise, location.x / layer->shape_scaling, location.z / layer->shape_scaling);
|
double coverage = 0.5 + noiseGet2DTotal(layer->_coverage_noise, location.x / layer->shape_scaling, location.z / layer->shape_scaling);
|
||||||
coverage -= (1.0 - layer->base_coverage);
|
coverage -= (1.0 - layer->base_coverage);
|
||||||
|
|
||||||
coverage *= curveGetValue(layer->_coverage_by_altitude, (location.y - layer->lower_altitude) / layer->thickness);
|
coverage *= curveGetValue(layer->_coverage_by_altitude, (location.y - layer->lower_altitude) / layer->thickness);
|
||||||
|
|
||||||
return (coverage <= 0.0) ? 0.0 : coverage;
|
if (coverage < 0.0)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
else if (coverage >= 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return coverage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, double coverage)
|
double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, double coverage)
|
||||||
{
|
{
|
||||||
if (coverage == 0.0)
|
if (coverage <= 0.0)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
else if (coverage == 1.0)
|
else if (coverage >= 1.0)
|
||||||
{
|
{
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
@ -39,11 +50,11 @@ double cloudsGetLayerDensity(CloudsLayerDefinition* layer, Vector3 location, dou
|
||||||
|
|
||||||
double cloudsGetEdgeDensity(CloudsLayerDefinition* layer, Vector3 location, double layer_density)
|
double cloudsGetEdgeDensity(CloudsLayerDefinition* layer, Vector3 location, double layer_density)
|
||||||
{
|
{
|
||||||
if (layer_density == 0.0)
|
if (layer_density <= 0.0)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
else if (layer_density == 1.0)
|
else if (layer_density >= 1.0)
|
||||||
{
|
{
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,30 @@ typedef struct
|
||||||
static void _walkerFilterCallback(CloudsWalker* walker)
|
static void _walkerFilterCallback(CloudsWalker* walker)
|
||||||
{
|
{
|
||||||
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
|
CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
|
||||||
|
Renderer* renderer = segment->renderer;
|
||||||
AccumulatedLightData* data = (AccumulatedLightData*)segment->data;
|
AccumulatedLightData* data = (AccumulatedLightData*)segment->data;
|
||||||
|
|
||||||
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->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0)
|
||||||
|
{
|
||||||
|
cloudsWalkerOrderRefine(walker, 1.0 / (double)renderer->render_quality);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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 + 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
data->out_scattering += 0.3 * density_integral;
|
data->out_scattering += 0.3 * density_integral;
|
||||||
|
|
||||||
|
@ -78,12 +97,13 @@ static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 locat
|
||||||
|
|
||||||
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
||||||
cloudsWalkerSetStepSize(walker, -1.0);
|
cloudsWalkerSetStepSize(walker, -1.0);
|
||||||
|
cloudsWalkerSetVoidSkipping(walker, 1);
|
||||||
cloudsStartWalking(walker, _walkerFilterCallback, &data);
|
cloudsStartWalking(walker, _walkerFilterCallback, &data);
|
||||||
cloudsDeleteWalker(walker);
|
cloudsDeleteWalker(walker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double max_power = colorGetPower(&light->color) - data.out_scattering;
|
double max_power = data.light_power - data.out_scattering;
|
||||||
if (max_power < 0.0)
|
if (max_power < 0.0)
|
||||||
{
|
{
|
||||||
light->color = COLOR_BLACK;
|
light->color = COLOR_BLACK;
|
||||||
|
@ -100,6 +120,8 @@ typedef struct
|
||||||
{
|
{
|
||||||
double out_scattering; /* Amount of light scattered away by heavy particles */
|
double out_scattering; /* Amount of light scattered away by heavy particles */
|
||||||
Color in_scattering; /* Amount of light redirected toward the viewer */
|
Color in_scattering; /* Amount of light redirected toward the viewer */
|
||||||
|
int entry_found; /* 1 if a cloud entry has been found */
|
||||||
|
Vector3 entry; /* Point of entry in the clouds */
|
||||||
} AccumulatedMaterialData;
|
} AccumulatedMaterialData;
|
||||||
|
|
||||||
static inline void _applyOutScattering(Color* col, double out_scattering)
|
static inline void _applyOutScattering(Color* col, double out_scattering)
|
||||||
|
@ -132,7 +154,12 @@ static void _walkerMaterialCallback(CloudsWalker* walker)
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (!segment->refined && segment->start.global_density == 0.0 && segment->end.global_density > 0.0)
|
||||||
|
{
|
||||||
|
cloudsWalkerOrderRefine(walker, 1.0 / (double)(renderer->render_quality * renderer->render_quality));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
cloudsWalkerOrderSubdivide(walker, renderer->render_quality + 3);
|
||||||
return;
|
return;
|
||||||
|
@ -140,7 +167,9 @@ static void _walkerMaterialCallback(CloudsWalker* walker)
|
||||||
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->out_scattering += 0.5 * density_integral;
|
if (density_integral > 0.0)
|
||||||
|
{
|
||||||
|
data->out_scattering += 0.3 * density_integral;
|
||||||
|
|
||||||
Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_ZERO, &layer->material);
|
Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_ZERO, &layer->material);
|
||||||
in_scattering.r *= density_integral * 5.0;
|
in_scattering.r *= density_integral * 5.0;
|
||||||
|
@ -151,6 +180,13 @@ static void _walkerMaterialCallback(CloudsWalker* walker)
|
||||||
data->in_scattering.r += in_scattering.r;
|
data->in_scattering.r += in_scattering.r;
|
||||||
data->in_scattering.g += in_scattering.g;
|
data->in_scattering.g += in_scattering.g;
|
||||||
data->in_scattering.b += in_scattering.b;
|
data->in_scattering.b += in_scattering.b;
|
||||||
|
|
||||||
|
if (!data->entry_found)
|
||||||
|
{
|
||||||
|
data->entry_found = 1;
|
||||||
|
data->entry = segment->start.location;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end)
|
static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end)
|
||||||
|
@ -182,9 +218,12 @@ static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 en
|
||||||
AccumulatedMaterialData data;
|
AccumulatedMaterialData data;
|
||||||
data.out_scattering = 0.0;
|
data.out_scattering = 0.0;
|
||||||
data.in_scattering = COLOR_BLACK;
|
data.in_scattering = COLOR_BLACK;
|
||||||
|
data.entry = ostart;
|
||||||
|
data.entry_found = 0;
|
||||||
|
|
||||||
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
walker = cloudsCreateWalker(renderer, layer, ostart, oend);
|
||||||
cloudsWalkerSetStepSize(walker, -1.0);
|
cloudsWalkerSetStepSize(walker, -1.0);
|
||||||
|
cloudsWalkerSetVoidSkipping(walker, 1);
|
||||||
cloudsStartWalking(walker, _walkerMaterialCallback, &data);
|
cloudsStartWalking(walker, _walkerMaterialCallback, &data);
|
||||||
cloudsDeleteWalker(walker);
|
cloudsDeleteWalker(walker);
|
||||||
|
|
||||||
|
@ -197,8 +236,7 @@ static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 en
|
||||||
base.b += data.in_scattering.b;
|
base.b += data.in_scattering.b;
|
||||||
|
|
||||||
/* Apply aerial perspective approximation */
|
/* Apply aerial perspective approximation */
|
||||||
/* TODO This should be done at cloud entry */
|
base = renderer->atmosphere->applyAerialPerspective(renderer, data.entry, base).final;
|
||||||
base = renderer->atmosphere->applyAerialPerspective(renderer, ostart, base).final;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue