intrude import depth_core
intrude import flat
-# Simple material with static colors used for debugging or display abstract objects
-class SmoothMaterial
- super Material
-
+redef class Material
# Get the default blueish material
- init default do init(
+ new do return new SmoothMaterial(
[0.0, 0.0, 0.3, 1.0],
[0.0, 0.0, 0.6, 1.0],
[1.0, 1.0, 1.0, 1.0])
+end
+
+# Simple material with static colors
+class SmoothMaterial
+ super Material
# Ambient color, always visible
+ #
+ # The RGB values should be premultiplied by the alpha value.
var ambient_color: Array[Float] is writable
# Diffuse color when covered by a light source
+ #
+ # The RGB values should be premultiplied by the alpha value.
var diffuse_color: Array[Float] is writable
# Specular color affecting reflections
+ #
+ # The RGB values should be premultiplied by the alpha value.
var specular_color: Array[Float] is writable
redef fun draw(actor, model)
# Actor specs
program.translation.uniform(actor.center.x, actor.center.y, actor.center.z, 0.0)
program.scale.uniform actor.scale
- program.rotation.uniform new Matrix.rotation(actor.rotation, 0.0, 1.0, 0.0)
+ program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
# From mesh
program.coord.array_enabled = true
program.camera.uniform(app.world_camera.position.x, app.world_camera.position.y, app.world_camera.position.z)
# Colors from the material
- program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
- program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
- program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+ var a = actor.alpha
+ program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+ ambient_color[2]*a, ambient_color[3]*a)
+ program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+ diffuse_color[2]*a, diffuse_color[3]*a)
+ program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+ specular_color[2]*a, specular_color[3]*a)
# Execute draw
if mesh.indices.is_empty then
- glDrawArrays(gl_TRIANGLES, 0, mesh.vertices.length/3)
+ glDrawArrays(mesh.draw_mode, 0, mesh.vertices.length/3)
else
- glDrawElements(gl_TRIANGLES, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
+ glDrawElements(mesh.draw_mode, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
end
end
end
# Texture applied to the specular color
var specular_texture: nullable Texture = null is writable
+ # Bump map TODO
+ private var normals_texture: nullable Texture = null is writable
+
redef fun draw(actor, model)
do
var mesh = model.mesh
program.use_map_specular.uniform false
end
+ texture = normals_texture
+ if texture != null then
+ glActiveTexture gl_TEXTURE3
+ glBindTexture(gl_TEXTURE_2D, texture.gl_texture)
+ program.use_map_bump.uniform true
+ program.map_bump.uniform 3
+ sample_used_texture = texture
+ else
+ program.use_map_bump.uniform false
+ end
+
program.translation.uniform(actor.center.x, actor.center.y, actor.center.z, 0.0)
program.scale.uniform actor.scale
# If using a texture, set `texture_coords`
program.tex_coord.array_enabled = sample_used_texture != null
if sample_used_texture != null then
- if sample_used_texture isa GamnitRootTexture then
+ if sample_used_texture isa RootTexture then
# Coordinates are directly valid
program.tex_coord.array(mesh.texture_coords, 2)
else
var xd = sample_used_texture.offset_right - xa
var ya = sample_used_texture.offset_top
var yd = sample_used_texture.offset_bottom - ya
+ xd *= 0.999
+ yd *= 0.999
var tex_coords = new Array[Float].with_capacity(mesh.texture_coords.length)
for i in [0..mesh.texture_coords.length/2[ do
tex_coords[i*2] = xa + xd * mesh.texture_coords[i*2]
- tex_coords[i*2+1] = ya + yd * mesh.texture_coords[i*2+1]
+ tex_coords[i*2+1] = 1.0 - (ya + yd * mesh.texture_coords[i*2+1])
end
program.tex_coord.array(tex_coords, 2)
program.coord.array_enabled = true
program.coord.array(mesh.vertices, 3)
- program.rotation.uniform new Matrix.rotation(actor.rotation, 0.0, 1.0, 0.0)
- program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
- program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
- program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+ program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
+
+ var a = actor.alpha
+ program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+ ambient_color[2]*a, ambient_color[3]*a)
+ program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+ diffuse_color[2]*a, diffuse_color[3]*a)
+ program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+ specular_color[2]*a, specular_color[3]*a)
program.normal.array_enabled = true
program.normal.array(mesh.normals, 3)
program.camera.uniform(app.world_camera.position.x, app.world_camera.position.y, app.world_camera.position.z)
if mesh.indices.is_empty then
- glDrawArrays(gl_TRIANGLES, 0, mesh.vertices.length/3)
+ glDrawArrays(mesh.draw_mode, 0, mesh.vertices.length/3)
else
- glDrawElements(gl_TRIANGLES, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
+ glDrawElements(mesh.draw_mode, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
end
end
end
program.coord.array_enabled = true
program.coord.array(mesh.vertices, 3)
- program.rotation.uniform new Matrix.rotation(actor.rotation, 0.0, 1.0, 0.0)
+
+ program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
program.normal.array_enabled = true
program.normal.array(mesh.normals, 3)
if mesh.indices.is_empty then
- glDrawArrays(gl_TRIANGLES, 0, mesh.vertices.length/3)
+ glDrawArrays(mesh.draw_mode, 0, mesh.vertices.length/3)
else
- glDrawElements(gl_TRIANGLES, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
+ glDrawElements(mesh.draw_mode, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
end
end
end
-# Graphic program to display 3D models with Lamber diffuse lighting
-class LambertProgram
+# Graphic program to display 3D models with Blinn-Phong specular lighting
+class BlinnPhongProgram
super GamnitProgramFromSource
redef var vertex_shader_source = """
// Output for the fragment shader
varying vec2 v_tex_coord;
varying vec3 v_normal;
- varying vec4 v_light_center;
- varying vec4 v_camera;
+ varying vec4 v_to_light;
+ varying vec4 v_to_camera;
void main()
{
+ vec4 pos = (vec4(coord.xyz * scale, 1.0) * rotation + translation);
+ gl_Position = pos * mvp;
+
// Pass varyings to the fragment shader
v_tex_coord = vec2(tex_coord.x, 1.0 - tex_coord.y);
- v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
-
- gl_Position = (vec4(coord.xyz * scale, 1.0) * rotation + translation) * mvp;
-
- // TODO compute v_light_center and v_camera on the CPU side and pass as uniforms
- v_light_center = vec4(light_center, 0.0) * mvp;
- v_camera = vec4(camera, 0.0) * mvp;
+ v_normal = normalize(vec4(normal, 0.0) * rotation).xyz;
+ v_to_light = normalize(vec4(light_center, 1.0) - pos);
+ v_to_camera = normalize(vec4(camera, 1.0) - pos);
}
""" @ glsl_vertex_shader
// Input from the vertex shader
varying vec2 v_tex_coord;
varying vec3 v_normal;
- varying vec4 v_light_center;
- varying vec4 v_camera;
+ varying vec4 v_to_light;
+ varying vec4 v_to_camera;
// Colors
uniform vec4 ambient_color;
void main()
{
- // Lambert diffusion
- vec3 light_dir = normalize(v_light_center.xyz);
- float lambert = max(dot(light_dir, v_normal), 0.0);
-
- if (use_map_ambient)
- gl_FragColor = ambient_color * texture2D(map_ambient, v_tex_coord);
- else
- gl_FragColor = ambient_color;
-
- if (use_map_diffuse)
- gl_FragColor += lambert * diffuse_color * texture2D(map_diffuse, v_tex_coord);
- else
- gl_FragColor += lambert * diffuse_color;
+ // Normal
+ vec3 normal = v_normal;
+ if (use_map_bump) {
+ // TODO
+ vec3 bump = 2.0 * texture2D(map_bump, v_tex_coord).rgb - 1.0;
+ }
+
+ // Ambient light
+ vec4 ambient = ambient_color;
+ if (use_map_ambient) ambient *= texture2D(map_ambient, v_tex_coord);
+
+ // Diffuse Lambert light
+ vec3 to_light = v_to_light.xyz;
+ float lambert = clamp(dot(normal, to_light), 0.0, 1.0);
+
+ vec4 diffuse = lambert * diffuse_color;
+ if (use_map_diffuse) diffuse *= texture2D(map_diffuse, v_tex_coord);
+
+ // Specular Phong light
+ float s = 0.0;
+ if (lambert > 0.0) {
+ vec3 l = reflect(-to_light, normal);
+ s = clamp(dot(l, v_to_camera.xyz), 0.0, 1.0);
+ s = pow(s, 8.0); // TODO make this `shininess` a material attribute
+ }
+
+ vec4 specular = s * specular_color;
+ if (use_map_specular) specular *= texture2D(map_specular, v_tex_coord).x;
+
+ gl_FragColor = ambient + diffuse + specular;
+ if (gl_FragColor.a < 0.01) discard;
+
+ //gl_FragColor = vec4(normalize(normal).rgb, 1.0); // Debug
}
""" @ glsl_fragment_shader
# Specularity texture unit
var map_specular = uniforms["map_specular"].as(UniformSampler2D) is lazy
+ # Should this program use the texture `map_bump`?
+ var use_map_bump = uniforms["use_map_bump"].as(UniformBool) is lazy
+
+ # Bump texture unit
+ var map_bump = uniforms["map_bump"].as(UniformSampler2D) is lazy
+
# Normal per vertex
var normal = attributes["normal"].as(AttributeVec3) is lazy
end
# Program to color objects from their normal vectors
+#
+# May be used in place of `BlinnPhongProgram` for debugging or effect.
class NormalProgram
- super LambertProgram
+ super BlinnPhongProgram
redef var fragment_shader_source = """
precision mediump float;
end
redef class App
- private var versatile_program = new LambertProgram is lazy
+ private var versatile_program = new BlinnPhongProgram is lazy
private var normals_program = new NormalProgram is lazy
end