Thanks for using Compiler Explorer
Impeller
CMake
impeller source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
impellerc
Options
Source code
// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. uniform samplerCube cube_map; uniform sampler2D blue_noise; uniform FragInfo { vec2 texture_size; float time; } frag_info; in vec2 v_screen_position; out vec4 frag_color; const float kPi = acos(-1.0); const float kHalfSqrtTwo = sqrt(2.0) / 2.0; const float kEpsilon = 0.001; // Materials (Albedo + reflectivity) const vec4 kBottomColor = vec4(0.0, 0.34, 0.61, 0.5); const vec4 kMiddleColor = vec4(0.16, 0.71, 0.96, 0.5); const vec4 kTopColor = vec4(0.33, 0.77, 0.97, 0.5); const vec4 kImpellerOuterColor = vec4(0.16, 0.71, 0.96, 0.5); const vec4 kImpellerRimColor = vec4(0.1, 0.1, 0.1, 0.0); const vec4 kImpellerBladeColor = vec4(0.1, 0.1, 0.1, 1.3); // Scene const int kMaxSteps = 70; const float kMaxDistance = 300.0; const vec3 kSunDirection = normalize(vec3(2, -5, 3)); const float kGlowBlend = 1.1; const vec4 kGlowColor = vec4(0.86, 0.98, 1.0, 1); const vec4 kGlowColor2 = vec4(1.66, 0.98, 0.5, 1); // These refraction ratios are inverted for style purposes. const float kAirToGlassIOR = 1.10; const float kGlassToAirIOR = 1.0 / kAirToGlassIOR; // Camera const float kFocalLength = 12.0; const float kApertureSize = 0.5; const int kRaysPerFrag = 4; mat3 RotateEuler(vec3 r) { return mat3( cos(r.x) * cos(r.y), cos(r.x) * sin(r.y) * sin(r.z) - sin(r.x) * cos(r.z), cos(r.x) * sin(r.y) * cos(r.z) + sin(r.x) * sin(r.z), sin(r.x) * cos(r.y), sin(r.x) * sin(r.y) * sin(r.z) + cos(r.x) * cos(r.z), sin(r.x) * sin(r.y) * cos(r.z) - cos(r.x) * sin(r.z), -sin(r.y), cos(r.y) * sin(r.z), cos(r.y) * cos(r.z)); } //------------------------------------------------------------------------------ /// Noise functions. /// vec2 Hash(float seed) { vec2 n = vec2(dot(vec2(seed, -0.1), vec2(13.8767971, 22.2091485)), dot(vec2(seed, -0.2), vec2(12.3432217, 48.0579381))); return fract(sin(n) * 24791.8159993); } vec4 BlueNoise(vec2 uv) { return texture(blue_noise, uv); } vec4 BlueNoiseWithRandomOffset(vec2 screen_position, float seed) { return BlueNoise(screen_position / 256.0 + Hash(seed)); } //------------------------------------------------------------------------------ /// Primitive distance functions. /// float SphereDistance(vec3 sample_position, vec3 sphere_position, float sphere_size) { return length(sample_position - sphere_position) - sphere_size; } float CuboidDistance(vec3 sample_position, vec3 cuboid_size) { vec3 space = abs(sample_position) - cuboid_size; return length(max(space, 0.0)) + min(max(space.x, max(space.y, space.z)), 0.0); } //------------------------------------------------------------------------------ /// Scene distance functions. /// float GlassBox(vec3 pos) { mat3 basis = RotateEuler(vec3(frag_info.time * 0.21, frag_info.time * 0.24, frag_info.time * 0.17)); vec3 glass_box_pos = pos + vec3(0, -4.5 + sin(frag_info.time), 0.0); return CuboidDistance(basis * glass_box_pos, vec3(1, 1, 1)) - 3.0; } vec2 FlutterLogoField(vec3 pos) { pos *= 1.3; // Scale down a bit. // The shape below is made up of three parallelepipeds, each of which is a // cuboid in scaled + skewed space. These shape fields are multiplied by the // inverse of the max basis vector length of the space (i.e. 1 / sqrt(2); the // same as kHalfSqrtTwo), which scales down the ray march step size by the // right amount to avoid overstepping errors. const float kFieldScale = kHalfSqrtTwo * 1.0 / 1.3; vec3 r = vec3(sin(frag_info.time * 1.137) / 7.0, // sin(frag_info.time * 1.398 + 0.7) / 8.0, // sin(frag_info.time * 0.873 + 0.3) / 5.0); // This homegrown rotation matrix isn't perfect, but it's fine for the < PI/2 // rotation being applied to the logo. mat3 logo_basis = mat3(cos(r.z) * cos(r.y), sin(r.z), -sin(r.y), // -sin(r.z), cos(r.z) * cos(r.x), -sin(r.x), // sin(r.y), sin(r.x), cos(r.x) * cos(r.y)); vec3 logo_pos = logo_basis * pos + vec3(-1.0, -4.0 + sin(frag_info.time), 0.0); // Bottom prism. float logo0 = CuboidDistance(logo_pos + vec3(-logo_pos.y, 0, 0), vec3(1, 2, 0.6)) * kFieldScale; float logo0_cutoff_plane = dot(logo_pos + vec3(0.5, 0.5, 0), normalize(vec3(1, 1, 0))); logo0 = max(logo0, logo0_cutoff_plane); float dist = logo0; float material = 1.0; // Middle prism. float logo1 = CuboidDistance(logo_pos + vec3(logo_pos.y, 0, 0), vec3(1, 2, 0.7)) * kFieldScale; float logo1_cutoff_plane = dot(logo_pos + vec3(-0.5, 0.5, 0), normalize(vec3(1, -1, 0))); logo1 = max(logo1, logo1_cutoff_plane); if (logo1 < dist) { dist = logo1; float material_cutoff_plane = dot(logo_pos + vec3(0.5, -0.5, 0), normalize(vec3(1, -1, 0))); material = material_cutoff_plane > 0.0 ? 2.0 : 3.0; } // Top prism. float logo2 = CuboidDistance(logo_pos + vec3(logo_pos.y - 3.0, -2, 0), vec3(1, 3.5, 0.7)) * kFieldScale; logo2 = max(logo2, logo1_cutoff_plane); if (logo2 < dist) { dist = logo2; material = 3.0; } return vec2(dist, material); } vec2 InnerGlassBoxField(vec3 pos) { vec2 flutter_logo = FlutterLogoField(pos); float dist = flutter_logo.x; float material = flutter_logo.y; // Inner glass box. float glass_box = -GlassBox(pos); if (glass_box < dist) { dist = glass_box; material = -3.0; // Transfer from glass to air. } return vec2(dist, material); } vec2 ImpellerField(vec3 pos) { float xz_dist = length(pos.xz); float impeller = min(0.5, xz_dist / 3.0) * sin(xz_dist * 2.0 - mod(frag_info.time, kPi) * 30.0 + atan(pos.z, pos.x) * 6.0) * 1.5; float impeller_side = xz_dist / 2.0 - 4.0; float stage_height = mix(impeller, impeller_side, clamp(xz_dist - 4.6, 0.0, 1.0)); float stage_plane = dot(pos + vec3(0, 3.0 + stage_height, 0), normalize(vec3(0, 1, 0))) * 0.5; float stage_sphere = SphereDistance(pos + vec3(0, 2, 0), vec3(0), 6.0); float stage = max(stage_plane, stage_sphere); float material = 4.0; if (xz_dist < 5.6 && pos.y > -7.0) { material = (pos.y > -2.36 && pos.y < -2.1) ? 5.0 : 6.0; } else { material = 4.0; } return vec2(stage, material); } vec2 SceneField(vec3 pos) { float glass_box = GlassBox(pos); float dist = glass_box; float material = -2.0; // Transfer from air to glass. vec2 impeller = ImpellerField(pos); if (impeller.x < dist) { dist = impeller.x; material = impeller.y; } return vec2(dist - 0.01, material); } /// For shadows, just ignore the glass box. vec2 ShadowField(vec3 pos) { vec2 flutter_logo = FlutterLogoField(pos); float dist = flutter_logo.x; float material = flutter_logo.y; vec2 impeller = ImpellerField(pos); if (impeller.x < dist) { dist = impeller.x; material = impeller.y; } return vec2(dist, material); } //------------------------------------------------------------------------------ /// Surface computation. /// vec2 March(vec3 sample_position, vec3 dir, out int steps_taken, bool inside_glass_box, bool shadow) { float depth = 0.0; for (int i = 0; i < kMaxSteps; i++) { if (depth > kMaxDistance) { steps_taken = i; return vec2(kMaxDistance, -1.0); } vec3 pos = sample_position + dir * depth; vec2 result; if (shadow) { result = ShadowField(pos); } else { result = inside_glass_box ? InnerGlassBoxField(pos) : SceneField(pos); } if (abs(result.x) < kEpsilon) { steps_taken = i; return vec2(depth, result.y); } depth += result.x; } steps_taken = kMaxSteps; return vec2(kMaxDistance, -1.0); } vec3 SceneGradient(vec3 sample_position) { return normalize( vec3(SceneField(sample_position + vec3(kEpsilon, 0, 0)).x - SceneField(sample_position + vec3(-kEpsilon, 0, 0)).x, SceneField(sample_position + vec3(0, kEpsilon, 0)).x - SceneField(sample_position + vec3(0, -kEpsilon, 0)).x, SceneField(sample_position + vec3(0, 0, kEpsilon)).x - SceneField(sample_position + vec3(0, 0, -kEpsilon)).x)); } vec3 InnerGlassGradient(vec3 sample_position) { return normalize( vec3(InnerGlassBoxField(sample_position + vec3(kEpsilon, 0, 0)).x - InnerGlassBoxField(sample_position + vec3(-kEpsilon, 0, 0)).x, InnerGlassBoxField(sample_position + vec3(0, kEpsilon, 0)).x - InnerGlassBoxField(sample_position + vec3(0, -kEpsilon, 0)).x, InnerGlassBoxField(sample_position + vec3(0, 0, kEpsilon)).x - InnerGlassBoxField(sample_position + vec3(0, 0, -kEpsilon)).x)); } float MarchShadow(vec3 position) { int shadow_steps; vec2 shadow_result = March(position + -kSunDirection * 0.03, -kSunDirection, shadow_steps, false, true); float shadow_percentage = (float(shadow_steps)) / float(kMaxSteps); float shadow_multiplier = 1.6 - shadow_percentage; if (shadow_result.x < kMaxDistance) { shadow_multiplier = 0.6; } return shadow_multiplier; } //------------------------------------------------------------------------------ /// Color composition. /// vec4 EnvironmentColor(vec3 ray_direction) { return texture(cube_map, ray_direction); } vec4 SurfaceColor(vec3 ray_direction, vec3 surface_position, vec3 surface_normal, float material, float shadow_multiplier) { vec3 reflection_direction = reflect(ray_direction, surface_normal); vec4 reflection_color = texture(cube_map, reflection_direction); vec4 material_value; if (material < 1.5) { material_value = kBottomColor; } else if (material < 2.5) { material_value = kMiddleColor; } else if (material < 3.5) { material_value = kTopColor; } else if (material < 4.5) { material_value = kImpellerOuterColor; } else if (material < 5.5) { material_value = kImpellerRimColor; } else { material_value = kImpellerBladeColor; } return mix(vec4(material_value.rgb * shadow_multiplier, 1.0), reflection_color, dot(-ray_direction, surface_normal) - 1.0 + material_value.a); } vec4 SceneColor(vec3 ray_position, vec3 ray_direction, vec3 surface_normal, float dist, float material, int steps_taken, float shadow_multiplier, vec4 ray_noise) { vec4 result_color; if (dist >= kMaxDistance) { result_color = EnvironmentColor(ray_direction); } else { vec3 surface_position = ray_position + ray_direction * dist; result_color = SurfaceColor(ray_direction, surface_position, surface_normal, material, shadow_multiplier); } float glow_factor = float(steps_taken) / float(kMaxSteps); vec4 glow_color = mix(kGlowColor, kGlowColor2, sin(frag_info.time / 3.0) * 0.5 + 0.5); return mix(result_color, glow_color, glow_factor * kGlowBlend); } vec4 CombinedColor(vec3 ray_position, vec3 ray_direction, vec4 ray_noise) { int steps_taken; vec2 result = March(ray_position, ray_direction, steps_taken, false, false); ray_position = ray_position + ray_direction * result.x; vec3 surface_normal = SceneGradient(ray_position); float glass_reflection_factor = 0.0; vec4 glass_reflection_color = vec4(0); if (result.y == -2.0) { // March into the glass. vec3 glass_reflection_direction = reflect(ray_direction, surface_normal); glass_reflection_color = EnvironmentColor(glass_reflection_direction); glass_reflection_factor = 0.5 - dot(glass_reflection_direction, surface_normal) * 0.6; ray_direction = refract(ray_direction, surface_normal, kAirToGlassIOR); ray_position += ray_direction * 0.5; int steps; result = March(ray_position, ray_direction, steps, true, false); steps_taken += steps; ray_position = ray_position + ray_direction * result.x; surface_normal = InnerGlassGradient(ray_position); } if (result.y == -3.0) { // March out of the glass. ray_direction = refract(ray_direction, surface_normal, kGlassToAirIOR); ray_position += ray_direction * 1.0; int steps; result = March(ray_position + ray_direction * result.x, ray_direction, steps, false, false); steps_taken += steps; ray_position = ray_position + ray_direction * result.x; surface_normal = SceneGradient(ray_position); } float shadow_multiplier = MarchShadow(ray_position); vec4 scene_color = SceneColor(ray_position, ray_direction, surface_normal, result.x, result.y, steps_taken, shadow_multiplier, ray_noise); return mix(scene_color, glass_reflection_color, glass_reflection_factor); } //------------------------------------------------------------------------------ /// Camera/lens. /// vec3 GetFragDirection(vec2 uv, vec3 cam_forward) { vec2 lens_uv = (uv - 0.5 * frag_info.texture_size) / frag_info.texture_size.xx; vec3 cam_right = cross(cam_forward, vec3(0, 1, 0)); vec3 cam_up = cross(cam_forward, cam_right); float fov = 65.0 * kPi / 180.0; return normalize(cam_forward * cos(fov) + cam_right * lens_uv.x * sin(fov) + cam_up * lens_uv.y * sin(fov)); } void main() { float cam_time = frag_info.time / 2.0; vec3 cam_position = vec3(-sin(cam_time + 0.2) * 6.25, -cos(cam_time + 0.3) * 2.9 + 1.0, -cos(cam_time - 0.1) * 5.4) * 2.0; vec3 cam_direction = normalize(-cam_position); cam_position += vec3(0, 2, 0); vec3 ray_direction = GetFragDirection(v_screen_position, cam_direction); vec3 lens_position = cam_position + ray_direction * kFocalLength; for (int i = 0; i < kRaysPerFrag; i++) { vec4 ray_noise = BlueNoiseWithRandomOffset( v_screen_position, float(i) + mod(frag_info.time, 10.0)); // The rays should be starting from a flat position on the lens, but just // jittering them around in a 3d box looks good enough. vec3 ray_start = cam_position + ray_noise.xyz * kApertureSize; vec3 ray_direction = normalize(lens_position - ray_start); vec4 result_color = CombinedColor(ray_start, ray_direction, ray_noise); frag_color += result_color / float(kRaysPerFrag); } }
Cheat-Sheet And Wiki
File A Compiler Bug
File An Explorer Bug
Learn How The Compiler Works
Browse Compiler Code
Metal Shading Language Specification
SPIRV Specification
SKSL (Android GSL) Quick Reference
OpenGL Shading Language Specification (4.60.7)
OpenGL ES Shading Language Specification (1.00)