#include "simple-render.hh" #include #include #include #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 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 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 facevertex_indices; std::vector facevarying_normals; std::vector 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 bool ConvertToRenderMesh(const tinyusdz::GeomMesh& mesh, DrawGeomMesh* dst) { #if 0 // Trianglate mesh // vertex points should be vec3f if (dst->vertices.size() != (mesh.GetNumPoints() * 3)) { std::cerr << __func__ << ":The number of vertices mismatch. " << dst->vertices.size() << " must be equal to mesh.GetNumPoints() * 3: " << mesh.GetNumPoints() * 3 << "\n"; return false; } dst->vertices.resize(mesh.points.size() * 3); memcpy(dst->vertices.data(), mesh.points.data(), dst->vertices.size() * sizeof(tinyusdz::value::point3f)); std::cout << __func__ << "# of mesh.points = " << mesh.points.size() << "\n"; //std::vector facevarying_normals; //if (!mesh.GetFacevaryingNormals(&facevarying_normals)) { // std::cout << __func__ << ":Warn: failed to retrieve facevarying normals\n"; //} //std::vector facevarying_texcoords; //if (!mesh.GetFacevaryingTexcoords(&facevarying_texcoords)) { // std::cout << __func__ // << ":Warn: failed to retrieve facevarying texcoords\n"; //} //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"; // for (size_t i = 0; i < facevarying_normals.size() / 3; i++) { // std::cout << "fid[" << i << "] = " << facevarying_normals[3 * i + 0] << ", // " << // facevarying_normals[3 * i + 1] << ", // " << facevarying_normals[3 * i + 2] // << "\n"; //} // Triangulate mesh dst->facevarying_normals.clear(); // Make facevarying indices // TODO(LTE): Make facevarying uvs, ... { size_t face_offset = 0; for (size_t fid = 0; fid < mesh.faceVertexCounts.size(); fid++) { int f_count = mesh.faceVertexCounts[fid]; // std::cout << "f_count = " << f_count << "\n"; assert(f_count >= 3); if (f_count == 3) { for (size_t f = 0; f < f_count; f++) { dst->facevertex_indices.push_back( mesh.faceVertexIndices[face_offset + f]); #if 0 if (facevarying_normals.size()) { // x, y, z dst->facevarying_normals.push_back( facevarying_normals[3 * (face_offset + f) + 0]); dst->facevarying_normals.push_back( facevarying_normals[3 * (face_offset + f) + 1]); dst->facevarying_normals.push_back( facevarying_normals[3 * (face_offset + f) + 2]); } if (facevarying_texcoords.size()) { // u, v dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * (face_offset + f) + 0]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * (face_offset + f) + 1]); } #endif } } else { // std::cout << "f_count " << f_count << "\n"; // Simple triangulation with triangle-fan decomposition for (size_t f = 0; f < f_count - 2; f++) { size_t f0 = 0; size_t f1 = f + 1; size_t f2 = f + 2; dst->facevertex_indices.push_back( mesh.faceVertexIndices[face_offset + f0]); dst->facevertex_indices.push_back( mesh.faceVertexIndices[face_offset + f1]); dst->facevertex_indices.push_back( mesh.faceVertexIndices[face_offset + f2]); #if 0 if (facevarying_normals.size()) { size_t fid0 = face_offset + f0; size_t fid1 = face_offset + f1; size_t fid2 = face_offset + f2; // std::cout << "fid0 = " << fid0 << "\n"; // x, y, z dst->facevarying_normals.push_back( facevarying_normals[3 * fid0 + 0]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid0 + 1]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid0 + 2]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid1 + 0]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid1 + 1]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid1 + 2]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid2 + 0]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid2 + 1]); dst->facevarying_normals.push_back( facevarying_normals[3 * fid2 + 2]); } if (facevarying_texcoords.size()) { size_t fid0 = face_offset + f0; size_t fid1 = face_offset + f1; size_t fid2 = face_offset + f2; // std::cout << "fid0 = " << fid0 << "\n"; dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid0 + 0]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid0 + 1]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid1 + 0]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid1 + 1]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid2 + 0]); dst->facevarying_texcoords.push_back( facevarying_texcoords[2 * fid2 + 1]); } #endif } } face_offset += f_count; } } #if 0 // TODO: Rewrite // Other facevarying attributes(property, primvars) dst->float_primvars.clear(); dst->float_primvars_map.clear(); dst->int_primvars.clear(); dst->int_primvars_map.clear(); for (const auto& attrib : mesh.attribs) { if (attrib.second.interpolation != tinyusdz::Interpolation::InterpolationFaceVarying) { std::cerr << "Interpolation must be facevarying\n"; continue; } if (attrib.second.buffer.data.empty()) { continue; } if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_FLOAT) { Buffer buf; buf.num_coords = attrib.second.buffer.GetNumCoords(); if (auto p = attrib.second.buffer.GetAsFloatArray()) { buf.data = (*p); } else { std::cerr << "Failed to get attribute value as float array\n"; continue; } dst->float_primvars_map[attrib.first] = dst->float_primvars.size(); dst->float_primvars.push_back(buf); std::cout << "Added [" << attrib.first << "] to float_primvars\n"; } else if (attrib.second.buffer.GetDataType() == tinyusdz::BufferData::BUFFER_DATA_TYPE_INT) { Buffer buf; buf.num_coords = attrib.second.buffer.GetNumCoords(); if (auto p = attrib.second.buffer.GetAsInt32Array()) { buf.data = (*p); std::cerr << "Failed to get attribute value as int array\n"; } dst->int_primvars_map[attrib.first] = dst->int_primvars.size(); dst->int_primvars.push_back(buf); std::cout << "Added [" << attrib.first << "] to int_primvars\n"; } else { // TODO } } #endif std::cout << "num points = " << dst->vertices.size() / 3 << "\n"; std::cout << "num triangulated faces = " << dst->facevertex_indices.size() / 3 << "\n"; #endif return false; } float3 Shade(const DrawGeomMesh& mesh, const DifferentialGeometry &dg, const PointLight &light) { float3 ldir = vnormalize(light.position - dg.position); // TODO float d = vdot(ldir, vnormalize(dg.shading_normal)); float ambient = 0.2f; d = std::max(ambient, d); float3 color{d, d, d}; return color; } void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v, const float quat[4], float eye[3], float lookat[3], float up[3], float fov, int width, int height) { float e[4][4]; Matrix::LookAt(e, eye, lookat, up); float r[4][4]; build_rotmatrix(r, quat); float3 lo; lo[0] = lookat[0] - eye[0]; lo[1] = lookat[1] - eye[1]; lo[2] = lookat[2] - eye[2]; float dist = vlength(lo); float dir[3]; dir[0] = 0.0; dir[1] = 0.0; dir[2] = dist; Matrix::Inverse(r); float rr[4][4]; float re[4][4]; float zero[3] = {0.0f, 0.0f, 0.0f}; float localUp[3] = {0.0f, 1.0f, 0.0f}; Matrix::LookAt(re, dir, zero, localUp); // translate re[3][0] += eye[0]; // 0.0; //lo[0]; re[3][1] += eye[1]; // 0.0; //lo[1]; re[3][2] += (eye[2] - dist); // rot -> trans Matrix::Mult(rr, r, re); float m[4][4]; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { m[j][i] = rr[j][i]; } } float vzero[3] = {0.0f, 0.0f, 0.0f}; float eye1[3]; Matrix::MultV(eye1, m, vzero); float lookat1d[3]; dir[2] = -dir[2]; Matrix::MultV(lookat1d, m, dir); float3 lookat1(lookat1d[0], lookat1d[1], lookat1d[2]); float up1d[3]; Matrix::MultV(up1d, m, up); float3 up1(up1d[0], up1d[1], up1d[2]); // absolute -> relative up1[0] -= eye1[0]; up1[1] -= eye1[1]; up1[2] -= eye1[2]; // printf("up1(after) = %f, %f, %f\n", up1[0], up1[1], up1[2]); // Use original up vector // up1[0] = up[0]; // up1[1] = up[1]; // up1[2] = up[2]; { float flen = (0.5f * (float)height / tanf(0.5f * (float)(fov * kPI / 180.0f))); float3 look1; look1[0] = lookat1[0] - eye1[0]; look1[1] = lookat1[1] - eye1[1]; look1[2] = lookat1[2] - eye1[2]; // vcross(u, up1, look1); // flip (*u) = nanort::vcross(look1, up1); (*u) = vnormalize((*u)); (*v) = vcross(look1, (*u)); (*v) = vnormalize((*v)); look1 = vnormalize(look1); look1[0] = flen * look1[0] + eye1[0]; look1[1] = flen * look1[1] + eye1[1]; look1[2] = flen * look1[2] + eye1[2]; (*corner)[0] = look1[0] - 0.5f * (width * (*u)[0] + height * (*v)[0]); (*corner)[1] = look1[1] - 0.5f * (width * (*u)[1] + height * (*v)[1]); (*corner)[2] = look1[2] - 0.5f * (width * (*u)[2] + height * (*v)[2]); (*origin)[0] = eye1[0]; (*origin)[1] = eye1[1]; (*origin)[2] = eye1[2]; } } bool Render(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); std::vector workers; std::atomic i(0); uint32_t num_threads = std::max(1U, std::thread::hardware_concurrency()); // auto startT = std::chrono::system_clock::now(); for (uint32_t t = 0; t < num_threads; t++) { workers.emplace_back(std::thread([&]() { int y = 0; while ((y = i++) < height) { for (int x = 0; x < width; x++) { nanort::Ray 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; bool hit = false; output->rgb[3 * pixel_idx + 0] = 0.0f; output->rgb[3 * pixel_idx + 1] = 0.0f; output->rgb[3 * pixel_idx + 2] = 0.0f; if (scene.draw_meshes.size()) { // FIXME(syoyo): Use NanoSG to trace meshes in the scene. const DrawGeomMesh& mesh = scene.draw_meshes[0]; // Intersector functor. nanort::TriangleIntersector<> triangle_intersector( mesh.vertices.data(), mesh.facevertex_indices.data(), sizeof(float) * 3); nanort::TriangleIntersection<> isect; // stores isect info hit = mesh.accel.Traverse(ray, triangle_intersector, &isect); if (hit) { float3 Ng; { // geometric normal. float3 v0; float3 v1; float3 v2; size_t vid0 = mesh.facevertex_indices[3 * isect.prim_id + 0]; size_t vid1 = mesh.facevertex_indices[3 * isect.prim_id + 1]; size_t vid2 = mesh.facevertex_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); } // For shading DifferentialGeometry dg; dg.tex_u = texcoord[0]; dg.tex_v = texcoord[1]; dg.bary_u = isect.u; dg.bary_v = isect.v; dg.geom_id = 0; // FIXME dg.geometric_normal = Ng; dg.shading_normal = Ns; PointLight light; // dummy float3 rgb = Shade(mesh, dg, light); output->rgb[3 * pixel_idx + 0] = rgb[0]; output->rgb[3 * pixel_idx + 1] = rgb[1]; output->rgb[3 * pixel_idx + 2] = rgb[2]; 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 { } if (!hit) { 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; } } } })); } for (auto& th : workers) { th.join(); } // auto endT = std::chrono::system_clock::now(); return true; } 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 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.facevertex_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.facevertex_indices[3 * isect.prim_id + 0]; size_t vid1 = mesh.facevertex_indices[3 * isect.prim_id + 1]; size_t vid2 = mesh.facevertex_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 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. nanosg::Node node(&draw_meshes[i]); std::cout << "SetName: " << draw_meshes[i].ref_mesh->name << "\n"; node.SetName(draw_meshes[i].ref_mesh->name); node.SetLocalXform(local_xform); this->nodes.push_back(node); this->scene.AddNode(node); } } for (size_t i = 0; i < draw_meshes.size(); i++) { if (!ConvertToRenderMesh(*(draw_meshes[i].ref_mesh), &draw_meshes[i])) { return false; } DrawGeomMesh& draw_mesh = draw_meshes[i]; nanort::TriangleMesh triangle_mesh( draw_mesh.vertices.data(), draw_mesh.facevertex_indices.data(), sizeof(float) * 3); nanort::TriangleSAHPred triangle_pred( draw_mesh.vertices.data(), draw_mesh.facevertex_indices.data(), sizeof(float) * 3); bool ret = draw_mesh.accel.Build(draw_mesh.facevertex_indices.size() / 3, triangle_mesh, triangle_pred); if (!ret) { std::cerr << "Failed to build BVH\n"; return false; } nanort::BVHBuildStatistics stats = draw_mesh.accel.GetStatistics(); printf(" BVH statistics:\n"); printf(" # of leaf nodes: %d\n", stats.num_leaf_nodes); printf(" # of branch nodes: %d\n", stats.num_branch_nodes); printf(" Max tree depth : %d\n", stats.max_tree_depth); float bmin[3], bmax[3]; draw_mesh.accel.BoundingBox(bmin, bmax); printf(" Bmin : %f, %f, %f\n", bmin[0], bmin[1], bmin[2]); printf(" Bmax : %f, %f, %f\n", bmax[0], bmax[1], bmax[2]); } return true; } } // namespace example