GPv3: Tint and Color modifiers #117297

Merged
Lukas Tönne merged 20 commits from LukasTonne/blender:gp3-color-modifier into main 2024-01-19 16:59:49 +01:00
11 changed files with 85 additions and 22 deletions
Showing only changes of commit 387715fa2e - Show all commits

View File

@ -80,7 +80,7 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
SpanAttributeWriter<float> stroke_hardnesses = attributes.lookup_or_add_for_write_span<float>(
"hardness", AttrDomain::Curve);
SpanAttributeWriter<float> stroke_point_aspect_ratios =
attributes.lookup_or_add_for_write_span<float>("point_aspect_ratio", AttrDomain::Curve);
attributes.lookup_or_add_for_write_span<float>("aspect_ratio", AttrDomain::Curve);
SpanAttributeWriter<float2> stroke_fill_translations =
attributes.lookup_or_add_for_write_span<float2>("fill_translation", AttrDomain::Curve);
SpanAttributeWriter<float> stroke_fill_rotations =

View File

@ -1189,7 +1189,7 @@ class NodeTreeMainUpdater {
}
/* Used to generate new unique IDs if necessary. */
RandomNumberGenerator rng(PIL_check_seconds_timer_i() & UINT_MAX);
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
Map<int32_t, bNestedNodePath> new_path_by_id;
for (const bNestedNodePath &path : nested_node_paths) {

View File

@ -62,6 +62,8 @@
#include "BLO_read_write.hh"
#include "DEG_depsgraph_query.hh"
#include "BIK_api.h"
#ifdef WITH_BULLET
@ -3349,6 +3351,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
/* clear baking flag */
PTCacheID pid_eval;
if (pid && cache) {
cache->flag &= ~(PTCACHE_BAKING | PTCACHE_REDO_NEEDED);
cache->flag |= PTCACHE_SIMULATION_VALID;
@ -3356,7 +3359,13 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
cache->flag |= PTCACHE_BAKED;
/* write info file */
if (cache->flag & PTCACHE_DISK_CACHE) {
BKE_ptcache_write(pid, 0);
ID *id = pid->owner_id;
Object *ob = (GS(id->name) == ID_OB) ? reinterpret_cast<Object *>(id) : nullptr;
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystem *psys = static_cast<ParticleSystem *>(pid->calldata);
ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
BKE_ptcache_id_from_particles(&pid_eval, ob_eval, psys_eval);
BKE_ptcache_write(&pid_eval, 0);
}
}
}
@ -3386,7 +3395,13 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
if (bake) {
cache->flag |= PTCACHE_BAKED;
if (cache->flag & PTCACHE_DISK_CACHE) {
BKE_ptcache_write(pid, 0);
ID *id = pid->owner_id;
Object *ob = (GS(id->name) == ID_OB) ? reinterpret_cast<Object *>(id) : nullptr;
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystem *psys = static_cast<ParticleSystem *>(pid->calldata);
ParticleSystem *psys_eval = psys_eval_get(depsgraph, ob, psys);
BKE_ptcache_id_from_particles(&pid_eval, ob_eval, psys_eval);
BKE_ptcache_write(&pid_eval, 0);
}
}
}

View File

@ -24,6 +24,12 @@ class RandomNumberGenerator {
this->seed(seed);
}
/**
* Creates a random number generator with a somewhat random seed. This can be used when
* determinism is not necessary or not desired.
*/
static RandomNumberGenerator from_random_seed();
/**
* Set the seed for future random numbers.
*/

View File

@ -25,6 +25,8 @@
#include "BLI_strict_flags.h"
#include "BLI_sys_types.h"
#include "PIL_time.h"
extern "C" uchar BLI_noise_hash_uchar_512[512]; /* `noise.cc` */
#define hash BLI_noise_hash_uchar_512
@ -363,6 +365,12 @@ void BLI_hammersley_2d_sequence(uint n, double *r)
namespace blender {
RandomNumberGenerator RandomNumberGenerator::from_random_seed()
{
const double time = PIL_check_seconds_timer() * 1000000.0;
return RandomNumberGenerator(*reinterpret_cast<const uint32_t *>(&time));
}
void RandomNumberGenerator::seed_random(uint32_t seed)
{
this->seed(seed + hash[seed & 255]);

View File

@ -12,6 +12,7 @@ void main()
ivec2 output_size = max(imageSize(output_img), imageSize(mask_img));
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(output_size);
float accumulated_mask = 0.0;
vec4 accumulated_color = vec4(0.0);
for (int i = 0; i < number_of_motion_blur_samples; i++) {
mat3 homography_matrix = mat3(homography_matrices[i]);
@ -25,11 +26,21 @@ void main()
vec2 x_gradient = homography_matrix[0].xy / transformed_coordinates.z;
vec2 y_gradient = homography_matrix[1].xy / transformed_coordinates.z;
accumulated_color += textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
accumulated_color += sampled_color;
/* The plane mask is 1 if it is inside the plane and 0 otherwise. However, we use the alpha
* value of the sampled color for pixels outside of the plane to utilize the anti-aliasing
* effect of the anisotropic filtering. Therefore, the input_tx sampler should use anisotropic
* filtering and be clamped to zero border color. */
bool is_inside_plane = all(greaterThanEqual(projected_coordinates, vec2(0.0))) &&
all(lessThanEqual(projected_coordinates, vec2(1.0)));
accumulated_mask += is_inside_plane ? 1.0 : sampled_color.a;
}
accumulated_mask /= number_of_motion_blur_samples;
accumulated_color /= number_of_motion_blur_samples;
imageStore(output_img, texel, accumulated_color);
imageStore(mask_img, texel, accumulated_color.aaaa);
imageStore(mask_img, texel, vec4(accumulated_mask));
}

View File

@ -54,12 +54,23 @@ vec3 gpencil_lighting(void)
return clamp(light_accum, 0.0, 1e10);
}
/* TODO: Remove this once we can render textures. */
vec4 debug_texture(vec2 uv)
{
vec4 col = vec4(mod(uv.xy, 1.0), 0.0, 1.0);
return col * min(length(uv.xy * 2 - 1), 1);
}
void main()
{
vec4 col;
if (flag_test(gp_interp_flat.mat_flag, GP_STROKE_TEXTURE_USE)) {
bool premul = flag_test(gp_interp_flat.mat_flag, GP_STROKE_TEXTURE_PREMUL);
col = texture_read_as_linearrgb(gpStrokeTexture, premul, gp_interp.uv);
/* TODO: Remove this once we can render textures. */
/* Debug color. (Because textures are not yet implemented) */
col = debug_texture(gp_interp.uv);
}
else if (flag_test(gp_interp_flat.mat_flag, GP_FILL_TEXTURE_USE)) {
bool use_clip = flag_test(gp_interp_flat.mat_flag, GP_FILL_TEXTURE_CLIP);

View File

@ -488,17 +488,24 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const VArray<float> opacities = info.drawing.opacities();
const VArray<ColorGeometry4f> vertex_colors = *attributes.lookup_or_default<ColorGeometry4f>(
"vertex_color", bke::AttrDomain::Point, ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
const VArray<float> rotations = *attributes.lookup_or_default<float>(
"rotation", bke::AttrDomain::Point, 0.0f);
/* Assumes that if the ".selection" attribute does not exist, all points are selected. */
const VArray<float> selection_float = *attributes.lookup_or_default<float>(
".selection", bke::AttrDomain::Point, true);
const VArray<int8_t> start_caps = *attributes.lookup_or_default<int8_t>(
"start_cap", bke::AttrDomain::Curve, GP_STROKE_CAP_TYPE_ROUND);
const VArray<int8_t> end_caps = *attributes.lookup_or_default<int8_t>(
"end_cap", bke::AttrDomain::Curve, GP_STROKE_CAP_TYPE_ROUND);
"end_cap", bke::AttrDomain::Curve, 0);
const VArray<float> stroke_hardnesses = *attributes.lookup_or_default<float>(
"hardness", bke::AttrDomain::Curve, 1.0f);
const VArray<float> stroke_point_aspect_ratios = *attributes.lookup_or_default<float>(
"aspect_ratio", bke::AttrDomain::Curve, 1.0f);
const VArray<ColorGeometry4f> stroke_fill_colors =
*attributes.lookup_or_default<ColorGeometry4f>(
"fill_color", bke::AttrDomain::Curve, ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f));
const VArray<int> materials = *attributes.lookup_or_default<int>(
"material_index", bke::AttrDomain::Curve, 0);
const VArray<float> hardness = *attributes.lookup_or_default<float>(
"hardness", bke::AttrDomain::Curve, 1.0f);
const Span<uint3> triangles = info.drawing.triangles();
const Span<int> verts_start_offsets = verts_start_offsets_per_visible_drawing[drawing_i];
const Span<int> tris_start_offsets = tris_start_offsets_per_visible_drawing[drawing_i];
@ -506,12 +513,15 @@ static void grease_pencil_geom_batch_ensure(Object &object,
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
object, info.drawing, memory);
curves.ensure_evaluated_lengths();
auto populate_point = [&](IndexRange verts_range,
int curve_i,
int8_t start_cap,
int8_t end_cap,
int point_i,
int idx,
float length,
GreasePencilStrokeVert &s_vert,
GreasePencilColorVert &c_vert) {
copy_v3_v3(s_vert.pos, positions[point_i]);
@ -522,15 +532,14 @@ static void grease_pencil_geom_batch_ensure(Object &object,
s_vert.stroke_id = verts_range.first();
s_vert.mat = materials[curve_i] % GPENCIL_MATERIAL_BUFFER_LEN;
/* TODO: Populate rotation and aspect. */
s_vert.packed_asp_hard_rot = pack_rotation_aspect_hardness(0.0f, 1.0f, hardness[curve_i]);
/* TODO: Populate stroke UVs. */
s_vert.u_stroke = 0;
s_vert.packed_asp_hard_rot = pack_rotation_aspect_hardness(
rotations[point_i], stroke_point_aspect_ratios[curve_i], stroke_hardnesses[curve_i]);
s_vert.u_stroke = length;
/* TODO: Populate fill UVs. */
s_vert.uv_fill[0] = s_vert.uv_fill[1] = 0;
copy_v4_v4(c_vert.vcol, vertex_colors[point_i]);
copy_v4_v4(c_vert.fcol, vertex_colors[point_i]);
copy_v4_v4(c_vert.fcol, stroke_fill_colors[curve_i]);
c_vert.fcol[3] = (int(c_vert.fcol[3] * 10000.0f) * 10.0f) + 1.0f;
int v_mat = (verts_range[idx] << GP_VERTEX_ID_SHIFT) | GP_IS_STROKE_VERTEX_BIT;
@ -548,6 +557,8 @@ static void grease_pencil_geom_batch_ensure(Object &object,
MutableSpan<GreasePencilStrokeVert> verts_slice = verts.slice(verts_range);
MutableSpan<GreasePencilColorVert> cols_slice = cols.slice(verts_range);
const Span<float> lengths = curves.evaluated_lengths_for_curve(curve_i, is_cyclic);
/* First vertex is not drawn. */
verts_slice.first().mat = -1;
@ -565,24 +576,28 @@ static void grease_pencil_geom_batch_ensure(Object &object,
/* Write all the point attributes to the vertex buffers. Create a quad for each point. */
for (const int i : IndexRange(points.size())) {
const int idx = i + 1;
const float length = (i >= 1) ? lengths[i - 1] : 0.0f;
populate_point(verts_range,
curve_i,
start_caps[curve_i],
end_caps[curve_i],
points[i],
idx,
length,
verts_slice[idx],
cols_slice[idx]);
}
if (is_cyclic) {
const int idx = points.size() + 1;
const float length = lengths[points.size() - 1];
populate_point(verts_range,
curve_i,
start_caps[curve_i],
end_caps[curve_i],
points[0],
idx,
length,
verts_slice[idx],
cols_slice[idx]);
}

View File

@ -179,9 +179,7 @@ struct AddOperationExecutor {
return;
}
const double time = PIL_check_seconds_timer() * 1000000.0;
/* Use a pointer cast to avoid overflow warnings. */
RandomNumberGenerator rng{*(uint32_t *)(&time)};
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
/* Sample points on the surface using one of multiple strategies. */
Vector<float2> sampled_uvs;

View File

@ -164,8 +164,7 @@ struct DensityAddOperationExecutor {
Vector<float3> new_positions_cu;
Vector<float2> new_uvs;
const double time = PIL_check_seconds_timer() * 1000000.0;
RandomNumberGenerator rng{*(uint32_t *)(&time)};
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
/* Find potential new curve root points. */
if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
@ -634,7 +633,7 @@ struct DensitySubtractOperationExecutor {
* strength. */
Array<bool> allow_remove_curve(curves_->curves_num(), false);
threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
RandomNumberGenerator rng(int(PIL_check_seconds_timer() * 1000000.0));
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
for (const int curve_i : range) {
if (!curves_to_keep[curve_i]) {
@ -724,7 +723,7 @@ struct DensitySubtractOperationExecutor {
* strength. */
Array<bool> allow_remove_curve(curves_->curves_num(), false);
threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
RandomNumberGenerator rng(int(PIL_check_seconds_timer() * 1000000.0));
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
for (const int curve_i : range) {
if (!curves_to_keep[curve_i]) {

View File

@ -884,7 +884,7 @@ static void update_nested_node_refs_after_moving_nodes_into_group(
const Map<int32_t, int32_t> &node_identifier_map)
{
/* Update nested node references in the parent and child node tree. */
RandomNumberGenerator rng(PIL_check_seconds_timer_i() & UINT_MAX);
RandomNumberGenerator rng = RandomNumberGenerator::from_random_seed();
Vector<bNestedNodeRef> new_nested_node_refs;
/* Keep all nested node references that were in the group before. */
for (const bNestedNodeRef &ref : group.nested_node_refs_span()) {