This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/scripts/startup/bl_operators/vertexpaint_dirt.py
Sergey Sharybin 03806d0b67 Re-design of submodules used in blender.git
This commit implements described in the #104573.

The goal is to fix the confusion of the submodule hashes change, which are not
ideal for any of the supported git-module configuration (they are either always
visible causing confusion, or silently staged and committed, also causing
confusion).

This commit replaces submodules with a checkout of addons and addons_contrib,
covered by the .gitignore, and locale and developer tools are moved to the
main repository.

This also changes the paths:
- /release/scripts are moved to the /scripts
- /source/tools are moved to the /tools
- /release/datafiles/locale is moved to /locale

This is done to avoid conflicts when using bisect, and also allow buildbot to
automatically "recover" wgen building older or newer branches/patches.

Running `make update` will initialize the local checkout to the changed
repository configuration.

Another aspect of the change is that the make update will support Github style
of remote organization (origin remote pointing to thy fork, upstream remote
pointing to the upstream blender/blender.git).

Pull Request #104755
2023-02-21 16:39:58 +01:00

199 lines
5.7 KiB
Python

# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright Campbell Barton.
def ensure_active_color_attribute(me):
if me.attributes.active_color:
return me.attributes.active_color
return me.color_attributes.new("Color", 'BYTE_COLOR', 'CORNER')
def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only, normalize):
from mathutils import Vector
from math import acos
import array
# We simulate the accumulation of dirt in the creases of geometric surfaces
# by comparing the vertex normal to the average direction of all vertices
# connected to that vertex. We can also simulate surfaces being buffed or
# worn by testing protruding surfaces.
#
# So if the angle between the normal and geometric direction is:
# < 90 - dirt has accumulated in the crease
# > 90 - surface has been worn or buffed
# ~ 90 - surface is flat and is generally unworn and clean
#
# This method is limited by the complexity or lack there of in the geometry.
#
# Original code and method by Keith "Wahooney" Boshoff.
vert_tone = array.array("f", [0.0]) * len(me.vertices)
# create lookup table for each vertex's connected vertices (via edges)
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()
# average the vector by dividing by the number of connected verts
tot_con = len(con[i])
if tot_con == 0:
ang = pi / 2.0 # assume 90°, i. e. flat
else:
vec /= tot_con
# angle is the acos() of the dot product between normal and connected verts.
# > 90 degrees: convex
# < 90 degrees: concave
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 = 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
del orig_vert_tone
if normalize:
min_tone = min(vert_tone)
max_tone = max(vert_tone)
else:
min_tone = clamp_dirt
max_tone = clamp_clean
tone_range = max_tone - min_tone
if tone_range < 0.0001:
# weak, don't cancel, see #43345
tone_range = 0.0
else:
tone_range = 1.0 / tone_range
active_color_attribute = ensure_active_color_attribute(me)
if not active_color_attribute:
return {'CANCELLED'}
point_domain = active_color_attribute.domain == 'POINT'
attribute_data = active_color_attribute.data
use_paint_mask = me.use_paint_mask
for i, p in enumerate(me.polygons):
if not use_paint_mask or p.select:
for loop_index in p.loop_indices:
loop = me.loops[loop_index]
v = loop.vertex_index
col = attribute_data[v if point_domain else loop_index].color
tone = vert_tone[v]
tone = (tone - min_tone) * tone_range
if dirt_only:
tone = min(tone, 0.5) * 2.0
col[0] = tone * col[0]
col[1] = tone * col[1]
col[2] = tone * col[2]
me.update()
return {'FINISHED'}
from bpy.types import Operator
from bpy.props import FloatProperty, IntProperty, BoolProperty
from math import pi
class VertexPaintDirt(Operator):
'''Generate a dirt map gradient based on cavity'''
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",
min=0.01, max=1.0,
default=1.0,
)
blur_iterations: IntProperty(
name="Blur Iterations",
description="Number of times to blur the colors (higher blurs more)",
min=0, max=40,
default=1,
)
clean_angle: FloatProperty(
name="Highlight Angle",
description="Less than 90 limits the angle used in the tonal range",
min=0.0, max=pi,
default=pi,
unit='ROTATION',
)
dirt_angle: FloatProperty(
name="Dirt Angle",
description="Less than 90 limits the angle used in the tonal range",
min=0.0, max=pi,
default=0.0,
unit='ROTATION',
)
dirt_only: BoolProperty(
name="Dirt Only",
description="Don't calculate cleans for convex areas",
default=False,
)
normalize: BoolProperty(
name="Normalize",
description="Normalize the colors, increasing the contrast",
default=True,
)
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.type == 'MESH')
def execute(self, context):
obj = context.object
mesh = obj.data
ret = applyVertexDirt(
mesh,
self.blur_iterations,
self.blur_strength,
self.dirt_angle,
self.clean_angle,
self.dirt_only,
self.normalize,
)
return ret
classes = (
VertexPaintDirt,
)