{F13294314}
# Process
In the pixel extraction process a larger domain will be extracted then the input mesh.
The borders of uv islands are extended with connected geometry of the input mesh.
The extended mesh is then fed into the pixel extraction process.
A mask is used to limit the extraction so UV islands will not overlap.
Input UV islands.
{F13206401}
Extended UV Island (only one showing).
{F13288764}
This patch doesn't include fixing uv seams at non-manifold edges (like suzannes eyes) as that
would require a different approach (edge extending or pixel copy-ing). The later has already been
implemented in D14702, but should be revisited to only use do the non-manifold edge fixing.
This patch supports fixing UV seams across UDIM textures.
There might be an issue when using a single texture on multiple uv maps.
Reviewed By: brecht, joeedh, JulienKaspar
Maniphest Tasks: T97352
Differential Revision: https://developer.blender.org/D14970
120 lines
2.5 KiB
C++
120 lines
2.5 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
#include <algorithm>
|
|
|
|
#include "BLI_vector.hh"
|
|
|
|
namespace blender {
|
|
|
|
/**
|
|
* A VectorList is a vector of vectors.
|
|
*
|
|
* VectorList can be used when:
|
|
*
|
|
* 1) Don't know up front the number of elements that will be added to the list. Use array or
|
|
* vector.reserve when known up front.
|
|
*
|
|
* 2) Number of reads/writes doesn't require sequential access
|
|
* of the whole list. A vector ensures memory is sequential which is fast when reading, writing can
|
|
* have overhead when the reserved memory is full.
|
|
*
|
|
* When a VectorList reserved memory is full it will allocate memory for the new items, breaking
|
|
* the sequential access. Within each allocated memory block the elements are ordered sequentially.
|
|
*/
|
|
template<typename T, int64_t CapacityStart = 32, int64_t CapacitySoftLimit = 4096>
|
|
class VectorList {
|
|
public:
|
|
using UsedVector = Vector<T, 0>;
|
|
|
|
private:
|
|
/**
|
|
* Contains the individual vectors. There must always be at least one vector
|
|
*/
|
|
Vector<UsedVector> vectors_;
|
|
|
|
public:
|
|
VectorList()
|
|
{
|
|
this->append_vector();
|
|
}
|
|
|
|
void append(const T &value)
|
|
{
|
|
this->append_as(value);
|
|
}
|
|
|
|
void append(T &&value)
|
|
{
|
|
this->append_as(std::move(value));
|
|
}
|
|
|
|
template<typename ForwardT> void append_as(ForwardT &&value)
|
|
{
|
|
UsedVector &vector = this->ensure_space_for_one();
|
|
vector.append_unchecked_as(std::forward<ForwardT>(value));
|
|
}
|
|
|
|
UsedVector *begin()
|
|
{
|
|
return vectors_.begin();
|
|
}
|
|
|
|
UsedVector *end()
|
|
{
|
|
return vectors_.end();
|
|
}
|
|
|
|
const UsedVector *begin() const
|
|
{
|
|
return vectors_.begin();
|
|
}
|
|
|
|
const UsedVector *end() const
|
|
{
|
|
return vectors_.end();
|
|
}
|
|
|
|
T &last()
|
|
{
|
|
return vectors_.last().last();
|
|
}
|
|
|
|
int64_t size() const
|
|
{
|
|
int64_t result = 0;
|
|
for (const UsedVector &vector : *this) {
|
|
result += vector.size();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
UsedVector &ensure_space_for_one()
|
|
{
|
|
UsedVector &vector = vectors_.last();
|
|
if (LIKELY(!vector.is_at_capacity())) {
|
|
return vector;
|
|
}
|
|
this->append_vector();
|
|
return vectors_.last();
|
|
}
|
|
|
|
void append_vector()
|
|
{
|
|
const int64_t new_vector_capacity = this->get_next_vector_capacity();
|
|
vectors_.append({});
|
|
vectors_.last().reserve(new_vector_capacity);
|
|
}
|
|
|
|
int64_t get_next_vector_capacity()
|
|
{
|
|
if (vectors_.is_empty()) {
|
|
return CapacityStart;
|
|
}
|
|
return std::min(vectors_.last().capacity() * 2, CapacitySoftLimit);
|
|
}
|
|
};
|
|
|
|
} // namespace blender
|