# Detailed Shading Techniques ## Colors and Gradients Before diving deep into color handling in shaders, let's first establish a fundamental understanding of how colors work in computer graphics. ### Basic Color Representation In Makepad shaders, we use `vec4` (RGBA vector) to represent colors: - Red: `0.0` to `1.0` - Green: `0.0` to `1.0` - Blue: `0.0` to `1.0` - Alpha (transparency): `0.0` (completely transparent) to `1.0` (completely opaque) ```rust // Basic solid color shader fn pixel(self) -> vec4 { // Format: vec4(red, green, blue, alpha) return vec4(1.0, 0.0, 0.0, 1.0); // Pure red } ``` ### Linear Gradients Linear gradients create smooth transitions between two colors. Here's an implementation of a horizontal gradient: ```rust fn pixel(self) -> vec4 { // self.pos.x provides horizontal position from 0.0 to 1.0 let mix_factor = self.pos.x; let color1 = vec4(1.0, 0.0, 0.0, 1.0); // Red let color2 = vec4(0.0, 0.0, 1.0, 1.0); // Blue // Linear interpolation between two colors return mix(color1, color2, mix_factor); } ``` Visual representation: ```plaintext Red [================>] Blue <- mix factor -> ``` For diagonal gradients, we can implement it like this: ```rust fn pixel(self) -> vec4 { // Combine x and y coordinates for diagonal direction let mix_factor = (self.pos.x + self.pos.y) * 0.5; let color1 = vec4(1.0, 0.0, 0.0, 1.0); // Red let color2 = vec4(0.0, 0.0, 1.0, 1.0); // Blue return mix(color1, color2, mix_factor); } ``` ### Radial Gradients Radial gradients create color transitions that spread outward from a center point: ```rust fn pixel(self) -> vec4 { // Calculate distance from center point let center = vec2(0.5, 0.5); let dist = length(self.pos - center); // Convert distance to mix factor let mix_factor = clamp(dist * 2.0, 0.0, 1.0); let inner_color = vec4(1.0, 1.0, 1.0, 1.0); // White at center let outer_color = vec4(0.0, 0.0, 0.0, 1.0); // Black at edge return mix(inner_color, outer_color, mix_factor); } ``` ## Texture Mapping Texture mapping is the technique of applying 2D images to geometric surfaces. ### Basic Texture Sampling ```rust DrawTexture = {{DrawTexture}} { texture tex: texture2d // Declare texture uniform fn pixel(self) -> vec4 { // Sample texture at current position return sample2d(self.tex, self.pos); } } ``` ### UV Coordinate System UV coordinates are used to map texture pixels to geometry: ```plaintext (0,0) +-----------+ (1,0) | | | Texture | | | (0,1) +-----------+ (1,1) ``` ```rust fn vertex(self) -> vec4 { // Transform UV coordinates self.uv = self.geom_pos * self.tex_scale + self.tex_offset; // Regular vertex transformation let clip_pos = self.geom_pos * self.rect_size + self.rect_pos; return self.camera_projection * vec4(clip_pos, 0.0, 1.0); } fn pixel(self) -> vec4 { // Use transformed UV for sampling return sample2d(self.tex, self.uv); } ``` ## Special Effects ### Gaussian Blur Here's an implementation of a simple Gaussian blur: ```rust fn blur(self) -> vec4 { let blur_radius = 2.0; // Blur radius let mut color = vec4(0.0); let mut total_weight = 0.0; // Sample in a 5x5 grid around current pixel for i in -2..3 { for j in -2..3 { let offset = vec2(float(i), float(j)) * blur_radius; // Calculate Gaussian weight let weight = exp(-(offset.x * offset.x + offset.y * offset.y)); color += sample2d(self.tex, self.pos + offset) * weight; total_weight += weight; } } return color / total_weight; // Normalize result } ``` ### Glow Effect ```rust fn glow(self) -> vec4 { let base_color = sample2d(self.tex, self.pos); // Original color let blur_color = self.blur(); // Blurred color // Overlay blurred version to create glow effect return base_color + blur_color * self.glow_strength; } ``` ### Shadow Effect ```rust // Using Makepad's built-in GaussShadow to implement shadow effect fn draw_shadow(self) -> vec4 { let shadow_color = vec4(0.0, 0.0, 0.0, 0.5); let shadow_offset = vec2(5.0, 5.0); // Calculate shadow area let shadow = GaussShadow::box_shadow( self.rect_pos + shadow_offset, self.rect_size, self.pos, 10.0 // Shadow blur radius ); return shadow_color * shadow; } ```