Skip to content

Commit

Permalink
Merge pull request #9 from mmcilroy/example_shaders_basic_lighting
Browse files Browse the repository at this point in the history
Basic lighting example
  • Loading branch information
ewpratten authored Jan 1, 2024
2 parents 944d726 + 8319b8e commit f976ee2
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 0 deletions.
76 changes: 76 additions & 0 deletions examples/shaders/lighting.fs
Original file line number Diff line number Diff line change
@@ -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));
}
32 changes: 32 additions & 0 deletions examples/shaders/lighting.vs
Original file line number Diff line number Diff line change
@@ -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);
}
188 changes: 188 additions & 0 deletions examples/shaders_basic_lighting.rs
Original file line number Diff line number Diff line change
@@ -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/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;
*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
//--------------------------------------------------------------------------------------
}
}

0 comments on commit f976ee2

Please sign in to comment.