diff --git a/assets/shader/standard.frag b/assets/shader/standard.frag index d475d17..0e850c4 100644 --- a/assets/shader/standard.frag +++ b/assets/shader/standard.frag @@ -1,5 +1,58 @@ {{GLSL_VERSION}} - +/////////////////////////////////////////////////////////////////////////////// +const int numberoflights = 5; +uniform vec3 ambientcolor;// = vec3(0.3, 0.3, 0.3); +uniform vec4 material; // = vec4(1., 0.4, 0.5, 1.); +/* +(ambient, diffuse, specular, specularcolorcoeff) ∈ [0, 1] +default vec4(1., 0.4, 0.5, 1.); +*/ +uniform float shininess; +struct lightSource +{ + vec3 color; + vec3 direction; + int onoff; // == 0 or 1 +}; +uniform vec3 lightdirection1; +uniform vec3 lightdirection2; +uniform vec3 lightdirection3; +uniform vec3 lightdirection4; +uniform vec3 lightdirection5; +uniform vec3 lightcolor1; +uniform vec3 lightcolor2; +uniform vec3 lightcolor3; +uniform vec3 lightcolor4; +uniform vec3 lightcolor5; +uniform int onoff1; uniform int onoff2; +uniform int onoff3; uniform int onoff4; uniform int onoff5; +lightSource light0 = lightSource( + lightcolor1, // color + lightdirection1, // direction + onoff1 +); +lightSource light1 = lightSource( + lightcolor2, // color + lightdirection2, // direction + onoff2 +); +lightSource light2 = lightSource( + lightcolor3, // color + lightdirection3, // direction + onoff3 +); +lightSource light3 = lightSource( + lightcolor4, // color + lightdirection4, // direction + onoff4 +); +lightSource light4 = lightSource( + lightcolor5, // color + lightdirection5, // direction + onoff5 +); +lightSource lights[numberoflights]; +/////////////////////////////////////////////////////////////////////////////// struct Nothing{ //Nothing type, to encode if some variable doesn't contain any data bool _; //empty structs are not allowed }; @@ -31,25 +84,43 @@ vec4 get_color(samplerBuffer color, vec2 uv){ vec4 get_color(sampler2D color, vec2 uv){ return texture(color, uv); } +// http://www.opengl-tutorial.org/fr/beginners-tutorials/tutorial-8-basic-shading/ +// https://github.com/JuliaGL/GLVisualize.jl/blob/master/assets/shader/standard.frag +// https://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Multiple_Lights +// https://fr.mathworks.com/matlabcentral/answers/91652-how-do-the-ambientstrength-diffusestrength-and-specularstrength-properties-of-the-material-command +vec3 blinnphong(vec3 N, vec3 V, vec3 color){ + // define lights + lights[0] = light0; + lights[1] = light1; + lights[2] = light2; + lights[3] = light3; + lights[4] = light4; + // initialize total lighting with ambient lighting + vec3 totalLighting = material[0] * vec3(ambientcolor); -vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color){ - float diff_coeff = max(dot(L, N), 0.0); - - // specular coefficient - vec3 H = normalize(L+V); + for (int index = 0; index < numberoflights; index++) // for all light sources + { + if (lights[index].onoff == 1) + { + vec3 Ldir = normalize(vec3(lights[index].direction)); + float cosTheta = clamp(dot(Ldir, N), 0, 1); + vec3 R = reflect(- Ldir, N); + // should the normalize(vec3(1)) be replaced by E = normalize(EyeDirection_cameraspace) + float cosAlpha = clamp(dot(R, normalize(vec3(1))), 0, 1); - float spec_coeff = pow(max(dot(H, N), 0.0), 8.0); - if (diff_coeff <= 0.0) - spec_coeff = 0.0; - - // final lighting model - return vec3( - vec3(0.1) * vec3(0.3) + - vec3(0.9) * color * diff_coeff + - vec3(0.3) * spec_coeff - ); + vec3 diffuseReflection = material[1] * vec3(lights[index].color) * + cosTheta * color; + vec3 specularcolor = (1 - material[3]) * vec3(lights[index].color) + + material[3] * vec3(1); + vec3 specularReflection = material[2] * vec3(specularcolor) * + pow(cosAlpha, shininess); + totalLighting = totalLighting + diffuseReflection + specularReflection; + } + } + return totalLighting; } + void write2framebuffer(vec4 color, uvec2 id); void main(){ diff --git a/assets/shader/uv_normal.frag b/assets/shader/uv_normal.frag index 854f23e..e091188 100644 --- a/assets/shader/uv_normal.frag +++ b/assets/shader/uv_normal.frag @@ -1,5 +1,58 @@ {{GLSL_VERSION}} - +/////////////////////////////////////////////////////////////////////////////// +const int numberoflights = 5; +uniform vec3 ambientcolor;// = vec3(0.3, 0.3, 0.3); +uniform vec4 material; // = vec4(1., 0.4, 0.5, 1.); +/* +(ambient, diffuse, specular, specularcolorcoeff) ∈ [0, 1] +default vec4(1., 0.4, 0.5, 1.); +*/ +uniform float shininess; +struct lightSource +{ + vec3 color; + vec3 direction; + int onoff; // == 0 or 1 +}; +uniform vec3 lightdirection1; +uniform vec3 lightdirection2; +uniform vec3 lightdirection3; +uniform vec3 lightdirection4; +uniform vec3 lightdirection5; +uniform vec3 lightcolor1; +uniform vec3 lightcolor2; +uniform vec3 lightcolor3; +uniform vec3 lightcolor4; +uniform vec3 lightcolor5; +uniform int onoff1; uniform int onoff2; +uniform int onoff3; uniform int onoff4; uniform int onoff5; +lightSource light0 = lightSource( + lightcolor1, // color + lightdirection1, // direction + onoff1 +); +lightSource light1 = lightSource( + lightcolor2, // color + lightdirection2, // direction + onoff2 +); +lightSource light2 = lightSource( + lightcolor3, // color + lightdirection3, // direction + onoff3 +); +lightSource light3 = lightSource( + lightcolor4, // color + lightdirection4, // direction + onoff4 +); +lightSource light4 = lightSource( + lightcolor5, // color + lightdirection5, // direction + onoff5 +); +lightSource lights[numberoflights]; +/////////////////////////////////////////////////////////////////////////////// in vec3 o_normal; in vec3 o_lightdir; in vec3 o_vertex; @@ -10,27 +63,6 @@ flat in uvec2 o_id; out vec4 fragment_color; out uvec2 fragment_groupid; - -vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color) -{ - float diff_coeff = max(dot(L,N), 0.0); - - // specular coefficient - vec3 H = normalize(L+V); - - float spec_coeff = pow(max(dot(H,N), 0.0), 8.0); - if (diff_coeff <= 0.0) - spec_coeff = 0.0; - - // final lighting model - return vec3( - vec3(0.1) * vec3(0.3) + - vec3(0.9) * color * diff_coeff + - vec3(0.3) * spec_coeff); -} - - - const float ALIASING_CONST = 0.70710678118654757; float aastep(float threshold1, float threshold2, float value) { @@ -51,13 +83,47 @@ float square(vec2 uv) ((1-xmin)*(1-xmax))*ymax; } +vec3 blinnphong(vec3 N, vec3 V, vec3 color){ + // define lights + lights[0] = light0; + lights[1] = light1; + lights[2] = light2; + lights[3] = light3; + lights[4] = light4; + // initialize total lighting with ambient lighting + vec3 totalLighting = material[0] * vec3(ambientcolor); + + for (int index = 0; index < numberoflights; index++) // for all light sources + { + if (lights[index].onoff == 1) + { + vec3 Ldir = normalize(vec3(lights[index].direction)); + float cosTheta = clamp(dot(Ldir, N), 0, 1); + vec3 R = reflect(- Ldir, N); + // should the normalize(vec3(1)) be replaced by E = normalize(EyeDirection_cameraspace) + float cosAlpha = clamp(dot(R, normalize(vec3(1))), 0, 1); + + vec3 diffuseReflection = material[1] * vec3(lights[index].color) * + cosTheta * color; + vec3 specularcolor = (1 - material[3]) * vec3(lights[index].color) + + material[3] * vec3(1); + vec3 specularReflection = material[2] * vec3(specularcolor) * + pow(cosAlpha, shininess); + totalLighting = totalLighting + diffuseReflection + specularReflection; + } + } + return totalLighting; +} + void main(){ vec3 L = normalize(o_lightdir); vec3 N = normalize(o_normal); vec3 f_color = mix(vec3(0,0,1), vec3(1), square(o_uv)); - vec3 light1 = blinnphong(N, o_vertex, L, f_color); - vec3 light2 = blinnphong(N, o_vertex, -L,f_color); - fragment_color = vec4(light1+light2*0.4, 1.0); + //vec3 light1 = blinnphong(N, o_vertex, L, f_color); + //vec3 light2 = blinnphong(N, o_vertex, -L,f_color); + //fragment_color = vec4(light1+light2*0.4, 1.0); + vec3 light1 = blinnphong(N, o_vertex, f_color); + fragment_color = vec4(light1, 1.0); if(fragment_color.a > 0.0) fragment_groupid = o_id; } diff --git a/examples/lights/lighting.jl b/examples/lights/lighting.jl new file mode 100644 index 0000000..680fbf9 --- /dev/null +++ b/examples/lights/lighting.jl @@ -0,0 +1,51 @@ +using GLVisualize, GeometryTypes, GLAbstraction, Colors, FileIO + +window = GLVisualize.glscreen(); δ = 0.45 +ambientcolordefault = Vec3f0(0.1) +materialdefault = Vec4f0(0.9, 0.7, 0.3, 0.9) # (ambient, diffuse, specular, specularcolorcoeff) ∈ [0, 1] +shininessdefault = Float32(5.) +lightd = Vec3f0[Vec3f0(1.0, 1.0, 1.0), Vec3f0(0.1, 0.1, 0.1), + Vec3f0(0.9, 0.9, 0.9), Vec3f0(20, 0, 20)] +markerm = :o +for x = 0:2 + for y = 0:2 + dc = linspace(0, 1, 3)[x + 1] * materialdefault[2] + sc = linspace(0, 1, 3)[3 - y] * materialdefault[3] + lmesh = if markerm == :o + GLNormalMesh(Sphere{Float32}(Point3f0(x, y, 0), Float32(δ)), 50) + elseif markerm == :□ + GLNormalMesh(GeometryTypes.HyperRectangle(Vec3f0(x - δ, y - δ , - δ), + Vec3f0(3 * δ / 2, 3 * δ / 2 , 3 * δ / 2))) + end + material = Vec4f0(1, dc, sc, 1.) + GLVisualize._view(GLVisualize.visualize(lmesh, color = RGBA{Float32}(1, 0, 0, 1.), + light = lightd, shininess = shininessdefault, + material = material, + ambientcolor = Vec3f0(0.01)), window) + end +end +lighting = GLVisualize.Lighting([lightd[end],]) +for x = 0:2 + for y = 0:2 + ac = if x == 0 + [0, 1, 0] + elseif x == 1 + [0.5, 0, 1] + elseif x == 2 + ones(3) + end + as = linspace(0, 1, 3)[y + 1] * materialdefault[1] + lmesh = if markerm == :o + GLNormalMesh(Sphere{Float32}(Point3f0(x , 2 - y - 4, 0), Float32(δ)), 50) + elseif markerm == :□ + GLNormalMesh(GeometryTypes.HyperRectangle(Vec3f0(x - δ, 2 - y - δ - 4 , - δ), + Vec3f0(3 * δ / 2, 3 * δ / 2 , 3 * δ / 2))) + end + material = Vec4f0(as, materialdefault[2:end]...) + GLVisualize._view(GLVisualize.visualize(lmesh, color = RGBA{Float32}(1, 0, 0, 1.), + ambientcolor = Vec3f0(ac...), + lighting = lighting, shininess = shininessdefault, + material = material), window) + end +end +GLVisualize.renderloop(window) diff --git a/src/types.jl b/src/types.jl index 28286de..e664248 100644 --- a/src/types.jl +++ b/src/types.jl @@ -269,3 +269,35 @@ struct GLVisualizeShader <: AbstractLazyShader new(map(x-> assetpath("shader", x), paths), args) end end + +# lighting related type +""" + Lighting(directions::Array{Vec3f0, 1}, colors::Array{Vec3f0, 1}, + ambientcolor::Vec3f0, material::Vec4f0, shininess::Float32) + +# Arguments +* the single attribute light is still take into account if :light[end] != default_light + using the backlight intensity 0.4 +* material descibes the fields (ambient, diffuse, specular, specularcolorcoeff) ∈ [0, 1] +""" +struct Lighting + directions::Array{Vec3f0, 1} + colors::Array{Vec3f0, 1} + ambientcolor::Vec3f0 + material::Vec4f0 + shininess::Float32 +end +ambientcolordefault = Vec3f0(0.1) +materialdefault = Vec4f0(.9, 0.7, 0.3, .9) +shininessdefault = Float32(5.) +function Lighting(lights::Array{Vec3f0, 1}) + Lighting(lights, [Vec3f0(1.) for k = 1:length(lights)], + ambientcolordefault, materialdefault, shininessdefault) +end +function Lighting(lights::Array{Vec3f0, 1}, lightscolors::Array{Vec3f0, 1}) + Lighting(lights, lightscolors, + ambientcolordefault, materialdefault, shininessdefault) +end +function GLAbstraction.gl_convert(x::GLVisualize.Lighting) + return x +end diff --git a/src/utils.jl b/src/utils.jl index 70de077..96440ea 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -50,10 +50,46 @@ function assemble_robj(data, program, bb, primitive, pre_fun, post_fun) robj end +function lightingoptions!(data) + numberoflights = 5 + _default_light = Vec3f0(20, 20, 20) + if value(data[:light])[end] != _default_light + # default direct and back lighting using the signgle attribute light + # using the initial light of intensity 0.4 + data[:lighting] = Lighting([value(data[:light])[end], Vec3f0(-[value(data[:light])[end]...])], + [Vec3f0(1), Vec3f0(0.4)]) + end + # export values in hard coded variables + for k = 1:numberoflights + data[Symbol("onoff", string(k))] = 0 + data[Symbol("lightdirection", string(k))] = Vec3f0(0) + data[Symbol("lightcolor", string(k))] = Vec3f0(1) + end + for k = 1:min(numberoflights, length(value(data[:lighting]).directions)) + data[Symbol("onoff", string(k))] = 1 + data[Symbol("lightdirection", string(k))] = value(data[:lighting]).directions[k] + data[Symbol("lightcolor", string(k))] = value(data[:lighting]).colors[k] + end + # add ambientcolor / material / shininess if not defined by argument + if :ambientcolor ∉ keys(data) + data[:ambientcolor] = value(data[:lighting]).ambientcolor + end + if :material ∉ keys(data) + data[:material] = value(data[:lighting]).material + end + if :shininess ∉ keys(data) + data[:shininess] = value(data[:lighting]).shininess + end + for symbl in [:ambientcolor, :material, :shininess] + data[symbl] = value(data[symbl]) + end + data +end function assemble_shader(data) shader = data[:shader] delete!(data, :shader) + lightingoptions!(data) default_bb = Signal(centered(AABB)) bb = get(data, :boundingbox, default_bb) if bb == nothing || isa(bb, Signal{Void}) diff --git a/src/visualize/surface.jl b/src/visualize/surface.jl index 5d51640..38a7a3b 100644 --- a/src/visualize/surface.jl +++ b/src/visualize/surface.jl @@ -54,11 +54,9 @@ end function light_calc(x::Bool) if x """ - vec3 L = normalize(o_lightdir); vec3 N = normalize(o_normal); - vec3 light1 = blinnphong(N, o_vertex, L, color.rgb); - vec3 light2 = blinnphong(N, o_vertex, -L, color.rgb); - color = vec4(light1 + light2 * 0.4, color.a); + vec3 light1 = blinnphong(N, o_vertex, color.rgb); + color = vec4(light1, color.a); """ else "" diff --git a/src/visualize_interface.jl b/src/visualize_interface.jl index 2b5c4b2..4c51e85 100644 --- a/src/visualize_interface.jl +++ b/src/visualize_interface.jl @@ -1,10 +1,14 @@ function default(main::ANY, s::ANY, data::ANY) - _default_light = Vec3f0[Vec3f0(1.0,1.0,1.0), Vec3f0(0.1,0.1,0.1), Vec3f0(0.9,0.9,0.9), Vec3f0(20,20,20)] + # other default lights attributes of a scene are defined in utils.jl + # in the function lightingoptions! + _default_light = Vec3f0[Vec3f0(1.0, 1.0, 1.0), Vec3f0(20, 20, 20)] data = _default(main, s, copy(data)) @gen_defaults! data begin # make sure every object has these! model = eye(Mat4f0) light = _default_light + lighting = Lighting([_default_light[end], Vec3f0(-[_default_light[end]...])], + [Vec3f0(1), Vec3f0(0.4)]) preferred_camera = :perspective is_transparent_pass = Cint(false) end