Materials shown in the view: each object's metal and rough reach the shader (Solid and Rendered); a Material picker with sixteen to start from (gold, chrome, wood, ceramic...); o.material and fry.materials() in scripts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-20 17:14:55 +02:00
commit e93ae44684
9 changed files with 101 additions and 5 deletions

View file

@ -53,7 +53,8 @@ struct DrawData { // DRAW_FIELDS in model.glsl
glm::vec4 cube[6];
glm::vec4 params; // x = sun visibility, y = lit by probes, z = liquid cut, w = LiquidStyle
glm::vec4 plane; // liquid surface
glm::vec4 probe; // the nearest reflection probe: x = its texture (0 = none), y = its top level; z = time (s)
glm::vec4 probe; // the nearest reflection probe: x = its texture (0 = none), y = its top level; z = time (s);
// w = its own surface without a material map: 0 none, else 1 + metal (0..255) + rough (0..255) * 256
};
struct FrameData { // FRAME_FIELDS in model.glsl, then (Vulkan) four buffer addresses
glm::mat4 cascades[4];

View file

@ -222,7 +222,7 @@ void Renderer::drawStreak(const glm::vec3& from, const glm::vec3& to, float widt
}
void Renderer::drawModel(ModelId model, const glm::mat4& transform, const glm::vec4& tint, const std::vector<glm::mat4>* skin,
const ModelLighting* lighting, bool castShadow, const glm::vec4* liquidPlane, LiquidStyle liquid) {
const ModelLighting* lighting, bool castShadow, const glm::vec4* liquidPlane, LiquidStyle liquid, const Surface* surface) {
if (!model.valid() || packet_.draws.size() >= kMaxDraws) return;
ModelDraw d{model.index, transform, tint};
d.castShadow = castShadow || shadowOnly_;
@ -261,6 +261,8 @@ void Renderer::drawModel(ModelId model, const glm::mat4& transform, const glm::v
}
static const auto t0 = std::chrono::steady_clock::now(); // water's waves move with this
dd.probe.z = hasClock_ ? float(std::fmod(clock_, 3600.0)) : std::fmod(std::chrono::duration<float>(std::chrono::steady_clock::now() - t0).count(), 3600.0f);
if (surface)
dd.probe.w = 1.0f + std::round(std::clamp(surface->metal, 0.0f, 1.0f) * 255.0f) + std::round(std::clamp(surface->rough, 0.0f, 1.0f) * 255.0f) * 256.0f;
packet_.draws.push_back(dd);
if (skin && mdl.skinned && packet_.joints.size() + skin->size() <= kMaxJointsPerFrame) {
d.firstJoint = uint32_t(packet_.joints.size());

View file

@ -25,6 +25,11 @@ struct Camera {
};
// Baked light for a moving model (from the map's probes): ambient cube + sun visibility.
// A whole model's surface where it has no material map: how metal (0..1) and how rough (0..1).
struct Surface {
float metal = 0.0f, rough = 0.85f;
};
struct ModelLighting {
glm::vec3 cube[6]; // light arriving from +X -X +Y -Y +Z -Z
float sunVisibility = 1.0f;
@ -98,7 +103,7 @@ public:
// lighting: probe light for moving things (nullptr = lightmap or simple sun shading).
void drawModel(ModelId model, const glm::mat4& transform, const glm::vec4& tint = glm::vec4(1.0f),
const std::vector<glm::mat4>* skin = nullptr, const ModelLighting* lighting = nullptr, bool castShadow = true,
const glm::vec4* liquidPlane = nullptr, LiquidStyle liquid = LiquidStyle::None);
const glm::vec4* liquidPlane = nullptr, LiquidStyle liquid = LiquidStyle::None, const Surface* surface = nullptr);
// liquidPlane (world space: xyz normal, w distance): draws a closed mesh as liquid filling it
// up to the plane — above it is cut away, and its back faces show as the flat surface.
// Alpha below 1 (tint × material) makes a submesh translucent: sorted, blended, after opaque.

View file

@ -159,6 +159,10 @@ void main() {
n = normalize(tbn * vec3(xy, sqrt(max(1.0 - dot(xy, xy), 0.0))));
metal = m.z;
gloss = m.w;
} else if (DRAW.probe.w > 0.5) { // the model's own surface (Renderer::Surface)
uint s = uint(DRAW.probe.w - 0.5);
metal = float(s & 255u) / 255.0;
gloss = 1.0 - float((s >> 8) & 255u) / 255.0;
}
// Weather: how open to the sky this spot is (the lightmap's sky map; moving things: their
// sun visibility), then rain wetting it (darker, glossy) and snow lying on what faces up.