Skip to content

Commit 546dad0

Browse files
committed
basic lighting example
1 parent 944d726 commit 546dad0

File tree

3 files changed

+296
-0
lines changed

3 files changed

+296
-0
lines changed

examples/lighting.fs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#version 330
2+
3+
// Input vertex attributes (from vertex shader)
4+
in vec3 fragPosition;
5+
in vec2 fragTexCoord;
6+
//in vec4 fragColor;
7+
in vec3 fragNormal;
8+
9+
// Input uniform values
10+
uniform sampler2D texture0;
11+
uniform vec4 colDiffuse;
12+
13+
// Output fragment color
14+
out vec4 finalColor;
15+
16+
// NOTE: Add here your custom variables
17+
18+
#define MAX_LIGHTS 4
19+
#define LIGHT_DIRECTIONAL 0
20+
#define LIGHT_POINT 1
21+
22+
struct Light {
23+
int enabled;
24+
int type;
25+
vec3 position;
26+
vec3 target;
27+
vec4 color;
28+
};
29+
30+
// Input lighting values
31+
uniform Light lights[MAX_LIGHTS];
32+
uniform vec4 ambient;
33+
uniform vec3 viewPos;
34+
35+
void main()
36+
{
37+
// Texel color fetching from texture sampler
38+
vec4 texelColor = texture(texture0, fragTexCoord);
39+
vec3 lightDot = vec3(0.0);
40+
vec3 normal = normalize(fragNormal);
41+
vec3 viewD = normalize(viewPos - fragPosition);
42+
vec3 specular = vec3(0.0);
43+
44+
// NOTE: Implement here your fragment shader code
45+
46+
for (int i = 0; i < MAX_LIGHTS; i++)
47+
{
48+
if (lights[i].enabled == 1)
49+
{
50+
vec3 light = vec3(0.0);
51+
52+
if (lights[i].type == LIGHT_DIRECTIONAL)
53+
{
54+
light = -normalize(lights[i].target - lights[i].position);
55+
}
56+
57+
if (lights[i].type == LIGHT_POINT)
58+
{
59+
light = normalize(lights[i].position - fragPosition);
60+
}
61+
62+
float NdotL = max(dot(normal, light), 0.0);
63+
lightDot += lights[i].color.rgb*NdotL;
64+
65+
float specCo = 0.0;
66+
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(light), normal))), 16.0); // 16 refers to shine
67+
specular += specCo;
68+
}
69+
}
70+
71+
finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
72+
finalColor += texelColor*(ambient/10.0)*colDiffuse;
73+
74+
// Gamma correction
75+
finalColor = pow(finalColor, vec4(1.0/2.2));
76+
}

examples/lighting.vs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#version 330
2+
3+
// Input vertex attributes
4+
in vec3 vertexPosition;
5+
in vec2 vertexTexCoord;
6+
in vec3 vertexNormal;
7+
in vec4 vertexColor;
8+
9+
// Input uniform values
10+
uniform mat4 mvp;
11+
uniform mat4 matModel;
12+
uniform mat4 matNormal;
13+
14+
// Output vertex attributes (to fragment shader)
15+
out vec3 fragPosition;
16+
out vec2 fragTexCoord;
17+
out vec4 fragColor;
18+
out vec3 fragNormal;
19+
20+
// NOTE: Add here your custom variables
21+
22+
void main()
23+
{
24+
// Send vertex attributes to fragment shader
25+
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
26+
fragTexCoord = vertexTexCoord;
27+
fragColor = vertexColor;
28+
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
29+
30+
// Calculate final vertex position
31+
gl_Position = mvp*vec4(vertexPosition, 1.0);
32+
}

examples/shaders_basic_lighting.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
use raylib_ffi::*;
2+
use ::std::os::raw::*;
3+
4+
const MAX_LIGHTS: usize = 4; // Max dynamic lights supported by shader
5+
6+
// Light data
7+
struct Light {
8+
enabled: i32,
9+
kind: i32,
10+
position: Vector3,
11+
target: Vector3,
12+
color: Color,
13+
14+
// Shader locations
15+
enabled_loc: i32,
16+
kind_loc: i32,
17+
position_loc: i32,
18+
target_loc: i32,
19+
color_loc: i32,
20+
}
21+
22+
// Create a light and get shader locations
23+
fn create_light(id: isize, kind: i32, position: Vector3, target : Vector3, color : Color, shader : Shader) -> Light {
24+
unsafe {
25+
let light = Light {
26+
enabled: 1,
27+
kind,
28+
position,
29+
target,
30+
color,
31+
32+
// NOTE: Lighting shader naming must be the provided ones
33+
enabled_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].enabled", id))),
34+
kind_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].type", id))),
35+
position_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].position", id))),
36+
target_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].target", id))),
37+
color_loc: GetShaderLocation(shader, rl_str!(format!("lights[{}].color", id)))
38+
};
39+
40+
update_light_values(shader, &light);
41+
return light;
42+
}
43+
}
44+
45+
// Send light properties to shader
46+
// NOTE: Light shader locations should be available
47+
fn update_light_values(shader: Shader, light: &Light) {
48+
unsafe {
49+
// Send to shader light enabled state and type
50+
let enabled = [light.enabled].as_ptr();
51+
SetShaderValue(shader, light.enabled_loc, enabled as *const c_void, enums::ShaderUniformDataType::Int as i32);
52+
let kind = [light.kind].as_ptr();
53+
SetShaderValue(shader, light.kind_loc, kind as *const c_void, enums::ShaderUniformDataType::Int as i32);
54+
55+
// Send to shader light position values
56+
let position = [light.position.x, light.position.y, light.position.z].as_ptr();
57+
SetShaderValue(shader, light.position_loc, position as *const c_void, enums::ShaderUniformDataType::Vec3 as i32);
58+
59+
// Send to shader light target position values
60+
let target = [light.position.x, light.position.y, light.position.z].as_ptr();
61+
SetShaderValue(shader, light.target_loc, target as *const c_void, enums::ShaderUniformDataType::Vec3 as i32);
62+
63+
// Send to shader light color values
64+
let color = [
65+
light.color.r as f32 / 255.0,
66+
light.color.g as f32 / 255.0,
67+
light.color.b as f32 / 255.0,
68+
light.color.a as f32 / 255.0
69+
].as_ptr();
70+
SetShaderValue(shader, light.color_loc, color as *const c_void, enums::ShaderUniformDataType::Vec4 as i32);
71+
}
72+
}
73+
74+
//------------------------------------------------------------------------------------
75+
// Program main entry point
76+
//------------------------------------------------------------------------------------
77+
pub fn main() {
78+
unsafe {
79+
// Initialization
80+
//--------------------------------------------------------------------------------------
81+
SetConfigFlags(enums::ConfigFlags::Msaa4xHint as u32); // Enable Multi Sampling Anti Aliasing 4x (if available)
82+
InitWindow(800, 450, rl_str!("raylib [shaders] example - basic lighting"));
83+
84+
// Define the camera to look into our 3d world
85+
let mut camera = Camera{
86+
position: Vector3{ x: 2.0, y: 4.0, z: 6.0 }, // Camera position
87+
target: Vector3{ x: 0.0, y: 0.5, z: 0.0 }, // Camera looking at point
88+
up: Vector3{ x: 0.0, y: 1.0, z: 0.0 }, // Camera up vector (rotation towards target)
89+
fovy: 45.0, // Camera field-of-view Y
90+
projection: enums::CameraProjection::Perspective as i32 // Camera projection type
91+
};
92+
93+
// Load plane model from a generated mesh
94+
let model = LoadModelFromMesh(GenMeshPlane(10.0, 10.0, 3, 3));
95+
let cube = LoadModelFromMesh(GenMeshCube(2.0, 4.0, 2.0));
96+
97+
// Load basic lighting shader
98+
let shader = LoadShader(rl_str!("examples/lighting.vs"), rl_str!("examples/lighting.fs"));
99+
100+
// Get some required shader locations
101+
let view_loc = shader.locs.offset(enums::ShaderLocationIndex::VectorView as isize) as *mut c_int;
102+
*view_loc = GetShaderLocation(shader, rl_str!("viewPos"));
103+
104+
// Ambient light level (some basic lighting)
105+
let ambient_loc = GetShaderLocation(shader, rl_str!("ambient"));
106+
let ambient_value = [0.1 as f32, 0.1 as f32, 0.1 as f32, 1.0 as f32].as_ptr();
107+
SetShaderValue(shader, ambient_loc, ambient_value as *const c_void, enums::ShaderUniformDataType::Ivec4 as i32);
108+
109+
// Assign lighting shader to model
110+
(*(model.materials.offset(0))).shader = shader;
111+
(*(cube.materials.offset(0))).shader = shader;
112+
113+
// Create lights
114+
let mut lights = [
115+
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),
116+
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),
117+
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),
118+
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)
119+
];
120+
121+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
122+
//--------------------------------------------------------------------------------------
123+
124+
// Main game loop
125+
while !WindowShouldClose() // Detect window close button or ESC key
126+
{
127+
// Update
128+
//----------------------------------------------------------------------------------
129+
UpdateCamera(&mut camera, enums::CameraMode::Orbital as i32);
130+
131+
// Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f })
132+
let camera_pos = [camera.position.x, camera.position.y, camera.position.z].as_ptr();
133+
SetShaderValue(shader, shader.locs.offset(enums::ShaderLocationIndex::VectorView as isize).read(), camera_pos as *mut c_void, enums::ShaderUniformDataType::Ivec3 as c_int);
134+
135+
// Check key inputs to enable/disable lights
136+
if IsKeyPressed(enums::KeyboardKey::R as i32) { lights[1].enabled = !lights[1].enabled; }
137+
if IsKeyPressed(enums::KeyboardKey::G as i32) { lights[2].enabled = !lights[2].enabled; }
138+
if IsKeyPressed(enums::KeyboardKey::B as i32) { lights[3].enabled = !lights[3].enabled; }
139+
if IsKeyPressed(enums::KeyboardKey::Y as i32) { lights[0].enabled = !lights[0].enabled; }
140+
141+
// Update light values (actually, only enable/disable them)
142+
for i in 0 .. MAX_LIGHTS {
143+
update_light_values(shader, &lights[i]);
144+
}
145+
//----------------------------------------------------------------------------------
146+
147+
// Draw
148+
//----------------------------------------------------------------------------------
149+
BeginDrawing();
150+
151+
ClearBackground(colors::WHITE);
152+
153+
BeginMode3D(camera);
154+
155+
DrawModel(model, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, 1.0, colors::WHITE);
156+
DrawModel(cube, Vector3{ x: 0.0, y: 0.0, z: 0.0 }, 1.0, colors::WHITE);
157+
158+
// Draw spheres to show where the lights are
159+
for i in 0 .. MAX_LIGHTS {
160+
if lights[i].enabled > 0 {
161+
DrawSphereEx(lights[i].position, 0.2, 8, 8, lights[i].color);
162+
} else {
163+
DrawSphereWires(lights[i].position, 0.2, 8, 8, ColorAlpha(lights[i].color, 0.3));
164+
}
165+
}
166+
167+
DrawGrid(10, 1.0);
168+
169+
EndMode3D();
170+
171+
DrawFPS(10, 10);
172+
173+
DrawText(rl_str!("Use keys [Y][R][G][B] to toggle lights"), 10, 40, 20, colors::DARKGRAY);
174+
175+
EndDrawing();
176+
//----------------------------------------------------------------------------------
177+
}
178+
179+
// De-Initialization
180+
//--------------------------------------------------------------------------------------
181+
UnloadModel(model); // Unload the model
182+
UnloadModel(cube); // Unload the model
183+
UnloadShader(shader); // Unload shader
184+
185+
CloseWindow(); // Close window and OpenGL context
186+
//--------------------------------------------------------------------------------------
187+
}
188+
}

0 commit comments

Comments
 (0)