Initial WebAssembly support.

This commit is contained in:
Syoyo Fujita
2021-07-31 21:25:55 +09:00
parent eaf0b67a08
commit b429314ca5
8 changed files with 512 additions and 81 deletions

View File

@@ -52,6 +52,9 @@ TinyUSDZ does not support Reality Composer file format(`.reality`) since it uses
* [x] macOS
* [x] Windows 10 64bit or later
* [ ] Windows ARM(should work)
* [x] WebAssembly(through Emscripten)
* See `examples/sdlviewer/` example.
* Multithreading is not available due to Browser's restriction.
## Requirements

View File

@@ -9,6 +9,11 @@ option(TINYUSDZ_USE_CCACHE "Use ccache for faster recompile." ON)
option(TINYUSDZ_WITH_OPENSUBDIV "Build with OpenSubdiv(osdCPU. if required, set `osd_DIR` to specify the path to your own OpenSubdiv)" ON)
option(USDVIEW_USE_NATIVEFILEDIALOG "Use nativefiledialog. Requires gtk+-3 libs on linux to build" ON)
if (EMSCRIPTEN)
# Disable nfd
set(USDVIEW_USE_NATIVEFILEDIALOG OFF CACHE INTERNAL "" FORCE)
endif ()
# Use embedded version of OpenSubdiv code by default
set(osd_DIR ${PROJECT_SOURCE_DIR}/../../src/osd)
@@ -68,13 +73,33 @@ function ( ADD_SDL2_LIB )
set(SDL_STATIC ON CACHE INTERNAL "" FORCE)
add_subdirectory(../common/SDL2-2.0.14/ SDL2)
endfunction ()
ADD_SDL2_LIB()
if (EMSCRIPTEN)
# Use emcc ported SDL2
# https://stackoverflow.com/questions/61590519/how-to-use-emscripten-ports-sdl2-and-freetype-with-cmake
# Assume `suzanne.usdc` is coped to build directory with PRE_BUILD custom command
# TODO: Read USD file from JS world
# TODO: Use max memory size.
set(USE_FLAGS "-s ASSERTIONS=1 -s USE_SDL=2 -s USE_FREETYPE=1 --embed-file suzanne.usdc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${USE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${USE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${USE_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
set(CMAKE_EXECUTABLE_SUFFIX .html)
set(USDVIEW_SDL2_LIBRARIES ${SDL2_LIBRARIES})
else()
ADD_SDL2_LIB()
set(USDVIEW_SDL2_LIBRARIES SDL2-static SDL2main)
endif()
if(WIN32)
# nothing.
# do nothing.
elseif(APPLE)
find_library(COCOA Cocoa REQUIRED)
elseif(EMSCRIPTEN)
# do nothing
else()
find_package(X11 REQUIRED)
endif()
@@ -194,6 +219,7 @@ set(GUI_SOURCES
add_executable(${BUILD_TARGET} ${SOURCES} ${GUI_SOURCES})
add_sanitizers(${BUILD_TARGET})
target_compile_options(${BUILD_TARGET} PRIVATE ${EXT_COMPILE_OPTIONS})
if (UNIX)
target_include_directories(${BUILD_TARGET} PUBLIC ${X11_INCLUDE_DIR})
@@ -212,29 +238,31 @@ if (USDVIEW_USE_NATIVEFILEDIALOG)
list(APPEND EXT_LIBRARIES nfd)
endif()
if(WIN32)
# nothing.
elseif(APPLE)
list(APPEND EXT_LIBRARIES ${COCOA})
else()
list(APPEND EXT_LIBRARIES ${X11_LIBRARIES})
endif()
target_link_libraries(
${BUILD_TARGET}
PRIVATE
SDL2-static
SDL2main
${USDVIEW_SDL2_LIBRARIES}
${EXT_LIBRARIES}
${CMAKE_DL_LIBS}
)
if(WIN32)
# nothing.
elseif(APPLE)
target_link_libraries(
${BUILD_TARGET}
${COCOA}
)
else()
target_link_libraries(
${BUILD_TARGET}
${X11_LIBRARIES}
)
if (EMSCRIPTEN)
add_custom_command(TARGET ${BUILD_TARGET} PRE_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/../../models/suzanne.usdc" # src
$<TARGET_FILE_DIR:${BUILD_TARGET}>) # dest
endif()
source_group("Source Files" FILES ${SOURCES})
# [VisualStudio]

View File

@@ -0,0 +1,7 @@
rm -rf build_emcc
mkdir build_emcc
cd build_emcc
# Assume emsdk env has been setup
emcmake cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..

View File

@@ -10,6 +10,11 @@
#include <mutex> // C++11
#include <thread> // C++11
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
// ../common/SDL2
#include <SDL.h>
@@ -20,12 +25,11 @@
// common
#include "imgui.h"
#include "imgui_sdl/imgui_sdl.h"
#include "roboto_mono_embed.inc.h"
#include "simple-render.hh"
#include "tinyusdz.hh"
#include "trackball.h"
#include "roboto_mono_embed.inc.h"
// sdlviewer
#include "gui.hh"
@@ -33,6 +37,14 @@
#include "nfd.h"
#endif
#define EMULATE_EMSCRIPTEN
#if defined(EMULATE_EMSCRIPTEN)
#define EM_BOOL int
#define EM_TRUE 1
#define EM_FALSE 0
#endif
struct GUIContext {
enum AOVMode {
AOV_COLOR = 0,
@@ -59,7 +71,7 @@ struct GUIContext {
bool ctrl_pressed = false;
bool tab_pressed = false;
float yaw = 90.0f; // for Z up scene
float yaw = 90.0f; // for Z up scene
float pitch = 0.0f;
float roll = 0.0f;
@@ -77,9 +89,21 @@ struct GUIContext {
std::atomic<bool> update_texture{false};
std::atomic<bool> redraw{true}; // require redraw
std::atomic<bool> quit{false};
SDL_Renderer* renderer;
SDL_Texture* texture; // Texture for rendered image
int render_width = 512;
int render_height = 512;
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
bool render_finished{false};
int current_render_line = 0;
int render_line_size = 32; // render images with this lines per animation loop.
// for emscripten environment
#endif
};
GUIContext gCtx;
GUIContext g_gui_ctx;
namespace {
@@ -114,7 +138,7 @@ static void DrawNode(const tinyusdz::Scene& scene, const tinyusdz::Node& node) {
}
for (const auto& child : node.children) {
//DrawNode(scene, scene.nodes.at(child));
// DrawNode(scene, scene.nodes.at(child));
}
if (node.type == tinyusdz::NODE_TYPE_XFORM) {
@@ -272,38 +296,193 @@ void RenderThread(GUIContext* ctx) {
}
};
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
// TODO: widechar(UTF-16) support for Windows
std::string OpenFileDialog() {
std::string path;
nfdchar_t *outPath;
nfdfilteritem_t filterItem[1] = { { "USD file", "usda,usdc,usdz"} };
nfdchar_t* outPath;
nfdfilteritem_t filterItem[1] = {{"USD file", "usda,usdc,usdz"}};
nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, NULL);
if ( result == NFD_OKAY )
{
puts("Success!");
path = outPath;
NFD_FreePath(outPath);
}
else if ( result == NFD_CANCEL )
{
puts("User pressed cancel.");
}
else
{
printf("Error: %s\n", NFD_GetError() );
}
return path;
if (result == NFD_OKAY) {
puts("Success!");
path = outPath;
NFD_FreePath(outPath);
} else if (result == NFD_CANCEL) {
puts("User pressed cancel.");
} else {
printf("Error: %s\n", NFD_GetError());
}
return path;
}
#endif
// Helper to display a little (?) mark which shows a tooltip when hovered.
// In your own code you may want to display an actual icon if you are using a
// merged icon fonts (see docs/FONTS.md)
static void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
#if defined(__EMSCRIPTEN__) || defined(EMULATE_EMSCRIPTEN)
EM_BOOL em_main_loop_frame(double tm, void* user) {
#if 1
// Render image fragment
if (g_gui_ctx.redraw) {
g_gui_ctx.render_finished = false;
g_gui_ctx.current_render_line = 0;
g_gui_ctx.redraw = false;
}
if (!g_gui_ctx.render_finished) {
std::cout << "RenderLines: " << g_gui_ctx.current_render_line << "\n";
RenderLines(g_gui_ctx.current_render_line, g_gui_ctx.current_render_line + g_gui_ctx.render_line_size, g_gui_ctx.render_scene, g_gui_ctx.camera, &g_gui_ctx.aov);
g_gui_ctx.current_render_line += g_gui_ctx.render_line_size;
if (g_gui_ctx.current_render_line >= g_gui_ctx.render_height) {
g_gui_ctx.current_render_line = 0;
g_gui_ctx.render_finished = true;
g_gui_ctx.update_texture = true;
}
}
#endif
ImGuiIO& io = ImGui::GetIO();
#if 1
int wheel = 0;
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
return EM_FALSE;
} else if (e.type == SDL_DROPFILE) {
char* filepath = e.drop.file;
printf("File dropped: %s\n", filepath);
SDL_free(filepath);
} else if (e.type == SDL_WINDOWEVENT) {
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
io.DisplaySize.x = static_cast<float>(e.window.data1);
io.DisplaySize.y = static_cast<float>(e.window.data2);
}
} else if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_ESCAPE) {
return EM_FALSE;
}
} else if (e.type == SDL_KEYUP) {
} else if (e.type == SDL_MOUSEWHEEL) {
wheel = e.wheel.y;
}
}
int mouseX, mouseY;
const int buttons = SDL_GetMouseState(&mouseX, &mouseY);
// Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or
// write to those fields from your Windows message loop handlers,
// etc.)
io.DeltaTime = 1.0f / 60.0f;
io.MousePos = ImVec2(static_cast<float>(mouseX), static_cast<float>(mouseY));
io.MouseDown[0] = buttons & SDL_BUTTON(SDL_BUTTON_LEFT);
io.MouseDown[1] = buttons & SDL_BUTTON(SDL_BUTTON_RIGHT);
io.MouseWheel = static_cast<float>(wheel);
#endif
#if 1
ImGui::NewFrame();
bool update = false;
bool update_display = false;
ImGui::Begin("Scene");
update |=
ImGui::SliderFloat("eye.z", &g_gui_ctx.camera.eye[2], -1000.0, 1000.0f);
update |= ImGui::SliderFloat("fov", &g_gui_ctx.camera.fov, 0.01f, 140.0f);
// TODO: Validate coordinate definition.
if (ImGui::SliderFloat("yaw", &g_gui_ctx.yaw, -360.0f, 360.0f)) {
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
radians(g_gui_ctx.roll));
g_gui_ctx.camera.quat[0] = q[0];
g_gui_ctx.camera.quat[1] = q[1];
g_gui_ctx.camera.quat[2] = q[2];
g_gui_ctx.camera.quat[3] = q[3];
update = true;
}
if (ImGui::SliderFloat("pitch", &g_gui_ctx.pitch, -360.0f, 360.0f)) {
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
radians(g_gui_ctx.roll));
g_gui_ctx.camera.quat[0] = q[0];
g_gui_ctx.camera.quat[1] = q[1];
g_gui_ctx.camera.quat[2] = q[2];
g_gui_ctx.camera.quat[3] = q[3];
update = true;
}
if (ImGui::SliderFloat("roll", &g_gui_ctx.roll, -360.0f, 360.0f)) {
auto q = ToQuaternion(radians(g_gui_ctx.yaw), radians(g_gui_ctx.pitch),
radians(g_gui_ctx.roll));
g_gui_ctx.camera.quat[0] = q[0];
g_gui_ctx.camera.quat[1] = q[1];
g_gui_ctx.camera.quat[2] = q[2];
g_gui_ctx.camera.quat[3] = q[3];
update = true;
}
ImGui::End();
ImGui::Begin("Image");
ImGui::Image(g_gui_ctx.texture,
ImVec2(g_gui_ctx.render_width, g_gui_ctx.render_height));
ImGui::End();
if (update) {
g_gui_ctx.redraw = true;
}
// Update texture
if (g_gui_ctx.update_texture || update_display) {
// Update texture for display
UpdateTexutre(g_gui_ctx.texture, g_gui_ctx, g_gui_ctx.aov);
g_gui_ctx.update_texture = false;
}
SDL_SetRenderDrawColor(g_gui_ctx.renderer, 114, 144, 154, 255);
SDL_RenderClear(g_gui_ctx.renderer);
// Imgui
ImGui::Render();
ImGuiSDL::Render(ImGui::GetDrawData());
// static int texUpdateCount = 0;
SDL_RenderPresent(g_gui_ctx.renderer);
#endif
return EM_TRUE;
}
#endif
} // namespace
@@ -333,6 +512,9 @@ int main(int argc, char** argv) {
#ifdef _WIN32
std::string filename = "../../models/suzanne.usdc";
#elif __EMSCRIPTEN__
// assume filename is embeded with --embed-file in emcc compile flag.
std::string filename = "suzanne.usdc";
#else
std::string filename = "../../../models/suzanne.usdc";
#endif
@@ -345,7 +527,6 @@ int main(int argc, char** argv) {
if (argc > 1) {
filename = std::string(argv[1]);
} else {
}
std::cout << "Loading file " << filename << "\n";
@@ -393,7 +574,8 @@ int main(int argc, char** argv) {
exit(-1);
}
GUIContext gui_ctx;
GUIContext& gui_ctx = g_gui_ctx;
gui_ctx.renderer = renderer;
for (size_t i = 0; i < scene.geom_meshes.size(); i++) {
example::DrawGeomMesh draw_mesh(&scene.geom_meshes[i]);
@@ -405,6 +587,7 @@ int main(int argc, char** argv) {
std::cerr << "Failed to setup render mesh.\n";
exit(-1);
}
std::cout << "Setup render mesh\n";
bool done = false;
@@ -422,19 +605,17 @@ int main(int argc, char** argv) {
font_size, &roboto_config);
}
ImGuiSDL::Initialize(renderer, 1600, 800);
// ImGui_ImplGlfw_InitForOpenGL(window, true);
// ImGui_ImplOpenGL2_Init();
int render_width = 512;
int render_height = 512;
std::cout << "Imgui initialized\n";
SDL_Texture* texture =
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32,
SDL_TEXTUREACCESS_TARGET, render_width, render_height);
gui_ctx.texture = SDL_CreateTexture(
renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET,
gui_ctx.render_width, gui_ctx.render_height);
{
SDL_SetRenderTarget(renderer, texture);
SDL_SetRenderTarget(renderer, gui_ctx.texture);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, nullptr);
@@ -444,8 +625,8 @@ int main(int argc, char** argv) {
ScreenActivate(window);
gui_ctx.aov.Resize(render_width, render_height);
UpdateTexutre(texture, gui_ctx, gui_ctx.aov);
gui_ctx.aov.Resize(gui_ctx.render_width, gui_ctx.render_height);
UpdateTexutre(gui_ctx.texture, gui_ctx, gui_ctx.aov);
int display_w, display_h;
ImVec4 clear_color = {0.1f, 0.18f, 0.3f, 1.0f};
@@ -460,20 +641,45 @@ int main(int argc, char** argv) {
gui_ctx.camera.quat[3] = q[3];
}
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
// no thread
#else
std::thread render_thread(RenderThread, &gui_ctx);
#endif
// Initial rendering requiest
gui_ctx.redraw = true;
std::map<std::string, int> aov_list = {
{ "color", GUIContext::AOV_COLOR },
{ "shading normal", GUIContext::AOV_SHADING_NORMAL },
{ "geometric normal", GUIContext::AOV_GEOMETRIC_NORMAL },
{ "texcoord", GUIContext::AOV_TEXCOORD }
};
{"color", GUIContext::AOV_COLOR},
{"shading normal", GUIContext::AOV_SHADING_NORMAL},
{"geometric normal", GUIContext::AOV_GEOMETRIC_NORMAL},
{"texcoord", GUIContext::AOV_TEXCOORD}};
std::string aov_name = "color";
#if __EMSCRIPTEN__ || defined(EMULATE_EMSCRIPTEN)
#if __EMSCRIPTEN__
std::cout << "enter loop\n";
emscripten_request_animation_frame_loop(em_main_loop_frame, /* fps */ 0);
//render_thread.join();
std::cout << "quit\n";
#else
while (!done) {
auto ret = em_main_loop_frame(0, nullptr);
if (ret == EM_FALSE) {
break;
}
}
#endif
#else
// Enable drop file
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
while (!done) {
ImGuiIO& io = ImGui::GetIO();
@@ -482,9 +688,16 @@ int main(int argc, char** argv) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT)
if (e.type == SDL_QUIT) {
done = true;
else if (e.type == SDL_WINDOWEVENT) {
} else if (e.type == SDL_DROPFILE) {
char* filepath = e.drop.file;
printf("File dropped: %s\n", filepath);
SDL_free(filepath);
} else if (e.type == SDL_WINDOWEVENT) {
if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
io.DisplaySize.x = static_cast<float>(e.window.data1);
io.DisplaySize.y = static_cast<float>(e.window.data2);
@@ -523,8 +736,12 @@ int main(int argc, char** argv) {
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
if (ImGui::Button("Open file ...")) {
std::string filename = OpenFileDialog();
std::cout << "TODO: Open file" << "\n";
std::cout << "TODO: Open file"
<< "\n";
}
ImGui::SameLine();
HelpMarker("You can also drop USDZ file to the window to open a file.");
#endif
if (example::ImGuiComboUI("aov", aov_name, aov_list)) {
@@ -532,10 +749,11 @@ int main(int argc, char** argv) {
update_display = true;
}
//update |= ImGui::InputFloat3("eye", gui_ctx.camera.eye);
//update |= ImGui::InputFloat3("look_at", gui_ctx.camera.look_at);
//update |= ImGui::InputFloat3("up", gui_ctx.camera.up);
update |= ImGui::SliderFloat("eye.z", &gui_ctx.camera.eye[2], -1000.0, 1000.0f);
// update |= ImGui::InputFloat3("eye", gui_ctx.camera.eye);
// update |= ImGui::InputFloat3("look_at", gui_ctx.camera.look_at);
// update |= ImGui::InputFloat3("up", gui_ctx.camera.up);
update |=
ImGui::SliderFloat("eye.z", &gui_ctx.camera.eye[2], -1000.0, 1000.0f);
update |= ImGui::SliderFloat("fov", &gui_ctx.camera.fov, 0.01f, 140.0f);
// TODO: Validate coordinate definition.
@@ -569,7 +787,8 @@ int main(int argc, char** argv) {
ImGui::End();
ImGui::Begin("Image");
ImGui::Image(texture, ImVec2(render_width, render_height));
ImGui::Image(gui_ctx.texture,
ImVec2(gui_ctx.render_width, gui_ctx.render_height));
ImGui::End();
if (update) {
@@ -586,7 +805,7 @@ int main(int argc, char** argv) {
// Update texture
if (gui_ctx.update_texture || update_display) {
// Update texture for display
UpdateTexutre(texture, gui_ctx, gui_ctx.aov);
UpdateTexutre(gui_ctx.texture, gui_ctx, gui_ctx.aov);
gui_ctx.update_texture = false;
}
@@ -633,6 +852,8 @@ int main(int argc, char** argv) {
#if defined(USDVIEW_USE_NATIVEFILEDIALOG)
NFD_Quit();
#endif
#endif
return EXIT_SUCCESS;

View File

@@ -8,9 +8,9 @@
#include "nanosg.h"
// common
#include "mapbox/earcut.hpp" // For polygon triangulation
#include "matrix.h"
#include "trackball.h"
#include "mapbox/earcut.hpp" // For polygon triangulation
const float kPI = 3.141592f;
@@ -53,8 +53,10 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
std::cout << "# of facevarying normals = " << facevarying_normals.size() / 3
<< "\n";
std::cout << "# of faceVertexCounts: " << mesh.faceVertexCounts.size() << "\n";
std::cout << "# of faceVertexIndices: " << mesh.faceVertexIndices.size() << "\n";
std::cout << "# of faceVertexCounts: " << mesh.faceVertexCounts.size()
<< "\n";
std::cout << "# of faceVertexIndices: " << mesh.faceVertexIndices.size()
<< "\n";
// for (size_t i = 0; i < facevarying_normals.size() / 3; i++) {
// std::cout << "fid[" << i << "] = " << facevarying_normals[3 * i + 0] << ",
@@ -183,7 +185,7 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
dst->int_primvars.clear();
dst->int_primvars_map.clear();
for (const auto &attrib : mesh.attribs) {
for (const auto& attrib : mesh.attribs) {
if (!attrib.second.facevarying) {
continue;
}
@@ -192,8 +194,8 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
continue;
}
if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_FLOAT) {
if (attrib.second.buffer.GetDataType() ==
tinyusdz::BufferData::BUFFER_DATA_TYPE_FLOAT) {
Buffer<float> buf;
buf.num_coords = attrib.second.buffer.GetNumCoords();
buf.data = attrib.second.buffer.GetAsFloatArray();
@@ -203,8 +205,8 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
std::cout << "Added [" << attrib.first << "] to float_primvars\n";
} else if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_INT) {
} else if (attrib.second.buffer.GetDataType() ==
tinyusdz::BufferData::BUFFER_DATA_TYPE_INT) {
Buffer<int32_t> buf;
buf.num_coords = attrib.second.buffer.GetNumCoords();
buf.data = attrib.second.buffer.GetAsInt32Array();
@@ -217,8 +219,6 @@ bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) {
} else {
// TODO
}
}
std::cout << "num points = " << dst->vertices.size() / 3 << "\n";
@@ -497,17 +497,172 @@ bool Render(const RenderScene& scene, const Camera& cam, AOV* output) {
return true;
}
bool RenderScene::Setup() {
bool RenderLines(int start_y, int end_y, const RenderScene& scene,
const Camera& cam, AOV* output) {
int width = output->width;
int height = output->height;
float eye[3] = {cam.eye[0], cam.eye[1], cam.eye[2]};
float look_at[3] = {cam.look_at[0], cam.look_at[1], cam.look_at[2]};
float up[3] = {cam.up[0], cam.up[1], cam.up[2]};
float fov = cam.fov;
float3 origin, corner, u, v;
BuildCameraFrame(&origin, &corner, &u, &v, cam.quat, eye, look_at, up, fov,
width, height);
// Single threaded
for (int y = start_y; y < std::min(end_y, height); y++) {
for (int x = 0; x < width; x++) {
nanort::Ray<float> ray;
ray.org[0] = origin[0];
ray.org[1] = origin[1];
ray.org[2] = origin[2];
float3 dir;
float u0 = 0.5f;
float u1 = 0.5f;
dir = corner + (float(x) + u0) * u + (float(y) + u1) * v;
dir = vnormalize(dir);
ray.dir[0] = dir[0];
ray.dir[1] = dir[1];
ray.dir[2] = dir[2];
size_t pixel_idx = y * width + x;
// HACK. Use the first mesh
const DrawGeomMesh& mesh = scene.draw_meshes[0];
// Intersector functor.
nanort::TriangleIntersector<> triangle_intersector(
mesh.vertices.data(), mesh.facevarying_indices.data(),
sizeof(float) * 3);
nanort::TriangleIntersection<> isect; // stores isect info
bool hit = mesh.accel.Traverse(ray, triangle_intersector, &isect);
if (hit) {
float3 Ng;
{
// geometric normal.
float3 v0;
float3 v1;
float3 v2;
size_t vid0 = mesh.facevarying_indices[3 * isect.prim_id + 0];
size_t vid1 = mesh.facevarying_indices[3 * isect.prim_id + 1];
size_t vid2 = mesh.facevarying_indices[3 * isect.prim_id + 2];
v0[0] = mesh.vertices[3 * vid0 + 0];
v0[1] = mesh.vertices[3 * vid0 + 1];
v0[2] = mesh.vertices[3 * vid0 + 2];
v1[0] = mesh.vertices[3 * vid1 + 0];
v1[1] = mesh.vertices[3 * vid1 + 1];
v1[2] = mesh.vertices[3 * vid1 + 2];
v2[0] = mesh.vertices[3 * vid2 + 0];
v2[1] = mesh.vertices[3 * vid2 + 1];
v2[2] = mesh.vertices[3 * vid2 + 2];
CalcNormal(Ng, v0, v1, v2);
}
float3 Ns;
if (mesh.facevarying_normals.size()) {
float3 n0;
float3 n1;
float3 n2;
n0[0] = mesh.facevarying_normals[9 * isect.prim_id + 0];
n0[1] = mesh.facevarying_normals[9 * isect.prim_id + 1];
n0[2] = mesh.facevarying_normals[9 * isect.prim_id + 2];
n1[0] = mesh.facevarying_normals[9 * isect.prim_id + 3];
n1[1] = mesh.facevarying_normals[9 * isect.prim_id + 4];
n1[2] = mesh.facevarying_normals[9 * isect.prim_id + 5];
n2[0] = mesh.facevarying_normals[9 * isect.prim_id + 6];
n2[1] = mesh.facevarying_normals[9 * isect.prim_id + 7];
n2[2] = mesh.facevarying_normals[9 * isect.prim_id + 8];
// lerp normal.
Ns = vnormalize(Lerp3(n0, n1, n2, isect.u, isect.v));
} else {
Ns = Ng;
}
float3 texcoord = {0.0f, 0.0f, 0.0f};
if (mesh.facevarying_texcoords.size()) {
float3 t0;
float3 t1;
float3 t2;
t0[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 0];
t0[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 1];
t0[2] = 0.0f;
t1[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 2];
t1[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 3];
t1[2] = 0.0f;
t2[0] = mesh.facevarying_texcoords[6 * isect.prim_id + 4];
t2[1] = mesh.facevarying_texcoords[6 * isect.prim_id + 5];
t2[2] = 0.0f;
texcoord = Lerp3(t0, t1, t2, isect.u, isect.v);
}
output->rgb[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
output->rgb[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
output->rgb[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
output->geometric_normal[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
output->geometric_normal[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
output->geometric_normal[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
output->shading_normal[3 * pixel_idx + 0] = 0.5f * Ns[0] + 0.5f;
output->shading_normal[3 * pixel_idx + 1] = 0.5f * Ns[1] + 0.5f;
output->shading_normal[3 * pixel_idx + 2] = 0.5f * Ns[2] + 0.5f;
output->texcoords[2 * pixel_idx + 0] = texcoord[0];
output->texcoords[2 * pixel_idx + 1] = texcoord[1];
} else {
output->rgb[3 * pixel_idx + 0] = 0.0f;
output->rgb[3 * pixel_idx + 1] = 0.0f;
output->rgb[3 * pixel_idx + 2] = 0.0f;
output->geometric_normal[3 * pixel_idx + 0] = 0.0f;
output->geometric_normal[3 * pixel_idx + 1] = 0.0f;
output->geometric_normal[3 * pixel_idx + 2] = 0.0f;
output->shading_normal[3 * pixel_idx + 0] = 0.0f;
output->shading_normal[3 * pixel_idx + 1] = 0.0f;
output->shading_normal[3 * pixel_idx + 2] = 0.0f;
output->texcoords[2 * pixel_idx + 0] = 0.0f;
output->texcoords[2 * pixel_idx + 1] = 0.0f;
}
}
}
return true;
}
bool RenderScene::Setup() {
//
// Construct scene
//
{
float local_xform[4][4]; // TODO
float local_xform[4][4]; // TODO
for (size_t i = 0; i < draw_meshes.size(); i++) {
// Construct Node by passing the pointer to draw_meshes[i]
// Pointer address of draw_meshes[i] must be identical during app's lifetime.
// Pointer address of draw_meshes[i] must be identical during app's
// lifetime.
nanosg::Node<float, example::DrawGeomMesh> node(&draw_meshes[i]);
std::cout << "SetName: " << draw_meshes[i].ref_mesh->name << "\n";
@@ -518,7 +673,6 @@ bool RenderScene::Setup() {
this->nodes.push_back(node);
this->scene.AddNode(node);
}
}
for (size_t i = 0; i < draw_meshes.size(); i++) {

View File

@@ -176,4 +176,13 @@ bool Render(
const Camera &cam,
AOV *output);
// Render images for lines [start_y, end_y]
// single-threaded. for webassembly.
bool RenderLines(
int start_y,
int end_y,
const RenderScene &scene,
const Camera &cam,
AOV *output);
} // namespace example

View File

@@ -4,6 +4,11 @@
#endif
#endif
#if defined(__EMSCRIPTEN__)
/* work around of DEPRECATE macro */
#define LZ4_DISABLE_DEPRECATE_WARNINGS
#endif
#include "lz4-compression.hh"
#include <cstring>

View File

@@ -83,6 +83,10 @@
# define LZ4_FORCE_SW_BITCOUNT
#endif
#if defined(__EMSCRIPTEN__)
/* work around of DEPRECATE macro */
#define LZ4_DISABLE_DEPRECATE_WARNINGS
#endif
/*-************************************
* Dependency