problem with HDRI and the angle of the Sun lamp

Hi,

I am experimenting with HDRI graphics for lighting outdoors scenes. This is amazing and I can use HDRIs in my scenes without an issue. However, I find a problem to align the sunlight to the light coming from the environment; since they two light sources don’t match, I get double shadows, the windows cast strange reflections on the wall, and the like. I have researched the issue and all the solution I could find was to eyeball it.

Does anybody know of a more accurate way of aligning the sunlight with that from the HDR environment light?

Can anybody help? Thanks in advance.

Sept

Not sure if this still works in current Blender:
That script provides a Sun + HDR mode which allows synchronization of sun and environment texture.

Hi IkariShinji,

Thank you for your response. Yes, I know about the Sun position addon, and it is the perfect solution to the problem; however,the addon doesn’t seem to work 100% in Blender’s latest official release: for example I cannot see the map, or the properties, or the button to bind the Blender sun with the HDRI sun; I’m currently testing Sun Position 3.0.1 (written for Blender 2.6) with Blender 2.7.8 c.

I wonder if there is an alternative solution or an update to the addon to work with Blender latest version. Can anybody help?

Kind Regards,

Sept

Hi,
as long as you dont animate the sun, place a sphere with a full glossy material in the center of the scene, and then move and rotate the sun until the reflected spot oft the lamp matches with the reflected spot of the sun of the hdr image that can be seen on the sphere. Not the most elegant method, but better than nothing.
I hope this may help.

Back in Realsoft3D days we had a builtin method of relocating lights by clicking where its reflection was. I’m wondering if something like that could be accomplished using a script?

it may be very simple. Get the normal by casting a ray under the mouse, calculate the reflected vector and pass the inversed vector into the Lamp.rotation…

Yeah I was thinking along those lines. Unfortunately last time I coded I got a Guru Meditation :slight_smile:

a small adaptation from the raycast template… didn’t wrote any implementation of this into the UI, so you need to call the operator by pressing SPACE.

The Sun Lamp must be selected to the script to work, and probably there’s a simpler way for converting the reflected vector into a rotation, but for the most it’s working.

import bpy
from bpy_extras import view3d_utils
from mathutils import *

def main(context, event):

    # get the context arguments
    scene = context.scene
    region = context.region
    rv3d = context.region_data
    coord = event.mouse_region_x, event.mouse_region_y

    # get the ray from the viewport and mouse
    view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
    ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)

    ray_target = ray_origin + view_vector

    def visible_objects_and_duplis():
        """Loop over (object, matrix) pairs (mesh only)"""

        for obj in context.visible_objects:
            if obj.type == 'MESH':
                yield (obj, obj.matrix_world.copy())

            if obj.dupli_type != 'NONE':
                obj.dupli_list_create(scene)
                for dob in obj.dupli_list:
                    obj_dupli = dob.object
                    if obj_dupli.type == 'MESH':
                        yield (obj_dupli, dob.matrix.copy())

            obj.dupli_list_clear()

    def obj_ray_cast(obj, matrix):
        """Wrapper for ray casting that moves the ray into object space"""

        # get the ray relative to the object
        matrix_inv = matrix.inverted()
        ray_origin_obj = matrix_inv * ray_origin
        ray_target_obj = matrix_inv * ray_target
        ray_direction_obj = ray_target_obj - ray_origin_obj

        # cast the ray
        success, location, normal, face_index = obj.ray_cast(ray_origin_obj, ray_direction_obj)

        if success:
            return location, normal, face_index
        else:
            return None, None, None

    # cast rays and find the closest object
    best_length_squared = -1.0
    best_normal = None

    for obj, matrix in visible_objects_and_duplis():
        if obj.type == 'MESH':
            hit, normal, face_index = obj_ray_cast(obj, matrix)
            if hit is not None:
                hit_world = matrix * hit
                length_squared = (hit_world - ray_origin).length_squared
                if best_normal is None or length_squared < best_length_squared:
                    best_length_squared = length_squared
                    best_normal = matrix*normal

    if best_normal is not None:
        reflection=-view_vector.reflect(normal)
        track=reflection.to_track_quat('-Z', 'X')
        context.active_object.rotation_euler=track.to_euler()
        
        
class ViewOperatorRayCast(bpy.types.Operator):
    """Align Sun Lamp to Reflection"""
    bl_idname = "view3d.alig_sun_reflect"
    bl_label = "Align Sun Lamp to Reflection"
    
    
    originalrotation=None
    
    def modal(self, context, event):
        if event.type in {'LEFTMOUSE'}:
            context.window.cursor_modal_restore()
            return {'FINISHED'}
        if event.type == 'MOUSEMOVE':
            main(context, event)
            return {'RUNNING_MODAL'}
        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            context.window.cursor_modal_restore()
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}


    def invoke(self, context, event):
        if context.space_data.type == 'VIEW_3D' and context.active_object.data.type=='SUN':
            originalrotation=context.active_object.rotation_euler
            context.window.cursor_modal_set('CROSSHAIR')
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "Active Object must be a Sun Lamp")
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(ViewOperatorRayCast)


def unregister():
    bpy.utils.unregister_class(ViewOperatorRayCast)


if __name__ == "__main__":
    register()

Couldn’t make it work. I load the script into text editor, run it, and with the 3D cursor positioned and a sun object selected, I hit space and run it. What do you mean “sun selected to the script”? It’s selected and active in the outliner. This is the thrown error:

ok, step by step:

You should have some objects in the scene (rounded objects will let you see a better result as they have a bigger variety of normals)
Those Objects should have a glossy material so you can see the Specular Highlight.
You need a Sun Lamp.

Copy the script into the text editor, and ‘Run Script’.
Go into the 3DView, and select the Sun Lamp.
Set your view to ‘Render’ so you can see the specular hightlights.
Press SPACE and look for ‘Align Sun Lamp to Reflection’
Move your mouse over the objects, and the Sun will automatically rotate so that the highlight will be under the mouse cursor.
Press the RMB or ESC to exit the script.