Geographic Sun addon!

I asked dougal2, the developer of LuxBlend2.5, if there was any plans for porting the Geographic Sun that exist in Luxblend2.49 to 2.5. The answer was that he thought that it should become a standalone addon on its own. And so I did it!
This is very useful for who wants to use Blender in Archviz :yes: and should be greatly advertised here.
I asked him permission for posting it here, he only said to “bear in mind that the addon is largely the work of other people (with respect to the actual sun calculations), I’ve only re-packaged it in Blender-2.5 form.”

Here is the link, and it only works with the must recent buils.
https://svn.blender.org/svnroot/bf-exte … cal_sun.py

Hmm, chrome tells me “The site’s security certificate is not trusted!” I don’t know if something has happened, or if this is safe to ignore.

it’s fine scuey. and wow what an addon camara!!

This is perfect!
I used to create a sun with luxblend on 2.49 and export it to 2.5 before. It was a pain to change this all the time. A must-have addon for anyone modeing for Archiviz in 2.5!

Thanks a lot!

sorry to ask
but can this be used in 2,5 blende
or need any external soft ?

happy 2.5

@RickyBlender, you have to use a recent build 2.5 blender from graphicall.org. But all you need is blender!
Geographic sun’s options will appear in the lamp configuration panel.

Does it also work with a regular Blender build 2.56.0 (r34076)

cul

I can’t seem to download it either, firefox won’t let me. Same issue with the certificate. Could you post on pasteall.org?

can’t wait to try this, very useful.

thanks!

is a great addon! tnx
I tried, but the script does not work. This is the result

Traceback (most recent call last):
File “lamp_geographical_sun”, line 36, in <module>
File “D:\FRANX2~1\blender\build\256\1693_B~1\2.56\scripts\addons\modules\exten
sions_framework_init_.py”, line 32, in <module>
bpy.types.register(EF_OT_msg)
AttributeError: bpy.types.register(…): already registered as a subclass

location:<unknown location>:-1

location:<unknown location>:-1

Brilliant! this is one sorely missed feature…! Thank you.
One question though… is the Y-axis the north direction?
It is pretty easy to find out with the addon but I have no option to do so this week…
Cheers.

Lovely! Takes some of the guesswork out of things.

Of course, now I want to do a faux-timelapse clip instead of the actual work I had planned.

thanks for updating it to 2.5!

i notice what seems like a bug: minimum longitude is -90 and maximum longitude is 90

i noticed because where i live, longitude is -178!

it can be fixed under “properties” by changing all 90s to 180s:

    'type': 'float',
            'attr': 'long',
            'name': 'Long.',
            'min': -90.0,
            'soft_min': -90.0,
            'max': 90.0,
            'soft_max': 90.0,
            'default': 0.0

then it works fine!

in fact, properties for lat shows min -180 to max 180 which should be -90 to +90
maybe these were swapped at some point…

Would love to use this, but I get the same error as afranx, “already a registered subclass”

someone has the latest py file for this
link seems to be dead !

did anybody ported the sun locator from 2.49 to 2.5?

thanks

got it
need to add an select a sun lamp to work !

this should be added to the list of 2.5 script

but how does sun angle works any idea?
i set my local coordinates and time and i get a high angle
even if i push the hour late at night !

i think give the sun location or there is the other one for sun lux

anything equivalent for the moon!

i got an old basic program for the moon
but don’t think parameters are still valid!

the fist sun geopgraphic at top in first post is not wokring in latest built

can you have a look to correct this and bring it back up to date

get error at line 562!

amy of the other sript are mostly for 2.49

one even had the moon location which ii would like to have
unless i can find the proper algo for it
i mean if the julian is already done
then it’s only a few algos to get it!

thanks

Ok changed script to have the sun move its location. The POV is assumed to be (0,0,0) and i just hardcoded in the arbitrary distance to the “sun” as 10 (should make it a property i suppose)

from math import acos, asin, cos, pi, sin, tan, atan2, radians
from mathutils import Vector
import bpy

twopi = pi * 2
rad = pi / 180
dEarthMeanRadius = 6371.01 # In km
dAstronomicalUnit = 149597890 # In km

class SunPos(object):
    def __init__(self, time, location):
        self.time = time
        self.location = location

    def __call__(self):
        self.elapsed_julian_days()
        self.ecliptic_obliquity()
        self.celestial_coordinates()
        return self.local_coordinates()

    def elapsed_julian_days(self):
        '''Calculate difference in days between the current Julian Day and JD 2451545.0, 
        which is noon 1 January 2000 Universal Time'''
        # Calculate time of the day in UT decimal hours
        self.dDecimalHours = self.time.hours + (self.time.minutes + self.time.seconds / 60.0 ) / 60.0

        # Calculate current Julian Day
        liAux1 = (self.time.month - 14) / 12

        liAux2 = (1461 * (self.time.year + 4800 + liAux1)) / 4 + \
                 (367 * (self.time.month - 2 - 12 * liAux1)) / 12 - \
                 (3 * ((self.time.year + 4900 + liAux1) / 100)) / 4 + self.time.day - 32075

        dJulianDate = liAux2 -0.5 + self.dDecimalHours / 24.0

        # Calculate difference between current Julian Day and JD 2451545.0 
        self.dElapsedJulianDays = dJulianDate - 2451545.0

    def ecliptic_obliquity(self):
        '''Calculate ecliptic coordinates (ecliptic longitude and obliquity of the 
        ecliptic in radians but without limiting the angle to be less than 2*Pi 
        (i.e., the result may be greater than 2*Pi)'''
        dOmega = 2.1429 - 0.0010394594 * self.dElapsedJulianDays

        dMeanLongitude = 4.8950630 + 0.017202791698 * self.dElapsedJulianDays # Radians

        dMeanAnomaly = 6.2400600 + 0.0172019699 * self.dElapsedJulianDays

        self.dEclipticLongitude = dMeanLongitude + 0.03341607 * sin(dMeanAnomaly) \
                             + 0.00034894 * sin(2 * dMeanAnomaly) - 0.0001134 \
                             - 0.0000203 * sin(dOmega)

        self.dEclipticObliquity = (0.4090928 - 6.2140e-9 * self.dElapsedJulianDays + 0.0000396 * cos(dOmega))

    def celestial_coordinates(self):
        '''Calculate celestial coordinates ( right ascension and declination ) in radians 
        but without limiting the angle to be less than 2*Pi (i.e., the result may be 
        greater than 2*Pi)'''
        dSin_EclipticLongitude = sin(self.dEclipticLongitude)
        dY = cos(self.dEclipticObliquity) * dSin_EclipticLongitude
        dX = cos(self.dEclipticLongitude)
        self.dRightAscension = atan2( dY,dX )

        if self.dRightAscension &lt; 0.0:
            self.dRightAscension = self.dRightAscension + twopi

        self.dDeclination = asin(sin(self.dEclipticObliquity) * dSin_EclipticLongitude)

    def local_coordinates(self):
        'Calculate local coordinates ( azimuth and zenith angle ) in degrees'
        dGreenwichMeanSiderealTime = 6.6974243242 + 0.0657098283 * self.dElapsedJulianDays + self.dDecimalHours
        dLocalMeanSiderealTime = (dGreenwichMeanSiderealTime * 15 + self.location.longitude) * rad
        dHourAngle = dLocalMeanSiderealTime - self.dRightAscension
        dLatitudeInRadians = self.location.latitude * rad
        dCos_Latitude = cos(dLatitudeInRadians)
        dSin_Latitude = sin(dLatitudeInRadians)
        dCos_HourAngle= cos(dHourAngle)

        dZenithAngle = (acos(dCos_Latitude * dCos_HourAngle * cos(self.dDeclination) + sin(self.dDeclination) * dSin_Latitude))
        dY = -sin(dHourAngle)
        dX = tan(self.dDeclination) * dCos_Latitude - dSin_Latitude * dCos_HourAngle

        dAzimuth = atan2( dY, dX )
        if dAzimuth &lt; 0.0: 
            dAzimuth = dAzimuth + twopi
        dAzimuth = dAzimuth / rad;

        # Parallax Correction
        dParallax = (dEarthMeanRadius / dAstronomicalUnit) * sin(dZenithAngle)
        dZenithAngle = (dZenithAngle + dParallax) / rad

        return (dZenithAngle, dAzimuth)

class OBJECT_OT_sunpos(bpy.types.Operator):
    ''''''
    bl_label = "Set Sun Angle"
    bl_idname = "lamp.sunpos"
    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return (obj.type == 'LAMP' and obj.data.type == 'SUN')

    def execute(self, context):
        sun = context.active_object

        time = sun.data.sunpos_time
        location = sun.data.sunpos_location

        sunpos = SunPos(time, location)

        zenith, azimuth = sunpos()
        print(azimuth,zenith)
        # QUICK HACK
        d = 10.0
        if zenith &lt; 0.0001:
            zloc = 1
        else:
            zloc = tan(radians(90-zenith))
            
        # SunPointer is a unit vector that points to the sun from (0,0,0)
        SunPointer = Vector([sin(radians(azimuth)),cos(radians(azimuth)),zloc]).normalized()
        
        sun.location = d * SunPointer

        sun.rotation_euler = (radians(zenith), radians(0), radians(-1*(azimuth-180)))

        return {'FINISHED'}


class OBJECT_PT_sunpos(bpy.types.Panel):
    bl_label = "Sun Position"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    @classmethod
    def poll(cls, context):
        obj = context.active_object
        return (obj.type == 'LAMP' and obj.data.type == 'SUN')

    def draw(self, context):
        layout = self.layout
        sun = context.active_object.data

        time = sun.sunpos_time
        location = sun.sunpos_location

        col = layout.column(align=True)
        col.label(text="Location:")
        col.prop(location, "longitude", text="Longitude")
        col.prop(location, "latitude", text="Latitude")

        col = layout.column(align=True)
        col.label(text="Time:")
        col.prop(time, "year")
        col.prop(time, "month")
        col.prop(time, "day")
        col.prop(time, "hours")
        col.prop(time, "minutes")
        col.prop(time, "seconds")

        col = layout.column()
        col.operator("lamp.sunpos", text="Set Sun Angle")

class SunPosTime(bpy.types.PropertyGroup):
    pass

class SunPosLocation(bpy.types.PropertyGroup):
    pass

def register():
    from bpy.props import PointerProperty, IntProperty, FloatProperty
    bpy.utils.register_class(SunPosTime)
    bpy.utils.register_class(SunPosLocation) 
    bpy.utils.register_class(OBJECT_PT_sunpos)
    bpy.utils.register_class(OBJECT_OT_sunpos)
    bpy.types.SunLamp.sunpos_time = PointerProperty(type=SunPosTime,                                                    
                                                    description="Sun Position Time Settings",options={'ANIMATABLE'})

    bpy.types.SunLamp.sunpos_location = PointerProperty(type=SunPosLocation,                                                        
                                                        description="Sun Position Location Settings",options={'ANIMATABLE'})

    SunPosLocation.longitude = FloatProperty(name="Longitute",
                                             description="Longitute in Decimal Degrees",
                                             default = 0.123611,
                                             precision=6,)
    SunPosLocation.latitude = FloatProperty(name="Latitude",
                                            description="Latitude in Decimal Degrees",
                                            default = 51.500556,
                                            precision=6,)

    SunPosTime.year = IntProperty(name="Year",
                                  description="Year",
                                  default = 2000)

    SunPosTime.month = IntProperty(name="Month",
                                   description="Month",
                                   default = 1,
                                   min = 1,
                                   max = 12)

    SunPosTime.day = IntProperty(name="Day",
                                 description="Day",
                                 default = 1,
                                 min = 1,
                                 max = 31)

    SunPosTime.hours = IntProperty(name="Hour",
                                   description="Hour",
                                   default = 12,
                                   min = 0,
                                   max = 23)

    SunPosTime.minutes = IntProperty(name="Minute",
                                     description="Minute",
                                     default = 0,
                                     min = 0,
                                     max = 59)

    SunPosTime.seconds = IntProperty(name="Second",
                                     description="Second",
                                     default = 0,
                                     min = 0,
                                     max = 59)

if __name__ == '__main__':
    register()

well ok GMT time

should be easy to add local time by adding new field with GMT i think!

also what is this angle representing
is it angle above horizon of the sun for instance ?

would definitively be nice to see the 2 or 3 others be translated
but first have to identify which is latest version in 2.49
any idea here ?

next week i can try to begin to do some porting if needed on one of these
but first have to be certain which one to do as the lastest version!LOL

i’m interested in an algo to give

the sun or moon location in sky from your own location on Earth
i mean the angle above horizon and the horizontal angle like longitude
compared to local position where you are on Earth

at least i can use this in another sript to locate sun or moon in a scene!

i can find an astronomie book and get the algos and then begin coding it
but there must already be something available somwhere for this!

Yep and this link explains it http://pvcdrom.pveducation.org/SUNLIGHT/SUNCALC.HTM

Having a play with driving the intensity / loc rot of the sun based on a time per frame