vcti-shader-mask
The mask shader feature: the vertex-stage cull that draws only the submeshes a client-owned mask marks.
Overview
A viewer needs to hide and show components of a mesh while the user works — and in a results viewer, to hide an element set the solver reported on, which is finer than a component. Rebuilding geometry for each of those is slow and gets slower as the model grows, so this feature does it differently: the mesh is divided once into submeshes — any subsets the client wants to address as units — every vertex carries the id of the one it belongs to, and the client keeps a mask of one byte per submesh, zero for hidden and one for drawn. The shader fetches each vertex's byte and collapses the vertex outside the clip volume when it is zero.
Hiding any scattered set of submeshes is then one texture write. No geometry is rebuilt, no buffer repacked, and the cost does not depend on how the affected submeshes are scattered through the mesh.
Which id the mask is indexed by, and what the mask means, are the client's choices per pass. A normal pass binds the visibility mask. A selection-outline pass binds the selection mask to the same shader and draws only the selected submeshes into an outline target. An isolate mode binds a third. The feature culls; the renderer composes passes.
vcti-shader-mask is the shader half of that arrangement. It ships the Slang
that addresses the mask and applies its rule, a Python mirror of the same rule
so a caller can build a mask and read one back, the specs saying what the cull
needs bound, and the ShaderDefinition saying what the feature is.
Everything here is a declaration or fixed shader source. Nothing compiles or runs a shader; a build step does that, using what this package declares.
Installation
pip install vcti-shader-mask
Requires Python 3.12, 3.13, or 3.14, matching vcti-shader-base. Nothing native
is built on that path, and nothing native is built by [test] either — only the
[gl] extra pulls a GL binding, and only on 3.14 does that compile from source
for want of a cp314 wheel.
In requirements.txt
vcti-shader-mask>=1.0.0
In pyproject.toml dependencies
dependencies = [
"vcti-shader-mask>=1.0.0",
]
Quick Start
Build a mask
The client owns the mask, so building it is the first thing a caller does. One value per submesh, in id order:
from vcti.shader.mask import DRAWN, HIDDEN, pack_mask
visible = pack_mask([True, True, False, True])
assert visible == (DRAWN, DRAWN, HIDDEN, DRAWN) == (1, 1, 0, 1)
The shader's rule is an integer compared with zero, and the Python mirror is the same rule — any non-zero value draws, so a client that writes 255 is not wrong:
from vcti.shader.mask import is_drawn
assert not is_drawn(0)
assert is_drawn(1) and is_drawn(255)
A value a byte cannot hold is refused rather than truncated, because 256 would upload as 0 and hide a submesh the caller meant to draw:
from vcti.shader.mask import check_value
check_value(255)
try:
check_value(256)
except ValueError as error:
assert "outside 0-255" in str(error)
Upload it
The mask is an R8UI texture, one texel per submesh, with NEAREST
filtering. The id is the address; there is no stride. The texture is
two-dimensional, because a single row would cap the submesh count at whatever
MAX_TEXTURE_SIZE a device reports; wrapped across rows, the cap is that
number squared. A caller picks a width and the address wraps:
from vcti.shader.mask import rows_needed, texel
assert texel(14_000, 2048) == (1712, 6)
assert rows_needed(50_000, 2048) == 25
Both refuse a width that is not positive, and a negative id or count. The shader divides by the same width, so a bad value would otherwise surface on the GPU as a wrong texel with nothing to say so:
try:
texel(0, 0)
except ValueError as error:
assert "not positive" in str(error)
Pass the width as u_maskLutWidth. An unwritten or incomplete texture reads as
zero and hides everything, which is the loud failure this design chooses over a
quiet one.
What a build step binds
from vcti.shader.mask import vertex_attributes, vertex_uniforms
(attribute,) = vertex_attributes()
assert (attribute.name, attribute.type, attribute.semantic) == ("a_maskId", "int", "mask-id")
(uniform,) = vertex_uniforms()
assert uniform.name == "u_maskLutWidth"
The attribute is named for the feature, not for what the id counts. The client binds whichever id buffer it likes to it — a submesh id, a mesh-component id — and where another feature is keyed by the same id, binds the same buffer to that feature's attribute too.
The table sampler itself is not in there — a texture input cannot yet be
expressed in vcti-shader-base, so it is contract rather than spec. See
docs/design.md.
Select a pipeline
One tag for the behaviour and one naming the table encoding:
from vcti.shader.mask import DEFINITION
assert DEFINITION.id == "mask"
assert DEFINITION.role.value == "vertex"
assert set(DEFINITION.capabilities) == {"mask", "mask-lut-r8ui"}
assert DEFINITION.slang_modules == ("mask.slang", "mask_r8ui.slang")
The mask
| Value | Meaning |
|---|---|
| 0 | hidden — the vertex is collapsed outside the clip volume |
| 1 | drawn |
| anything else | drawn; the shader tests != 0 |
One byte per submesh — not a bit, not a word — and no stride. A second per-submesh state — a selection, an isolate set — is a second mask of the same shape bound in a different pass, never a second bit here.
API surface
| Name | What it is |
|---|---|
DEFINITION |
the ShaderDefinition a build step imports to compose this feature |
SLANG_DIR, SLANG_MODULES |
the installed Slang directory, and the modules in it |
pack_mask, mask_value, is_drawn, check_value |
build a mask, and read it the way the shader does |
HIDDEN, DRAWN, VALUE_MAX |
the values |
texel, rows_needed |
where a submesh's value lands, and how tall the texture is |
vertex_attributes, vertex_uniforms, ATTRIBUTE, WIDTH |
what a build step binds |
CAPABILITY, ENCODING, ENCODING_CAPABILITY |
the tags, and the shipped texture format |
Dependencies
vcti-shader-base is the only runtime dependency — declaring a feature is pure
data. vcti-shader-compiler>=4.0.0 and numpy are test-only, and a separate
gl extra adds the GL binding the shader tests need to execute rather than
skip.
Documentation
| If you want to… | Read |
|---|---|
| Get started using the package | Quick Start above |
| Understand the mask contract and the decisions behind it | docs/design.md |
| Navigate or modify the source, including the Slang | docs/source-guide.md |
The full API reference is generated from the source docstrings and published in the unified VCollab docs.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vcti_shader_mask-1.0.0.tar.gz.
File metadata
- Download URL: vcti_shader_mask-1.0.0.tar.gz
- Upload date:
- Size: 33.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2f156b079353757bfdbed0ad6401ec45470a60480e8d90b50c748bb6fb4895a6
|
|
| MD5 |
bac716999e8389ed68e3156a166797c3
|
|
| BLAKE2b-256 |
e1b23f1d1b09cf76fbde08142b2ed2d8056f23be84e8179bf4b50f07ffbb7c73
|
Provenance
The following attestation bundles were made for vcti_shader_mask-1.0.0.tar.gz:
Publisher:
release.yml on vcollab/vcti-python-shader-mask
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_shader_mask-1.0.0.tar.gz -
Subject digest:
2f156b079353757bfdbed0ad6401ec45470a60480e8d90b50c748bb6fb4895a6 - Sigstore transparency entry: 2851939831
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-shader-mask@2c0a07eea27b72aee99e6418f42932701cc907f0 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c0a07eea27b72aee99e6418f42932701cc907f0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file vcti_shader_mask-1.0.0-py3-none-any.whl.
File metadata
- Download URL: vcti_shader_mask-1.0.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f429034595b1c0cea35b3a86689bd41316af09218cdcba1ffc02eaf27495a698
|
|
| MD5 |
892583e56a587ae097b6302e6afab825
|
|
| BLAKE2b-256 |
c50e7945cf3e8b375d33fad8039105f1b8cba0da6979253dd3f736825749061b
|
Provenance
The following attestation bundles were made for vcti_shader_mask-1.0.0-py3-none-any.whl:
Publisher:
release.yml on vcollab/vcti-python-shader-mask
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
vcti_shader_mask-1.0.0-py3-none-any.whl -
Subject digest:
f429034595b1c0cea35b3a86689bd41316af09218cdcba1ffc02eaf27495a698 - Sigstore transparency entry: 2851939898
- Sigstore integration time:
-
Permalink:
vcollab/vcti-python-shader-mask@2c0a07eea27b72aee99e6418f42932701cc907f0 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/vcollab
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@2c0a07eea27b72aee99e6418f42932701cc907f0 -
Trigger Event:
push
-
Statement type: