chsh2 / nijiGPen

An add-on of Blender focusing on Grease Pencil
GNU General Public License v3.0
220 stars 9 forks source link

idea: use concavity and convexity to refine stroke thickness automatically. #15

Open Ulf3000 opened 1 year ago

Ulf3000 commented 1 year ago

one technique to refine lineart is to thicken it a bit in concave areas and thinnen it a bit in convex areas, easpecially around long convex arcs even sometimes breaking the line up in the process.

most mangas and comics use this technique and even some cartoons to some extend.

this is easy to do manually in blender with the sculpt thickness brush.

But since you seem to be such a genius with this stuff i wanted to ask you if you could detect the concavity/convexity of grease pencil strokes and apply thickness (and strength, mabe even tint) to it ?

b4zz4 commented 1 year ago

Looking for these?. nijiGpen also has a similar tool.

https://user-images.githubusercontent.com/643833/221215365-23ecc2f3-e070-481c-855e-10190036b4c0.mp4

Ulf3000 commented 1 year ago

nope thats not it .

i mean something like this grafik

this could also be extended to light direction instead of concavity/convexity and corner detection

chsh2 commented 1 year ago

Yes, I will start thinking about how to achieve that. Do you have more references such as tutorials or art theories? I have seen some articles that introduce how to adjust line thickness in different situations, like this one. But it does not talk about concavity.

One existing tool in Blender to achieve a similar effect, as far as I know, is the Envelope modifier. However, it only thickens the stroke, not thins it. image

Ulf3000 commented 1 year ago

That gives a decent effect already, but it would be nice if we could just apply it to selected strokes in a one time operation.

Ulf3000 commented 1 year ago

Do you have more references such as tutorials or art theories?

well not realy , to make lineart more interesting and polished you can change linestrength for example according to light and dark , the concave/convex is like applying AO to the lineart , in cavities the lineart gets a little thicker and on outer corners a little thinner... for example a bit of thicknes around the eye sockets is good manners. you can reverse this method to emphesize rocky, hard, spiky materials and emphesize sharp corners and spikes with thicker outline..

or thicken every corner like the modifier works too.

i dont think there are any rules on how to draw comics apart from the basics. the broken lines i mentioned above around knees ,lips, shiny round objects and other rounded corners can be seen in many mangas. theres not always a rule which applies to all lines in a drawing equally so like i said it would be nice to have one time operations to selected strokes

edit: this one been sitting in my mind since forever grafik

and here is a detailed guide of several lineart enhancements:

https://www.yampuff.com/inking-tutorial-yampuff/

grafik

Ulf3000 commented 1 year ago

grafik

this is my first try , it kinda does the right thing but very unsmooth . i probably need to smooth all the values and maybe go from extreme point to extreme point to apply the smoothing

chsh2 commented 1 year ago

this is my first try , it kinda does the right thing but very unsmooth . i probably need to smooth all the values and maybe go from extreme point to extreme point to apply the smoothing

Thank you. Since the curvature is the second derivative, it is common for it to amplify the noise. Maybe we can do some smoothing before calculating the curvature (e.g. to smooth the location or the tangent direction).

I have adopted different smoothing methods several times when implementing other functions. I will try to see if they can be used here. I am busy with something else right now, but I think I will work on this function soon, maybe within a week.

Ulf3000 commented 1 year ago

grafik

i now got it with smoothing. works only on selected strokes. and only thinning and thickening by curvature level. no concave convex differentiation yet because for that we need to know or assume the inside and outside, which mightbe just a left/right trigger on a vertical stroke but harder if the stroke goes around (like a bald head for example)

import bpy 
from bpy.types import GreasePencil 
from mathutils import Vector 
import math

import numpy as np
from scipy.signal import savgol_filter

# Get the active Grease Pencil object
gp_object = bpy.context.active_object

# Get the active Grease Pencil data
gp_data = gp_object.data

# Get all selected Grease Pencil strokes
selected_strokes = [stroke for stroke in gp_data.layers.active.active_frame.strokes if stroke.select]

# Iterate through all the strokes 
for gp_stroke in selected_strokes: 

    curve_data = []
    # Iterate through all the points in the stroke 
    for i in range(len(gp_stroke.points)):
        p0 = gp_stroke.points[i-1].co
        p1 = gp_stroke.points[i].co
        p2 = gp_stroke.points[(i+1) % len(gp_stroke.points)].co

        v1 = p1 - p0
        v2 = p2 - p1

        angle = v1.angle(v2)

        if angle < 0.001:
            curvature = 0.0
        else:
            radius = v1.length / (2 * math.sin(angle / 2))
            curvature = 1 / radius

        if curvature > 10:
            curvature = 10

        print('curve',curvature)

        curve_data.append(curvature)

    # Apply a Savitzky-Golay filter to smooth the curvature
    window_size = 11
    order = 3
    smoothed_data = savgol_filter(curve_data, window_size, order)
    print('smoothed', smoothed_data)

     # Normalize the smoothed data to a range of 0 to 1
    min_curvature = min(smoothed_data)
    max_curvature = max(smoothed_data)
    normalized_data = [2 * ((c - min_curvature) / (max_curvature - min_curvature)) - 1 for c in smoothed_data]   
    print(normalized_data)    
    # Apply the normalized curvature to each point's radius
    for i, point in enumerate(gp_stroke.points):
        point.pressure = point.pressure + normalized_data[i]/10

        #gp_stroke.points[i].pressure = gp_stroke.points[i].pressure + curvature/10
Ulf3000 commented 1 year ago

got the concavity convexity going

grafik

now the next step would be to segment the stroke and then use the segments length as a to widen the smoothing by factor. if that works the next step would be to use length property to thicken and thinnen over long arcs (the longer the arc the higher the factor)

chsh2 commented 1 year ago

Thank you for your efforts! I have integrated this function into the Taper operator. I adopted a different way of calculation to avoid using scipy, but the results should be similar. The convexity/concavity difference and smooth level can all be configured. I may add other options later.

Ulf3000 commented 1 year ago

Thank you for your efforts! I have integrated this function into the Taper operator. I adopted a different way of calculation to avoid using scipy, but the results should be similar. The convexity/concavity difference and smooth level can all be configured. I may add other options later.

in the 3.4 release ? i cant find it

:edit sorry i needed to restart then it worked , works really great ..