Sun Position: add Show Surface and Show Analemmas options

Sometimes during the design it's difficult to rapidly visualize the
Sun trajectory for a given location in the viewport.

This patch adds the possibility to visualize the sun path surface and
analemmas for each hour in the viewport.

Currently there is an option to create a collection with objects to
draw analemmas and diurnal ready for render but these new options
options give fast viewport feedback, something like the Show North
option.

Reviewed By: pioverfour

Differential Revision: https://developer.blender.org/D16936
This commit is contained in:
Eduardo Schilling 2023-01-07 17:33:26 +01:00 committed by Damien Picard
parent 7a41cf88cf
commit 29a67357a0
4 changed files with 149 additions and 3 deletions

View File

@ -16,7 +16,7 @@
bl_info = {
"name": "Sun Position",
"author": "Michael Martin",
"version": (3, 1, 3),
"version": (3, 2, 0),
"blender": (3, 0, 0),
"location": "World > Sun Position",
"description": "Show sun position with objects and/or sky texture",
@ -48,6 +48,8 @@ register_classes, unregister_classes = bpy.utils.register_classes_factory(
@persistent
def sun_scene_handler(scene):
sun_props = bpy.context.scene.sun_pos_properties
sun_props.show_surface = sun_props.show_surface
sun_props.show_analemmas = sun_props.show_analemmas
sun_props.show_north = sun_props.show_north

View File

@ -5,7 +5,7 @@ from bpy.types import AddonPreferences, PropertyGroup
from bpy.props import (StringProperty, EnumProperty, IntProperty,
FloatProperty, BoolProperty, PointerProperty)
from .sun_calc import sun_update, parse_coordinates
from .sun_calc import sun_update, parse_coordinates, surface_update, analemmas_update
from .draw import north_update
from math import pi
@ -53,6 +53,18 @@ class SunPosProperties(PropertyGroup):
soft_min=-pi, soft_max=pi, step=10.0, default=0.0,
update=sun_update)
show_surface: BoolProperty(
name="Show Surface",
description="Draw sun surface",
default=False,
update=surface_update)
show_analemmas: BoolProperty(
name="Show Analemmas",
description="Draw sun analemmas",
default=False,
update=analemmas_update)
latitude: FloatProperty(
name="Latitude",
description="Latitude: (+) Northern (-) Southern",
@ -186,7 +198,6 @@ class SunPosProperties(PropertyGroup):
soft_min=1.0, soft_max=24.0, step=1.0, default=23.0,
update=sun_update)
############################################################################
# Preference panel properties
############################################################################
@ -211,6 +222,18 @@ class SunPosAddonPreferences(AddonPreferences):
default=True,
update=sun_update)
show_surface: BoolProperty(
name="Show Surface",
description="Show sun surface choice and slider",
default=True,
update=sun_update)
show_analemmas: BoolProperty(
name="Show Analemmas",
description="Show analemmas choice and slider",
default=True,
update=sun_update)
show_refraction: BoolProperty(
name="Refraction",
description="Show sun refraction choice",
@ -244,6 +267,8 @@ class SunPosAddonPreferences(AddonPreferences):
flow.prop(self, "show_time_place")
flow.prop(self, "show_dms")
flow.prop(self, "show_north")
flow.prop(self, "show_surface")
flow.prop(self, "show_analemmas")
flow.prop(self, "show_refraction")
flow.prop(self, "show_az_el")
flow.prop(self, "show_daylight_savings")

View File

@ -2,6 +2,8 @@
import bpy
from bpy.app.handlers import persistent
import gpu
from gpu_extras.batch import batch_for_shader
from mathutils import Euler, Vector
import math
from math import degrees, radians, pi
@ -51,6 +53,10 @@ sun = SunInfo()
def sun_update(self, context):
update_time(context)
move_sun(context)
if self.show_surface:
surface_update(self, context)
if self.show_analemmas:
analemmas_update(self, context)
def parse_coordinates(self, context):
@ -563,3 +569,107 @@ def mean_anomaly_sun(t):
def eccentricity_earth_orbit(t):
return (0.016708634 - 0.000042037 * t - 0.0000001267 * t ** 2)
def calc_surface(context):
coords = []
sun_props = context.scene.sun_pos_properties
zone = -sun_props.UTC_zone
north_offset = degrees(sun_props.north_offset)
def get_surface_coordinates(time, month):
_, theta, phi, _, _ = get_sun_coordinates(
time, sun_props.latitude, sun_props.longitude, north_offset,
zone, month, 1, sun_props.year, sun_props.sun_distance)
sun_vector = get_sun_vector(theta, phi) * sun_props.sun_distance
sun_vector.z = max(0, sun_vector.z)
return sun_vector
for month in range(1, 7):
for time in range(24):
coords.append(get_surface_coordinates(time, month))
coords.append(get_surface_coordinates(time + 1, month))
coords.append(get_surface_coordinates(time, month + 1))
coords.append(get_surface_coordinates(time, month + 1))
coords.append(get_surface_coordinates(time + 1, month + 1))
coords.append(get_surface_coordinates(time + 1, month))
return coords
def calc_analemma(context, h):
vertices = []
sun_props = context.scene.sun_pos_properties
zone = -sun_props.UTC_zone
north_offset = degrees(sun_props.north_offset)
for day_of_year in range(1, 367, 5):
day, month = day_of_year_to_month_day(sun_props.year, day_of_year)
_, theta, phi, _, _ = get_sun_coordinates(
h, sun_props.latitude, sun_props.longitude,
north_offset, zone, month, day, sun_props.year,
sun_props.sun_distance)
sun_vector = get_sun_vector(theta, phi) * sun_props.sun_distance
if sun_vector.z > 0:
vertices.append(sun_vector)
return vertices
def draw_surface(batch, shader):
blend = gpu.state.blend_get()
gpu.state.blend_set("ALPHA")
shader.uniform_float("color", (.8, .6, 0, 0.2))
batch.draw(shader)
gpu.state.blend_set(blend)
def draw_analemmas(batch, shader):
shader.uniform_float("color", (1, 0, 0, 1))
batch.draw(shader)
_handle_surface = None
def surface_update(self, context):
global _handle_surface
if self.show_surface:
coords = calc_surface(context)
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": coords})
if _handle_surface is not None:
bpy.types.SpaceView3D.draw_handler_remove(_handle_surface, 'WINDOW')
_handle_surface = bpy.types.SpaceView3D.draw_handler_add(
draw_surface, (batch, shader), 'WINDOW', 'POST_VIEW')
elif _handle_surface is not None:
bpy.types.SpaceView3D.draw_handler_remove(_handle_surface, 'WINDOW')
_handle_surface = None
_handle_analemmas = None
def analemmas_update(self, context):
global _handle_analemmas
if self.show_analemmas:
coords = []
indices = []
coord_offset = 0
for h in range(24):
analemma_verts = calc_analemma(context, h)
coords.extend(analemma_verts)
for i in range(len(analemma_verts) - 1):
indices.append((coord_offset + i,
coord_offset + i+1))
coord_offset += len(analemma_verts)
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'LINES',
{"pos": coords}, indices=indices)
if _handle_analemmas is not None:
bpy.types.SpaceView3D.draw_handler_remove(_handle_analemmas, 'WINDOW')
_handle_analemmas = bpy.types.SpaceView3D.draw_handler_add(
draw_analemmas, (batch, shader), 'WINDOW', 'POST_VIEW')
elif _handle_analemmas is not None:
bpy.types.SpaceView3D.draw_handler_remove(_handle_analemmas, 'WINDOW')
_handle_analemmas = None

View File

@ -199,6 +199,14 @@ class SUNPOS_PT_Location(bpy.types.Panel):
col.prop(sp, "north_offset")
col.separator()
if p.show_surface or p.show_analemmas:
col = flow.column(align=True)
if p.show_surface:
col.prop(sp, "show_surface", toggle=True)
if p.show_analemmas:
col.prop(sp, "show_analemmas", toggle=True)
col.separator()
if p.show_az_el:
col = flow.column(align=True)
split = col.split(factor=0.4, align=True)
@ -216,6 +224,7 @@ class SUNPOS_PT_Location(bpy.types.Panel):
col = flow.column()
col.prop(sp, "sun_distance")
col.separator()
class SUNPOS_PT_Time(bpy.types.Panel):