LEARN BY MAKING

Using Shaders

Guide to loading and applying fragment shaders in Kraken.

Kraken shaders are loaded with kn.shaders.Shader. A shader object owns the compiled fragment shader plus the render state needed to use it for later draw calls.

import pykraken as kn

invert_shader = kn.shaders.Shader(
    "assets/shaders/invert.frag",
    uniform_buffer_count=0,
    sampler_count=1,
)
kn::shaders::Shader invertShader("assets/shaders/invert.frag", 0, 1);

Pass the shader base path to Shader, not a source file path. For example, if your baked outputs include assets/shaders/invert.frag.spv, pass "assets/shaders/invert.frag". Kraken picks the platform file it needs at runtime.

Bake HLSL Shaders

The recommended workflow is:

  1. Write the fragment shader in HLSL.
  2. Bake it with kraken bake.
  3. Load the baked shader by base path with Shader.
  4. Bind any texture samplers and uniforms before drawing with it.
kraken bake shaders/invert.frag.hlsl -o assets/shaders

The CLI accepts one input file and an optional output directory:

kraken bake [-h] [-o OUT] [-v] input

A One-Texture Fragment Shader

This shader inverts the color of the texture being drawn. It uses one texture sampler and no uniforms.

Texture2D spriteTex : register(t0, space2);
SamplerState spriteSamp : register(s0, space2);

struct PSInput {
    float4 v_color : COLOR0;
    float2 v_uv    : TEXCOORD0;
};

struct PSOutput {
    float4 o_color : SV_Target;
};

PSOutput main(PSInput input) {
    float4 color = spriteTex.Sample(spriteSamp, input.v_uv) * input.v_color;
    color.rgb = 1.0 - color.rgb;

    PSOutput output;
    output.o_color = color;
    return output;
}
#version 450

layout(set = 2, binding = 0) uniform sampler2D spriteTex;

layout(location = 0) in vec4 v_color;
layout(location = 1) in vec2 v_uv;

layout(location = 0) out vec4 o_color;

void main() {
    vec4 color = texture(spriteTex, v_uv) * v_color;
    color.rgb = 1.0 - color.rgb;
    o_color = color;
}

Load it with one sampler slot:

invert_shader = kn.shaders.Shader(
    "assets/shaders/invert.frag",
    uniform_buffer_count=0,
    sampler_count=1,
)
kn::shaders::Shader invertShader("assets/shaders/invert.frag", 0, 1);

Since the only texture and sampler we have are in binding 0, we do not need to explicitly set it in code or make the texture shader-sampled. The texture passed to kn.renderer.draw is already available to the shader as t0/s0.

sprite_texture = kn.Texture("assets/player.png")
kn::Texture spriteTexture("assets/player.png");

For extra textures beyond t0/s0, use set_texture_sampler. That more advanced workflow is covered in Texture Samplers.

Drawing With a Shader

bind() makes the shader active for later draw calls. unbind() returns rendering to the default shader state.

invert_shader.bind()
kn.renderer.draw(sprite_texture)
invert_shader.unbind()

kn.renderer.draw(sprite_texture)  # Draws normally again.
invertShader.bind();
kn::renderer::draw(spriteTexture);
invertShader.unbind();
kn::renderer::draw(spriteTexture); // Draws normally again.

Bind the shader as tightly as possible around the draw calls that need it. That keeps later rendering from accidentally inheriting the effect.

KEEP EXPLORING Uniforms

Find your next step

Start typing to search the manual.