[update] Improved the shading of CubeProgram.

This commit is contained in:
falsycat 2019-10-12 00:00:00 +00:00
parent 79654d6da4
commit 0f17719b79
2 changed files with 114 additions and 34 deletions

View File

@ -2,7 +2,8 @@
module sj.CubeProgram; module sj.CubeProgram;
import std.conv, import std.conv,
std.range.primitives; std.range.primitives,
std.string;
import gl4d; import gl4d;
@ -10,7 +11,27 @@ import gl4d;
class CubeProgram { class CubeProgram {
public: 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 enum ShaderHeader = "#version 330 core
@ -18,6 +39,10 @@ class CubeProgram {
/// ///
enum VertexShaderSrc = ShaderHeader ~ q{ 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 = 0) in vec3 vert;
layout(location = 1) in vec3 normal; layout(location = 1) in vec3 normal;
@ -26,29 +51,63 @@ class CubeProgram {
layout(location = 4) in vec4 m3; layout(location = 4) in vec4 m3;
layout(location = 5) in vec4 m4; layout(location = 5) in vec4 m4;
out vec3 lightdir_;
out vec3 normal_; out vec3 normal_;
out vec3 eyedir_;
out float distance_;
void main() { void main() {
mat4 m = transpose(mat4(m1, m2, m3, m4)); mat4 M = transpose(mat4(m1, m2, m3, m4));
normal_ = (m * vec4(normal, 1)).xyz; vec3 lightpos_camera = (V * vec4(lightpos, 1)).xyz;
gl_Position = m * vec4(vert, 1); 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{ enum FragmentShaderSrc = ShaderHeader ~ q{
layout(location = 0) uniform vec3 light_color; layout(std140) uniform Material {
layout(location = 1) uniform vec3 light_direction; vec3 diffuse_color;
layout(location = 2) uniform vec3 ambient_color;
vec3 specular_color;
vec3 light_color;
vec3 light_power;
vec3 ambient_color;
} material;
in vec3 lightdir_;
in vec3 normal_; in vec3 normal_;
in vec3 eyedir_;
in float distance_;
out vec4 pixel_; out vec4 pixel_;
void main() { void main() {
float light = dot(normalize(light_direction), normalize(normal_)); vec3 l = normalize(lightdir_);
vec3 color = clamp(light_color * light + ambient_color, 0, 1); 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); pixel_ = vec4(color, 1);
} }
}; };
@ -64,6 +123,18 @@ class CubeProgram {
program_ = linker.Link(); program_ = linker.Link();
program_.Validate(); 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(); vao_ = VertexArray.Create();
verts_ = ArrayBuffer.Create(); verts_ = ArrayBuffer.Create();
instances_ = ArrayBuffer.Create(); instances_ = ArrayBuffer.Create();
@ -156,28 +227,35 @@ class CubeProgram {
ArrayBufferAllocator instances_allocator; ArrayBufferAllocator instances_allocator;
with (instances_allocator) { with (instances_allocator) {
data = null; data = null;
size = MaxInstanceCount * Instance.sizeof; size = MaxInstanceCount * mat4.sizeof;
usage = GL_DYNAMIC_DRAW; usage = GL_DYNAMIC_DRAW;
Allocate(instances_); Allocate(instances_);
} }
} }
/// ///
void Draw(R)(R cubes, vec3 lcolor, vec3 light, vec3 acolor) void Draw(R)(R cubes, mat4 projection, mat4 view, vec3 lightpos, Material material)
if (isInputRange!R && is(ElementType!R == Instance)) { 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; size_t length;
{ {
auto ptr = instances_.MapToWrite!Instance(); auto ptr = instances_.MapToWrite!mat4();
foreach (const ref c; cubes) { foreach (const ref c; cubes) {
assert(length < MaxInstanceCount); assert(length < MaxInstanceCount);
ptr[length++] = c; ptr[length++] = c;
} }
} }
if (length == 0) return;
program_.Use();
program_.uniform!0 = lcolor;
program_.uniform!1 = light;
program_.uniform!2 = acolor;
vao_.Bind(); vao_.Bind();
gl.DrawArraysInstanced(GL_TRIANGLES, 0, 6*6, length.to!int); gl.DrawArraysInstanced(GL_TRIANGLES, 0, 6*6, length.to!int);
@ -186,9 +264,13 @@ class CubeProgram {
private: private:
ProgramRef program_; ProgramRef program_;
UniformBufferRef material_;
VertexArrayRef vao_; VertexArrayRef vao_;
ArrayBufferRef verts_; ArrayBufferRef verts_;
ArrayBufferRef instances_; ArrayBufferRef instances_;
const GLuint material_index_;
} }

View File

@ -14,12 +14,12 @@ import sj.CubeProgram,
class LobbyWorld { class LobbyWorld {
public: 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) { this(ProgramSet programs) {
background_ = new Background(programs.Get!BackgroundProgram); background_ = new Background(programs.Get!BackgroundProgram);
cube_ = programs.Get!CubeProgram; cube_program_ = programs.Get!CubeProgram;
} }
/// ///
@ -30,9 +30,9 @@ class LobbyWorld {
gl.Enable(GL_DEPTH_TEST); gl.Enable(GL_DEPTH_TEST);
gl.DepthMask(true); gl.DepthMask(true);
cube_.Draw( cube_program_.Draw(
cubes.map!(x => Perspective * view * x), cubes.map!"a.Create()",
light_color, light_direction, ambient_color); 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); CubeProgram.Material cube_material;
///
vec3 ambient_color = vec3(0.1, 0.1, 0.1);
private: private:
Background background_; Background background_;
CubeProgram cube_; CubeProgram cube_program_;
} }