[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;
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 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;
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_;
}

View File

@ -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;
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_;
}