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:
parent
7a41cf88cf
commit
29a67357a0
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue