diff --git a/src/sj/CubeProgram.d b/src/sj/CubeProgram.d index 56d79a1..938512d 100644 --- a/src/sj/CubeProgram.d +++ b/src/sj/CubeProgram.d @@ -2,7 +2,8 @@ module sj.CubeProgram; import std.conv, - std.range.primitives; + std.range.primitives, + std.string; import gl4d; @@ -10,7 +11,27 @@ import gl4d; class CubeProgram { public: /// - alias Instance = mat4; + static struct Material { + public: + /// + vec3 diffuse_color = vec3(1, 1, 1); + private float padding0_; + + /// + vec3 specular_color = vec3(1, 1, 1); + private float padding1_; + + /// + vec3 light_color = vec3(1, 1, 1); + private float padding2_; + /// + vec3 light_power = vec3(20, 20, 20); + private float padding3_; + + /// + vec3 ambient_color = vec3(0.3, 0.3, 0.3); + private float padding4_; + } /// enum ShaderHeader = "#version 330 core @@ -18,6 +39,10 @@ class CubeProgram { /// enum VertexShaderSrc = ShaderHeader ~ q{ + layout(location = 0) uniform mat4 P; + layout(location = 1) uniform mat4 V; + layout(location = 2) uniform vec3 lightpos; + layout(location = 0) in vec3 vert; layout(location = 1) in vec3 normal; @@ -26,29 +51,63 @@ class CubeProgram { layout(location = 4) in vec4 m3; layout(location = 5) in vec4 m4; - out vec3 normal_; + out vec3 lightdir_; + out vec3 normal_; + out vec3 eyedir_; + out float distance_; void main() { - mat4 m = transpose(mat4(m1, m2, m3, m4)); + mat4 M = transpose(mat4(m1, m2, m3, m4)); - normal_ = (m * vec4(normal, 1)).xyz; - gl_Position = m * vec4(vert, 1); + vec3 lightpos_camera = (V * vec4(lightpos, 1)).xyz; + vec3 vert_camera = (V * M * vec4(vert, 1)).xyz; + vec3 normal_camera = (V * M * vec4(normal, 0)).xyz; + + eyedir_ = vec3(0, 0, 0) - vert_camera; + normal_ = normal_camera; + lightdir_ = lightpos_camera + eyedir_; + distance_ = length(lightpos_camera - vert_camera); + + gl_Position = P * V * M * vec4(vert, 1); } }; /// enum FragmentShaderSrc = ShaderHeader ~ q{ - layout(location = 0) uniform vec3 light_color; - layout(location = 1) uniform vec3 light_direction; - layout(location = 2) uniform vec3 ambient_color; + layout(std140) uniform Material { + vec3 diffuse_color; - in vec3 normal_; + vec3 specular_color; + + vec3 light_color; + vec3 light_power; + + vec3 ambient_color; + } material; + + in vec3 lightdir_; + in vec3 normal_; + in vec3 eyedir_; + in float distance_; out vec4 pixel_; void main() { - float light = dot(normalize(light_direction), normalize(normal_)); - vec3 color = clamp(light_color * light + ambient_color, 0, 1); + vec3 l = normalize(lightdir_); + vec3 n = normalize(normal_); + vec3 e = normalize(eyedir_); + vec3 r = reflect(-l, n); + + float diffuse_cos = clamp(dot(l, n), 0, 1); + float reflect_cos = clamp(dot(e, r), 0, 1); + + vec3 color_without_ambient = + material.diffuse_color * diffuse_cos + + material.specular_color * pow(reflect_cos, 5); + + vec3 color = + material.ambient_color + + color_without_ambient * material.light_color * material.light_power / pow(distance_, 2); pixel_ = vec4(color, 1); } }; @@ -64,6 +123,18 @@ class CubeProgram { program_ = linker.Link(); program_.Validate(); + material_ = UniformBuffer.Create(); + material_index_ = gl.GetUniformBlockIndex(program_.id, "Material".toStringz); + + material_.Bind(); + UniformBufferAllocator material_allocator; + with (material_allocator) { + data = null; + size = Material.sizeof; + usage = GL_DYNAMIC_DRAW; + Allocate(material_); + } + vao_ = VertexArray.Create(); verts_ = ArrayBuffer.Create(); instances_ = ArrayBuffer.Create(); @@ -156,28 +227,35 @@ class CubeProgram { ArrayBufferAllocator instances_allocator; with (instances_allocator) { data = null; - size = MaxInstanceCount * Instance.sizeof; + size = MaxInstanceCount * mat4.sizeof; usage = GL_DYNAMIC_DRAW; Allocate(instances_); } } /// - void Draw(R)(R cubes, vec3 lcolor, vec3 light, vec3 acolor) - if (isInputRange!R && is(ElementType!R == Instance)) { + void Draw(R)(R cubes, mat4 projection, mat4 view, vec3 lightpos, Material material) + if (isInputRange!R && is(ElementType!R == mat4)) { + { + auto ptr = material_.MapToWrite!Material(); + *ptr = material; + } + + program_.Use(); + program_.uniform!0 = projection; + program_.uniform!1 = view; + program_.uniform!2 = lightpos; + material_.BindForUniformBlock(material_index_); + size_t length; { - auto ptr = instances_.MapToWrite!Instance(); + auto ptr = instances_.MapToWrite!mat4(); foreach (const ref c; cubes) { assert(length < MaxInstanceCount); ptr[length++] = c; } } - - program_.Use(); - program_.uniform!0 = lcolor; - program_.uniform!1 = light; - program_.uniform!2 = acolor; + if (length == 0) return; vao_.Bind(); gl.DrawArraysInstanced(GL_TRIANGLES, 0, 6*6, length.to!int); @@ -186,9 +264,13 @@ class CubeProgram { private: ProgramRef program_; + UniformBufferRef material_; + VertexArrayRef vao_; ArrayBufferRef verts_; ArrayBufferRef instances_; + + const GLuint material_index_; } diff --git a/src/sj/LobbyWorld.d b/src/sj/LobbyWorld.d index f1823e8..d8332d1 100644 --- a/src/sj/LobbyWorld.d +++ b/src/sj/LobbyWorld.d @@ -14,12 +14,12 @@ import sj.CubeProgram, class LobbyWorld { public: /// - enum Perspective = mat4.perspective(-0.5, 0.5, -0.5, 0.5, 0.1, 100); + enum Projection = mat4.perspective(1, 1, 60, 0.1, 100); /// this(ProgramSet programs) { - background_ = new Background(programs.Get!BackgroundProgram); - cube_ = programs.Get!CubeProgram; + background_ = new Background(programs.Get!BackgroundProgram); + cube_program_ = programs.Get!CubeProgram; } /// @@ -30,9 +30,9 @@ class LobbyWorld { gl.Enable(GL_DEPTH_TEST); gl.DepthMask(true); - cube_.Draw( - cubes.map!(x => Perspective * view * x), - light_color, light_direction, ambient_color); + cube_program_.Draw( + cubes.map!"a.Create()", + Projection, view.Create(), light_pos, cube_material); } /// @@ -41,18 +41,16 @@ class LobbyWorld { } /// - mat4[] cubes; + ModelMatrixFactory!4[] cubes; /// - mat4 view = mat4.look_at(vec3(0, 0, -1), vec3(0, 0, 0), vec3(0, 1, 0)); + ViewMatrixFactory view; /// - vec3 light_color = vec3(1, 1, 1); + vec3 light_pos = vec3(0, 10, 0); /// - vec3 light_direction = vec3(0, 1, 0); - /// - vec3 ambient_color = vec3(0.1, 0.1, 0.1); + CubeProgram.Material cube_material; private: Background background_; - CubeProgram cube_; + CubeProgram cube_program_; }