MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.39k stars 302 forks source link

lighting attributes #27

Closed edljk closed 6 years ago

edljk commented 6 years ago

Can we access/modify the lighting/reflectance properties of an object/mesh in Makie?

edljk commented 6 years ago

In link with lighting questions. The following example show an illumination different for spheres and cylinders whereas the source light seems to be the same. From one side, the spheres are brighting whereas the cylinder are dark and reversely on the other side of the grid. I suspect an orientation choice but this should only affect interior/exterior lighting differences of cylinders, no ?

using GeometryTypes, Makie

scene = Scene(resolution = (500, 500))
δx = 0.1; h1 = []; h2= []
for x in 0:δx:1
    for y in 0:δx:1
        h1 = mesh(Sphere(Point3f0(x, y, 0), Float32(δx * 0.35)))
        h2 = mesh(GLNormalMesh(Cylinder(Point3f0(x, y, 0),
                                        Point3f0(x + δx, y, 0),
                                        Float32(δx * 0.3)), 10))
    end
end
println(h1[:light])
println(h2[:light])
edljk commented 6 years ago

The lighting of the cylinders, pyramids, cubes and cats seems to be compatible and coherent with a light coming from Float32[20.0, 20.0, 20.0].

chess

using GeometryTypes, Makie, GLVisualize
scene = Scene(resolution = (500, 500))
δx = 0.1; nbc = 5; it = 0; h = []
for x in 0:δx:1
    for y in 0:δx:1
        h = if mod(it, nbc) == 0
            objG = Sphere(Point3f0(x, y, 0), Float32(δx * 0.35))
            mesh(GLNormalMesh(objG, 30))
        elseif  mod(it, nbc) == 1
            objG = Cylinder(Point3f0(x - δx / 2, y, 0), Point3f0(x + δx / 2, y, 0),
                            Float32(δx * 0.3))
            mesh(GLNormalMesh(objG, 30))
        elseif mod(it, nbc) == 2
            objG = GLVisualize.loadasset("cat.obj")
            meshscatter([Vec3f0(x, y, 0),], marker = GLNormalMesh(objG), markersize = 1.5 * δx)
        elseif mod(it, nbc) == 3
            objG = GeometryTypes.HyperRectangle(Vec3f0(- 1 / 2), Vec3f0(1 / 2))
            meshscatter([Vec3f0(x, y, 0),], marker = GLNormalMesh(objG), markersize = 1. * δx)
        elseif mod(it, nbc) == 4
            objG = GeometryTypes.Pyramid(Point3f0(0), 1f0, 1f0)
            meshscatter([Vec3f0(x, y, 0),], marker = GLNormalMesh(objG), markersize = 1. * δx)
        end
        it += 1
    end
end
println(h[:light])
Makie.axis(linspace(0, 1, 4), linspace(0, 1, 4), linspace(0, 1, 4))
Makie.center!(scene)
edljk commented 6 years ago

Should be fixed by the PR

chess

edljk commented 6 years ago

@SimonDanisch I am interested in looking at the possibilities to extend lighting options in Makie. Where should I start? I guess reflectance properties have first to be accessible in GLVisualize?

SimonDanisch commented 6 years ago

You can start by changing this shader to use uniforms instead of hard coded values:

https://github.com/JuliaGL/GLVisualize.jl/blob/master/assets/shader/standard.frag#L47

You can first do something like changing the hard coded vec3(0.1) to :

uniform vec3 diffuse_amount = vec3(0.1);

And then this should already work in a non breaking fashion:

_view(visualize(mesh, diffuse_amount = Vec3f0(0.5)))

Then you can start putting the defaults in: https://github.com/JuliaGL/GLVisualize.jl/blob/master/src/visualize_interface.jl#L8

And that's pretty much it :) The bigger change will be to have something that is global to a scene. But I think this will come pretty naturally in Makie!

edljk commented 6 years ago

Thank you for the precise road map! Nice, I will try this. By the way other constant vectors vec3(0.3), vec3(0.9)and vec(0.3) in the formula

return vec3(
        vec3(0.1) * vec3(0.3)  +
        vec3(0.9) * color * diff_coeff +
        vec3(0.3) * spec_coeff
);

have to be hard coded or they correspond to classical parameters? If it is the case what could be their name? I tried to identify them but their is plenty of different formula related to blinnphong..

Finally, I noticed that the light attribute in Makie is made of 4 vectors. The last one corresponds to the position. Do the others 3 should correspond to some of these vec3? Thanks.

edljk commented 6 years ago

I just have a more careful look to your last pointer and understood that diffuse_amount = vec3(0.1) should correspond to the second component of

_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)]

I see the vec3(0.9) but I do not know to which characteristic it corresponds. I do not know neither to which vector should correspond the first one Vec3f0(1.0,1.0,1.0). Sorry for the noise.

SimonDanisch commented 6 years ago

in this order: ambient, diffuse, specular.

Do the others 3 should correspond to some of these vec3?

Yes :) I think I used the same order for the light... Although ambient of 1.0 would be terrible... Just play around with it, and either swap them, or use the second slot as ambient.... Or maybe those values are all super bad :D I don't remember anymore why I took them out, and what they corresponded to last :(

Have a look at https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_shading_model to get an idea

edljk commented 6 years ago

OK, I will have a look when I find some time and let you know. Thanks for the details.

edljk commented 6 years ago

Some conclusions and (too much) questions. Based on wikipedia Blinn-Phong as suggested.

Fact that should be checked can I effectively conclude that color <-> lightColor * lightPower / distance

uniform vec3 ambientcolor = vec3(0.03); uniform vec3 diffusecolor = vec3(0.9); uniform vec3 specularcolor = vec3(0.3); uniform float shininess = 8.0;

and implement the new descriptions.

spheres

using GLVisualize, GeometryTypes, GLAbstraction, Colors, FileIO

window = GLVisualize.glscreen()

lightd = Vec3f0[Vec3f0(1.0,1.0,1.0), Vec3f0(0.1,0.1,0.1), Vec3f0(0.9,0.9,0.9), Vec3f0(0,0,200)]
for x = 0:2
    for y = 0:2
        dc = linspace(0, 2, 3)[x + 1]
        sc = linspace(0, 2, 3)[y + 1]
        sphere_mesh = GLNormalMesh(Sphere{Float32}(Point3f0(x, y, 0), 0.5f0), 50)
        GLVisualize._view(GLVisualize.visualize(sphere_mesh, color = RGBA{Float32}(1, 0, 0, 1.),
                                                ambientcolor = Vec3f0(0.01),
                                                diffusioncolor = Vec3f0(dc),
                                                specularcolor = Vec3f0(sc),
                                                light = lightd, shininess = Float32(3.)),
                                                window)
    end
end
GLVisualize.renderloop(window)
edljk commented 6 years ago

Proposal to be checked

Perhaps adding 3 last (?) intensity parameters ambientintensity, diffuseintensity and specularintensity. The last two could be by default equal to ~ 4 and this would be a simple way to have the possibility to force effects preserving colors in [0, 1] ^ 3, no? Thus we would have the final relation

ambientintensity * ambientcolor
+ diffuseintensity * diffusecolor * diff_coeff * color
+ specularintensity * specularcolor * spec_coeff * color

and the 4 new parameters ( ambientintensity, diffuseintensity, specularintensity, shininess) could be collected in a 5th vector of the lightarray?

At least this seems to be compatible with parameters illustrated in matlab help.

It would remain to define default parameters :-( and to connect the light fileds with these parameter.

edljk commented 6 years ago

With the above formulation, I tried to reproduce the two illustrations of matlab's help with the default parameters

uniform vec3 ambientcolor = vec3(0.03);
uniform vec3 diffusecolor = vec3(0.9);
uniform vec3 specularcolor = vec3(0.3);
uniform float ambientintensity = 1.;
uniform float diffuseintensity = 1.;
uniform float specularintensity = 1.;
uniform float shininess = 8.0;

The first tests seem to correspond whereas the results of the second one seem to me different but more intuitive..

sphereslighting

window = GLVisualize.glscreen()
lightd = Vec3f0[Vec3f0(1.0,1.0,1.0), Vec3f0(0.1,0.1,0.1), Vec3f0(0.9,0.9,0.9), Vec3f0(0,0,200)]
for x = 0:2
    for y = 0:2
        dc = linspace(0, 1, 3)[x + 1]
        sc = linspace(0, 1, 3)[2 - y + 1]
        sphere_mesh = GLNormalMesh(Sphere{Float32}(Point3f0(x, y, 0), 0.45f0), 50)
        GLVisualize._view(GLVisualize.visualize(sphere_mesh, color = RGBA{Float32}(1, 0, 0, 1.),
                                                ambientcolor = Vec3f0(0.03),
                                                diffusecolor = Vec3f0(0.9),
                                                specularcolor = Vec3f0(0.3),
                                                light = lightd, shininess = Float32(8.),
                                                ambientintensity = Float32(1),
                                                diffuseintensity = Float32(dc),
                                                specularintensity = Float32(sc)),
                                                window)#,  camera = :orthographic_pixel)
    end
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 / 2, 3)[y + 1] 
        sphere_mesh = GLNormalMesh(Sphere{Float32}(Point3f0(x , 2 - y - 4, 0), 0.45f0), 50)
        GLVisualize._view(GLVisualize.visualize(sphere_mesh, color = RGBA{Float32}(1, 0, 0, 1.),
                                                ambientcolor = Vec3f0(ac...),
                                                diffusecolor = Vec3f0(0.9),
                                                specularcolor = Vec3f0(0.3),
                                                light = lightd, shininess = Float32(8.),
                                                ambientintensity = Float32(as),
                                                diffuseintensity = Float32(1.),
                                                specularintensity = Float32(1.)),
                                                window)#,  camera = :orthographic_pixel)
    end
end
GLVisualize.renderloop(window)
SimonDanisch commented 6 years ago

Hm, I would have thought that the ambient light should change the color :D https://cglearn.codelight.eu/pub/computer-graphics/shading-and-lighting

edljk commented 6 years ago

It affects definitely the color (second test on the right) but it only changes dramatically the color if its intensity is sufficient..

Le 07/12/2017 à 11:33, Simon a écrit :

Hm, I would have thought that the ambient light should change the color :D https://cglearn.codelight.eu/pub/computer-graphics/shading-and-lighting

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/SimonDanisch/Makie.jl/issues/27#issuecomment-349928150, or mute the thread https://github.com/notifications/unsubscribe-auth/AOTEe-UGgU_JZU3XHoaU1kQJz3pW82PQks5s978LgaJpZM4Qx8ce.

-- Edouard Oudet : http://www-ljk.imag.fr/membres/Edouard.Oudet/ IMAG - Bureau 164 700 avenue Centrale 38400 Saint Martin d'Hères +33 (0)4 57 42 17 71 (office LJK) +33 (0)4 79 68 82 06 (home)

SimonDanisch commented 6 years ago

It affects definitely the color

I mean compared to matlab, your results seem more likely ;)

edljk commented 6 years ago

ah ok ;-), yes in fact !

SimonDanisch commented 6 years ago

They probably developed a plotting friendly shading model, that doesn't become super white and doesn't change the color too much ;)

edljk commented 6 years ago

Still some remarks on the lighting

edljk commented 6 years ago

@SimonDanisch I guess points (1) above requires a global point of view of the design of Makie.jl and how it interacts with the GL* packages, while (3) seems to me more related to the shader. Unfortunately, I can not help directly to improve (1) & (3) but if you have some idea of intermediate tasks, I would be happy to contribute. Point (2) looks more straightforward(?)

SimonDanisch commented 6 years ago

we could implement previous options but I do not know how to attach uniform data to light vectors/parameters

What is exactly the problem? just pass the data as a keyword argument to GLVisualize and it should pick it up automatically. For Makie, that's not always true since I do some filtering, but we could include it ;)

2) Yeah, they should all be the same and controlled by the same uniforms. I think the only exception was the volume shader, where performance is a bit more crucial so a simpler version might be appropriate - but it should still use the same uniforms!

3) In Makie, missing attributes will be inherited from the parent scene, so if you don't pass a light attribute to a plotting function, they should all end up with the same light uniforms!

edljk commented 6 years ago

(1) & (3) Ah, I see, when you write uniform you mean a single light. "The problem" was for me precisely related to several lights: I do not know how to attach the (global/uniform) parameters to a specific light. Actually, I understood that this possibility does not exist for the moment but it seems to me that it is perhaps more efficient to define the strategy to have several lights before to give the possibility to adjust parameters, no?

(2) You mean only keep the definition of blinnphong function only in standard.frag ("extended" version), and volume.frag (actual version)?

SimonDanisch commented 6 years ago

1) You could do something like:


struct Light{
vec3 color;
vec3 position;
...
};
uniform Light[5] lights; // 5 lights

But sadly the infrastructure in GLAbstraction isn't ready for that quite yet. GLSL does it best to make arrays of structs awkward. I've some prototypes for this, but was never 100% sure how to integrate it into the current design. Let me think about this, maybe there is an easy adhoc solution!

2) not sure what you mean by actual version... But I'd be happy with any solution that unifies things, without drastically reducing performance of the iso surface rendering ;)

edljk commented 6 years ago

I just found this

GLSL tuto on multiple lights

which looks very close to what we are looking for. Also the fields of a light are a little bit different but seem more generic! Additionally, it also implements the material properties which could be very convenient in some specific situations.

I could try to follow very closely (~ copy / paste) this code or do you see source of troubles in GLVisualize context? This would define a new type light and a new type material.

Last naive question: Is the const type in const int numberOfLights = 2; mandatory..?

SimonDanisch commented 6 years ago

Well, that's very close to what I've suggested, and comes exactly with the problems I mentioned... Although the posted code doesn't actually have the problems, since it hard codes the light sources so they don't need to get set from the julia side, but I'm sure that's not what you're aiming for ;)

Yes, I think the const is needed, you can't have the size of the array be non const.

edljk commented 6 years ago

Ah ok sorry, this is the GLAbstraction infrastructure point you mentioned related to GLSL structures.

For me this pointer was a progress since I was not sure how to define/tune all these parameters and this piece of code seems to me generic enough for most situations. I guess you already had a look to it in the past ;-)

SimonDanisch commented 6 years ago

Yes I did ;) Yeah passing arrays of struct to OpenGL is no fun... Well if you want, play around with it with hardcoded values as in the example, and hopefully I can backport some code from Visualize.jl, where I have the struct stuff figured all out...

edljk commented 6 years ago

Actually, we could also use the convenient structure at julia level and pass an array of array if it is simpler. The crucial point would be the non fixed size of the array (== nb of lights). I guess it would have the same complexity..? Perfect plan for me, I will first try to get familiar with the model using hardcoded values.

edljk commented 6 years ago

I tried to have a look and it compiles..but the current experimental version gives me only black object :-). Regarding the GLSL code, (at least) two points are not clear to me

SimonDanisch commented 6 years ago

yes, material.diffuse == color

edljk commented 6 years ago

OK cool! Thanks. Let's forget spotlights for the moment ;-)

edljk commented 6 years ago

OK, I managed to make it work in a very pedestrian way. Sorry for the naivety of the code!! Finally

uniform vec3 ambientcolor;
const int numberOfLights = 5;
struct lightSource
{
    vec3 color;
    vec3 position;
    int onoff; // == 0 or 1
};
uniform vec3 position1;
uniform vec3 position2;
uniform vec3 position3;
uniform vec3 position4;
uniform vec3 position5;
uniform vec3 colorlight1;
uniform vec3 colorlight2;
uniform vec3 colorlight3;
uniform vec3 colorlight4;
uniform vec3 colorlight5;
uniform int onoff1; uniform int onoff2;
uniform int onoff3; uniform int onoff4; uniform int onoff5;
lightSource light0 = lightSource(
    colorlight1,    // color
    position1,      // position
    onoff1
);
lightSource light1 = lightSource(
    colorlight2,    // color
    position2,      // position
    onoff2
);
lightSource light2 = lightSource(
    colorlight3,    // color
    position3,      // position
    onoff3
);
lightSource light3 = lightSource(
    colorlight4,    // color
    position4,      // position
    onoff4
);
lightSource light4 = lightSource(
    colorlight5,    // color
    position5,      // position
    onoff5
);
lightSource lights[numberOfLights];
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 Nothing{ //Nothing type, to encode if some variable doesn't contain any data
    bool _; //empty structs are not allowed
};

in vec3 o_normal;
in vec3 o_lightdir;
in vec3 o_vertex;
in vec4 o_color;
in vec2 o_uv;
flat in uvec2 o_id;

{{color_type}} color;

vec4 get_color(vec3 color, vec2 uv){
    return vec4(color, 1.0 + (0.0 * uv)); // we must prohibit uv from getting into dead variable removal
}

vec4 get_color(vec4 color, vec2 uv){
    return color + uv.x * 0.0; // we must prohibit uv from getting into dead variable removal
}

vec4 get_color(Nothing color, vec2 uv){
    return o_color + uv.x * 0.0;
}
vec4 get_color(samplerBuffer color, vec2 uv){
    return o_color + uv.x * 0.0;
}

vec4 get_color(sampler2D color, vec2 uv){
    return texture(color, uv);
}

/*
1) L light direction still needed as input parameters?
2) Term pow(max(0.0, dot(reflect(-L, N), V)), shininess) different
   from first implementation??
*/
vec3 blinnphong(vec3 N, vec3 V, vec3 L, 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)
        {
            //??? L
            L = normalize(vec3(lights[index].position));

            vec3 diffuseReflection = material[1] * vec3(lights[index].color) *
                                     max(0.0, dot(N, L)) * color;

            vec3 specularReflection;
            if (dot(N, L) < 0.0) // light source on the wrong side?
            {
                specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection
            }
            else // light source on the right side
            {
                vec3 specularcolor = (1 - material[3]) * vec3(lights[index].color) +
                                      material[3] *vec3(1);
                specularReflection = material[2] * vec3(specularcolor) *
                                     pow(max(dot(L, N), 0.0), shininess);
            }
            totalLighting = totalLighting + diffuseReflection + specularReflection;
        }
    }
    return totalLighting;
}

and the piece of code in vizualize_interface.jl is simply

@gen_defaults! data begin # make sure every object has these!
        model = eye(Mat4f0)
        light = _default_light
        preferred_camera = :perspective
        is_transparent_pass = Cint(false)

        # default lights attributes of a scene
        material = Vec4f0(1., 0.4, 0.5, 1.) # (ambient, diffuse, specular, specularcolorcoeff) ∈ [0, 1]
        shininess = Float32(8.); ambientcolor = Vec3f0(0.01)
        onoff1 = 1; position1 = Vec3f0(10.0,  100.0, 200.0); colorlight1 = Vec3f0(1.)
        onoff2 = 0; position2 = Vec3f0(10.0,  100.0, -200.0); colorlight2 = Vec3f0(1.)
        onoff3 = 0; position3 = Vec3f0(10.0,  100.0, 200.0); colorlight3 = Vec3f0(1.)
        onoff4 = 0; position4 = Vec3f0(10.0,  100.0, 200.0); colorlight4 = Vec3f0(1.)
        onoff5 = 0; position5 = Vec3f0(10.0,  100.0, 200.0); colorlight5 = Vec3f0(1.)
    end

Illustration of two lights in a single scene and other material properties side 1/ side 2

side1 side2

and the example code

window = GLVisualize.glscreen(); δ = 0.45
lightd = Vec3f0[Vec3f0(1.0, 1.0, 1.0), Vec3f0(0.1, 0.1, 0.1),
                Vec3f0(0.9, 0.9, 0.9), Vec3f0(10, 50, 200)]
markerm = :o
#markerm = :□
for x = 0:2
    for y = 0:2
        dc = linspace(0, 0.5, 3)[x + 1]
        sc = linspace(0, 0.5, 3)[2 - y + 1]
        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 = Float32(8.),
                                                material = material,
                                                position1 = Vec3f0(100), onoff2 = 1, colorlight1 = Vec3f0(0.8),
                                                ambientcolor = Vec3f0(0.01)), window)
    end
end
cd = 1.
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
        ac /= cd
        as = linspace(0, 0.5, 3)[y + 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, 0.4, 0.8, 1.)
        GLVisualize._view(GLVisualize.visualize(lmesh, color = RGBA{Float32}(1, 0, 0, 1.),
                                                ambientcolor = Vec3f0(ac...),
                                                light = lightd, shininess = Float32(8.),
                                                material = material), window)
    end
end
GLVisualize.renderloop(window)
edljk commented 6 years ago

Since the modifications described below,

scene = Makie.Scene(resolution = (500, 500))
Makie.mesh(GLNormalMesh(Sphere{Float32}(Point3f0(0), Float32(1)), 50))
center!(scene)

produces a colored shining sphere whereas

scene = Makie.Scene(resolution = (500, 500))
Makie.meshscatter([Vec3f0(0),], maker = GLNormalMesh(Sphere{Float32}(Point3f0(0), Float32(1)), 50))
center!(scene)

produces a black sphere (no light, no colors).. Any idea of what could be at the origin of the problem?

SimonDanisch commented 6 years ago

You haven't updated particles.vert?

edljk commented 6 years ago

No, should I?

SimonDanisch commented 6 years ago

I guess, it also uses standard.frag, and I'm guessing it's not receiving the correct inputs? Or did you actually not touch any vertex shader at all?

edljk commented 6 years ago
git diff master lightattributes

only gives me differences between the assets/shader/standard.frag, assets/shader/uv_normal.frag and src/visualize_interface.jl files.

SimonDanisch commented 6 years ago

ah maybe, meshscatter doesn't pass through the attributes or something...

SimonDanisch commented 6 years ago

can you open a PR so that I can have a look at it?

edljk commented 6 years ago

Here it is lights attributes. Thanks.

edljk commented 6 years ago

Changing the two lines

https://github.com/SimonDanisch/Makie.jl/blob/7c3b3fdeb276f870ca334a9538604f378f9a88ee/src/atomics/scatter.jl#L103-L104

into

viz = visualize(main, Style(:default), gl_data).children[]

seems to fix the problem

edljk commented 6 years ago

I try to identify what could be a more general but still efficient and generic way of handling lighting. Let us first focalize on GLVisualize and the shader:

If we take that direction we need to:

  1. define default values in src/vizualize_interface.jl
  2. write a small conversion of the lights positions / colors to the limited number of global parameters of our blinnphong function. Where/when should we define/call such a function? . In utils.jl, in the function assemble_shader seems to be a reasonable place.
  3. update the files assets/shader/standard.frag and assets/shader/uv_normal.frag with the new blinnphong function.
  4. update light_calc to cancle backlighting but enables backlighting by default when using a single light.
  5. for compatibility, make sure volume.frag is ok with previous changes: is it still possible to have an efficient and simple lighting ;-)?
edljk commented 6 years ago

It would give something like this PR