Преглед на файлове

add normalized depth functions

Bigfoot71 преди 3 седмици
родител
ревизия
85254d030c
променени са 2 файла, в които са добавени 474 реда и са изтрити 0 реда
  1. 462 0
      docs/shaders/screen_shader.md
  2. 12 0
      shaders/post/screen.frag

+ 462 - 0
docs/shaders/screen_shader.md

@@ -0,0 +1,462 @@
+# Surface Shaders
+
+Surface shaders are custom shaders that can be applied to materials and decals in R3D. They provide a simplified way to write GLSL code by abstracting away the complexity of multiple render passes.
+
+## Table of Contents
+
+- [Overview](#overview)
+- [Entry Points](#entry-points)
+- [Built-in Variables](#built-in-variables)
+- [Varyings](#varyings)
+- [Uniforms](#uniforms)
+- [Material Sampling](#material-sampling)
+- [Usage Hints](#usage-hints)
+- [Best Practices](#best-practices)
+- [Quick Reference](#quick-reference)
+
+---
+
+## Overview
+
+A surface shader is a simplified shader interface that allows you to modify vertex and fragment behavior without worrying about the underlying render pipeline. R3D automatically handles multiple render passes (opaque, transparent, shadows, etc.) from a single shader definition.
+
+### Basic Example
+
+```glsl
+uniform float u_time;
+
+void fragment() {
+    ALBEDO *= 0.5 + 0.5 * sin(u_time);
+}
+```
+
+### Loading a Shader
+
+```c
+// From file
+R3D_SurfaceShader* shader = R3D_LoadSurfaceShader("my_shader.glsl");
+
+// From memory
+const char* code = "void fragment() { ALBEDO = vec3(1.0, 0.0, 0.0); }";
+R3D_SurfaceShader* shader = R3D_LoadSurfaceShaderFromMemory(code);
+
+// Don't forget to unload when done
+R3D_UnloadSurfaceShader(shader);
+```
+
+---
+
+## Entry Points
+
+Surface shaders have two optional entry points: `vertex()` and `fragment()`. At least one must be defined.
+
+### Vertex Stage
+
+Runs once per vertex, before rasterization. Use it to modify vertex positions, colors, or pass data to the fragment stage.
+
+```glsl
+void vertex() {
+    POSITION.y += sin(POSITION.x * 10.0) * 0.1;
+}
+```
+
+### Fragment Stage
+
+Runs once per pixel. Use it to modify final surface properties like albedo, roughness, or emission.
+
+```glsl
+void fragment() {
+    ALBEDO = vec3(1.0, 0.0, 0.0); // Red surface
+    ROUGHNESS = 0.5;
+}
+```
+
+### Both Stages
+
+You can define both stages to create complex effects:
+
+```glsl
+varying float v_height;
+
+void vertex() {
+    v_height = POSITION.y;
+}
+
+void fragment() {
+    ALBEDO = mix(vec3(0.0, 0.5, 0.0), vec3(1.0, 1.0, 1.0), v_height);
+}
+```
+
+---
+
+## Built-in Variables
+
+Built-in variables are pre-defined values you can read and modify in your shader. They can only be accessed within their corresponding entry point.
+
+### Vertex Stage
+
+All vertex-stage variables are initialized with local (pre-transformation) attribute values:
+
+| Variable | Type | Description |
+|----------|------|-------------|
+| `POSITION` | `vec3` | Vertex position |
+| `TEXCOORD` | `vec2` | Texture coordinates |
+| `NORMAL` | `vec3` | Vertex normal |
+| `TANGENT` | `vec4` | Vertex tangent (w = handedness) |
+| `COLOR` | `vec4` | Vertex color |
+| `EMISSION` | `vec3` | Vertex emission |
+
+**Example:**
+```glsl
+void vertex() {
+    POSITION *= 1.5; // Scale vertex position
+    COLOR.rgb *= 0.5; // Darken vertex color
+}
+```
+
+### Fragment Stage
+
+Fragment-stage variables are pre-initialized with material values (unless `R3D_NO_AUTO_FETCH` is defined):
+
+| Variable | Type | Description |
+|----------|------|-------------|
+| `TEXCOORD` | `vec2` | Interpolated texture coordinates |
+| `NORMAL` | `vec3` | Surface normal (world space) |
+| `TANGENT` | `vec3` | Surface tangent |
+| `BITANGENT` | `vec3` | Surface bitangent |
+| `ALBEDO` | `vec3` | Base color |
+| `ALPHA` | `float` | Transparency |
+| `EMISSION` | `vec3` | Emissive color |
+| `NORMAL_MAP` | `vec3` | Normal map value |
+| `OCCLUSION` | `float` | Ambient occlusion |
+| `ROUGHNESS` | `float` | Surface roughness (0 = smooth, 1 = rough) |
+| `METALNESS` | `float` | Metallic property (0 = dielectric, 1 = metal) |
+
+**Example:**
+```glsl
+void fragment() {
+    ALBEDO = vec3(1.0, 0.0, 0.0); // Red surface
+    ROUGHNESS = 0.2; // Shiny
+    METALNESS = 1.0; // Metallic
+}
+```
+
+### Important Notes
+
+- Built-in variables are **scoped to their entry point**. You cannot access `ALBEDO` in `vertex()` or `POSITION` in `fragment()`.
+- If you need to pass data between stages, use [varyings](#varyings).
+- To use built-in variables in helper functions, pass them as parameters:
+
+```glsl
+vec3 darken(vec3 color, float amount) {
+    return color * amount;
+}
+
+void fragment() {
+    ALBEDO = darken(ALBEDO, 0.5);
+}
+```
+
+---
+
+## Varyings
+
+Varyings allow you to pass data from the vertex stage to the fragment stage. They are automatically interpolated across the triangle.
+
+### Basic Usage
+
+```glsl
+varying float v_height;
+
+void vertex() {
+    v_height = POSITION.y;
+}
+
+void fragment() {
+    ALBEDO = mix(vec3(0.2, 0.8, 0.2), vec3(1.0), v_height);
+}
+```
+
+### Interpolation Qualifiers
+
+You can control how varyings are interpolated using qualifiers:
+
+| Qualifier | Description |
+|-----------|-------------|
+| `flat` | No interpolation (use value from provoking vertex) |
+| `smooth` | Perspective-correct interpolation (default) |
+| `noperspective` | Linear interpolation in screen space |
+
+**Example:**
+```glsl
+flat varying int v_material_id;
+noperspective varying vec2 v_screen_uv;
+
+void vertex() {
+    v_material_id = 1;
+    v_screen_uv = TEXCOORD;
+}
+
+void fragment() {
+    if (v_material_id == 1) {
+        ALBEDO = texture(u_texture, v_screen_uv).rgb;
+    }
+}
+```
+
+### Limits
+
+- **Maximum varyings:** 32 (hardware permitting)
+- In practice, you'll rarely need more than a handful
+
+---
+
+## Uniforms
+
+Uniforms are constant values that can be set from your C code. They remain constant across all vertices/fragments in a draw call.
+
+### Supported Types
+
+**Values:**
+- Scalars: `bool`, `int`, `float`
+- Vectors: `vec2`, `vec3`, `vec4`
+- Matrices: `mat2`, `mat3`, `mat4`
+
+**Samplers:**
+- `sampler1D`, `sampler2D`, `sampler3D`, `samplerCube`
+
+### Declaring Uniforms
+
+```glsl
+uniform float u_time;
+uniform vec3 u_color;
+uniform mat4 u_transform;
+uniform sampler2D u_texture;
+```
+
+### Setting Uniforms from C
+
+**Values:**
+```c
+float time = GetTime();
+R3D_SetSurfaceShaderUniform(shader, "u_time", &time);
+
+Vector3 color = {1.0f, 0.0f, 0.0f};
+R3D_SetSurfaceShaderUniform(shader, "u_color", &color);
+```
+
+**Samplers:**
+```c
+Texture2D texture = LoadTexture("texture.png");
+R3D_SetSurfaceShaderSampler(shader, "u_texture", texture);
+```
+
+### Important Notes
+
+- **Default values:** All uniforms default to zero (samplers have no default texture)
+- **Persistence:** Uniform values persist across frames until changed
+- **Per-shader state:** Each shader maintains its own uniform state
+- **Update timing:** Uniforms are uploaded to GPU only when needed (marked dirty)
+- **No per-draw updates:** You cannot change uniforms between draw calls within a single frame. Since rendering happens at `R3D_End()`, only the last uniform value set before `R3D_End()` will be used.
+
+### Example
+
+```glsl
+uniform float u_time;
+uniform sampler2D u_noise;
+
+void fragment() {
+    vec2 uv = TEXCOORD + texture(u_noise, TEXCOORD * 2.0).xy * 0.1;
+    ALBEDO *= 0.5 + 0.5 * sin(u_time + uv.x * 10.0);
+}
+```
+
+```c
+float time = 0.0f;
+Texture2D noise = LoadTexture("noise.png");
+
+R3D_SetSurfaceShaderSampler(shader, "u_noise", noise);
+
+while (!WindowShouldClose()) {
+    time += GetFrameTime();
+    R3D_SetSurfaceShaderUniform(shader, "u_time", &time);
+    
+    R3D_Begin();
+    // ... draw with shader ...
+    R3D_End();
+}
+```
+
+---
+
+## Material Sampling
+
+By default, material textures (albedo, normal, ORM) are automatically sampled and available as built-in variables in the fragment stage.
+
+### Disabling Auto-Fetch
+
+If you want to start with zero values and sample materials manually, define:
+
+```glsl
+#define R3D_NO_AUTO_FETCH
+```
+
+This sets `ALBEDO`, `NORMAL_MAP`, and `OCCLUSION`/`ROUGHNESS`/`METALNESS` to zero.
+
+### Manual Sampling Functions
+
+```glsl
+vec4 SampleAlbedo(vec2 texCoord);
+vec3 SampleEmission(vec2 texCoord);
+vec3 SampleNormal(vec2 texCoord);
+vec3 SampleOrm(vec2 texCoord); // (Occlusion, Roughness, Metalness)
+```
+
+### Quick Auto-Fill
+
+To automatically fill all built-in variables with material values:
+
+```glsl
+void FetchMaterial(vec2 texCoord);
+```
+
+### Example
+
+```glsl
+#define R3D_NO_AUTO_FETCH
+
+void fragment() {
+    // Sample material at distorted UV
+    vec2 distorted_uv = TEXCOORD + vec2(sin(TEXCOORD.y * 10.0) * 0.1, 0.0);
+    FetchMaterial(distorted_uv);
+    
+    // Or sample individual textures
+    // ALBEDO = SampleAlbedo(distorted_uv).rgb;
+    // vec3 orm = SampleOrm(distorted_uv);
+    // ROUGHNESS = orm.g;
+}
+```
+
+---
+
+## Usage Hints
+
+R3D compiles multiple shader variants for different render passes (opaque, transparent, shadows, etc.). By default, only the opaque variant is pre-compiled; others compile on-demand when needed.
+
+### The Problem
+
+On-demand compilation can cause stuttering when a new variant is first used. For example, if your shader is used on a transparent object, the transparent variant compiles when the object first becomes visible.
+
+### The Solution
+
+Use `#pragma usage` to specify which variants should be pre-compiled:
+
+```glsl
+#pragma usage transparent shadow
+```
+
+### Available Usage Hints
+
+| Hint | Description |
+|------|-------------|
+| `opaque` | Opaque rendering (default if no pragma specified) |
+| `prepass` | Transparent pre-pass rendering |
+| `transparent` | Transparent rendering (alpha blending) |
+| `shadow` | Shadow map rendering |
+| `decal` | Decal rendering |
+| `probe` | Reflection probe rendering |
+
+### Examples
+
+**Opaque object with shadows:**
+```glsl
+#pragma usage opaque shadow
+
+void fragment() {
+    ALBEDO = vec3(1.0, 0.0, 0.0);
+}
+```
+
+**Transparent object:**
+```glsl
+#pragma usage transparent
+
+void fragment() {
+    ALBEDO = vec3(0.0, 0.5, 1.0);
+    ALPHA = 0.5;
+}
+```
+
+**Decal shader:**
+```glsl
+#pragma usage decal
+
+void fragment() {
+    ALBEDO = vec3(1.0, 1.0, 0.0);
+}
+```
+
+### Important Notes
+
+- Usage hints are **optional**; missing variants will still compile on-demand
+- Multiple hints can be specified: `#pragma usage opaque transparent shadow`
+- If no pragma is specified, only `opaque` is pre-compiled
+- Variants not in the pragma can still be used; they just compile lazily
+
+---
+
+## Best Practices
+
+### Performance
+
+1. **Minimize varyings:** Only pass what's needed
+2. **Leverage vertex math:** Compute values per-vertex when they can be interpolated
+3. **Avoid dynamic loops & heavy branches:** Keep loops bounded and branches predictable/simple
+4. **Reuse calculations:** Don't repeat work in shader
+
+### Debugging
+
+1. **Test incrementally:** Start simple, add complexity gradually
+2. **Use constants first:** Replace textures or calculations with constants to confirm logic
+3. **Isolate effects:** Disable parts of the shader to identify issues
+4. **Use emissive for debugging:** `EMISSION = vec3(some_value)` to visualize values
+
+### Organization
+
+1. **One shader per effect:** Don't create mega-shaders with branches for different effects
+2. **Use meaningful names:** You can prefix uniforms with `u_`, varyings with `v_`
+3. **Use usage hints:** Pre-compile variants you know you'll need
+
+---
+
+## Quick Reference
+
+### Loading/Unloading
+```c
+R3D_SurfaceShader* R3D_LoadSurfaceShader(const char* filePath);
+R3D_SurfaceShader* R3D_LoadSurfaceShaderFromMemory(const char* code);
+void R3D_UnloadSurfaceShader(R3D_SurfaceShader* shader);
+```
+
+### Setting Uniforms
+```c
+void R3D_SetSurfaceShaderUniform(R3D_SurfaceShader* shader, const char* name, const void* value);
+void R3D_SetSurfaceShaderSampler(R3D_SurfaceShader* shader, const char* name, Texture texture);
+```
+
+### Shader Structure
+```glsl
+#pragma usage <hints>           // Optional: opaque, transparent, shadow, etc.
+#define R3D_NO_AUTO_FETCH       // Optional: disable automatic material sampling
+
+uniform <type> <name>;          // Uniforms
+varying <type> <name>;          // Varyings (communication between stages)
+
+void vertex() {                 // Optional: vertex stage
+    // Modify POSITION, NORMAL, etc.
+}
+
+void fragment() {               // Optional: fragment stage
+    // Modify ALBEDO, ROUGHNESS, etc.
+}
+```

+ 12 - 0
shaders/post/screen.frag

@@ -62,6 +62,18 @@ float SampleDepth(vec2 texCoord)
     return texture(uDepthTex, texCoord).r;
 }
 
+float FetchDepth01(ivec2 pixCoord)
+{
+    float z = texelFetch(uDepthTex, pixCoord, 0).r;
+    return clamp((z - uView.near) / (uView.far - uView.near), 0.0, 1.0);
+}
+
+float SampleDepth01(vec2 texCoord)
+{
+    float z = texture(uDepthTex, texCoord).r;
+    return clamp((z - uView.near) / (uView.far - uView.near), 0.0, 1.0);
+}
+
 vec3 FetchPosition(ivec2 pixCoord)
 {
     return V_GetViewPosition(uDepthTex, pixCoord);