mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
288 lines
7.7 KiB
C++
288 lines
7.7 KiB
C++
|
|
#include <atomic>
|
|
#include <cassert>
|
|
#include <thread>
|
|
|
|
// tinyusdz & Tydra
|
|
#include "io-util.hh"
|
|
#include "tydra/render-data.hh"
|
|
|
|
//
|
|
#include "simple-render.hh"
|
|
|
|
#include "nanort.h"
|
|
#include "nanosg.h"
|
|
|
|
// Loading image is the part of TinyUSDZ core
|
|
//#define STB_IMAGE_IMPLEMENTATION
|
|
//#include "external/stb_image.h"
|
|
|
|
// common
|
|
//#include "mapbox/earcut.hpp" // For polygon triangulation
|
|
#include "matrix.h"
|
|
#include "trackball.h"
|
|
|
|
#define PAR_SHAPES_IMPLEMENTATION
|
|
#include "par_shapes.h" // For meshing
|
|
|
|
|
|
const float kPI = 3.141592f;
|
|
|
|
typedef nanort::real3<float> float3;
|
|
|
|
namespace example {
|
|
|
|
struct DifferentialGeometry {
|
|
|
|
float t; // hit t
|
|
float bary_u, bary_v; // barycentric coordinate.
|
|
uint32_t geom_id; // geom id(Currently GeomMesh only)
|
|
float tex_u, tex_v; // texture u and v
|
|
|
|
float3 position;
|
|
float3 shading_normal;
|
|
float3 geometric_normal;
|
|
};
|
|
|
|
struct PointLight {
|
|
float3 position{1000.0f, 1000.0f, 1000.0f};
|
|
float3 color{0.8f, 0.8f, 0.8f};
|
|
float intensity{1.0f};
|
|
};
|
|
|
|
inline float3 Lerp3(float3 v0, float3 v1, float3 v2, float u, float v) {
|
|
return (1.0f - u - v) * v0 + u * v1 + v * v2;
|
|
}
|
|
|
|
inline void CalcNormal(float3& N, float3 v0, float3 v1, float3 v2) {
|
|
float3 v10 = v1 - v0;
|
|
float3 v20 = v2 - v0;
|
|
|
|
N = vcross(v10, v20);
|
|
N = vnormalize(N);
|
|
}
|
|
|
|
#if 0
|
|
bool LoadTextureImage(const tinyusdz::UVTexture &tex, Image *out_image) {
|
|
|
|
// Asssume asset name = file name
|
|
std::string filename = tex.asset;
|
|
|
|
// TODO: 16bit PNG image, EXR image
|
|
int w, h, channels;
|
|
stbi_uc *image = stbi_load(filename.c_str(), &w, &h, &channels, /* desired_channels */3);
|
|
if (!image) {
|
|
return false;
|
|
}
|
|
|
|
size_t n = w * h * channels;
|
|
out_image->image.resize(n);
|
|
memcpy(out_image->image.data(), image, n);
|
|
|
|
out_image->width = w;
|
|
out_image->height = h;
|
|
out_image->channels = channels;
|
|
|
|
return true;
|
|
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
// TODO: Move to Tydra
|
|
bool ConvertToRenderMesh(const tinyusdz::GeomSphere& sphere,
|
|
DrawGeomMesh* dst) {
|
|
// TODO: Write our own sphere -> polygon converter
|
|
|
|
// TODO: Read subdivision parameter from somewhere.
|
|
int slices = 16;
|
|
int stacks = 8;
|
|
|
|
// icohedron subdivision does not generate UV coordinate, so use
|
|
// par_shapes_create_parametric_sphere for now
|
|
par_shapes_mesh* par_mesh =
|
|
par_shapes_create_parametric_sphere(slices, stacks);
|
|
|
|
dst->vertices.resize(par_mesh->npoints * 3);
|
|
|
|
// TODO: Animated radius
|
|
float radius = 1.0;
|
|
if (sphere.radius.IsTimeSampled()) {
|
|
// TODO
|
|
} else {
|
|
// TODO
|
|
//radius = sphere.radius.Get();
|
|
}
|
|
|
|
// scale by radius
|
|
for (size_t i = 0; i < dst->vertices.size(); i++) {
|
|
dst->vertices[i] = par_mesh->points[i] * radius;
|
|
}
|
|
|
|
std::vector<uint32_t> facevertex_indices;
|
|
std::vector<float> facevarying_normals;
|
|
std::vector<float> facevarying_texcoords;
|
|
|
|
// Make uv and normal facevarying
|
|
// ntriangles = slices * 2 + (stacks - 2) * slices * 2
|
|
for (size_t i = 0; i < par_mesh->ntriangles; i++) {
|
|
PAR_SHAPES_T vidx0 = par_mesh->triangles[3 * i + 0];
|
|
PAR_SHAPES_T vidx1 = par_mesh->triangles[3 * i + 1];
|
|
PAR_SHAPES_T vidx2 = par_mesh->triangles[3 * i + 2];
|
|
|
|
facevertex_indices.push_back(vidx0);
|
|
facevertex_indices.push_back(vidx1);
|
|
facevertex_indices.push_back(vidx2);
|
|
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 0]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 1]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx0 + 2]);
|
|
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 0]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 1]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx1 + 2]);
|
|
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 0]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 1]);
|
|
facevarying_normals.push_back(par_mesh->normals[3 * vidx2 + 2]);
|
|
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx0 + 0]);
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx0 + 1]);
|
|
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx1 + 0]);
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx1 + 1]);
|
|
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx2 + 0]);
|
|
facevarying_texcoords.push_back(par_mesh->tcoords[2 * vidx2 + 1]);
|
|
}
|
|
|
|
par_shapes_free_mesh(par_mesh);
|
|
|
|
dst->facevertex_indices = facevertex_indices;
|
|
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
namespace detail {
|
|
|
|
// Build flattened mesh list.
|
|
void MeshRec(const tinyusdz::tydra::Node &node,
|
|
std::vector<DrawGeomMesh<float>> &meshes) {
|
|
|
|
if (node.nodeType == tinyusdz::tydra::NodeType::Mesh) {
|
|
|
|
DrawGeomMesh<float> mesh;
|
|
for (size_t i = 0; i < 4; i++) {
|
|
for (size_t j = 0; j < 4; j++) {
|
|
mesh.world_matrix[i][j] = node.global_matrix.m[i][j];
|
|
}
|
|
}
|
|
|
|
meshes.push_back(mesh);
|
|
|
|
}
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
bool RTRenderScene::SetupFromUSDFile(const std::string &usd_filename,
|
|
std::string &warn, std::string &err) {
|
|
|
|
// When Xform, Mesh, Material, etc. have time-varying values,
|
|
// values are evaluated at `timecode` time(except for animation values in
|
|
// SkelAnimation)
|
|
double timecode = tinyusdz::value::TimeCode::Default();
|
|
|
|
tinyusdz::Stage stage;
|
|
|
|
if (!tinyusdz::IsUSD(usd_filename)) {
|
|
std::cerr << "File not found or not a USD format: " << usd_filename << "\n";
|
|
}
|
|
|
|
bool ret = tinyusdz::LoadUSDFromFile(usd_filename, &stage, &warn, &err);
|
|
if (!warn.empty()) {
|
|
std::cerr << "WARN : " << warn << "\n";
|
|
}
|
|
|
|
if (!ret) {
|
|
return false;
|
|
}
|
|
|
|
bool is_usdz = tinyusdz::IsUSDZ(usd_filename);
|
|
|
|
// RenderScene: Scene graph object which is suited for GL/Vulkan renderer
|
|
tinyusdz::tydra::RenderScene render_scene;
|
|
tinyusdz::tydra::RenderSceneConverter converter;
|
|
tinyusdz::tydra::RenderSceneConverterEnv env(stage);
|
|
|
|
// TODO: Do not triangulate & build indices for raytraced renderer.
|
|
env.mesh_config.triangulate = true;
|
|
env.mesh_config.build_vertex_indices = true;
|
|
|
|
// Add base directory of .usd file to search path.
|
|
std::string usd_basedir = tinyusdz::io::GetBaseDir(usd_filename);
|
|
std::cout << "Add seach path: " << usd_basedir << "\n";
|
|
|
|
tinyusdz::USDZAsset usdz_asset;
|
|
if (is_usdz) {
|
|
// Setup AssetResolutionResolver to read a asset(file) from memory.
|
|
if (!tinyusdz::ReadUSDZAssetInfoFromFile(usd_filename, &usdz_asset, &warn,
|
|
&err)) {
|
|
std::cerr << "Failed to read USDZ assetInfo from file: " << err << "\n";
|
|
exit(-1);
|
|
}
|
|
if (warn.size()) {
|
|
std::cout << warn << "\n";
|
|
}
|
|
|
|
tinyusdz::AssetResolutionResolver arr;
|
|
|
|
// NOTE: Pointer address of usdz_asset must be valid until the call of
|
|
// RenderSceneConverter::ConvertToRenderScene.
|
|
if (!tinyusdz::SetupUSDZAssetResolution(arr, &usdz_asset)) {
|
|
std::cerr << "Failed to setup AssetResolution for USDZ asset\n";
|
|
exit(-1);
|
|
};
|
|
|
|
env.asset_resolver = arr;
|
|
|
|
} else {
|
|
env.set_search_paths({usd_basedir});
|
|
|
|
// TODO: Add example to set user-defined AssetResolutionResolver
|
|
// AssetResolutionResolver arr;
|
|
// ...
|
|
// env.asset_resolver(arr);
|
|
}
|
|
|
|
if (!tinyusdz::value::TimeCode(timecode).is_default()) {
|
|
std::cout << "Use timecode : " << timecode << "\n";
|
|
}
|
|
env.timecode = timecode;
|
|
ret = converter.ConvertToRenderScene(env, &render_scene);
|
|
if (!ret) {
|
|
std::cerr << "Failed to convert USD Stage to RenderScene: \n"
|
|
<< converter.GetError() << "\n";
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (converter.GetWarning().size()) {
|
|
std::cout << "ConvertToRenderScene warn: " << converter.GetWarning()
|
|
<< "\n";
|
|
}
|
|
|
|
// TODO: Setup RTMesh
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool Render(const RTRenderScene &scene, const Camera &cam, AOV *output) {
|
|
// TODO
|
|
return false;
|
|
}
|
|
|
|
} // namespace example
|