Files
test/source/blender/blenkernel/intern/multires_reshape.h
Kévin Dietrich 4425e0cd64 Subdivision: add support for vertex creasing
This adds vertex creasing support for OpenSubDiv for modeling, rendering,
Alembic and USD I/O.

For modeling, vertex creasing follows the edge creasing implementation with an
operator accessible through the Vertex menu in Edit Mode, and some parameter in
the properties panel. The option in the Subsurf and Multires to use edge
creasing also affects vertex creasing.

The vertex crease data is stored as a CustomData layer, unlike edge creases
which for now are stored in `MEdge`, but will in the future also be moved to
a `CustomData` layer. See comments for details on the difference in behavior
for the `CD_CREASE` layer between egdes and vertices.

For Cycles this adds sockets on the Mesh node to hold data about which vertices
are creased (one socket for the indices, one for the weigths).

Viewport rendering of vertex creasing reuses the same color scheme as for edges
and creased vertices are drawn bigger than uncreased vertices.

For Alembic and USD, vertex crease support follows the edge crease
implementation, they are always read, but only exported if a `Subsurf` modifier
is present on the Mesh.

Reviewed By: brecht, fclem, sergey, sybren, campbellbarton

Differential Revision: https://developer.blender.org/D10145
2022-01-20 12:21:34 +01:00

389 lines
14 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup bke
*/
#pragma once
#include "BLI_sys_types.h"
#include "BKE_multires.h"
struct Depsgraph;
struct GridPaintMask;
struct MDisps;
struct Mesh;
struct MultiresModifierData;
struct Object;
struct Subdiv;
struct SubdivCCG;
typedef struct MultiresReshapeContext {
/* NOTE: Only available when context is initialized from object. */
struct Depsgraph *depsgraph;
struct Object *object;
struct MultiresModifierData *mmd;
/* Base mesh from original object.
* NOTE: Does NOT include any leading modifiers in it. */
struct Mesh *base_mesh;
/* 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. */
struct 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. */
struct MDisps *mdisps;
struct 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. */
struct MDisps *mdisps;
struct 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 (poly) index in the base mesh from which the grid has
* been created (in other words, index of a poly 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, null if none is present. */
const float *cd_vertex_crease;
} MultiresReshapeContext;
/**
* Coordinate which identifies element of a grid.
* This is directly related on how #CD_MDISPS stores displacement.
*/
typedef struct GridCoord {
int grid_index;
float u, v;
} GridCoord;
/**
* Coordinate within ptex, which is what OpenSubdiv API operates on.
*/
typedef struct PTexCoord {
int ptex_face_index;
float u, v;
} PTexCoord;
/**
* Element of a grid data stored in the destination mesh.
* This is where reshaped coordinates and mask values will be written to.
*/
typedef struct ReshapeGridElement {
float *displacement;
float *mask;
} ReshapeGridElement;
typedef struct ReshapeConstGridElement {
float displacement[3];
float mask;
} ReshapeConstGridElement;
/* --------------------------------------------------------------------
* Construct/destruct reshape context.
*/
/**
* Create subdivision surface descriptor which is configured for surface evaluation at a given
* multi-res modifier.
*/
struct Subdiv *multires_reshape_create_subdiv(struct Depsgraph *depsgraph,
struct Object *object,
const struct 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,
struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *reshape_context,
struct Depsgraph *depsgraph,
struct Object *object,
struct MultiresModifierData *mmd);
bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_context,
struct SubdivCCG *subdiv_ccg,
struct Mesh *base_mesh,
int top_level);
bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *reshape_context,
struct Object *object,
struct MultiresModifierData *mmd,
int top_level);
bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape_context,
struct Object *object,
struct MultiresModifierData *mmd,
struct 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(struct 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,
struct 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);