pub struct Shader {
pub asset_id: AssetId,
pub vertex: StageSource,
pub fragment: StageSource,
pub vertex_instanced: Option<StageSource>,
pub locator: Option<PayloadLocator>,
}Expand description
Declares a custom shader program: the vertex and fragment stages, plus the optional GPU-instanced vertex stage.
A Shader is entirely optional. The engine ships its own main-pass
program and uses it for every draw a Shader does not claim, so a world that
wants standard lighting declares no Shader at all. Declare one only to
replace that program with your own. The shadow pass is engine-internal (no
Shader stage of its own); enable or size it with shadow_map_size in
GraphicsConfig.
The engine-internal shadow map covers a ±20 m world-space region centred at
the origin with 80 m depth. For larger scenes, increase shadow_map_size in
GraphicsConfig to maintain resolution.
A stage that resolves no source for the running backend falls back to the engine’s own program for that stage, so a Shader may cover only the platforms it has sources for.
§More than one Shader
The first declared Shader is the world’s default: everything renders with it
unless a Material names another one through its shader field.
A world may declare up to 8 Shaders in total.
Three rules come with the second Shader, all enforced at build time:
- Every fragment stage must define
fragment_main_bindless. Multi-Shader worlds render through the GPU-driven bindless path, which is the only path that can switch programs per draw. A single-Shader world has no such requirement and may define justfragment_main. This applies to.metalsources, which carry one program per entry point; an.hlslor GLSL stage compiles a singlemain, so there is no entry point to pick – what it must match instead is the bindless binding layout (see below). - Instanced, skinned, and voxel-chunk draws always use the world default. A Material naming a Shader cannot be used by an InstancedProp, a SkinnedMesh, or a VoxelWorld; give those a Material without one.
- At most 8 Shaders, the world default included.
Planar reflections are the one case with no build-time signal: a surface reflected in a mirror is drawn with the world default Shader regardless of its Material. Reflection probe cubes capture it the same way.
A non-default Shader’s stages must be written against the engine’s bindless binding layout, not the per-draw one: the material, transform, and texture indices come from the per-frame object buffer rather than per-draw constants.
A Shader referenced only by materials belonging to one Scene is owned by that scene: its pipeline is built when the scene loads (behind the loading screen, alongside that scene’s textures and meshes) and released when the scene unloads. A Shader used across scenes, or by the world default, loads at startup.
Custom shader vertex layout: the engine always supplies vertices with 5
attributes at a fixed 56-byte stride. Any custom .metal shader must declare
struct Vertex exactly as shown below: wrong attribute indices cause tangent
data to be read as vertex colour, producing red/green/blue geometry:
struct Vertex {
float3 pos [[attribute(0)]]; // offset 0
float3 normal [[attribute(1)]]; // offset 12
float3 tangent [[attribute(2)]]; // offset 24
float3 color [[attribute(3)]]; // offset 36
float2 uv [[attribute(4)]]; // offset 48
};Buffer and texture bindings that must match:
struct DirectionalLightData {
packed_float3 direction;
float intensity;
packed_float3 color;
float _pad;
};
struct PointLightData {
packed_float3 position;
float range;
packed_float3 color;
float intensity;
};
struct ShadowUniforms {
float4x4 light_vp;
};Fields§
§asset_id: AssetIdAsset identity; injected via inject_name. Not part of args.
vertex: StageSourceThe vertex stage. Required.
fragment: StageSourceThe fragment stage. Required.
vertex_instanced: Option<StageSource>The GPU-instanced vertex stage. Required only for worlds with InstancedProp components.
locator: Option<PayloadLocator>Injected at load time from BlobAssetDef::payload.
Implementations§
Source§impl Shader
impl Shader
Sourcepub fn stage(&self, kind: ShaderKind) -> Option<&StageSource>
pub fn stage(&self, kind: ShaderKind) -> Option<&StageSource>
The declared source for kind, if that stage is present.
Trait Implementations§
Source§impl Component for Shader
impl Component for Shader
Source§fn from_baked(bytes: &[u8]) -> Result<Shader, CnResult>
fn from_baked(bytes: &[u8]) -> Result<Shader, CnResult>
Source§fn inject_locator(&mut self, locator: PayloadLocator)
fn inject_locator(&mut self, locator: PayloadLocator)
Source§fn inject_name(&mut self, id: AssetId)
fn inject_name(&mut self, id: AssetId)
Source§impl ComponentSlot for Shader
impl ComponentSlot for Shader
Source§const DISCRIMINANT: u8
const DISCRIMINANT: u8
ComponentId.Source§impl<'de> Deserialize<'de> for Shader
impl<'de> Deserialize<'de> for Shader
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<Shader, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<Shader, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
Source§impl From<Shader> for ComponentAsset
impl From<Shader> for ComponentAsset
Source§fn from(c: Shader) -> ComponentAsset
fn from(c: Shader) -> ComponentAsset
impl RuntimeComponent for Shader
Source§impl Serialize for Shader
impl Serialize for Shader
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
Auto Trait Implementations§
impl Freeze for Shader
impl RefUnwindSafe for Shader
impl Send for Shader
impl Sync for Shader
impl Unpin for Shader
impl UnsafeUnpin for Shader
impl UnwindSafe for Shader
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().