tornavis/source/blender/blenkernel/intern/multires_reshape.hh

385 lines
14 KiB
C++

/* SPDX-FileCopyrightText: 2020 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#pragma once
#include "BLI_math_vector_types.hh"
#include "BLI_offset_indices.hh"
#include "BLI_span.hh"
#include "BLI_sys_types.h"
#include "BLI_virtual_array.hh"
#include "BKE_multires.hh"
struct Depsgraph;
struct GridPaintMask;
struct MDisps;
struct Mesh;
struct MultiresModifierData;
struct Object;
struct Subdiv;
struct SubdivCCG;
struct MultiresReshapeContext {
/* NOTE: Only available when context is initialized from object. */
Depsgraph *depsgraph;
Object *object;
MultiresModifierData *mmd;
/* Base mesh from original object.
* NOTE: Does NOT include any leading modifiers in it. */
Mesh *base_mesh;
blender::Span<blender::float3> base_positions;
blender::Span<blender::int2> base_edges;
blender::OffsetIndices<int> base_faces;
blender::Span<int> base_corner_verts;
blender::Span<int> base_corner_edges;
/* Subdivision surface created for multires modifier.
*
* The coarse mesh of this subdivision surface is a base mesh with all deformation modifiers
* leading multires applied on it. */
Subdiv *subdiv;
bool need_free_subdiv;
struct {
/* Level at which displacement is being assigned to.
* It will be propagated up from this level to top.level. */
int level;
/* Grid size for reshape.level. */
int grid_size;
} reshape;
struct {
/* Top level of the displacement grids.
* The displacement will be propagated up to this level. */
int level;
/* Grid size for top.level. */
int grid_size;
} top;
struct {
/* Copy of original displacement and painting masks. */
MDisps *mdisps;
GridPaintMask *grid_paint_masks;
} orig;
/* Number of grids which are required for base_mesh. */
int num_grids;
/* Destination displacement and mask.
* Points to a custom data on a destination mesh. */
MDisps *mdisps;
GridPaintMask *grid_paint_masks;
/* Indexed by face index, gives first grid index of the face. */
int *face_start_grid_index;
/* Indexed by grid index, contains face index in the base mesh from which the grid has
* been created (in other words, index of a face which contains loop corresponding to the grid
* index). */
int *grid_to_face_index;
/* Indexed by ptex face index, gives first grid index of the ptex face.
*
* For non-quad base faces ptex face is created for every face corner, so it's similar to a
* grid in this case. In this case start grid index will be the only one for this ptex face.
*
* For quad base faces there is a single ptex face but 4 grids. So in this case there will be
* 4 grids for the ptex, starting at a value stored in this mapping. */
int *ptex_start_grid_index;
/* Indexed by base face index, returns first ptex face index corresponding
* to that base face. */
int *face_ptex_offset;
/* Vertex crease custom data layer, empty if none is present. */
blender::VArraySpan<float> cd_vertex_crease;
/* Edge crease custom data layer, empty if none is present. */
blender::VArraySpan<float> cd_edge_crease;
};
/**
* Coordinate which identifies element of a grid.
* This is directly related on how #CD_MDISPS stores displacement.
*/
struct GridCoord {
int grid_index;
float u, v;
};
/**
* Coordinate within ptex, which is what OpenSubdiv API operates on.
*/
struct PTexCoord {
int ptex_face_index;
float u, v;
};
/**
* Element of a grid data stored in the destination mesh.
* This is where reshaped coordinates and mask values will be written to.
*/
struct ReshapeGridElement {
float *displacement;
float *mask;
};
struct ReshapeConstGridElement {
float displacement[3];
float mask;
};
/* --------------------------------------------------------------------
* Construct/destruct reshape context.
*/
/**
* Create subdivision surface descriptor which is configured for surface evaluation at a given
* multi-res modifier.
*/
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
Object *object,
const MultiresModifierData *mmd);
/**
* \note Initialized base mesh to object's mesh, the Subdivision is created from the deformed
* mesh prior to the multi-res modifier if depsgraph is not NULL. If the depsgraph is NULL
* then Subdivision is created from base mesh (without any deformation applied).
*/
bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape_context,
Depsgraph *depsgraph,
Object *object,
MultiresModifierData *mmd);
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
Depsgraph *depsgraph,
Object *object,
MultiresModifierData *mmd);
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context,
SubdivCCG *subdiv_ccg,
Mesh *base_mesh,
int top_level);
bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *reshape_context,
Object *object,
MultiresModifierData *mmd,
int top_level);
bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape_context,
Object *object,
MultiresModifierData *mmd,
Subdiv *subdiv,
int top_level);
void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_context_free(MultiresReshapeContext *reshape_context);
/* --------------------------------------------------------------------
* Helper accessors.
*/
/**
* For the given grid index get index of face it was created for.
*/
int multires_reshape_grid_to_face_index(const MultiresReshapeContext *reshape_context,
int grid_index);
/**
* For the given grid index get corner of a face it was created for.
*/
int multires_reshape_grid_to_corner(const MultiresReshapeContext *reshape_context, int grid_index);
bool multires_reshape_is_quad_face(const MultiresReshapeContext *reshape_context, int face_index);
/**
* For the given grid index get index of corresponding PTEX face.
*/
int multires_reshape_grid_to_ptex_index(const MultiresReshapeContext *reshape_context,
int grid_index);
/**
* Convert normalized coordinate within a grid to a normalized coordinate within a PTEX face.
*/
PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord);
/**
* Convert a normalized coordinate within a PTEX face to a normalized coordinate within a grid.
*/
GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *reshape_context,
const PTexCoord *ptex_coord);
/**
* Calculate tangent matrix which converts displacement to a object vector.
* Is calculated for the given surface derivatives at a given base face corner.
*/
void multires_reshape_tangent_matrix_for_corner(const MultiresReshapeContext *reshape_context,
int face_index,
int corner,
const float dPdu[3],
const float dPdv[3],
float r_tangent_matrix[3][3]);
/**
* Get grid elements which are to be reshaped at a given or PTEX coordinate.
* The data is coming from final custom mdata layers.
*/
ReshapeGridElement multires_reshape_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
ReshapeGridElement multires_reshape_grid_element_for_ptex_coord(
const MultiresReshapeContext *reshape_context, const PTexCoord *ptex_coord);
/**
* Get original grid element for the given coordinate.
*/
ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
const MultiresReshapeContext *reshape_context, const GridCoord *grid_coord);
/* --------------------------------------------------------------------
* Sample limit surface of the base mesh.
*/
/**
* Evaluate limit surface created from base mesh.
* This is the limit surface which defines tangent space for MDisps.
*/
void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *reshape_context,
const GridCoord *grid_coord,
float r_P[3],
float r_tangent_matrix[3][3]);
/* --------------------------------------------------------------------
* Custom data preparation.
*/
/**
* Make sure custom data is allocated for the given level.
*/
void multires_reshape_ensure_grids(Mesh *mesh, int level);
/* --------------------------------------------------------------------
* Functions specific to reshaping from a set of vertices in a object position.
*/
/**
* Set displacement grids values at a reshape level to a object coordinates of the given source.
*
* \returns truth if all coordinates were assigned.
*
* False will be returned if the number of vertex coordinates did not match required number of
* vertices at a reshape level.
*/
bool multires_reshape_assign_final_coords_from_vertcos(
const MultiresReshapeContext *reshape_context,
const float (*vert_coords)[3],
int num_vert_coords);
/* --------------------------------------------------------------------
* Functions specific to reshaping from CCG.
*/
/**
* Store final object-space coordinates in the displacement grids.
* The reason why displacement grids are used for storage is based on memory
* footprint optimization.
*
* \note Displacement grids to be at least at a reshape level.
*
* \return truth if all coordinates have been updated.
*/
bool multires_reshape_assign_final_coords_from_ccg(const MultiresReshapeContext *reshape_context,
SubdivCCG *subdiv_ccg);
/* --------------------------------------------------------------------
* Functions specific to reshaping from MDISPS.
*/
/**
* Reads and writes to the current mesh #CD_MDISPS.
*/
void multires_reshape_assign_final_coords_from_mdisps(
const MultiresReshapeContext *reshape_context);
/**
* Reads from original #CD_MIDTSPS, writes to the current mesh #CD_MDISPS.
*/
void multires_reshape_assign_final_elements_from_orig_mdisps(
const MultiresReshapeContext *reshape_context);
/* --------------------------------------------------------------------
* Displacement smooth.
*/
/**
* Operates on a displacement grids (CD_MDISPS) which contains object space coordinates stored for
* the reshape level.
*
* The result is grids which are defining mesh with a smooth surface and details starting from
* reshape level up to top level added back from original displacement grids.
*/
void multires_reshape_smooth_object_grids_with_details(
const MultiresReshapeContext *reshape_context);
/**
* Operates on a displacement grids (CD_MDISPS) which contains object space-coordinates stored for
* the reshape level.
*
* Makes it so surface on top level looks smooth. Details are not preserved
*/
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
enum eMultiresSubdivideModeType mode);
/* --------------------------------------------------------------------
* Displacement, space conversion.
*/
/**
* Store original grid data, so then it's possible to calculate delta from it and add
* high-frequency content on top of reshaped grids.
*/
void multires_reshape_store_original_grids(MultiresReshapeContext *reshape_context);
void multires_reshape_object_grids_to_tangent_displacement(
const MultiresReshapeContext *reshape_context);
/* --------------------------------------------------------------------
* Apply base.
*/
/**
* Update mesh coordinates to the final positions of displacement in object space.
* This is effectively desired position of base mesh vertices after canceling out displacement.
*
* \note Expects that mesh's CD_MDISPS has been set to object space positions.
*/
void multires_reshape_apply_base_update_mesh_coords(MultiresReshapeContext *reshape_context);
/**
* Perform better fitting of the base mesh so its subdivided version brings vertices to their
* desired locations.
*/
void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape_context);
/**
* Refine subdivision surface to the new positions of the base mesh.
*/
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context);
/**
* Refine subdivision surface to the new positions of the deformed mesh (base mesh with all
* modifiers leading the multi-res applied).
*
* \note Will re-evaluate all leading modifiers, so it's not cheap.
*/
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context);