Page MenuHome

Add rectangle and ellipse shape to spotlights
ClosedPublic

Authored by Mitchell Stokes (moguri) on Jun 25 2015, 11:58 PM.

Details

Summary

Hi, this patch adds rectangle and ellipse shape to spotlights instead of square. Please let me know what do you think about the idea and the patch itself. The startup.blend in release/datafiles has to be modified: (modify spotlamp rectangle sizeX/Y to 1.0f and save startup file (this worked for me...))

Diff Detail

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes

Hi! Thanks HG1 for review :) About the 0.85f in the shader code, I can't explain it unless "it does not work correctly without" (It doesn't fit the circle dotted lines)... But maybe the formula isn't correct. I just played with the formula of the link to have a result which sounds good to me but I didn't understand it. Maybe someone could find a better formula or could explain mine :) .
I haven't found where I can add a notifier to update light when we press "S" key (I've not much time this days but I'll ask on IRC).

Updated for the last version of the trunk. Now you can scale with S+X and S+Y.

@Thomas Szepe (hg1): I realized that if I computed scale*0.85 in gpu_material.c, the spotScale option in the BGE didn't worked as expected so I put the code in the glsl shader...

Z scale option (should have the same effect than spotsize) is still missing but I could, if you agree, try to implement the Z scaling according to spotsize...?

Do you agree with the design choice? Before, I took example on area size, spotblend and other lamps options but know, I don't know where I have to put the code (for example, I did not know if I had to add the notifiers to update the lights in gpu_material.c or in rna_object.c or elsewhere...)?

source/blender/makesdna/DNA_lamp_types.h
61

This is calculated at runtime and differs for each object now, so this should be removed.

source/gameengine/Ketsji/KX_Light.cpp
456–478

Can't this be removed? and the BGE can use the object size - as with Blender.

Campbell Barton (campbellbarton) requested changes to this revision.Jul 23 2015, 11:19 AM
Campbell Barton (campbellbarton) edited edge metadata.
Campbell Barton (campbellbarton) added inline comments.
source/blender/editors/transform/transform.c
3388–3392 ↗(On Diff #4702)

This is an unreliable way to enforce scale updates the lamp.
Since you could scale object in scale buttons, or Alt+S to remove scale, or animated scale.


I think attempting to have this NC_LAMP notifier called on any object scale is unreliable.

Since the lamp already redraws and moves without having to get a notifier when location changes. Am not sure why this is needed, but also dont know answer,.... would need to try get it working myself. It just seems like it shouldn't be needed.

This revision now requires changes to proceed.Jul 23 2015, 11:19 AM

@Campbell Barton (campbellbarton): Thanks for review! About float spotscale[2] in DNA_lamp_types: I think it's a good idea to keep this attribute for lamp since I'm using it in a lot files and it's not always easy (I don't know an easy way) to access "lamp object" from lamp. But if someone gives me a tip to access "lamp object" from lamp, I can remove this and each time I call lamp->spotscale, I'll replace it with Object *ob = lamp->id->object/data??? (something like that)> But I may have to include DNA_object_types in some files... For the moment, I make the link beetween lamp->spotscale and object->obmat in gpu_material.c in the gpu_lamp_from_blender function line 1912.

About the second point: Can this be removed in KX_Light.cpp: This could be removed but: - This part (up) of the code can be used to change color of a lamp too this way: lamp.color[0] = 1.0.
If you remove this part of the code, you have to write lamp.color = [1.0, 0.0, 0.0] (you can't set each rgb component separately. Same for the scale.

  • If you use object scale instead of spotscale, you loose some controls on the lamp children behaviour and the lamp physics (Personnaly, I think that it's better to keep the possibility to 1) scale the object light/ 2) only modifiy the shape of the light itself (it costs nothing, you have more control, Blender internal users don't care about it, it concerns only bge).

About the third point: You're right. It's a mess to add notifiers each time you use SKEY, you release SKEY, you use ALT+S etc... What you can try if you want is to add a notifier only in gpu_material.c in gpu_lamp_from_blender function. example: if (something):
{
lamp->spotvec[0] = len_v3(ob->obmat[0]);
lamp->spotvec[1] = len_v3(ob->obmat[1]);

copy_v2_v2(la->spotscale, lamp->spotvec);

DAG_id_tag_update(&la->id, 0);

WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, la);
}

If you don't use an if statement, this part of the code will slow down blender (you can try by dupicating spots). The problem is to find this "something" in the if statement. I did not succeed to find what to put in this condition. So I tried to add notifiers in transform.c (applyResize, and line 1255 case RIGHTMOUSE (to cancel transformation) and in other parts of the code...), and in RNA_object.c (rna_Object_internal_update).

Anyway, the last version of the patch needs many improvements. I think I'll delete the ellipse spot support for the moment, and I have to find a proper way to update spotlight shape each time we use SKEY for scaling. I may need help for this (if someone has any suggestion :) ? ). Tell me @Campbell Barton (campbellbarton) if you continue to disagree with the first and the second point :) . I'll try to find a way to satisfy everyone.

Have all a wonderfull day/night :)

It seems I was tired when I tried to update lamp in gpu_material.c:

That works this way:

#include "BKE_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"

lamp->spotvec[0] = len_v3(ob->obmat[0]);
lamp->spotvec[1] = len_v3(ob->obmat[1]);
if (la->spotscale[0] != len_v3(ob->obmat[0]) || la->spotscale[1] != len_v3(ob->obmat[1]))
{
copy_v2_v2(la->spotscale, lamp->spotvec);
DAG_id_tag_update(&la->id, 0);
WM_main_add_notifier(NC_LAMP | ND_LIGHTING_DRAW, la);
}

Can I do like this? I make a little clean up, remove ellipse support, and update the .diff

No, That doesn't work :( . Sorry, I may have tested with the wrong blender.exe :) ... Or I'm missing something. If you have a tip, it will be welcome!

Ulysse Martin (youle) edited edge metadata.

Hi! I simplified a lot the patch considering Campbell Barton's recommandations. But 1 problem remains: the realtime spotlamp textures update in the viewport: http://www.mediafire.com/watch/js3vzz3hjbtk57a/capture-1.avi (you have to call rna_Lamp_draw_update in rna_lamp.c to make it work but I don't know how to call this function only each time you press a scale button or "S" key). TristanPorteries suggested me to update lamp->viewmat with scaling factors in GPU_lamp_update_buffer_mats in gpu_material.c, but I didn't found a way to make it work properly (causes problems in the game engine). If anybody has a suggestion to solve this problem, it will be welcome. I haven't included spotlamps ellipse support to make it easier to review. Thanks! I'll be very grateful if someone can help me to solve this last bug.

My testFile: http://www.pasteall.org/blend/37714

Ulysse Martin (youle) edited edge metadata.
Ulysse Martin (youle) marked 15 inline comments as done.

Hi! It seems that moving gpu_lamp_calc_winmat(lamp); from gpu_lamp_update_spot to gpu_lamp_update function in gpu_material.c solved the problem. I removed also an useless line in gpu_lamp_update_spot. So I don't see any problem now. I'll make more tests but I think it's good...

source/blender/editors/space_view3d/drawobject.c
1100

Remove this line.

source/blender/gpu/intern/gpu_material.c
1864

and readd thsi line

1899

it's to avoid double update ? you can't move before gpu_lamp_calc_winmat ?

	​ lamp->spotvec[0] = len_v3(obmat[0]);
	​ lamp->spotvec[1] = len_v3(obmat[1]);
Ulysse Martin (youle) retitled this revision from Add rectangle shape to spotlights to Add rectangle and ellipse shape to spotlights.
Ulysse Martin (youle) updated this object.

Finally I added ellipse shape support for spotlights. I removed gpu_lamp_calc_winmat(lamp); from GPU_lamp_update_spot function (only used in the game engine in RAS_OpenGLLight.cpp) and moved gpu_lamp_calc_winmat(lamp); from static void gpu_lamp_from_blender to void GPU_lamp_update (in order to update lamp textures in realtime in the viewport >scaling textures is now also available for pointlights).

@Ulysse Martin (youle): now you use the scale from the matrix so all variables for the 2d spot scale can be removed ? stop me if i'm wrong.
I tested the patch, all seems work properly.

source/blender/gpu/intern/gpu_material.c
1908

you can remove argument spotscale.

1958

Please add a code comment why you commented this function.

source/blender/gpu/shaders/gpu_shader_material.glsl
1586

Since we use object scale you can get it from lampima instead of scale argument.

1600

space between if and (

source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
63

you can remove all these ad in this file since ou use obmat for scale, no ?

Hi! Thanks for review @TristanPorteries. You're right, GPU_lamp_spot_update modification were useless. I'm sure there are many other possible simplifications :) but I did not know how to extract scale X and Y from lampimat, so I looked at math_vector_inline.c to see what is len_v3 and it's a bit complex:

float len_v3(const float a[3])
{
return sqrtf(dot_v3v3(a, a));
}

So I prefered leave lamp->spotvec as it is to avoid len_v3 computation in gpu_shader_material.glsl . But I can try to change if it's really important :) Anyway, thanks for the simplifications you suggested (my 300 lines patch became tiny and there are still some gross errors haha)

So glad people are getting into coding the game engine

I need to finish wrectified, and start getting tutored by one of you.,

Thanks !

the conversion of len_v3 in glsl is : "vector.length()"
so x : imat[0].length() and y : imat[1].length()

@Brecht Van Lommel (brecht) and @Antonis Ryakiotakis (psy-fi): If you've got a moment, could you take a look at the last version of the patch (very simplified) and tell me what do you think about it, please? Thanks very much!

Some minor stuff, will check functionality tomorrow

source/blender/editors/space_view3d/drawobject.c
1362

Please avoid immediate mode in newer commits, it just adds more code to clean up later.

1368

No immediate mode please. This can be GL_LINES too and done with one draw call.

source/blender/gpu/intern/gpu_material.c
1916

no dead code

1963

same

Ulysse Martin (youle) edited edge metadata.

@Antonis Ryakiotakis (psy-fi): Thanks very much for your review! I have no experience in openGL so I didn't understand the difference beetween immediate mode and retained mode but I tried a simplification in drawobject.c . It seems to work but I'm not sure this is correct and if it can be more simplified :) . I removed dead code.

Immediate mode means when you draw your graphic with glBegin(), glEnd() directly to the graphic card. Which is very slow.

glBegin(GL_LINES);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(z_abs, z_abs, x);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(-z_abs, -z_abs, x);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(z_abs, -z_abs, x);
    glVertex3f(0.0f, 0.0f, 0.0f);
    glVertex3f(-z_abs, z_abs, x);
glEnd();

Here an example which is drawing a cube using vertex arrays.
Actually I don't know if Blender now use vertex arrays or vertex buffer objects to draw the objects on the viewport.
So it is best to ask Antony which mode Blender actually use.

// draw a cube drawn with triangles. (initialize arrays)
GLfloat vertices[] = {1.0f, 1.0f, 0.0f,  // 8 of vertex coords oft the cube
                      0.0f, 1.0f, 0.0f,
                      0.0f, 0.0f, 0.0f,
                      1.0f, 0.0f, 0.0f,
                      1.0f, 0.0f, 1.0f,
                      1.0f, 1.0f, 1.0f,
                      0.0f, 1.0f, 1.0f,
                      0.0f, 0.0f, 1.0f};
GLfloat vertices_col[] = {1.0f, 0.352f, 0.0f, 1.0f,  // 8 of vertex colors oft the cube (rgba) if neccesary.
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f,
                          1.0f, 0.352f, 0.0f, 1.0f}; 
GLubyte indices[] = {0,1,2, 2,3,0, // 36 of indices first triangle drawn from vertex 0 to 1 to 2 and so on. 
                     0,3,4, 4,5,0,
                     0,5,6, 6,1,0,
                     1,6,7, 7,2,1,
                     7,4,3, 3,2,7,
                     4,7,6, 6,5,4};

// ----Draw call----
// activate and specify pointer to vertex array
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glColorPointer(4, GL_FLOAT, 0, vertices_col); //GL_FLOAT for 0.0f to 0.1f, GL_UNSIGNED_BYTE for 0 to 255 

// draw the cube
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, indices);

// deactivate vertex arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);

@Thomas Szepe (hg1): Thanks very much for the example :) I think I understood (not sure but it works) (I considered the highest point of the pyramid to have index 0 then make 4 triangles: 0, 1, 2; 0, 2, 3; 0, 3, 4; 0, 4, 1)... I hope this is correct.
@Antonis Ryakiotakis (psy-fi): I hope this is what you expected :)

Thanks again for your reviews and your tips!

Update comments in the code

source/blender/editors/space_view3d/drawobject.c
1368

You have to move "vertices" and "indices" before "x *= y" to compile with gcc.

@Porteries Tristan (panzergame): Hi! The problem is that if I move "vertices" and "indices" before "x *= y", the lines aren't drawn correctly... I'll discuss it with you tonight if you're on IRC :)

I think this will work with gcc now. I changed the draw lines method (GL_LINE_STRIP instead of GL_LINES) and I removed fdrawbox function to draw the square at the end of the cone (all the pyramid is drawn with one draw call)

@Porteries Tristan (panzergame) fixed lamp_visibility_spot_circle function (removed scale *= 0.85...) and made clean up and fixed compilation on Linux. Thanks ;)

Add GPU_DYNAMIC_LAMP_SPOTSCALE to gpu module constants in gpu.c


With uniform scale this narrows down the lamps beam on both X and Y axis. this should be resolved.


Select all objects in the attached file and scale, this will change the cone angle.

@Campbell Barton (campbellbarton): Thanks very much for the test! Is this this behaviour you are waiting for: https://youtu.be/ismfJWxIdxU ? (Uniform scale does not change the light beam)

@Ulysse Martin (youle), looks good, for now can you match the behavior of Blender-Internals 'Halo' (view in preview for eg).
Then at least its consistent (and it looks like its doing what you've got working already).

Even though you've likely figured this out - noting that the XYZ scale values should just define a relative aspect for the lamp - if you check Halo behavior - this is whats happening there too.

@Campbell Barton (campbellbarton): I hope the corrections I made are what you expected... Sorry if I misanderstood something...
I implemented Z scale axis for spotlamps (update light beam and shadows). I hope I made no mistake.
Thanks very much to Tristan for the test he made :)

source/blender/gpu/intern/gpu_material.c
48–50

Quite sure this can stay a float2, just take the len_v3(obmat[2]); into account when calculating lamp->spotvec

spotvec_z = len_v3(obmat[2]);
lamp->spotvec[0] = len_v3(obmat[0]) / spotvec_z;
lamp->spotvec[1] = len_v3(obmat[1]) / spotvec_z;

@Campbell Barton (campbellbarton): Yes! You're right (But why do things simple whereas we can make it complex?? :) )

Looks good, noticed opportunity to avoid calculating all 3 axis lengths twice.

source/blender/gpu/intern/gpu_material.c
1887–1890

len_v3 functions are quite expensive (performing a sqrt each time).

It turns out that we're already doing the 3 len_v3 above, (indirectly), by calling normalize_m4.

I think its worth avoiding doing it twice.

eg:

float spotvec_axis_len[3];
...
copy_m4_m4(mat, obmat);

/* inline normalize_m4(), since we want to reuse the lengths */
ARRAY_SET_ITEMS(
        spotvec_axis_len,
        normalize_v3(mat[0]),
        normalize_v3(mat[1]),
        normalize_v3(mat[2]))
...
lamp->spotvec[0] = spotvec_axis_len[0] / spotvec_axis_len[2];
lamp->spotvec[1] = spotvec_axis_len[1] / spotvec_axis_len[2];
1888

float spotvec_z; should be defined at the function start, unfortunately we can't enforce MSVC to warn about this.

Added normalize_m4_m4_ex, nicer then doing inline.

This revision is now accepted and ready to land.Oct 15 2015, 12:14 PM
  • Make use of newly added normalize_m4_m4_ex
  • minor formatting
  • Make use of newly added normalize_m4_m4_ex
  • minor formatting
  • Add handy comments

Think this is ready to apply to master. (@Ulysse Martin (youle). please *commandeer* back)

@Campbell Barton (campbellbarton): I trust you (much) more than I trust myself so let's apply this patch :) I definitely approve the decision to remove me from command :) Thanks very much for review, tests and corrections.

Ulysse Martin (youle) edited edge metadata.