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 < 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 < 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 < 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()