USD Export: Add the ability to downsample textures for USDZ
This allows for exporting multiple versions of an asset's textures without having to manually save or do manual edits from within the UI. This is beneficial for game creators who might want to store the original textures at full resolution, but then bake down at export time for multiple different targets quality levels. It can also be good for compressing textures for VR usage. This only affects USDZ exports. Default option: Keep textures at the same resolution. Choosing a resolution will downsample any images that exceed that maximum resolution while leaving the others. A custom setting is provided to allow the user to manually enter their desired size if the provided options aren't suitable. Co-authored-by: Charles Wardlaw <cwardlaw@nvidia.com> Pull Request: https://projects.blender.org/blender/blender/pulls/121237
This commit is contained in:
committed by
Jesse Yurkovich
parent
9182d449d1
commit
3e73b9caa5
@@ -145,6 +145,17 @@ const EnumPropertyItem rna_enum_usd_xform_op_mode_items[] = {
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
const EnumPropertyItem prop_usdz_downscale_size[] = {
|
||||
{USD_TEXTURE_SIZE_KEEP, "KEEP", 0, "Keep", "Keep all current texture sizes"},
|
||||
{USD_TEXTURE_SIZE_256, "256", 0, "256", "Resize to a maximum of 256 pixels"},
|
||||
{USD_TEXTURE_SIZE_512, "512", 0, "512", "Resize to a maximum of 512 pixels"},
|
||||
{USD_TEXTURE_SIZE_1024, "1024", 0, "1024", "Resize to a maximum of 1024 pixels"},
|
||||
{USD_TEXTURE_SIZE_2048, "2048", 0, "2048", "Resize to a maximum of 2048 pixels"},
|
||||
{USD_TEXTURE_SIZE_4096, "4096", 0, "4096", "Resize to a maximum of 4096 pixels"},
|
||||
{USD_TEXTURE_SIZE_CUSTOM, "CUSTOM", 0, "Custom", "Specify a custom size"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
|
||||
* This is set when the operator is invoked, and not set when it is only executed. */
|
||||
enum { AS_BACKGROUND_JOB = 1 };
|
||||
@@ -246,6 +257,11 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
|
||||
|
||||
const eUSDXformOpMode xform_op_mode = eUSDXformOpMode(RNA_enum_get(op->ptr, "xform_op_mode"));
|
||||
|
||||
const eUSDZTextureDownscaleSize usdz_downscale_size = eUSDZTextureDownscaleSize(
|
||||
RNA_enum_get(op->ptr, "usdz_downscale_size"));
|
||||
|
||||
const int usdz_downscale_custom_size = RNA_int_get(op->ptr, "usdz_downscale_custom_size");
|
||||
|
||||
char root_prim_path[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "root_prim_path", root_prim_path);
|
||||
process_prim_path(root_prim_path);
|
||||
@@ -284,6 +300,8 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
|
||||
export_cameras,
|
||||
export_curves,
|
||||
export_volumes,
|
||||
usdz_downscale_size,
|
||||
usdz_downscale_custom_size,
|
||||
};
|
||||
|
||||
STRNCPY(params.root_prim_path, root_prim_path);
|
||||
@@ -364,6 +382,14 @@ static void wm_usd_export_draw(bContext *C, wmOperator *op)
|
||||
const bool preview = RNA_boolean_get(ptr, "generate_preview_surface");
|
||||
uiLayoutSetActive(row, export_mtl && preview);
|
||||
|
||||
uiLayout *col2 = uiLayoutColumn(col, true);
|
||||
uiLayoutSetPropSep(col2, true);
|
||||
uiLayoutSetEnabled(col2, RNA_boolean_get(ptr, "export_textures"));
|
||||
uiItemR(col2, ptr, "usdz_downscale_size", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
if (RNA_enum_get(ptr, "usdz_downscale_size") == USD_TEXTURE_SIZE_CUSTOM) {
|
||||
uiItemR(col2, ptr, "usdz_downscale_custom_size", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
row = uiLayoutRow(col, true);
|
||||
uiItemR(row, ptr, "overwrite_textures", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
const bool export_tex = RNA_boolean_get(ptr, "export_textures");
|
||||
@@ -651,6 +677,23 @@ void WM_OT_usd_export(wmOperatorType *ot)
|
||||
MOD_TRIANGULATE_NGON_BEAUTY,
|
||||
"N-gon Method",
|
||||
"Method for splitting the n-gons into triangles");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"usdz_downscale_size",
|
||||
prop_usdz_downscale_size,
|
||||
DAG_EVAL_VIEWPORT,
|
||||
"USDZ Texture Downsampling",
|
||||
"Choose a maximum size for all exported textures");
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"usdz_downscale_custom_size",
|
||||
128,
|
||||
64,
|
||||
16384,
|
||||
"USDZ Custom Downscale Size",
|
||||
"Custom size for downscaling exported textures",
|
||||
128,
|
||||
8192);
|
||||
}
|
||||
|
||||
/* ====== USD Import ====== */
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "BKE_blender_version.h"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_image_save.h"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_scene.hh"
|
||||
@@ -49,12 +51,16 @@
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
static CLG_LogRef LOG = {"io.usd"};
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
struct ExportJobData {
|
||||
Main *bmain;
|
||||
Depsgraph *depsgraph;
|
||||
wmWindowManager *wm;
|
||||
Scene *scene;
|
||||
|
||||
/** Unarchived_filepath is used for USDA/USDC/USD export. */
|
||||
char unarchived_filepath[FILE_MAX];
|
||||
@@ -188,6 +194,78 @@ static void report_job_duration(const ExportJobData *data)
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
static void process_usdz_textures(const ExportJobData *data, const char *path)
|
||||
{
|
||||
const eUSDZTextureDownscaleSize enum_value = data->params.usdz_downscale_size;
|
||||
if (enum_value == USD_TEXTURE_SIZE_KEEP) {
|
||||
return;
|
||||
}
|
||||
|
||||
int image_size = ((enum_value == USD_TEXTURE_SIZE_CUSTOM ?
|
||||
data->params.usdz_downscale_custom_size :
|
||||
enum_value));
|
||||
|
||||
char texture_path[FILE_MAX];
|
||||
BLI_strncpy_rlen(texture_path, path, FILE_MAX);
|
||||
BLI_path_append(texture_path, FILE_MAX, "textures");
|
||||
BLI_path_slash_ensure(texture_path, sizeof(texture_path));
|
||||
|
||||
struct direntry *entries;
|
||||
unsigned int num_files = BLI_filelist_dir_contents(texture_path, &entries);
|
||||
|
||||
for (int index = 0; index < num_files; index++) {
|
||||
/* We can skip checking extensions as this folder is only created
|
||||
* when we're doing a USDZ export. */
|
||||
if (!BLI_is_dir(entries[index].path)) {
|
||||
Image *im = BKE_image_load(data->bmain, entries[index].path);
|
||||
if (!im) {
|
||||
CLOG_WARN(&LOG, "-- Unable to open file for downscaling: %s", entries[index].path);
|
||||
continue;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
BKE_image_get_size(im, NULL, &width, &height);
|
||||
const int longest = width >= height ? width : height;
|
||||
const float scale = 1.0 / ((float)longest / (float)image_size);
|
||||
|
||||
if (longest > image_size) {
|
||||
const int width_adjusted = float(width) * scale;
|
||||
const int height_adjusted = float(height) * scale;
|
||||
BKE_image_scale(im, width_adjusted, height_adjusted, nullptr);
|
||||
|
||||
ImageSaveOptions opts;
|
||||
|
||||
if (BKE_image_save_options_init(&opts, data->bmain, data->scene, im, NULL, false, false)) {
|
||||
bool result = BKE_image_save(NULL, data->bmain, im, NULL, &opts);
|
||||
if (!result) {
|
||||
CLOG_ERROR(&LOG,
|
||||
"-- Unable to resave %s (new size: %dx%d)",
|
||||
data->usdz_filepath,
|
||||
width_adjusted,
|
||||
height_adjusted);
|
||||
}
|
||||
else {
|
||||
CLOG_INFO(&LOG,
|
||||
2,
|
||||
"Downscaled %s to %dx%d",
|
||||
entries[index].path,
|
||||
width_adjusted,
|
||||
height_adjusted);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_image_save_options_free(&opts);
|
||||
}
|
||||
|
||||
/* Make sure to free the image so it doesn't stick
|
||||
* around in the library of the open file. */
|
||||
BKE_id_free(data->bmain, (void *)im);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_filelist_free(entries, num_files);
|
||||
}
|
||||
|
||||
/**
|
||||
* For usdz export, we must first create a usd/a/c file and then covert it to usdz. In Blender's
|
||||
* case, we first create a usdc file in Blender's temporary working directory, and store the path
|
||||
@@ -217,6 +295,8 @@ static bool perform_usdz_conversion(const ExportJobData *data)
|
||||
|
||||
BLI_change_working_dir(usdc_temp_dir);
|
||||
|
||||
process_usdz_textures(data, usdc_temp_dir);
|
||||
|
||||
pxr::UsdUtilsCreateNewUsdzPackage(pxr::SdfAssetPath(usdc_file), usdz_file);
|
||||
BLI_change_working_dir(original_working_dir);
|
||||
|
||||
@@ -525,6 +605,7 @@ bool USD_export(bContext *C,
|
||||
|
||||
job->bmain = CTX_data_main(C);
|
||||
job->wm = CTX_wm_manager(C);
|
||||
job->scene = scene;
|
||||
job->export_ok = false;
|
||||
set_job_filepath(job, filepath);
|
||||
|
||||
|
||||
@@ -85,6 +85,16 @@ typedef enum eUSDXformOpMode {
|
||||
USD_XFORM_OP_MAT = 2,
|
||||
} eUSDXformOpMode;
|
||||
|
||||
typedef enum eUSDZTextureDownscaleSize {
|
||||
USD_TEXTURE_SIZE_CUSTOM = -1,
|
||||
USD_TEXTURE_SIZE_KEEP = 0,
|
||||
USD_TEXTURE_SIZE_256 = 256,
|
||||
USD_TEXTURE_SIZE_512 = 512,
|
||||
USD_TEXTURE_SIZE_1024 = 1024,
|
||||
USD_TEXTURE_SIZE_2048 = 2048,
|
||||
USD_TEXTURE_SIZE_4096 = 4096
|
||||
} eUSDZTextureDownscaleSize;
|
||||
|
||||
struct USDExportParams {
|
||||
bool export_animation = false;
|
||||
bool export_hair = true;
|
||||
@@ -120,6 +130,8 @@ struct USDExportParams {
|
||||
bool export_curves = true;
|
||||
bool export_volumes = true;
|
||||
|
||||
eUSDZTextureDownscaleSize usdz_downscale_size = eUSDZTextureDownscaleSize::USD_TEXTURE_SIZE_KEEP;
|
||||
int usdz_downscale_custom_size = 128;
|
||||
char root_prim_path[1024] = ""; /* FILE_MAX */
|
||||
char collection[MAX_IDPROP_NAME] = "";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user