Separate sun lamp size as angular diameter
Open, LowPublic

Description

The sun lamp Size property in Cycles and Blender Internal is currently shared with point, spot and area lights. However as these lamps are rendered as if infinitely far away, it makes no sense to specify them in meters.

Rather you should be able to specify an angle instead. For example the real sun as seen from earth has an angular diameter of about 0.526° to 0.545°.
http://en.wikipedia.org/wiki/Angular_diameter

Implementation of this involves:

  • Add a new sun_size property and give it a default value roughly the size of the real sun.
  • Change the Cycles and Blender Internal code to use an angle (figure out conversion formula, this requires some math skills).
  • Add a version patch in do_versions to convert the existing lamp size to an angle for backwards compatibility.

Details

Differential Revisions
Restricted Differential Revision
Type
To Do
Brecht Van Lommel (brecht) set Type to To Do.
Brecht Van Lommel (brecht) changed the title from "Separate sun lamp size as angle" to "Separate sun lamp size as angular diameter".
Brecht Van Lommel (brecht) edited projects, added Rendering; removed User Interface.

Hi ,

So I walked around the intern code (sunsky.c) and found that their is a sun_size property in it. I understand that from the current UI , I am able to define the sun size property as float which as per you is the distance in meters. I get the concept of angular diameter that needs to be implemented here but could you please give me a starting point ? or point me to a resource that will help me figure things out on my own ?

I am new to development in blender and this is my first task.

Thanks

I was actually thinking of the "Soft Size" property for Blender Internal shadows and the Size property for Cycles, although getting the sunsky setting to match would be good too.

In Cycles the code to change is in intern/cycles/render/light.cpp, LightManager::device_update_points, the LIGHT_DISTANT case. The radius there now is the radius of a disk pointed towards the origin, placed 1 unit away from the origin. So you need to figure out the math to convert that to an angle.

For Blender Internal this code actually seems quite broken, if you look in ray_shadow in rayshade.c, the LA_SUN case, then there's a comment about this not working correct. But you'd want to do the same kind of thing as Cycles, sample a disk with some radius, and you compute that radius from the user specified angle.

Anyway, this probably ends up being a relatively simple change but you need to be familiar with the math for it.

The formula was relatively easy if one knows their trigonometry. This indeed was a quick hack. Just needed to be pointed to the right file.

I have created a differential which has sun_size property set as sun's actual diameter in meters.

I understand the scenario that you're trying to apply in the la_sun case but the block also match the hemi lamp case. Do you really want me to sample a disk with the radius of the sun again ?

Also could you walk me through these variables so that I have a better understanding of implementing this in ray shade .

lampco[0]= shi->co[0] - R.maxdist*lar->vec[0];
		lampco[1]= shi->co[1] - R.maxdist*lar->vec[1];
		lampco[2]= shi->co[2] - R.maxdist*lar->vec[2];

And what exactly is lar ? LampRen doesn't really help.

LampRen is the data structure for Lamps in blender internal, many data structures there have a Ren postfix to indicate they are renderer data structures.

ShadeInput describes the current shading point, ShadeInput.co is the location of the current shading point. LampRen.vec is the normalized direction vector of the lamp. R.maxdist actually should not be used here at all, not sure why it was ever done. It's the diameter of the scene bounding box I think. But really it should be taken into account at all.

What it has to do here is indeed sample a disk, just like Cycles.

I'm not sure what exactly you did in D229, the purpose of this change isn't really to hardcode the sun diameter. The point is to let users specify the sun size as an angle. The diameter of the sun in our solar system doesn't really come into it directly, just the angular diameter as seen from the earth should be enough.

Alright .. that's okay. I understand what I implemented was different from what you expected.

My only point is, to do this, you have to take into account the sun's diameter too. Consider this :

As per the wikipedia page that you mentioned, the user now specifies the angle 'delta'. Now to calculate the radius 'D' , we have to take into account the sun's diameter 'd'.

When the user inputs the angle 'delta', we can calculate 'D' only if we take the sun's diameter 'd' as a constant.

I am updating the differential again for you to see. Please see if that suits what you had in mind.

Once you approve of it, i'll try changing the code for rayshade.c

Thanks

You don't need the distance to the sun or the diameter of the sun, the angle 'delta' is enough. The distance to the sun D = ∞, as the Cycles world background is assumed to be infinitely far away. For sampling you can understand of the code as setting D = 1, it doesn't really matter which distance you assume because you only need to sample a direction vector. There's this comment in the code, not sure if clears things up but it's the math I used:

/* a distant light is infinitely far away, but equivalent to a disk
 * shaped light exactly 1 unit away from the current shading point.
 *
 *     radius              t^2/cos(theta)
 *  <---------->           t = sqrt(1^2 + tan(theta)^2)
 *       tan(th)           area = radius*radius*pi
 *       <----->
 *        \    |           (1 + tan(theta)^2)/cos(theta)
 *         \   |           (1 + tan(acos(cos(theta)))^2)/cos(theta)
 *       t  \th| 1         simplifies to
 *           \-|           1/(cos(theta)^3)
 *            \|           magic!
 *             P
 */

Anyway, looking at the code, I think the angular diameter is almost there anyway. I think the float angle in light.cpp and the theta in the above comment are half the angular diameter. So the code might just need to be:

float angle = light->size/2.0f;
float radius = tanf(angle);

The figure clears things out for sure. I think i'll have to read through the code more to understand the hardcore set of trignometric identities you had to use.

I have no understanding as to why you're choosing "the disk shape light exactly 1 unit away from the current shading point."

The distance does matter as it helps me to calculate the precise value of the radius.

But then again, choosing that distance as a constant (1), gives me the exact value of radius (tan(theta)) rather than tanf(theta) * the distance from the current shading point "P".

Anyway, thats just my trignometry talking. It'll be great if you point me to a resource that tells me more about cycles and light rendering in blender so that I understand the code more. Sounds exciting :)

You're right ... the float angle would be half the angular diameter. The only thing is that the math library in c++ calculates trignometric values only if the angle is passed as radians not degrees. So we need to do the necessary conversion before calculating the radius.

radians = (PI * angle / 180 ).

Here's the differential for it.

Thanks

Brecht Van Lommel (brecht) moved this task from Backlog to UI on the Cycles board.Feb 21 2016, 2:58 PM
  1. I will work from Samarth Mediratta's diff , and modify as needed.
  2. I will create a demo video when it is ready for review.
  3. I will hand this back if I cannot complete 1. or 2. by April.

https://developer.blender.org/D229

intern/cycles/app/cycles_xml.cpp 	
/* Generic */
 	xml_read_float(&light->size, node, "size");
+	xml_read_float(&light->sun_angle, node, "sun_angle");
 	xml_read_float3(&light->dir, node, "dir");
 	xml_read_float3(&light->co, node, "P");
 	light->co = transform_point(&state.tfm, light->co);

I cannot find any of that block in :
blender-build/blender/intern/cycles/app/cycles_xml.cpp Did it move or get re-done?