From 546dad07256849ed20439da123310654955604d6 Mon Sep 17 00:00:00 2001 From: Mark McIlroy Date: Sat, 16 Dec 2023 20:31:58 +0000 Subject: [PATCH 1/2] basic lighting example --- examples/lighting.fs | 76 ++++++++++++ examples/lighting.vs | 32 +++++ examples/shaders_basic_lighting.rs | 188 +++++++++++++++++++++++++++++ 3 files changed, 296 insertions(+) create mode 100644 examples/lighting.fs create mode 100644 examples/lighting.vs create mode 100644 examples/shaders_basic_lighting.rs diff --git a/examples/lighting.fs b/examples/lighting.fs new file mode 100644 index 0000000..fc1fdaa --- /dev/null +++ b/examples/lighting.fs @@ -0,0 +1,76 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec3 fragPosition; +in vec2 fragTexCoord; +//in vec4 fragColor; +in vec3 fragNormal; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// NOTE: Add here your custom variables + +#define MAX_LIGHTS 4 +#define LIGHT_DIRECTIONAL 0 +#define LIGHT_POINT 1 + +struct Light { + int enabled; + int type; + vec3 position; + vec3 target; + vec4 color; +}; + +// Input lighting values +uniform Light lights[MAX_LIGHTS]; +uniform vec4 ambient; +uniform vec3 viewPos; + +void main() +{ + // Texel color fetching from texture sampler + vec4 texelColor = texture(texture0, fragTexCoord); + vec3 lightDot = vec3(0.0); + vec3 normal = normalize(fragNormal); + vec3 viewD = normalize(viewPos - fragPosition); + vec3 specular = vec3(0.0); + + // NOTE: Implement here your fragment shader code + + for (int i = 0; i < MAX_LIGHTS; i++) + { + if (lights[i].enabled == 1) + { + vec3 light = vec3(0.0); + + if (lights[i].type == LIGHT_DIRECTIONAL) + { + light = -normalize(lights[i].target - lights[i].position); + } + + if (lights[i].type == LIGHT_POINT) + { + light = normalize(lights[i].position - fragPosition); + } + + float NdotL = max(dot(normal, light), 0.0); + lightDot += lights[i].color.rgb*NdotL; + + float specCo = 0.0; + if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine + specular += specCo; + } + } + + finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0))); + finalColor += texelColor*(ambient/10.0)*colDiffuse; + + // Gamma correction + finalColor = pow(finalColor, vec4(1.0/2.2)); +} \ No newline at end of file diff --git a/examples/lighting.vs b/examples/lighting.vs new file mode 100644 index 0000000..6b17635 --- /dev/null +++ b/examples/lighting.vs @@ -0,0 +1,32 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; +uniform mat4 matNormal; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec4 fragColor; +out vec3 fragNormal; + +// NOTE: Add here your custom variables + +void main() +{ + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel*vec4(vertexPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0))); + + // Calculate final vertex position + gl_Position = mvp*vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/examples/shaders_basic_lighting.rs b/examples/shaders_basic_lighting.rs new file mode 100644 index 0000000..0e26aa7 --- /dev/null +++ b/examples/shaders_basic_lighting.rs @@ -0,0 +1,188 @@ +use raylib_ffi::*; +use ::std::os::raw::*; + +const MAX_LIGHTS: usize = 4; // Max dynamic lights supported by shader + +// Light data +struct Light { + enabled: i32, + kind: i32, + position: Vector3, + target: Vector3, + color: Color, + + // Shader locations + enabled_loc: i32, + kind_loc: i32, + position_loc: i32, + target_loc: i32, + color_loc: i32, +} + +// Create a light and get shader locations +fn create_light(id: isize, kind: i32, position: Vector3, target : Vector3, color : Color, shader : Shader) -> Light { + unsafe { + let light = Light { + enabled: 1, + kind, + position, + target, + color, + + // NOTE: Lighting shader naming must be the provided ones + enabled_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].enabled", id))), + kind_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].type", id))), + position_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].position", id))), + target_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].target", id))), + color_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].color", id))) + }; + + update_light_values(shader, &light); + return light; + } +} + +// Send light properties to shader +// NOTE: Light shader locations should be available +fn update_light_values(shader: Shader, light: &Light) { + unsafe { + // Send to shader light enabled state and type + let enabled = [light.enabled].as_ptr(); + SetShaderValue(shader, light.enabled_loc, enabled as *const c_void, enums::ShaderUniformDataType::Int as i32); + let kind = [light.kind].as_ptr(); + SetShaderValue(shader, light.kind_loc, kind as *const c_void, enums::ShaderUniformDataType::Int as i32); + + // Send to shader light position values + let position = [light.position.x, light.position.y, light.position.z].as_ptr(); + SetShaderValue(shader, light.position_loc, position as *const c_void, enums::ShaderUniformDataType::Vec3 as i32); + + // Send to shader light target position values + let target = [light.position.x, light.position.y, light.position.z].as_ptr(); + SetShaderValue(shader, light.target_loc, target as *const c_void, enums::ShaderUniformDataType::Vec3 as i32); + + // Send to shader light color values + let color = [ + light.color.r as f32 / 255.0, + light.color.g as f32 / 255.0, + light.color.b as f32 / 255.0, + light.color.a as f32 / 255.0 + ].as_ptr(); + SetShaderValue(shader, light.color_loc, color as *const c_void, enums::ShaderUniformDataType::Vec4 as i32); + } +} + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +pub fn main() { + unsafe { + // Initialization + //-------------------------------------------------------------------------------------- + SetConfigFlags(enums::ConfigFlags::Msaa4xHint as u32); // Enable Multi Sampling Anti Aliasing 4x (if available) + InitWindow(800, 450, rl_str!("raylib [shaders] example - basic lighting")); + + // Define the camera to look into our 3d world + let mut camera = Camera{ + position: Vector3{ x: 2.0, y: 4.0, z: 6.0 }, // Camera position + target: Vector3{ x: 0.0, y: 0.5, z: 0.0 }, // Camera looking at point + up: Vector3{ x: 0.0, y: 1.0, z: 0.0 }, // Camera up vector (rotation towards target) + fovy: 45.0, // Camera field-of-view Y + projection: enums::CameraProjection::Perspective as i32 // Camera projection type + }; + + // Load plane model from a generated mesh + let model = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 3, 3)); + let cube = LoadModelFromMesh(GenMeshCube(2.0, 4.0, 2.0)); + + // Load basic lighting shader + let shader = LoadShader(rl_str!("examples/lighting.vs"), rl_str!("examples/lighting.fs")); + + // Get some required shader locations + let view_loc = shader.locs.offset(enums::ShaderLocationIndex::VectorView as isize) as *mut c_int; + *view_loc = GetShaderLocation(shader, rl_str!("viewPos")); + + // Ambient light level (some basic lighting) + let ambient_loc = GetShaderLocation(shader, rl_str!("ambient")); + let ambient_value = [0.1 as f32, 0.1 as f32, 0.1 as f32, 1.0 as f32].as_ptr(); + SetShaderValue(shader, ambient_loc, ambient_value as *const c_void, enums::ShaderUniformDataType::Ivec4 as i32); + + // Assign lighting shader to model + (*(model.materials.offset(0))).shader = shader; + (*(cube.materials.offset(0))).shader = shader; + + // Create lights + let mut lights = [ + create_light(0, 1, Vector3{ x: -2.0, y: 1.0, z: -2.0 }, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, colors::YELLOW, shader), + create_light(1, 1, Vector3{ x: 2.0, y: 1.0, z: 2.0 }, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, colors::RED, shader), + create_light(2, 1, Vector3{ x: -2.0, y: 1.0, z: 2.0 }, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, colors::GREEN, shader), + create_light(3, 1, Vector3{ x: 2.0, y: 1.0, z: -2.0 }, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, colors::BLUE, shader) + ]; + + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while !WindowShouldClose() // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + UpdateCamera(&mut camera, enums::CameraMode::Orbital as i32); + + // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f }) + let camera_pos = [camera.position.x, camera.position.y, camera.position.z].as_ptr(); + SetShaderValue(shader, shader.locs.offset(enums::ShaderLocationIndex::VectorView as isize).read(), camera_pos as *mut c_void, enums::ShaderUniformDataType::Ivec3 as c_int); + + // Check key inputs to enable/disable lights + if IsKeyPressed(enums::KeyboardKey::R as i32) { lights[1].enabled = !lights[1].enabled; } + if IsKeyPressed(enums::KeyboardKey::G as i32) { lights[2].enabled = !lights[2].enabled; } + if IsKeyPressed(enums::KeyboardKey::B as i32) { lights[3].enabled = !lights[3].enabled; } + if IsKeyPressed(enums::KeyboardKey::Y as i32) { lights[0].enabled = !lights[0].enabled; } + + // Update light values (actually, only enable/disable them) + for i in 0 .. MAX_LIGHTS { + update_light_values(shader, &lights[i]); + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(colors::WHITE); + + BeginMode3D(camera); + + DrawModel(model, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, 1.0, colors::WHITE); + DrawModel(cube, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, 1.0, colors::WHITE); + + // Draw spheres to show where the lights are + for i in 0 .. MAX_LIGHTS { + if lights[i].enabled > 0 { + DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color); + } else { + DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3)); + } + } + + DrawGrid(10, 1.0); + + EndMode3D(); + + DrawFPS(10, 10); + + DrawText(rl_str!("Use keys [Y][R][G][B] to toggle lights"), 10, 40, 20, colors::DARKGRAY); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadModel(model); // Unload the model + UnloadModel(cube); // Unload the model + UnloadShader(shader); // Unload shader + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + } +} From 8319b8e1918c544549ef90e2df270e84c606c021 Mon Sep 17 00:00:00 2001 From: Mark McIlroy Date: Wed, 20 Dec 2023 10:15:21 +0000 Subject: [PATCH 2/2] Move shaders --- examples/{ => shaders}/lighting.fs | 0 examples/{ => shaders}/lighting.vs | 0 examples/shaders_basic_lighting.rs | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/{ => shaders}/lighting.fs (100%) rename examples/{ => shaders}/lighting.vs (100%) diff --git a/examples/lighting.fs b/examples/shaders/lighting.fs similarity index 100% rename from examples/lighting.fs rename to examples/shaders/lighting.fs diff --git a/examples/lighting.vs b/examples/shaders/lighting.vs similarity index 100% rename from examples/lighting.vs rename to examples/shaders/lighting.vs diff --git a/examples/shaders_basic_lighting.rs b/examples/shaders_basic_lighting.rs index 0e26aa7..5665481 100644 --- a/examples/shaders_basic_lighting.rs +++ b/examples/shaders_basic_lighting.rs @@ -95,7 +95,7 @@ pub fn main() { let cube = LoadModelFromMesh(GenMeshCube(2.0, 4.0, 2.0)); // Load basic lighting shader - let shader = LoadShader(rl_str!("examples/lighting.vs"), rl_str!("examples/lighting.fs")); + let shader = LoadShader(rl_str!("examples/shaders/lighting.vs"), rl_str!("examples/shaders/lighting.fs")); // Get some required shader locations let view_loc = shader.locs.offset(enums::ShaderLocationIndex::VectorView as isize) as *mut c_int;