feat(web): wire Blender world lighting controls
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled

This commit is contained in:
mes123456
2026-08-30 20:10:15 +08:00
parent e9e1788b14
commit b15ac3770a
40 changed files with 1985 additions and 22 deletions

View File

@@ -5192,6 +5192,13 @@ json scene_ir_from_blend(const ParsedBlend &blend,
{"color", json::array({horizon_r, horizon_g, horizon_b})},
{"exposure", exposure},
{"backgroundVisible", true} };
world["ambientOcclusionDistance"] = read_float(*blend.sdna, element, "aodist").value_or(10.0f);
world["ambientOcclusionEnergy"] = read_float(*blend.sdna, element, "aoenergy").value_or(1.0f);
world["sunThreshold"] = read_float(*blend.sdna, element, "sun_threshold").value_or(10.0f);
world["sunAngle"] = read_float(*blend.sdna, element, "sun_angle").value_or(0.00918f);
world["sunShadowMaximumResolution"] = read_float(*blend.sdna, element, "sun_shadow_maximum_resolution").value_or(0.001f);
world["sunShadowJitterOverblur"] = read_float(*blend.sdna, element, "sun_shadow_jitter_overblur").value_or(10.0f);
world["sunShadowFilterRadius"] = read_float(*blend.sdna, element, "sun_shadow_filter_radius").value_or(1.0f);
if (const std::optional<uint64_t> lightgroup_pointer = read_pointer(*blend.sdna, element, "lightgroup")) {
if (const std::optional<ElementRef> membership = element_for_pointer(blend, *lightgroup_pointer)) {
const std::string lightgroup_name = read_string(*blend.sdna, *membership, "name");

View File

@@ -5592,6 +5592,45 @@ bool web_engine_blend_main_set_light_clip_start(WebBlendMainState *state,
return true;
}
bool web_engine_blend_main_set_world_lighting_controls(WebBlendMainState *state,
const char *target_id,
const float ao_distance,
const float ao_energy,
const float sun_threshold,
const float sun_angle,
const float sun_shadow_maximum_resolution,
const float sun_shadow_jitter_overblur,
const float sun_shadow_filter_radius,
std::string &error)
{
if (state == nullptr || state->main == nullptr || target_id == nullptr) {
error = "RENDER_PROPERTY_INVALID: world lighting target is missing";
return false;
}
World *world = find_world(state->main, target_id);
if (world == nullptr || world->id.lib != nullptr) {
error = "LINKED_DATA_MUTATION_BLOCKED: World is not editable";
return false;
}
const float values[] = {ao_distance, ao_energy, sun_threshold, sun_angle, sun_shadow_maximum_resolution, sun_shadow_jitter_overblur, sun_shadow_filter_radius};
if (!std::all_of(std::begin(values), std::end(values), [](const float value) { return std::isfinite(value) && value >= 0.0f; }) ||
ao_distance > 1.0e9f || ao_energy > 1.0e9f || sun_threshold > 1.0e9f || sun_angle > 3.14159265f ||
sun_shadow_maximum_resolution < 0.0000001f || sun_shadow_maximum_resolution > 1.0e9f ||
sun_shadow_jitter_overblur > 1.0e9f || sun_shadow_filter_radius > 1.0e9f) {
error = "RENDER_PROPERTY_INVALID: world lighting control is outside the bounded range";
return false;
}
world->aodist = ao_distance;
world->aoenergy = ao_energy;
world->sun_threshold = sun_threshold;
world->sun_angle = sun_angle;
world->sun_shadow_maximum_resolution = sun_shadow_maximum_resolution;
world->sun_shadow_jitter_overblur = sun_shadow_jitter_overblur;
world->sun_shadow_filter_radius = sun_shadow_filter_radius;
world->id.recalc |= ID_RECALC_PARAMETERS;
return true;
}
bool web_engine_blend_main_set_render_properties(WebBlendMainState *state,
const char *target_id,
const char *properties_json,
@@ -5913,13 +5952,32 @@ bool web_engine_blend_main_set_render_properties(WebBlendMainState *state,
if (strncmp(target_id, "world:", 6) == 0) {
World *world = find_world(state->main, target_id);
if (world == nullptr || world->id.lib != nullptr ||
!reject_unknown({"color", "exposure", "mist"}) ||
!reject_unknown({"color", "exposure", "ambientOcclusionDistance", "ambientOcclusionEnergy", "sunThreshold", "sunAngle", "sunShadowMaximumResolution", "sunShadowJitterOverblur", "sunShadowFilterRadius", "mist"}) ||
!read_color("color", &world->horr) ||
!read_float("exposure", -20.0f, 20.0f, world->exposure))
{
if (error.empty()) error = "LINKED_DATA_MUTATION_BLOCKED: World is not editable";
return false;
}
if (properties.contains("ambientOcclusionDistance") || properties.contains("ambientOcclusionEnergy") || properties.contains("sunThreshold") || properties.contains("sunAngle") || properties.contains("sunShadowMaximumResolution") || properties.contains("sunShadowJitterOverblur") || properties.contains("sunShadowFilterRadius")) {
const auto lighting_value = [&](const char *key, const float current) {
if (!properties.contains(key)) return current;
if (!properties[key].is_number()) {
error = std::string("RENDER_PROPERTY_INVALID: ") + key + " must be numeric";
return -1.0f;
}
return properties[key].get<float>();
};
const float ao_distance = lighting_value("ambientOcclusionDistance", world->aodist);
const float ao_energy = lighting_value("ambientOcclusionEnergy", world->aoenergy);
const float sun_threshold = lighting_value("sunThreshold", world->sun_threshold);
const float sun_angle = lighting_value("sunAngle", world->sun_angle);
const float sun_shadow_maximum_resolution = lighting_value("sunShadowMaximumResolution", world->sun_shadow_maximum_resolution);
const float sun_shadow_jitter_overblur = lighting_value("sunShadowJitterOverblur", world->sun_shadow_jitter_overblur);
const float sun_shadow_filter_radius = lighting_value("sunShadowFilterRadius", world->sun_shadow_filter_radius);
if (ao_distance < 0.0f || ao_energy < 0.0f || sun_threshold < 0.0f || sun_angle < 0.0f || sun_shadow_maximum_resolution < 0.0f || sun_shadow_jitter_overblur < 0.0f || sun_shadow_filter_radius < 0.0f ||
!web_engine_blend_main_set_world_lighting_controls(state, target_id, ao_distance, ao_energy, sun_threshold, sun_angle, sun_shadow_maximum_resolution, sun_shadow_jitter_overblur, sun_shadow_filter_radius, error)) return false;
}
if (properties.contains("mist")) {
const json &mist = properties["mist"];
if (!mist.is_object() || mist.empty()) {

View File

@@ -553,6 +553,16 @@ bool web_engine_blend_main_set_light_clip_start(WebBlendMainState *state,
const char *target_id,
float clip_start,
std::string &error);
bool web_engine_blend_main_set_world_lighting_controls(WebBlendMainState *state,
const char *target_id,
float ao_distance,
float ao_energy,
float sun_threshold,
float sun_angle,
float sun_shadow_maximum_resolution,
float sun_shadow_jitter_overblur,
float sun_shadow_filter_radius,
std::string &error);
bool web_engine_blend_main_set_scene_properties(WebBlendMainState *state,
const char *target_id,
const char *properties_json,