-
Notifications
You must be signed in to change notification settings - Fork 5
How to adapt your Shaderpack
This section will not cover adding photonics settings to your shaderpack, and expects you have read the documentation. To understand what options Photonics gives you access to see properties.
There are two ways to add Photonics to your shaderpack
- Use the provided photonics pass (in deferred) that accepts gbuffer data and populates a lighting buffer; this is the easy route where photonics does everything for you
- Use the tracing API directly, works in gbuffers, you are responsible for usage and optimization.
This section will only cover option 1.
To add raytraced lighting to your shaderpack you need to create 2 files:
Create a file under /shaders/photonics/ called shader_interface.glsl
This is the main file Photonics uses to obtain information from your shader for the sake of its lighting pass.
You need to implement the following functions:
vec3 load_world_position();Should return the world position for the current fragment.
void load_fragment_variables(
out vec3 albedo,
out vec3 world_pos,
out vec3 geometry_normal,
out vec3 texture_normal
);This function is responsible for loading information about the current fragment into its arguments.
out vec3 albedo;This argument is pretty simple, it's just the albedo for the current fragment.
out vec3 geometry_normal;The geometry normal for the current fragment in world space.
out vec3 texture_normal;The texture normal of the current fragment in world space.
out vec3 world_pos;This argument is the world position for the current fragment, you first however need to nudge the position outside the block.
To do this you can subtract 0.01f * world_normal from the result of load_world_position()
vec3 sun_direction;The direction of the sun/moon in world space.
vec3 indirect_light_color;The indirect light color used by GI for the sun/sky, should be your sky color.
vec2 get_taa_jitter();Should return the taa jitter for the current fragment in NDC space.
bool is_in_world();Should return true if the current fragment is in the world.
In most cases this can default to:
bool is_in_world() {
return texelFetch(depthtex0, ivec2(gl_FragCoord.xy), 0).x <= 0.99999f;
}Create a file under /shaders/photonics/ called write_indirect.glsl
Photonics uses this file during its lighting pass in a fragment shader.
You need to implement the following functions:
void write_indirect(vec3 color);This function writes the GI contribution for a fragment, and is unused if photonics.restirCombinedGi is set to true
Photonics doesn't store GI in an accessible way for you, you instead must store and sample it yourself.
To sample light contributions see ph_samplers.glsl.
Photonics supports a special kind of rendering (referred to here as voxelized blocks) for blocks that utilizes its Volume Rendering techniques that are used for all other graphical effects in Photonics. Under the hood, voxelized blocks have the same mesh as a normal solid block (e.g. Stone Block). The only difference, is that they use 2 custom programs: gbuffers_voxels and shadow_voxels.
Voxelized blocks do not support any PBR features or transparency.
Responsible for rendering voxelized blocks for terrain.
A mock implementation for gbuffers_voxels.fsh for sampling albedo & normals.
This implementation requires block_normal from the vertex shader, which is equal to gl_Normal
// Placeholder for obtaining the screen pos
vec3 screen_pos = get_screen_pos();
// These functions are placeholders for however you do these conversions
vec3 view_pos = screen_to_view_space(screen_pos); // You should not account for TAA jitter
vec3 player_pos = view_to_player_space(view_pos);
vec3 rt_pos = player_pos + rt_camera_position;
RayJob ray = RayJob(
// The offset along the normal is very important to ensure that the ray doesn't start outside the block
rt_pos - 0.001f * block_normal, // Ray origin
// View direction of the current pixel is calculated by subtracting the camera position from the player position
normalize(player_pos - gbufferModelViewInverse[3].xyz), // Ray direction
// Initialize results to default
vec3(0), vec3(0), vec3(0), false
);
// stop raytracing once the ray leaves the block
ray_constraint = ivec3(ray.origin);
trace_ray(ray);
// Ray didn't hit any part of the 3d block (e.g. corners of the Crafting Table)
if (!ray.result_hit) discard;
if (ray.result_normal == vec3(0.0)) ray.result_normal = block_normal;
player_pos = ray.result_position - rt_camera_position;
// These functions are placeholders for however you do these conversions
view_pos = player_to_view_space(player_pos);
screen_pos = view_to_screen_space(view_pos);
// Also update the depth!
gl_FragDepth = screen_pos.z;
vec3 world_normal = ray.result_normal; // The normal in world space
vec4 albedo = vec4(ray.result_color, 1f);Responsible for rendering voxelized blocks in shadows.
A mock implementation for shadow_voxels.fsh for detecting hits.
This implementation requires:
-
block_normalfrom the vertex shader, which is equal togl_Normal -
player_posfrom the vertex shader, which is the position of the vertex in player space.
RayJob ray = RayJob(
// The offset along the normal is very important to ensure that the ray doesn't start outside the block
player_pos + rt_camera_position - 0.01f * block_normal, // Ray origin
mat3(shadowModelViewInverse) * vec3(0f, 0f, -1f), // Ray direction
// Initialize results to default
vec3(0f), vec3(0f), vec3(0f), false
);
ray_constraint = ivec3(ray.origin);
trace_ray(ray);
// Ray didn't hit any part of the 3d block (e.g. corners of the Crafting Table)
if (!ray.result_hit) discard;
// In shadow!
// If you need the color you can use this, but it will always be opaque.
vec4 voxel_color = vec4(ray.result_color, 1f);- Home
- Documentation
- How to adapt your Shaderpack