Skip to content

[Bug]: Packed RGBA lets emissive replace an authored PBR base color #3046

Description

@NoahLinckeScout

Summary

BSDF.get_rgba() gives emissive_texture unconditional precedence over an authored PBR base-color texture. The packed RGBA representation therefore replaces a vehicle's intended base color with its emissive map.

HLOD tiles are the complementary case: they deliberately use a black base-color factor and place visible imagery in emissive. A fix must preserve ordinary PBR base color without regressing that representation.

Minimal reproduction

repro.py creates two 2×2 in-memory textures; it requires only a local genesis-world install and NumPy:

python repro.py

Before the fix, the normal-PBR assertion fails. After the fix both material shapes print PASS. It uses no GPU, renderer, downloaded asset, or network request.

Expected behavior

A nonblack PBR base-color texture remains authoritative. When its effective factor is black, the packed representation falls back to emissive imagery.

Root cause

The selection gives emissive unconditional precedence. That does not match glTF PBR semantics, where emissive is additive rather than a replacement for base color.

Proposed fix

Prefer a nonblack diffuse_texture; otherwise use emissive_texture. This retains normal PBR color while supporting black-factor emissive terrain.

Proposed change

Implemented by #3038.

Reproduction script

#!/usr/bin/env python3
"""Hermetic repro for packed-RGBA PBR/emissive selection.

Run with a local genesis-world install:

    python repro.py

Before the fix, the normal-PBR assertion fails. No renderer, GPU, or external
asset is required.
"""

import numpy as np

import genesis as gs


def image(rgb: tuple[int, int, int], *, factor: tuple[float, float, float] = (1.0, 1.0, 1.0)):
    return gs.textures.ImageTexture(
        image_array=np.full((2, 2, 3), rgb, dtype=np.uint8),
        image_color=factor,
    )


def rgb(surface) -> np.ndarray:
    return surface.get_rgba().image_array[..., :3]


def main() -> None:
    gs.init(backend=gs.cpu, logging_level="warning")
    try:
        base_color = image((201, 166, 105))
        emissive = image((76, 122, 64))

        # Ordinary PBR keeps its base color even when an emissive map exists.
        pbr = gs.surfaces.BSDF(diffuse_texture=base_color, emissive_texture=emissive)
        assert np.array_equal(rgb(pbr), base_color.image_array)

        # HLOD uses a base-color texture with a black factor and
        # stores the visible imagery in emissive. This guards the fallback
        # needed when replacing unconditional emissive precedence.
        disabled_base_color = image((201, 166, 105), factor=(0.0, 0.0, 0.0))
        hlod = gs.surfaces.BSDF(diffuse_texture=disabled_base_color, emissive_texture=emissive)
        assert np.array_equal(
            rgb(hlod),
            emissive.image_array,
        )
    finally:
        gs.destroy()

    print("PASS: packed RGBA preserves PBR base color and HLOD emissive imagery")


if __name__ == "__main__":
    main()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions