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/source/blender/blenkernel/BKE_shrinkwrap.h
Hans Goudey 7966cd16d6 Mesh: Replace MPoly struct with offset indices
Implements #95967.

Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.

The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.

Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.

Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.

Some:
- The offset integer array has to be one longer than the face count to
  avoid a branch for every face, which means the data is no longer part
  of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
  until more reusable CoW from #104478 is committed. That will be added
  in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
  copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
  structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
  corners, but just in case, meshes with mismatched order are fixed by
  versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
  necessary here unfortunately. It should be worth it in 3.6, since
  that's the best way to allow loading meshes from 4.0, which is
  important for an LTS version.

Pull Request: blender/blender#105938
2023-04-04 20:39:28 +02:00

224 lines
7.7 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright Blender Foundation */
#pragma once
/** \file
* \ingroup bke
*/
/* Shrinkwrap stuff */
#include "BKE_bvhutils.h"
#include "BLI_bitmap.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Shrinkwrap is composed by a set of functions and options that define the type of shrink.
*
* 3 modes are available:
* - Nearest vertex.
* - Nearest surface.
* - Normal projection.
*
* #ShrinkwrapCalcData encapsulates all needed data for shrink-wrap functions.
* (So that you don't have to pass an enormous amount of arguments to functions)
*/
struct BVHTree;
struct MDeformVert;
struct Mesh;
struct ModifierEvalContext;
struct Object;
struct ShrinkwrapGpencilModifierData;
struct ShrinkwrapModifierData;
struct SpaceTransform;
/* Information about boundary edges in the mesh. */
typedef struct ShrinkwrapBoundaryVertData {
/* Average direction of edges that meet here. */
float direction[3];
/* Closest vector to direction that is orthogonal to vertex normal. */
float normal_plane[3];
} ShrinkwrapBoundaryVertData;
typedef struct ShrinkwrapBoundaryData {
/* True if the edge belongs to exactly one face. */
const BLI_bitmap *edge_is_boundary;
/* True if the looptri has any boundary edges. */
const BLI_bitmap *looptri_has_boundary;
/* Mapping from vertex index to boundary vertex index, or -1.
* Used for compact storage of data about boundary vertices. */
const int *vert_boundary_id;
unsigned int num_boundary_verts;
/* Direction data about boundary vertices. */
const ShrinkwrapBoundaryVertData *boundary_verts;
} ShrinkwrapBoundaryData;
/**
* Free boundary data for target project.
*/
void BKE_shrinkwrap_boundary_data_free(ShrinkwrapBoundaryData *data);
void BKE_shrinkwrap_compute_boundary_data(struct Mesh *mesh);
/* Information about a mesh and BVH tree. */
typedef struct ShrinkwrapTreeData {
Mesh *mesh;
BVHTree *bvh;
BVHTreeFromMesh treeData;
const int *poly_offsets;
const float (*vert_normals)[3];
const int *corner_edges;
const float (*poly_normals)[3];
const bool *sharp_faces;
const float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
/**
* Checks if the modifier needs target normals with these settings.
*/
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode);
/**
* Initializes the mesh data structure from the given mesh and settings.
*/
bool BKE_shrinkwrap_init_tree(struct ShrinkwrapTreeData *data,
Mesh *mesh,
int shrinkType,
int shrinkMode,
bool force_normals);
/**
* Frees the tree data if necessary.
*/
void BKE_shrinkwrap_free_tree(struct ShrinkwrapTreeData *data);
/**
* Main shrink-wrap function (implementation of the shrink-wrap modifier).
*/
void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd,
const struct ModifierEvalContext *ctx,
struct Scene *scene,
struct Object *ob,
struct Mesh *mesh,
const struct MDeformVert *dvert,
int defgrp_index,
float (*vertexCos)[3],
int numVerts);
/* Implementation of the Shrinkwrap Grease Pencil modifier. */
void shrinkwrapGpencilModifier_deform(struct ShrinkwrapGpencilModifierData *mmd,
struct Object *ob,
struct MDeformVert *dvert,
int defgrp_index,
float (*vertexCos)[3],
int numVerts);
/**
* Used in `editmesh_mask_extract.cc` to shrink-wrap the extracted mesh to the sculpt.
*/
void BKE_shrinkwrap_mesh_nearest_surface_deform(struct bContext *C,
struct Object *ob_source,
struct Object *ob_target);
/**
* Used in `object_remesh.cc` to preserve the details and volume in the voxel remesher.
*/
void BKE_shrinkwrap_remesh_target_project(struct Mesh *src_me,
struct Mesh *target_me,
struct Object *ob_target);
/**
* This function ray-cast a single vertex and updates the hit if the "hit" is considered valid.
*
* \param options: Opts control whether an hit is valid or not.
* Supported options are:
* - #MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
* - #MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
*
* \param transf: Take into consideration the space_transform, that is:
* if `transf` was configured with `SPACE_TRANSFORM_SETUP( &transf, ob1, ob2)`
* then the input (vert, dir, #BVHTreeRayHit) must be defined in ob1 coordinates space
* and the #BVHTree must be built in ob2 coordinate space.
* Thus it provides an easy way to cast the same ray across several trees
* (where each tree was built on its own coords space).
*
* \return true if "hit" was updated.
*/
bool BKE_shrinkwrap_project_normal(char options,
const float vert[3],
const float dir[3],
float ray_radius,
const struct SpaceTransform *transf,
struct ShrinkwrapTreeData *tree,
BVHTreeRayHit *hit);
/**
* Maps the point to the nearest surface, either by simple nearest, or by target normal projection.
*/
void BKE_shrinkwrap_find_nearest_surface(struct ShrinkwrapTreeData *tree,
struct BVHTreeNearest *nearest,
float co[3],
int type);
/**
* Compute a smooth normal of the target (if applicable) at the hit location.
*
* \param tree: information about the mesh.
* \param transform: transform from the hit coordinate space to the object space; may be null.
* \param r_no: output in hit coordinate space; may be shared with inputs.
*/
void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int looptri_idx,
const float hit_co[3],
const float hit_no[3],
float r_no[3]);
/**
* Apply the shrink to surface modes to the given original coordinates and nearest point.
*
* \param tree: mesh data for smooth normals.
* \param transform: transform from the hit coordinate space to the object space; may be null.
* \param r_point_co: may be the same memory location as `point_co`, `hit_co`, or `hit_no`.
*/
void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree,
const struct SpaceTransform *transform,
int mode,
int hit_idx,
const float hit_co[3],
const float hit_no[3],
float goal_dist,
const float point_co[3],
float r_point_co[3]);
/*
* NULL initializes to local data
*/
#define NULL_ShrinkwrapCalcData \
{ \
NULL, \
}
#define NULL_BVHTreeFromMesh \
{ \
NULL, \
}
#define NULL_BVHTreeRayHit \
{ \
NULL, \
}
#define NULL_BVHTreeNearest \
{ \
0, \
}
#ifdef __cplusplus
}
#endif