forked from bartvdbraak/blender
177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
# ***** BEGIN GPL LICENSE BLOCK *****
|
|
#
|
|
# Script copyright (C) Campbell J Barton
|
|
#
|
|
# 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 LICENCE BLOCK *****
|
|
# --------------------------------------------------------------------------
|
|
|
|
# <pep8 compliant>
|
|
|
|
# History
|
|
#
|
|
# Originally written by Campbell Barton aka ideasman42
|
|
#
|
|
# 2009-11-01: * 2.5 port by Keith "Wahooney" Boshoff
|
|
# * Replaced old method with my own, speed is similar (about 0.001 sec on Suzanne)
|
|
# but results are far more accurate
|
|
#
|
|
|
|
|
|
def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only):
|
|
from mathutils import Vector
|
|
from math import acos
|
|
|
|
#BPyMesh.meshCalcNormals(me)
|
|
|
|
vert_tone = [0.0] * len(me.vertices)
|
|
|
|
min_tone = 180.0
|
|
max_tone = 0.0
|
|
|
|
# create lookup table for each vertex's connected vertices (via edges)
|
|
con = []
|
|
|
|
con = [[] for i in range(len(me.vertices))]
|
|
|
|
# add connected verts
|
|
for e in me.edges:
|
|
con[e.vertices[0]].append(e.vertices[1])
|
|
con[e.vertices[1]].append(e.vertices[0])
|
|
|
|
for i, v in enumerate(me.vertices):
|
|
vec = Vector()
|
|
no = v.normal
|
|
co = v.co
|
|
|
|
# get the direction of the vectors between the vertex and it's connected vertices
|
|
for c in con[i]:
|
|
vec += (me.vertices[c].co - co).normalized()
|
|
|
|
# normalize the vector by dividing by the number of connected verts
|
|
tot_con = len(con[i])
|
|
|
|
if tot_con == 0:
|
|
continue
|
|
|
|
vec /= tot_con
|
|
|
|
# angle is the acos of the dot product between vert and connected verts normals
|
|
ang = acos(no.dot(vec))
|
|
|
|
# enforce min/max
|
|
ang = max(clamp_dirt, ang)
|
|
|
|
if not dirt_only:
|
|
ang = min(clamp_clean, ang)
|
|
|
|
vert_tone[i] = ang
|
|
|
|
# blur tones
|
|
for i in range(blur_iterations):
|
|
# backup the original tones
|
|
orig_vert_tone = list(vert_tone)
|
|
|
|
# use connected verts look up for blurring
|
|
for j, c in enumerate(con):
|
|
for v in c:
|
|
vert_tone[j] += blur_strength * orig_vert_tone[v]
|
|
|
|
vert_tone[j] /= len(c) * blur_strength + 1
|
|
|
|
min_tone = min(vert_tone)
|
|
max_tone = max(vert_tone)
|
|
|
|
# debug information
|
|
# print(min_tone * 2 * math.pi)
|
|
# print(max_tone * 2 * math.pi)
|
|
# print(clamp_clean)
|
|
# print(clamp_dirt)
|
|
|
|
tone_range = max_tone - min_tone
|
|
|
|
if not tone_range:
|
|
return
|
|
|
|
active_col_layer = None
|
|
|
|
if len(me.vertex_colors):
|
|
for lay in me.vertex_colors:
|
|
if lay.active:
|
|
active_col_layer = lay.data
|
|
else:
|
|
bpy.ops.mesh.vertex_color_add()
|
|
me.vertex_colors[0].active = True
|
|
active_col_layer = me.vertex_colors[0].data
|
|
|
|
if not active_col_layer:
|
|
return('CANCELLED', )
|
|
|
|
for i, f in enumerate(me.faces):
|
|
if not me.use_paint_mask or f.select:
|
|
|
|
f_col = active_col_layer[i]
|
|
|
|
f_col = [f_col.color1, f_col.color2, f_col.color3, f_col.color4]
|
|
|
|
for j, v in enumerate(f.vertices):
|
|
col = f_col[j]
|
|
tone = vert_tone[me.vertices[v].index]
|
|
tone = (tone - min_tone) / tone_range
|
|
|
|
if dirt_only:
|
|
tone = min(tone, 0.5)
|
|
tone *= 2
|
|
|
|
col[0] = tone * col[0]
|
|
col[1] = tone * col[1]
|
|
col[2] = tone * col[2]
|
|
|
|
|
|
import bpy
|
|
from bpy.props import FloatProperty, IntProperty, BoolProperty
|
|
|
|
|
|
class VertexPaintDirt(bpy.types.Operator):
|
|
bl_idname = "paint.vertex_color_dirt"
|
|
bl_label = "Dirty Vertex Colors"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
blur_strength = FloatProperty(name="Blur Strength", description="Blur strength per iteration", default=1.0, min=0.01, max=1.0)
|
|
blur_iterations = IntProperty(name="Blur Iterations", description="Number times to blur the colors. (higher blurs more)", default=1, min=0, max=40)
|
|
clean_angle = FloatProperty(name="Highlight Angle", description="Less then 90 limits the angle used in the tonal range", default=180.0, min=0.0, max=180.0)
|
|
dirt_angle = FloatProperty(name="Dirt Angle", description="Less then 90 limits the angle used in the tonal range", default=0.0, min=0.0, max=180.0)
|
|
dirt_only = BoolProperty(name="Dirt Only", description="Dont calculate cleans for convex areas", default=False)
|
|
|
|
def execute(self, context):
|
|
import time
|
|
from math import radians
|
|
obj = context.object
|
|
|
|
if not obj or obj.type != 'MESH':
|
|
self.report({'ERROR'}, "Error, no active mesh object, aborting")
|
|
return {'CANCELLED'}
|
|
|
|
mesh = obj.data
|
|
|
|
t = time.time()
|
|
|
|
applyVertexDirt(mesh, self.blur_iterations, self.blur_strength, radians(self.dirt_angle), radians(self.clean_angle), self.dirt_only)
|
|
|
|
print('Dirt calculated in %.6f' % (time.time() - t))
|
|
|
|
return {'FINISHED'}
|