diff --git a/lib/game_objects/light.rb b/lib/game_objects/light.rb index cbc924d..93027d7 100644 --- a/lib/game_objects/light.rb +++ b/lib/game_objects/light.rb @@ -1,26 +1,35 @@ class IMICFPS class Light + DIRECTIONAL = 0 + POINT = 1 + attr_reader :light_id - attr_accessor :ambient, :diffuse, :specular, :position, :intensity - def initialize(id:, - ambient: Vector.new(0.5, 0.5, 0.5, 1), - diffuse: Vector.new(1, 0.5, 0, 1), specular: Vector.new(0.2, 0.2, 0.2, 1), - position: Vector.new(0, 0, 0, 0), intensity: 1 + attr_accessor :type, :ambient, :diffuse, :specular, :position, :intensity + def initialize( + id:, + type: Light::POINT, + ambient: Vector.new(0.5, 0.5, 0.5, 1), + diffuse: Vector.new(1, 0.5, 0, 1), + specular: Vector.new(0.2, 0.2, 0.2, 1), + position: Vector.new(0, 0, 0, 0), + intensity: 1 ) @light_id = id - @intensity = intensity + @type = type @ambient = ambient @diffuse = diffuse @specular = specular @position = position + + @intensity = intensity end def draw - glLightfv(@light_id, GL_AMBIENT, @ambient) - glLightfv(@light_id, GL_DIFFUSE, @diffuse) - glLightfv(@light_id, GL_SPECULAR, @specular) - glLightfv(@light_id, GL_POSITION, @position) + glLightfv(@light_id, GL_AMBIENT, convert(@ambient).pack("f*")) + glLightfv(@light_id, GL_DIFFUSE, convert(@diffuse, true).pack("f*")) + glLightfv(@light_id, GL_SPECULAR, convert(@specular, true).pack("f*")) + glLightfv(@light_id, GL_POSITION, convert(@position).pack("f*")) glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1) glEnable(GL_LIGHTING) glEnable(@light_id) @@ -28,7 +37,7 @@ class IMICFPS def convert(struct, apply_intensity = false) if apply_intensity - return struct.to_a.compact.map{|i| i*@intensity} + return struct.to_a.compact.map{ |i| i * @intensity } else return struct.to_a.compact end diff --git a/lib/map.rb b/lib/map.rb index fc8ea8f..8057ff0 100644 --- a/lib/map.rb +++ b/lib/map.rb @@ -30,7 +30,7 @@ class IMICFPS # TODO: Load lights from MapLoader add_light(Light.new(id: available_light, position: Vector.new(30, 10.0, 30))) - # add_light(Light.new(id: available_light, x: 0, y: 100, z: 0, diffuse: Color.new(1.0, 0.5, 0.1))) + add_light(Light.new(id: available_light, position: Vector.new(0, 100, 0), diffuse: Color.new(1.0, 0.5, 0.1))) end def data diff --git a/lib/model.rb b/lib/model.rb index 9292a43..e43439d 100644 --- a/lib/model.rb +++ b/lib/model.rb @@ -225,5 +225,11 @@ class IMICFPS def has_texture? @has_texture end + + def release_gl_resources + if @vertex_array_id + + end + end end end diff --git a/lib/renderer/opengl_renderer.rb b/lib/renderer/opengl_renderer.rb index c410901..e987d66 100644 --- a/lib/renderer/opengl_renderer.rb +++ b/lib/renderer/opengl_renderer.rb @@ -9,13 +9,23 @@ class IMICFPS def draw_object(camera, lights, object) if Shader.available?("default") Shader.use("default") do |shader| - shader.set_uniform("projection", camera.projection_matrix) - shader.set_uniform("view", camera.view_matrix) - shader.set_uniform("model", object.model_matrix) - shader.set_uniform("hasTexture", object.model.has_texture?) + shader.uniform_transform("projection", camera.projection_matrix) + shader.uniform_transform("view", camera.view_matrix) + shader.uniform_transform("model", object.model_matrix) + shader.uniform_boolean("hasTexture", object.model.has_texture?) + shader.uniform_vec3("cameraPosition", camera.position) # TODO: Upload and use lights - shader.set_uniform("lightPos", lights.first.position) + lights.each_with_index do |light, i| + shader.uniform_float("lights[#{i}.end", -1.0); + shader.uniform_float("lights[#{i}.type", light.type); + shader.uniform_vec3("lights[#{i}].position", light.position) + shader.uniform_vec3("lights[#{i}].ambient", light.ambient) + shader.uniform_vec3("lights[#{i}].diffuse", light.diffuse) + shader.uniform_vec3("lights[#{i}].specular", light.specular) + end + + shader.uniform_float("totalLights", lights.size) handleGlError draw_model(object.model) diff --git a/shaders/fragment/default.glsl b/shaders/fragment/default.glsl index c1d28b3..f04fc62 100644 --- a/shaders/fragment/default.glsl +++ b/shaders/fragment/default.glsl @@ -1,26 +1,96 @@ # version 330 core +const int MAX_LIGHTS = 4; + +struct Light { + float end; + float type; + vec3 position; + + vec3 diffuse; + vec3 ambient; + vec3 specular; + + vec3 direction; + + float intensity; +}; + in vec3 outPosition; in vec3 outColor; in vec4 outNormal; in vec3 outUV; in float outTextureID; -in vec3 outLightPos; +in Light outLights[MAX_LIGHTS]; +in float outTotalLights; in vec3 outFragPos; +in vec3 outCameraPos; +in vec3 outInverseNormal; // optimizing compilers are annoying at this stage of my understanding of GLSL vec4 lokiVar; +// https://learnopengl.com/Lighting/Multiple-lights +vec3 calculatePointLight(Light light) { + vec3 viewDir = normalize(outCameraPos - outFragPos); + vec3 lightDir = normalize(light.position - outFragPos); + float diff = max(dot(vec3(outNormal), lightDir), 0.0); + vec3 reflectDir = reflect(-lightDir, vec3(outNormal)); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 16.0); + + float distance = length(light.position - outFragPos); + float attenuation = 1.0 / (1.0 + 0.09 * distance + + 0.032 * (distance * distance)); + + vec3 ambient = light.ambient * outColor; + vec3 diffuse = light.diffuse * outColor; + vec3 specular = light.specular * spec * vec3(1.0, 1.0, 1.0); + + ambient *= attenuation; + diffuse *= attenuation; + specular *= attenuation; + + return (ambient + diffuse + specular); +} + +// https://learnopengl.com/Lighting/Basic-Lighting +vec3 calculateBasicLight(Light light) { + vec3 lightDir = normalize(light.position - outFragPos); + + float ambientStrength = 0.25; + vec3 ambient = ambientStrength * light.ambient; + + float diff = max(dot(normalize(vec3(outNormal)), lightDir), 0.0); + vec3 diffuse = diff * light.diffuse; + + float specularStrength = 0.5; + vec3 viewDir = normalize(outCameraPos - outFragPos); + vec3 reflectDir = reflect(-lightDir, outInverseNormal); + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); + vec3 specular = specularStrength * spec * light.specular; + + return vec3(ambient + diffuse + specular); +} + +vec3 calculateLighting() { + vec3 result = vec3(0.0, 0.0, 0.0); + + for (int i = 0; i < min(int(outTotalLights), MAX_LIGHTS); i++) { + if (int(outLights[i].type) == 0) { + result += calculateBasicLight(outLights[i]); + } else if (int(outLights[i].type) == 1) { + result += calculateBasicLight(outLights[i]); + } + } + + return result; +} + void main() { lokiVar = vec4(outColor, 1.0) + outNormal + vec4(outUV, 1.0) + vec4(outTextureID, 1.0, 1.0, 1.0); lokiVar = normalize(lokiVar); - vec3 lightDir = normalize(outLightPos - outFragPos); - vec3 ambient = vec3(0.5, 0.5, 0.35); - float diffuse = max(dot(vec3(outNormal), lightDir), -0.2); - vec3 specular = vec3(0, 0, 0); - - vec3 result =(ambient + diffuse + specular) * outColor; + vec3 result = calculateLighting() * outColor; gl_FragColor = vec4(result, 1.0); } \ No newline at end of file diff --git a/shaders/vertex/default.glsl b/shaders/vertex/default.glsl index 335d055..4acce1f 100644 --- a/shaders/vertex/default.glsl +++ b/shaders/vertex/default.glsl @@ -1,4 +1,19 @@ # version 330 core +const int MAX_LIGHTS = 4; + +struct Light { + float end; + float type; + vec3 position; + + vec3 diffuse; + vec3 ambient; + vec3 specular; + + vec3 direction; + + float intensity; +}; layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inColor; @@ -12,14 +27,20 @@ out vec4 outNormal; out vec3 outUV; out float outTextureID; out float outHasTexture; -out vec3 outLightPos; +out Light outLights[MAX_LIGHTS]; +out float outTotalLights; out vec3 outFragPos; +out vec3 outViewPos; +out vec3 outCameraPos; +out vec3 outInverseNormal; uniform mat4 projection; uniform mat4 view; uniform mat4 model; uniform int hasTexture; -uniform vec3 lightPos; +uniform float totalLights; +uniform Light lights[MAX_LIGHTS]; +uniform vec3 cameraPos; void main() { @@ -30,7 +51,10 @@ void main() { outUV = inUV; outTextureID = inTextureID; outHasTexture = hasTexture; - outLightPos = lightPos; + outLights = lights; + outTotalLights = totalLights; + outCameraPos = cameraPos; + outInverseNormal = mat3(transpose(inverse(model))) * vec3(inNormal); outFragPos = vec3(model * vec4(inPosition, 1.0));