Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Picard <dam.pic@free.fr>2019-12-09 14:02:34 +0300
committerDamien Picard <dam.pic@free.fr>2019-12-09 14:03:58 +0300
commitefbc5e5db7c73ae43ddc11abf8db8bc8f98c9945 (patch)
tree2f5a3fce49e89a35264abf0d2576deaf932ae446 /sun_position/hdr.py
parentc5f0bbde29a9406c33ac84a04aa1ab6b2a27ff35 (diff)
sun_position: move to release: T69936
Diffstat (limited to 'sun_position/hdr.py')
-rw-r--r--sun_position/hdr.py303
1 files changed, 303 insertions, 0 deletions
diff --git a/sun_position/hdr.py b/sun_position/hdr.py
new file mode 100644
index 00000000..257daf58
--- /dev/null
+++ b/sun_position/hdr.py
@@ -0,0 +1,303 @@
+### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# -*- coding: utf-8 -*-
+
+import bpy
+import gpu
+import bgl
+from gpu_extras.batch import batch_for_shader
+from mathutils import Vector
+from math import sqrt, pi, atan2, asin
+
+
+vertex_shader = '''
+uniform mat4 ModelViewProjectionMatrix;
+
+/* Keep in sync with intern/opencolorio/gpu_shader_display_transform_vertex.glsl */
+in vec2 texCoord;
+in vec2 pos;
+out vec2 texCoord_interp;
+
+void main()
+{
+ gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f);
+ gl_Position.z = 1.0;
+ texCoord_interp = texCoord;
+}'''
+
+fragment_shader = '''
+in vec2 texCoord_interp;
+out vec4 fragColor;
+
+uniform sampler2D image;
+uniform float exposure;
+
+void main()
+{
+ fragColor = texture(image, texCoord_interp) * exposure;
+}'''
+
+# shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
+
+
+def draw_callback_px(self, context):
+ nt = context.scene.world.node_tree.nodes
+ env_tex_node = nt.get(context.scene.sun_pos_properties.hdr_texture)
+ image = env_tex_node.image
+
+ if self.area != context.area:
+ return
+
+ if image.gl_load():
+ raise Exception()
+
+ bottom = 0
+ top = context.area.height
+ right = context.area.width
+
+ position = Vector((right, top)) / 2 + self.offset
+ scale = Vector((context.area.width, context.area.width / 2)) * self.scale
+
+ shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
+
+ coords = ((-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5))
+ uv_coords = ((0, 0), (1, 0), (1, 1), (0, 1))
+ batch = batch_for_shader(shader, 'TRI_FAN',
+ {"pos" : coords,
+ "texCoord" : uv_coords})
+
+ bgl.glActiveTexture(bgl.GL_TEXTURE0)
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
+
+
+ with gpu.matrix.push_pop():
+ gpu.matrix.translate(position)
+ gpu.matrix.scale(scale)
+
+ shader.bind()
+ shader.uniform_int("image", 0)
+ shader.uniform_float("exposure", self.exposure)
+ batch.draw(shader)
+
+ # Crosshair
+ # vertical
+ coords = ((self.mouse_position[0], bottom), (self.mouse_position[0], top))
+ colors = ((1,)*4,)*2
+ shader = gpu.shader.from_builtin('2D_FLAT_COLOR')
+ batch = batch_for_shader(shader, 'LINES',
+ {"pos": coords, "color": colors})
+ shader.bind()
+ batch.draw(shader)
+
+ # horizontal
+ if bottom <= self.mouse_position[1] <= top:
+ coords = ((0, self.mouse_position[1]), (context.area.width, self.mouse_position[1]))
+ batch = batch_for_shader(shader, 'LINES',
+ {"pos": coords, "color": colors})
+ shader.bind()
+ batch.draw(shader)
+
+
+class SUNPOS_OT_ShowHdr(bpy.types.Operator):
+ """Tooltip"""
+ bl_idname = "world.sunpos_show_hdr"
+ bl_label = "Sync Sun to Texture"
+
+ exposure = 1.0
+
+ @classmethod
+ def poll(self, context):
+ sun_props = context.scene.sun_pos_properties
+ return sun_props.hdr_texture and sun_props.sun_object is not None
+
+ def update(self, context, event):
+ sun_props = context.scene.sun_pos_properties
+ mouse_position_abs = Vector((event.mouse_x, event.mouse_y))
+
+ # Get current area
+ for area in context.screen.areas:
+ # Compare absolute mouse position to area bounds
+ if (area.x < mouse_position_abs.x < area.x + area.width
+ and area.y < mouse_position_abs.y < area.y + area.height):
+ self.area = area
+ if area.type == 'VIEW_3D':
+ # Redraw all areas
+ area.tag_redraw()
+
+ if self.area.type == 'VIEW_3D':
+ self.top = self.area.height
+ self.right = self.area.width
+
+ nt = context.scene.world.node_tree.nodes
+ env_tex = nt.get(sun_props.hdr_texture)
+
+ # Mouse position relative to window
+ self.mouse_position = Vector((mouse_position_abs.x - self.area.x,
+ mouse_position_abs.y - self.area.y))
+
+ self.selected_point = (self.mouse_position - self.offset - Vector((self.right, self.top))/2) / self.scale
+ u = self.selected_point.x / self.area.width + 0.5
+ v = (self.selected_point.y) / (self.area.width / 2) + 0.5
+
+ # Set elevation and azimuth from selected point
+ if env_tex.projection == 'EQUIRECTANGULAR':
+ el = v * pi - pi/2
+ az = u * pi*2 - pi/2 + env_tex.texture_mapping.rotation.z
+
+ # Clamp elevation
+ el = max(el, -pi/2)
+ el = min(el, pi/2)
+
+ sun_props.hdr_elevation = el
+ sun_props.hdr_azimuth = az
+ elif env_tex.projection == 'MIRROR_BALL':
+ # Formula from intern/cycles/kernel/kernel_projection.h
+ # Point on sphere
+ dir = Vector()
+
+ # Normalize to -1, 1
+ dir.x = 2.0 * u - 1.0
+ dir.z = 2.0 * v - 1.0
+
+ # Outside bounds
+ if (dir.x * dir.x + dir.z * dir.z > 1.0):
+ dir = Vector()
+
+ else:
+ dir.y = -sqrt(max(1.0 - dir.x * dir.x - dir.z * dir.z, 0.0))
+
+ # Reflection
+ i = Vector((0.0, -1.0, 0.0))
+
+ dir = 2.0 * dir.dot(i) * dir - i
+
+ # Convert vector to euler
+ el = asin(dir.z)
+ az = atan2(dir.x, dir.y) + env_tex.texture_mapping.rotation.z
+ sun_props.hdr_elevation = el
+ sun_props.hdr_azimuth = az
+
+ else:
+ self.report({'ERROR'}, 'Unknown projection')
+ return {'CANCELLED'}
+
+ def pan(self, context, event):
+ self.offset += Vector((event.mouse_region_x - self.mouse_prev_x,
+ event.mouse_region_y - self.mouse_prev_y))
+ self.mouse_prev_x, self.mouse_prev_y = event.mouse_region_x, event.mouse_region_y
+
+ def modal(self, context, event):
+ self.area.tag_redraw()
+ if event.type == 'MOUSEMOVE':
+ if self.is_panning:
+ self.pan(context, event)
+ self.update(context, event)
+
+ # Confirm
+ elif event.type in {'LEFTMOUSE', 'RET'}:
+ bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+ for area in context.screen.areas:
+ area.tag_redraw()
+ # Bind the environment texture to the sun
+ context.scene.sun_pos_properties.bind_to_sun = True
+ context.workspace.status_text_set(None)
+ return {'FINISHED'}
+
+ # Cancel
+ elif event.type in {'RIGHTMOUSE', 'ESC'}:
+ bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
+ for area in context.screen.areas:
+ area.tag_redraw()
+ # Reset previous values
+ context.scene.sun_pos_properties.hdr_elevation = self.initial_elevation
+ context.scene.sun_pos_properties.hdr_azimuth = self.initial_azimuth
+ context.workspace.status_text_set(None)
+ return {'CANCELLED'}
+
+ # Set exposure or zoom
+ elif event.type == 'WHEELUPMOUSE':
+ # Exposure
+ if event.ctrl:
+ self.exposure *= 1.1
+ # Zoom
+ else:
+ self.scale *= 1.1
+ self.offset -= (self.mouse_position - (Vector((self.right, self.top)) / 2 + self.offset)) / 10.0
+ self.update(context, event)
+ elif event.type == 'WHEELDOWNMOUSE':
+ # Exposure
+ if event.ctrl:
+ self.exposure /= 1.1
+ # Zoom
+ else:
+ self.scale /= 1.1
+ self.offset += (self.mouse_position - (Vector((self.right, self.top)) / 2 + self.offset)) / 11.0
+ self.update(context, event)
+
+ # Toggle pan
+ elif event.type == 'MIDDLEMOUSE':
+ if event.value == 'PRESS':
+ self.mouse_prev_x, self.mouse_prev_y = event.mouse_region_x, event.mouse_region_y
+ self.is_panning = True
+ elif event.value == 'RELEASE':
+ self.is_panning = False
+
+ else:
+ return {'PASS_THROUGH'}
+
+ return {'RUNNING_MODAL'}
+
+ def invoke(self, context, event):
+ self.is_panning = False
+ self.mouse_prev_x = 0.0
+ self.mouse_prev_y = 0.0
+ self.offset = Vector((0.0, 0.0))
+ self.scale = 1.0
+
+ # Get at least one 3D View
+ area_3d = None
+ for a in context.screen.areas:
+ if a.type == 'VIEW_3D':
+ area_3d = a
+ break
+
+ if area_3d is None:
+ self.report({'ERROR'}, 'Could not find 3D View')
+ return {'CANCELLED'}
+
+ nt = context.scene.world.node_tree.nodes
+ env_tex_node = nt.get(context.scene.sun_pos_properties.hdr_texture)
+ if env_tex_node.type != "TEX_ENVIRONMENT":
+ self.report({'ERROR'}, 'Please select an Environment Texture node')
+ return {'CANCELLED'}
+
+ self.area = context.area
+
+ self.mouse_position = event.mouse_region_x, event.mouse_region_y
+
+ self.initial_elevation = context.scene.sun_pos_properties.hdr_elevation
+ self.initial_azimuth = context.scene.sun_pos_properties.hdr_azimuth
+
+ context.workspace.status_text_set("Enter/LMB: confirm, Esc/RMB: cancel, MMB: pan, mouse wheel: zoom, Ctrl + mouse wheel: set exposure")
+
+ self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px,
+ (self, context), 'WINDOW', 'POST_PIXEL')
+ context.window_manager.modal_handler_add(self)
+
+ return {'RUNNING_MODAL'}