mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-07-16 16:51:47 +08:00
Merge branch 'devel' of github.com:syoyo/tinygltf into devel
This commit is contained in:
commit
ba809ff52f
22
.gitignore
vendored
22
.gitignore
vendored
@ -9,6 +9,28 @@ install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
|
||||
#Files created by the CI scripts (downloading and installing premake)
|
||||
premake5
|
||||
premake5.tar.gz
|
||||
|
||||
#built examples
|
||||
/examples/raytrace/bin/
|
||||
|
||||
#visual studio files
|
||||
*.sln
|
||||
*.vcxproj*
|
||||
.vs
|
||||
|
||||
#binary directories
|
||||
bin/
|
||||
obj/
|
||||
|
||||
#runtime gui config
|
||||
imgui.ini
|
||||
|
||||
#visual stuido code
|
||||
.vscode
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
|
10
.travis-before-install.sh
Executable file
10
.travis-before-install.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]
|
||||
then
|
||||
brew upgrade
|
||||
curl -o premake5.tar.gz https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-macosx.tar.gz
|
||||
else
|
||||
wget https://github.com/premake/premake-core/releases/download/v5.0.0-alpha12/premake-5.0.0-alpha12-linux.tar.gz -O premake5.tar.gz
|
||||
fi
|
||||
tar xzf premake5.tar.gz
|
@ -33,7 +33,7 @@ matrix:
|
||||
env: COMPILER_VERSION=3.7 BUILD_TYPE=Debug CFLAGS="-O0" CXXFLAGS="-O0"
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew upgrade; fi
|
||||
- ./.travis-before-install.sh
|
||||
|
||||
|
||||
script:
|
||||
@ -42,3 +42,6 @@ script:
|
||||
- ${CC} -v
|
||||
- ${CXX} ${EXTRA_CXXFLAGS} -std=c++11 -Wall -g -o loader_example loader_example.cc
|
||||
- ./loader_example ./models/Cube/Cube.gltf
|
||||
- cd examples/raytrace
|
||||
- ../../premake5 gmake
|
||||
- make
|
||||
|
@ -107,6 +107,7 @@ if (!ret) {
|
||||
## Compile options
|
||||
|
||||
* `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF.
|
||||
* `TINYGLTF_NO_STB_IMAGE` : Do not load images with stb_image. Instead use `TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data)` to set a callback for loading images.
|
||||
|
||||
### Saving gltTF 2.0 model
|
||||
|
||||
|
@ -13,3 +13,6 @@ configuration: Release
|
||||
build:
|
||||
parallel: true
|
||||
project: TinyGLTFSolution.sln
|
||||
|
||||
after_build:
|
||||
- examples.bat
|
||||
|
3
examples.bat
Normal file
3
examples.bat
Normal file
@ -0,0 +1,3 @@
|
||||
cd examples\raytrace
|
||||
..\..\tools\windows\premake5.exe vs2015
|
||||
msbuild NanoSGSolution.sln /property:Configuration=Release
|
@ -21,7 +21,9 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "imgui.h"
|
||||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include "imgui_internal.h"
|
||||
#include "ImGuizmo.h"
|
||||
|
||||
@ -65,6 +67,8 @@ namespace ImGuizmo
|
||||
//template <typename T> T LERP(T x, T y, float z) { return (x + (y - x)*z); }
|
||||
template <typename T> T Clamp(T x, T y, T z) { return ((x<y) ? y : ((x>z) ? z : x)); }
|
||||
template <typename T> T max(T x, T y) { return (x > y) ? x : y; }
|
||||
template <typename T> T min(T x, T y) { return (x < y) ? x : y; }
|
||||
template <typename T> bool IsWithin(T x, T y, T z) { return (x>=y) && (x<=z); }
|
||||
|
||||
struct matrix_t;
|
||||
struct vec_t
|
||||
@ -86,7 +90,7 @@ namespace ImGuizmo
|
||||
vec_t& operator -= (const vec_t& v) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; }
|
||||
vec_t& operator += (const vec_t& v) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; }
|
||||
vec_t& operator *= (const vec_t& v) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; }
|
||||
vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
|
||||
vec_t& operator *= (float v) { x *= v; y *= v; z *= v; w *= v; return *this; }
|
||||
|
||||
vec_t operator * (float f) const;
|
||||
vec_t operator - () const;
|
||||
@ -99,7 +103,7 @@ namespace ImGuizmo
|
||||
float LengthSq() const { return (x*x + y*y + z*z); };
|
||||
vec_t Normalize() { (*this) *= (1.f / Length()); return (*this); }
|
||||
vec_t Normalize(const vec_t& v) { this->Set(v.x, v.y, v.z, v.w); this->Normalize(); return (*this); }
|
||||
vec_t Abs() const;
|
||||
vec_t Abs() const;
|
||||
void Cross(const vec_t& v)
|
||||
{
|
||||
vec_t res;
|
||||
@ -147,7 +151,6 @@ namespace ImGuizmo
|
||||
vec_t vec_t::operator + (const vec_t& v) const { return makeVect(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||
vec_t vec_t::operator * (const vec_t& v) const { return makeVect(x * v.x, y * v.y, z * v.z, w * v.w); }
|
||||
vec_t vec_t::Abs() const { return makeVect(fabsf(x), fabsf(y), fabsf(z)); }
|
||||
ImVec2 operator+ (const ImVec2& a, const ImVec2& b) { return ImVec2(a.x + b.x, a.y + b.y); }
|
||||
|
||||
vec_t Normalized(const vec_t& v) { vec_t res; res = v; res.Normalize(); return res; }
|
||||
vec_t Cross(const vec_t& v1, const vec_t& v2)
|
||||
@ -188,7 +191,7 @@ namespace ImGuizmo
|
||||
{
|
||||
vec_t right, up, dir, position;
|
||||
} v;
|
||||
vec_t component[4];
|
||||
vec_t component[4];
|
||||
};
|
||||
|
||||
matrix_t(const matrix_t& other) { memcpy(&m16[0], &other.m16[0], sizeof(float) * 16); }
|
||||
@ -491,7 +494,7 @@ namespace ImGuizmo
|
||||
SCALE_Y,
|
||||
SCALE_Z,
|
||||
SCALE_XYZ,
|
||||
BOUNDS
|
||||
BOUNDS
|
||||
};
|
||||
|
||||
struct Context
|
||||
@ -520,6 +523,7 @@ namespace ImGuizmo
|
||||
vec_t mRayOrigin;
|
||||
vec_t mRayVector;
|
||||
|
||||
float mRadiusSquareCenter;
|
||||
ImVec2 mScreenSquareCenter;
|
||||
ImVec2 mScreenSquareMin;
|
||||
ImVec2 mScreenSquareMax;
|
||||
@ -551,23 +555,25 @@ namespace ImGuizmo
|
||||
bool mBelowPlaneLimit[3];
|
||||
float mAxisFactor[3];
|
||||
|
||||
// bounds stretching
|
||||
vec_t mBoundsPivot;
|
||||
vec_t mBoundsAnchor;
|
||||
vec_t mBoundsPlan;
|
||||
vec_t mBoundsLocalPivot;
|
||||
int mBoundsBestAxis;
|
||||
int mBoundsAxis[2];
|
||||
bool mbUsingBounds;
|
||||
matrix_t mBoundsMatrix;
|
||||
// bounds stretching
|
||||
vec_t mBoundsPivot;
|
||||
vec_t mBoundsAnchor;
|
||||
vec_t mBoundsPlan;
|
||||
vec_t mBoundsLocalPivot;
|
||||
int mBoundsBestAxis;
|
||||
int mBoundsAxis[2];
|
||||
bool mbUsingBounds;
|
||||
matrix_t mBoundsMatrix;
|
||||
|
||||
//
|
||||
int mCurrentOperation;
|
||||
|
||||
float mX = 0.f;
|
||||
float mY = 0.f;
|
||||
float mWidth = 0.f;
|
||||
float mHeight = 0.f;
|
||||
float mX = 0.f;
|
||||
float mY = 0.f;
|
||||
float mWidth = 0.f;
|
||||
float mHeight = 0.f;
|
||||
float mXMax = 0.f;
|
||||
float mYMax = 0.f;
|
||||
};
|
||||
|
||||
static Context gContext;
|
||||
@ -577,7 +583,11 @@ namespace ImGuizmo
|
||||
|
||||
static const vec_t directionUnary[3] = { makeVect(1.f, 0.f, 0.f), makeVect(0.f, 1.f, 0.f), makeVect(0.f, 0.f, 1.f) };
|
||||
static const ImU32 directionColor[3] = { 0xFF0000AA, 0xFF00AA00, 0xFFAA0000 };
|
||||
static const ImU32 selectionColor = 0xFF1080FF;
|
||||
|
||||
// Alpha: 100%: FF, 87%: DE, 70%: B3, 54%: 8A, 50%: 80, 38%: 61, 12%: 1F
|
||||
static const ImU32 planeBorderColor[3] = { 0xFFAA0000, 0xFF0000AA, 0xFF00AA00 };
|
||||
static const ImU32 planeColor[3] = { 0x610000AA, 0x6100AA00, 0x61AA0000 };
|
||||
static const ImU32 selectionColor = 0x8A1080FF;
|
||||
static const ImU32 inactiveColor = 0x99999999;
|
||||
static const ImU32 translationLineColor = 0xAAAAAAAA;
|
||||
static const char *translationInfoMask[] = { "X : %5.3f", "Y : %5.3f", "Z : %5.3f", "X : %5.3f Y : %5.3f", "Y : %5.3f Z : %5.3f", "X : %5.3f Z : %5.3f", "X : %5.3f Y : %5.3f Z : %5.3f" };
|
||||
@ -598,18 +608,16 @@ namespace ImGuizmo
|
||||
|
||||
static ImVec2 worldToPos(const vec_t& worldPos, const matrix_t& mat)
|
||||
{
|
||||
//ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
vec_t trans;
|
||||
trans.TransformPoint(worldPos, mat);
|
||||
trans *= 0.5f / trans.w;
|
||||
trans += makeVect(0.5f, 0.5f);
|
||||
trans.y = 1.f - trans.y;
|
||||
trans.x *= gContext.mWidth;
|
||||
trans.y *= gContext.mHeight;
|
||||
trans.x += gContext.mX;
|
||||
trans.y += gContext.mY;
|
||||
return ImVec2(trans.x, trans.y);
|
||||
trans.x *= gContext.mWidth;
|
||||
trans.y *= gContext.mHeight;
|
||||
trans.x += gContext.mX;
|
||||
trans.y += gContext.mY;
|
||||
return ImVec2(trans.x, trans.y);
|
||||
}
|
||||
|
||||
static void ComputeCameraRay(vec_t &rayOrigin, vec_t &rayDir)
|
||||
@ -619,9 +627,9 @@ namespace ImGuizmo
|
||||
matrix_t mViewProjInverse;
|
||||
mViewProjInverse.Inverse(gContext.mViewMat * gContext.mProjectionMat);
|
||||
|
||||
float mox = ((io.MousePos.x - gContext.mX) / gContext.mWidth) * 2.f - 1.f;
|
||||
float moy = (1.f - ((io.MousePos.y - gContext.mY) / gContext.mHeight)) * 2.f - 1.f;
|
||||
|
||||
float mox = ((io.MousePos.x - gContext.mX) / gContext.mWidth) * 2.f - 1.f;
|
||||
float moy = (1.f - ((io.MousePos.y - gContext.mY) / gContext.mHeight)) * 2.f - 1.f;
|
||||
|
||||
rayOrigin.Transform(makeVect(mox, moy, 0.f, 1.f), mViewProjInverse);
|
||||
rayOrigin *= 1.f / rayOrigin.w;
|
||||
vec_t rayEnd;
|
||||
@ -641,23 +649,38 @@ namespace ImGuizmo
|
||||
return -(numer / denom);
|
||||
}
|
||||
|
||||
static bool IsInContextRect( ImVec2 p )
|
||||
{
|
||||
return IsWithin( p.x, gContext.mX, gContext.mXMax ) && IsWithin(p.y, gContext.mY, gContext.mYMax );
|
||||
}
|
||||
|
||||
void SetRect(float x, float y, float width, float height)
|
||||
{
|
||||
gContext.mX = x;
|
||||
gContext.mY = y;
|
||||
gContext.mWidth = width;
|
||||
gContext.mHeight = height;
|
||||
gContext.mX = x;
|
||||
gContext.mY = y;
|
||||
gContext.mWidth = width;
|
||||
gContext.mHeight = height;
|
||||
gContext.mXMax = gContext.mX + gContext.mWidth;
|
||||
gContext.mYMax = gContext.mY + gContext.mXMax;
|
||||
}
|
||||
|
||||
void SetDrawlist()
|
||||
{
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
}
|
||||
|
||||
void BeginFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::Begin("gizmo", NULL, io.DisplaySize, 0, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus);
|
||||
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
const ImU32 flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus;
|
||||
ImGui::SetNextWindowSize(io.DisplaySize);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, 0);
|
||||
ImGui::Begin("gizmo", NULL, flags);
|
||||
gContext.mDrawList = ImGui::GetWindowDrawList();
|
||||
ImGui::End();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
bool IsUsing()
|
||||
@ -673,11 +696,11 @@ namespace ImGuizmo
|
||||
void Enable(bool enable)
|
||||
{
|
||||
gContext.mbEnable = enable;
|
||||
if (!enable)
|
||||
{
|
||||
gContext.mbUsing = false;
|
||||
gContext.mbUsingBounds = false;
|
||||
}
|
||||
if (!enable)
|
||||
{
|
||||
gContext.mbUsing = false;
|
||||
gContext.mbUsingBounds = false;
|
||||
}
|
||||
}
|
||||
|
||||
static float GetUniform(const vec_t& position, const matrix_t& mat)
|
||||
@ -738,7 +761,8 @@ namespace ImGuizmo
|
||||
{
|
||||
int colorPlaneIndex = (i + 2) % 3;
|
||||
colors[i + 1] = (type == (int)(MOVE_X + i)) ? selectionColor : directionColor[i];
|
||||
colors[i + 4] = (type == (int)(MOVE_XY + i)) ? selectionColor : directionColor[colorPlaneIndex];
|
||||
colors[i + 4] = (type == (int)(MOVE_XY + i)) ? selectionColor : planeColor[colorPlaneIndex];
|
||||
colors[i + 4] = (type == MOVE_SCREEN) ? selectionColor : colors[i + 4];
|
||||
}
|
||||
break;
|
||||
case ROTATE:
|
||||
@ -751,8 +775,6 @@ namespace ImGuizmo
|
||||
for (int i = 0; i < 3; i++)
|
||||
colors[i + 1] = (type == (int)(SCALE_X + i)) ? selectionColor : directionColor[i];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -848,7 +870,6 @@ namespace ImGuizmo
|
||||
static void DrawRotationGizmo(int type)
|
||||
{
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
//ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// colors
|
||||
ImU32 colors[7];
|
||||
@ -857,6 +878,7 @@ namespace ImGuizmo
|
||||
vec_t cameraToModelNormalized = Normalized(gContext.mModel.v.position - gContext.mCameraEye);
|
||||
cameraToModelNormalized.TransformVector(gContext.mModelInverse);
|
||||
|
||||
gContext.mRadiusSquareCenter = screenRotateSize * gContext.mHeight;
|
||||
for (int axis = 0; axis < 3; axis++)
|
||||
{
|
||||
ImVec2 circlePos[halfCircleSegmentCount];
|
||||
@ -870,9 +892,14 @@ namespace ImGuizmo
|
||||
vec_t pos = makeVect(axisPos[axis], axisPos[(axis+1)%3], axisPos[(axis+2)%3]) * gContext.mScreenFactor;
|
||||
circlePos[i] = worldToPos(pos, gContext.mMVP);
|
||||
}
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2, true);
|
||||
|
||||
float radiusAxis = sqrtf( (ImLengthSqr(worldToPos(gContext.mModel.v.position, gContext.mViewProjection) - circlePos[0]) ));
|
||||
if(radiusAxis > gContext.mRadiusSquareCenter)
|
||||
gContext.mRadiusSquareCenter = radiusAxis;
|
||||
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, colors[3 - axis], false, 2);
|
||||
}
|
||||
drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), screenRotateSize * gContext.mHeight, colors[0], 64);
|
||||
drawList->AddCircle(worldToPos(gContext.mModel.v.position, gContext.mViewProjection), gContext.mRadiusSquareCenter, colors[0], 64, 3.f);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
@ -889,8 +916,8 @@ namespace ImGuizmo
|
||||
pos *= gContext.mScreenFactor;
|
||||
circlePos[i] = worldToPos(pos + gContext.mModel.v.position, gContext.mViewProjection);
|
||||
}
|
||||
drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF, true);
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2, true);
|
||||
drawList->AddConvexPolyFilled(circlePos, halfCircleSegmentCount, 0x801080FF);
|
||||
drawList->AddPolyline(circlePos, halfCircleSegmentCount, 0xFF1080FF, true, 2);
|
||||
|
||||
ImVec2 destinationPosOnScreen = circlePos[1];
|
||||
char tmps[512];
|
||||
@ -918,9 +945,6 @@ namespace ImGuizmo
|
||||
ImU32 colors[7];
|
||||
ComputeColors(colors, type, SCALE);
|
||||
|
||||
// draw screen cirle
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 12.f, colors[0], 32);
|
||||
|
||||
// draw
|
||||
vec_t scaleDisplay = { 1.f, 1.f, 1.f, 1.f };
|
||||
|
||||
@ -942,17 +966,20 @@ namespace ImGuizmo
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 6.f);
|
||||
drawList->AddCircleFilled(worldDirSSpaceNoScale, 10.f, 0xFF404040);
|
||||
drawList->AddLine(baseSSpace, worldDirSSpaceNoScale, 0xFF404040, 3.f);
|
||||
drawList->AddCircleFilled(worldDirSSpaceNoScale, 6.f, 0xFF404040);
|
||||
}
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
|
||||
drawList->AddCircleFilled(worldDirSSpace, 10.f, colors[i + 1]);
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
|
||||
drawList->AddCircleFilled(worldDirSSpace, 6.f, colors[i + 1]);
|
||||
|
||||
if (gContext.mAxisFactor[i] < 0.f)
|
||||
DrawHatchedAxis(dirPlaneX * scaleDisplay[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// draw screen cirle
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
@ -978,21 +1005,21 @@ namespace ImGuizmo
|
||||
static void DrawTranslationGizmo(int type)
|
||||
{
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
if (!drawList)
|
||||
return;
|
||||
if (!drawList)
|
||||
return;
|
||||
|
||||
// colors
|
||||
ImU32 colors[7];
|
||||
ComputeColors(colors, type, TRANSLATE);
|
||||
|
||||
// draw screen quad
|
||||
drawList->AddRectFilled(gContext.mScreenSquareMin, gContext.mScreenSquareMax, colors[0], 2.f);
|
||||
|
||||
const ImVec2 origin = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
|
||||
// draw
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
bool belowAxisLimit = false;
|
||||
bool belowPlaneLimit = false;
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
{
|
||||
vec_t dirPlaneX, dirPlaneY;
|
||||
bool belowAxisLimit, belowPlaneLimit;
|
||||
ComputeTripodAxisAndVisibility(i, dirPlaneX, dirPlaneY, belowAxisLimit, belowPlaneLimit);
|
||||
|
||||
// draw axis
|
||||
@ -1001,8 +1028,20 @@ namespace ImGuizmo
|
||||
ImVec2 baseSSpace = worldToPos(dirPlaneX * 0.1f * gContext.mScreenFactor, gContext.mMVP);
|
||||
ImVec2 worldDirSSpace = worldToPos(dirPlaneX * gContext.mScreenFactor, gContext.mMVP);
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 6.f);
|
||||
|
||||
drawList->AddLine(baseSSpace, worldDirSSpace, colors[i + 1], 3.f);
|
||||
|
||||
// Arrow head begin
|
||||
ImVec2 dir(origin - worldDirSSpace);
|
||||
|
||||
float d = sqrtf(ImLengthSqr(dir));
|
||||
dir /= d; // Normalize
|
||||
dir *= 6.0f;
|
||||
|
||||
ImVec2 ortogonalDir(dir.y, -dir.x); // Perpendicular vector
|
||||
ImVec2 a(worldDirSSpace + dir);
|
||||
drawList->AddTriangleFilled(worldDirSSpace - dir, a + ortogonalDir, a - ortogonalDir, colors[i + 1]);
|
||||
// Arrow head end
|
||||
|
||||
if (gContext.mAxisFactor[i] < 0.f)
|
||||
DrawHatchedAxis(dirPlaneX);
|
||||
}
|
||||
@ -1011,15 +1050,18 @@ namespace ImGuizmo
|
||||
if (belowPlaneLimit)
|
||||
{
|
||||
ImVec2 screenQuadPts[4];
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int j = 0; j < 4; ++j)
|
||||
{
|
||||
vec_t cornerWorldPos = (dirPlaneX * quadUV[j * 2] + dirPlaneY * quadUV[j * 2 + 1]) * gContext.mScreenFactor;
|
||||
screenQuadPts[j] = worldToPos(cornerWorldPos, gContext.mMVP);
|
||||
}
|
||||
drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4], true);
|
||||
drawList->AddPolyline(screenQuadPts, 4, planeBorderColor[i], true, 1.0f);
|
||||
drawList->AddConvexPolyFilled(screenQuadPts, 4, colors[i + 4]);
|
||||
}
|
||||
}
|
||||
|
||||
drawList->AddCircleFilled(gContext.mScreenSquareCenter, 6.f, colors[0], 32);
|
||||
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImVec2 sourcePosOnScreen = worldToPos(gContext.mMatrixOrigin, gContext.mViewProjection);
|
||||
@ -1040,176 +1082,233 @@ namespace ImGuizmo
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanActivate()
|
||||
{
|
||||
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemActive())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void HandleAndDrawLocalBounds(float *bounds, matrix_t *matrix, float *snapValues)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* drawList = gContext.mDrawList;
|
||||
|
||||
// compute best projection axis
|
||||
vec_t bestAxisWorldDirection;
|
||||
int bestAxis = gContext.mBoundsBestAxis;
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
|
||||
float bestDot = 0.f;
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
vec_t dirPlaneNormalWorld;
|
||||
dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
|
||||
dirPlaneNormalWorld.Normalize();
|
||||
// compute best projection axis
|
||||
vec_t axesWorldDirections[3];
|
||||
vec_t bestAxisWorldDirection = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
int axes[3];
|
||||
unsigned int numAxes = 1;
|
||||
axes[0] = gContext.mBoundsBestAxis;
|
||||
int bestAxis = axes[0];
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
numAxes = 0;
|
||||
float bestDot = 0.f;
|
||||
for (unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
vec_t dirPlaneNormalWorld;
|
||||
dirPlaneNormalWorld.TransformVector(directionUnary[i], gContext.mModelSource);
|
||||
dirPlaneNormalWorld.Normalize();
|
||||
|
||||
float dt = Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld);
|
||||
if (fabsf(dt) >= bestDot)
|
||||
{
|
||||
bestDot = fabsf(dt);
|
||||
bestAxis = i;
|
||||
bestAxisWorldDirection = dirPlaneNormalWorld;
|
||||
}
|
||||
}
|
||||
}
|
||||
float dt = fabsf( Dot(Normalized(gContext.mCameraEye - gContext.mModelSource.v.position), dirPlaneNormalWorld) );
|
||||
if ( dt >= bestDot )
|
||||
{
|
||||
bestDot = dt;
|
||||
bestAxis = i;
|
||||
bestAxisWorldDirection = dirPlaneNormalWorld;
|
||||
}
|
||||
|
||||
// corners
|
||||
vec_t aabb[4];
|
||||
if( dt >= 0.1f )
|
||||
{
|
||||
axes[numAxes] = i;
|
||||
axesWorldDirections[numAxes] = dirPlaneNormalWorld;
|
||||
++numAxes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int secondAxis = (bestAxis + 1) % 3;
|
||||
int thirdAxis = (bestAxis + 2) % 3;
|
||||
if( numAxes == 0 )
|
||||
{
|
||||
axes[0] = bestAxis;
|
||||
axesWorldDirections[0] = bestAxisWorldDirection;
|
||||
numAxes = 1;
|
||||
}
|
||||
else if( bestAxis != axes[0] )
|
||||
{
|
||||
unsigned int bestIndex = 0;
|
||||
for (unsigned int i = 0; i < numAxes; i++)
|
||||
{
|
||||
if( axes[i] == bestAxis )
|
||||
{
|
||||
bestIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int tempAxis = axes[0];
|
||||
axes[0] = axes[bestIndex];
|
||||
axes[bestIndex] = tempAxis;
|
||||
vec_t tempDirection = axesWorldDirections[0];
|
||||
axesWorldDirections[0] = axesWorldDirections[bestIndex];
|
||||
axesWorldDirections[bestIndex] = tempDirection;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
aabb[i][3] = aabb[i][bestAxis] = 0.f;
|
||||
aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
|
||||
aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
|
||||
}
|
||||
for (unsigned int axisIndex = 0; axisIndex < numAxes; ++axisIndex)
|
||||
{
|
||||
bestAxis = axes[axisIndex];
|
||||
bestAxisWorldDirection = axesWorldDirections[axisIndex];
|
||||
|
||||
// draw bounds
|
||||
unsigned int anchorAlpha = gContext.mbEnable ? 0xFF000000 : 0x80000000;
|
||||
// corners
|
||||
vec_t aabb[4];
|
||||
|
||||
matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
|
||||
for (int i = 0; i < 4;i++)
|
||||
{
|
||||
ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
|
||||
ImVec2 worldBound2 = worldToPos(aabb[(i+1)%4], boundsMVP);
|
||||
float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
|
||||
int stepCount = (int)(boundDistance / 10.f);
|
||||
float stepLength = 1.f / (float)stepCount;
|
||||
for (int j = 0; j < stepCount; j++)
|
||||
{
|
||||
float t1 = (float)j * stepLength;
|
||||
float t2 = (float)j * stepLength + stepLength * 0.5f;
|
||||
ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
|
||||
ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
|
||||
drawList->AddLine(worldBoundSS1, worldBoundSS2, 0xAAAAAA + anchorAlpha, 3.f);
|
||||
}
|
||||
vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4] ) * 0.5f;
|
||||
ImVec2 midBound = worldToPos(midPoint, boundsMVP);
|
||||
static const float AnchorBigRadius = 8.f;
|
||||
static const float AnchorSmallRadius = 6.f;
|
||||
bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
int secondAxis = (bestAxis + 1) % 3;
|
||||
int thirdAxis = (bestAxis + 2) % 3;
|
||||
|
||||
|
||||
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
|
||||
drawList->AddCircleFilled(worldBound1, AnchorBigRadius, bigAnchorColor);
|
||||
drawList->AddCircleFilled(midBound, AnchorSmallRadius, smallAnchorColor);
|
||||
int oppositeIndex = (i + 2) % 4;
|
||||
// big anchor on corners
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && io.MouseDown[0])
|
||||
{
|
||||
gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
gContext.mBoundsAxis[0] = secondAxis;
|
||||
gContext.mBoundsAxis[1] = thirdAxis;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
aabb[i][3] = aabb[i][bestAxis] = 0.f;
|
||||
aabb[i][secondAxis] = bounds[secondAxis + 3 * (i >> 1)];
|
||||
aabb[i][thirdAxis] = bounds[thirdAxis + 3 * ((i >> 1) ^ (i & 1))];
|
||||
}
|
||||
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
|
||||
gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
|
||||
// draw bounds
|
||||
unsigned int anchorAlpha = gContext.mbEnable ? 0xFF000000 : 0x80000000;
|
||||
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
// small anchor on middle of segment
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && io.MouseDown[0])
|
||||
{
|
||||
vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
|
||||
gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
int indices[] = { secondAxis , thirdAxis };
|
||||
gContext.mBoundsAxis[0] = indices[i%2];
|
||||
gContext.mBoundsAxis[1] = -1;
|
||||
matrix_t boundsMVP = gContext.mModelSource * gContext.mViewProjection;
|
||||
for (int i = 0; i < 4;i++)
|
||||
{
|
||||
ImVec2 worldBound1 = worldToPos(aabb[i], boundsMVP);
|
||||
ImVec2 worldBound2 = worldToPos(aabb[(i+1)%4], boundsMVP);
|
||||
if( !IsInContextRect( worldBound1 ) || !IsInContextRect( worldBound2 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
float boundDistance = sqrtf(ImLengthSqr(worldBound1 - worldBound2));
|
||||
int stepCount = (int)(boundDistance / 10.f);
|
||||
stepCount = min( stepCount, 1000 );
|
||||
float stepLength = 1.f / (float)stepCount;
|
||||
for (int j = 0; j < stepCount; j++)
|
||||
{
|
||||
float t1 = (float)j * stepLength;
|
||||
float t2 = (float)j * stepLength + stepLength * 0.5f;
|
||||
ImVec2 worldBoundSS1 = ImLerp(worldBound1, worldBound2, ImVec2(t1, t1));
|
||||
ImVec2 worldBoundSS2 = ImLerp(worldBound1, worldBound2, ImVec2(t2, t2));
|
||||
drawList->AddLine(worldBoundSS1, worldBoundSS2, 0xAAAAAA + anchorAlpha, 3.f);
|
||||
}
|
||||
vec_t midPoint = (aabb[i] + aabb[(i + 1) % 4] ) * 0.5f;
|
||||
ImVec2 midBound = worldToPos(midPoint, boundsMVP);
|
||||
static const float AnchorBigRadius = 8.f;
|
||||
static const float AnchorSmallRadius = 6.f;
|
||||
bool overBigAnchor = ImLengthSqr(worldBound1 - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
bool overSmallAnchor = ImLengthSqr(midBound - io.MousePos) <= (AnchorBigRadius*AnchorBigRadius);
|
||||
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
|
||||
|
||||
unsigned int bigAnchorColor = overBigAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
unsigned int smallAnchorColor = overSmallAnchor ? selectionColor : (0xAAAAAA + anchorAlpha);
|
||||
|
||||
drawList->AddCircleFilled(worldBound1, AnchorBigRadius, bigAnchorColor);
|
||||
drawList->AddCircleFilled(midBound, AnchorSmallRadius, smallAnchorColor);
|
||||
int oppositeIndex = (i + 2) % 4;
|
||||
// big anchor on corners
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overBigAnchor && CanActivate())
|
||||
{
|
||||
gContext.mBoundsPivot.TransformPoint(aabb[(i + 2) % 4], gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(aabb[i], gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
gContext.mBoundsAxis[0] = secondAxis;
|
||||
gContext.mBoundsAxis[1] = thirdAxis;
|
||||
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
}
|
||||
|
||||
if (gContext.mbUsingBounds)
|
||||
{
|
||||
matrix_t scale;
|
||||
scale.SetToIdentity();
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[secondAxis] = aabb[oppositeIndex][secondAxis];
|
||||
gContext.mBoundsLocalPivot[thirdAxis] = aabb[oppositeIndex][thirdAxis];
|
||||
|
||||
// compute projected mouse position on plan
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
// small anchor on middle of segment
|
||||
if (!gContext.mbUsingBounds && gContext.mbEnable && overSmallAnchor && CanActivate())
|
||||
{
|
||||
vec_t midPointOpposite = (aabb[(i + 2) % 4] + aabb[(i + 3) % 4]) * 0.5f;
|
||||
gContext.mBoundsPivot.TransformPoint(midPointOpposite, gContext.mModelSource);
|
||||
gContext.mBoundsAnchor.TransformPoint(midPoint, gContext.mModelSource);
|
||||
gContext.mBoundsPlan = BuildPlan(gContext.mBoundsAnchor, bestAxisWorldDirection);
|
||||
gContext.mBoundsBestAxis = bestAxis;
|
||||
int indices[] = { secondAxis , thirdAxis };
|
||||
gContext.mBoundsAxis[0] = indices[i%2];
|
||||
gContext.mBoundsAxis[1] = -1;
|
||||
|
||||
// compute a reference and delta vectors base on mouse move
|
||||
vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
|
||||
vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
|
||||
gContext.mBoundsLocalPivot.Set(0.f);
|
||||
gContext.mBoundsLocalPivot[gContext.mBoundsAxis[0]] = aabb[oppositeIndex][indices[i % 2]];// bounds[gContext.mBoundsAxis[0]] * (((i + 1) & 2) ? 1.f : -1.f);
|
||||
|
||||
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int axisIndex = gContext.mBoundsAxis[i];
|
||||
if (axisIndex == -1)
|
||||
continue;
|
||||
gContext.mbUsingBounds = true;
|
||||
gContext.mBoundsMatrix = gContext.mModelSource;
|
||||
}
|
||||
}
|
||||
|
||||
if (gContext.mbUsingBounds)
|
||||
{
|
||||
matrix_t scale;
|
||||
scale.SetToIdentity();
|
||||
|
||||
float ratioAxis = 1.f;
|
||||
vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex].Abs();
|
||||
// compute projected mouse position on plan
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mBoundsPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
|
||||
float dtAxis = axisDir.Dot(referenceVector);
|
||||
float boundSize = bounds[axisIndex + 3] - bounds[axisIndex];
|
||||
if (dtAxis > FLT_EPSILON)
|
||||
ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
|
||||
// compute a reference and delta vectors base on mouse move
|
||||
vec_t deltaVector = (newPos - gContext.mBoundsPivot).Abs();
|
||||
vec_t referenceVector = (gContext.mBoundsAnchor - gContext.mBoundsPivot).Abs();
|
||||
|
||||
if (snapValues)
|
||||
{
|
||||
float length = boundSize * ratioAxis;
|
||||
ComputeSnap(&length, snapValues[axisIndex]);
|
||||
if (boundSize > FLT_EPSILON)
|
||||
ratioAxis = length / boundSize;
|
||||
}
|
||||
scale.component[axisIndex] *= ratioAxis;
|
||||
}
|
||||
// for 1 or 2 axes, compute a ratio that's used for scale and snap it based on resulting length
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int axisIndex1 = gContext.mBoundsAxis[i];
|
||||
if (axisIndex1 == -1)
|
||||
continue;
|
||||
|
||||
// transform matrix
|
||||
matrix_t preScale, postScale;
|
||||
preScale.Translation(-gContext.mBoundsLocalPivot);
|
||||
postScale.Translation(gContext.mBoundsLocalPivot);
|
||||
matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
|
||||
*matrix = res;
|
||||
float ratioAxis = 1.f;
|
||||
vec_t axisDir = gContext.mBoundsMatrix.component[axisIndex1].Abs();
|
||||
|
||||
// info text
|
||||
char tmps[512];
|
||||
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f"
|
||||
, (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
|
||||
, (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
|
||||
, (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
|
||||
);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
|
||||
}
|
||||
float dtAxis = axisDir.Dot(referenceVector);
|
||||
float boundSize = bounds[axisIndex1 + 3] - bounds[axisIndex1];
|
||||
if (dtAxis > FLT_EPSILON)
|
||||
ratioAxis = axisDir.Dot(deltaVector) / dtAxis;
|
||||
|
||||
if (!io.MouseDown[0])
|
||||
gContext.mbUsingBounds = false;
|
||||
if (snapValues)
|
||||
{
|
||||
float length = boundSize * ratioAxis;
|
||||
ComputeSnap(&length, snapValues[axisIndex1]);
|
||||
if (boundSize > FLT_EPSILON)
|
||||
ratioAxis = length / boundSize;
|
||||
}
|
||||
scale.component[axisIndex1] *= ratioAxis;
|
||||
}
|
||||
|
||||
// transform matrix
|
||||
matrix_t preScale, postScale;
|
||||
preScale.Translation(-gContext.mBoundsLocalPivot);
|
||||
postScale.Translation(gContext.mBoundsLocalPivot);
|
||||
matrix_t res = preScale * scale * postScale * gContext.mBoundsMatrix;
|
||||
*matrix = res;
|
||||
|
||||
// info text
|
||||
char tmps[512];
|
||||
ImVec2 destinationPosOnScreen = worldToPos(gContext.mModel.v.position, gContext.mViewProjection);
|
||||
ImFormatString(tmps, sizeof(tmps), "X: %.2f Y: %.2f Z:%.2f"
|
||||
, (bounds[3] - bounds[0]) * gContext.mBoundsMatrix.component[0].Length() * scale.component[0].Length()
|
||||
, (bounds[4] - bounds[1]) * gContext.mBoundsMatrix.component[1].Length() * scale.component[1].Length()
|
||||
, (bounds[5] - bounds[2]) * gContext.mBoundsMatrix.component[2].Length() * scale.component[2].Length()
|
||||
);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 15, destinationPosOnScreen.y + 15), 0xFF000000, tmps);
|
||||
drawList->AddText(ImVec2(destinationPosOnScreen.x + 14, destinationPosOnScreen.y + 14), 0xFFFFFFFF, tmps);
|
||||
}
|
||||
|
||||
if (!io.MouseDown[0])
|
||||
gContext.mbUsingBounds = false;
|
||||
|
||||
if( gContext.mbUsingBounds )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1255,7 +1354,7 @@ namespace ImGuizmo
|
||||
|
||||
vec_t deltaScreen = { io.MousePos.x - gContext.mScreenSquareCenter.x, io.MousePos.y - gContext.mScreenSquareCenter.y, 0.f, 0.f };
|
||||
float dist = deltaScreen.Length();
|
||||
if (dist >= (screenRotateSize - 0.002f) * gContext.mHeight && dist < (screenRotateSize + 0.002f) * gContext.mHeight)
|
||||
if (dist >= (gContext.mRadiusSquareCenter - 1.0f) && dist < (gContext.mRadiusSquareCenter + 1.0f))
|
||||
type = ROTATE_SCREEN;
|
||||
|
||||
const vec_t planNormals[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir};
|
||||
@ -1327,6 +1426,7 @@ namespace ImGuizmo
|
||||
// move
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
|
||||
@ -1385,8 +1485,9 @@ namespace ImGuizmo
|
||||
// find new possible way to move
|
||||
vec_t gizmoHitProportion;
|
||||
type = GetMoveType(&gizmoHitProportion);
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.up, -gContext.mCameraDir };
|
||||
@ -1409,8 +1510,9 @@ namespace ImGuizmo
|
||||
{
|
||||
// find new possible way to scale
|
||||
type = GetScaleType();
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t movePlanNormal[] = { gContext.mModel.v.up, gContext.mModel.v.dir, gContext.mModel.v.right, gContext.mModel.v.dir, gContext.mModel.v.up, gContext.mModel.v.right, -gContext.mCameraDir };
|
||||
@ -1429,6 +1531,7 @@ namespace ImGuizmo
|
||||
// scale
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
const float len = IntersectRayPlane(gContext.mRayOrigin, gContext.mRayVector, gContext.mTranslationPlan);
|
||||
vec_t newPos = gContext.mRayOrigin + gContext.mRayVector * len;
|
||||
vec_t newOrigin = newPos - gContext.mRelativeOrigin * gContext.mScreenFactor;
|
||||
@ -1448,7 +1551,7 @@ namespace ImGuizmo
|
||||
gContext.mScale[axisIndex] = max(ratio, 0.001f);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
float scaleDelta = (io.MousePos.x - gContext.mSaveMousePosx) * 0.01f;
|
||||
gContext.mScale.Set(max(1.f + scaleDelta, 0.001f));
|
||||
}
|
||||
@ -1492,14 +1595,15 @@ namespace ImGuizmo
|
||||
if (!gContext.mbUsing)
|
||||
{
|
||||
type = GetRotateType();
|
||||
|
||||
|
||||
if (type == ROTATE_SCREEN)
|
||||
{
|
||||
applyRotationLocaly = true;
|
||||
}
|
||||
|
||||
if (io.MouseDown[0] && type != NONE)
|
||||
if (CanActivate() && type != NONE)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mbUsing = true;
|
||||
gContext.mCurrentOperation = type;
|
||||
const vec_t rotatePlanNormal[] = { gContext.mModel.v.right, gContext.mModel.v.up, gContext.mModel.v.dir, -gContext.mCameraDir };
|
||||
@ -1523,6 +1627,7 @@ namespace ImGuizmo
|
||||
// rotation
|
||||
if (gContext.mbUsing)
|
||||
{
|
||||
ImGui::CaptureMouseFromApp();
|
||||
gContext.mRotationAngle = ComputeAngleOnPlan();
|
||||
if (snap)
|
||||
{
|
||||
@ -1627,41 +1732,41 @@ namespace ImGuizmo
|
||||
int type = NONE;
|
||||
if (gContext.mbEnable)
|
||||
{
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
HandleRotation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
HandleTranslation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case SCALE:
|
||||
HandleScale(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
HandleRotation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
HandleTranslation(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
case SCALE:
|
||||
HandleScale(matrix, deltaMatrix, type, snap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (localBounds && !gContext.mbUsing)
|
||||
HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap);
|
||||
if (localBounds && !gContext.mbUsing)
|
||||
HandleAndDrawLocalBounds(localBounds, (matrix_t*)matrix, boundsSnap);
|
||||
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
DrawRotationGizmo(type);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
DrawTranslationGizmo(type);
|
||||
break;
|
||||
case SCALE:
|
||||
DrawScaleGizmo(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gContext.mbUsingBounds)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case ROTATE:
|
||||
DrawRotationGizmo(type);
|
||||
break;
|
||||
case TRANSLATE:
|
||||
DrawTranslationGizmo(type);
|
||||
break;
|
||||
case SCALE:
|
||||
DrawScaleGizmo(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawCube(const float *view, const float *projection, float *matrix)
|
||||
@ -1713,7 +1818,7 @@ namespace ImGuizmo
|
||||
continue;
|
||||
|
||||
// draw face with lighter color
|
||||
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080, true);
|
||||
gContext.mDrawList->AddConvexPolyFilled(faceCoordsScreen, 4, directionColor[normalIndex] | 0x808080);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -112,6 +112,9 @@ void EditTransform(const Camera& camera, matrix_t& matrix)
|
||||
|
||||
namespace ImGuizmo
|
||||
{
|
||||
// call inside your own window and before Manipulate() in order to draw gizmo to that window.
|
||||
IMGUI_API void SetDrawlist();
|
||||
|
||||
// call BeginFrame right after ImGui_XXXX_NewFrame();
|
||||
IMGUI_API void BeginFrame();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -17,6 +17,7 @@
|
||||
#include "OpenGLWindow/X11OpenGLWindow.h"
|
||||
#endif
|
||||
|
||||
#include <imgui_internal.h>
|
||||
#include <cstdio>
|
||||
|
||||
#define IMGUI_B3G_CONTROL (300)
|
||||
@ -122,12 +123,12 @@ void ImGui_ImplBtGui_RenderDrawLists(ImDrawData* draw_data) {
|
||||
(GLsizei)last_viewport[3]);
|
||||
}
|
||||
|
||||
static const char* ImGui_ImplBtGui_GetClipboardText() {
|
||||
static const char* ImGui_ImplBtGui_GetClipboardText(void* user_ctx) {
|
||||
// @todo
|
||||
return NULL; // glfwGetClipboardString(g_Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplBtGui_SetClipboardText(const char* text) {
|
||||
static void ImGui_ImplBtGui_SetClipboardText(void* user_ctx, const char* text) {
|
||||
// @todo
|
||||
return;
|
||||
// glfwSetClipboardString(g_Window, text);
|
||||
@ -259,7 +260,7 @@ bool ImGui_ImplBtGui_Init(b3gDefaultOpenGLWindow* window) {
|
||||
io.SetClipboardTextFn = ImGui_ImplBtGui_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplBtGui_GetClipboardText;
|
||||
#ifdef _WIN32
|
||||
//io.ImeWindowHandle = glfwGetWin32Window(g_Window);
|
||||
// io.ImeWindowHandle = glfwGetWin32Window(g_Window);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@ -277,7 +278,7 @@ bool ImGui_ImplBtGui_Init(b3gDefaultOpenGLWindow* window) {
|
||||
|
||||
void ImGui_ImplBtGui_Shutdown() {
|
||||
ImGui_ImplBtGui_InvalidateDeviceObjects();
|
||||
ImGui::Shutdown();
|
||||
ImGui::Shutdown(ImGui::GetCurrentContext());
|
||||
}
|
||||
|
||||
void ImGui_ImplBtGui_NewFrame(int mouse_x, int mouse_y) {
|
||||
|
File diff suppressed because it is too large
Load Diff
9
examples/gltfutil/CMakeLists.txt
Normal file
9
examples/gltfutil/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.6)
|
||||
project(gltfutil)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
||||
include_directories(../../)
|
||||
|
||||
file(GLOB gltfutil_sources *.cc *.h)
|
||||
add_executable(gltfutil ${gltfutil_sources})
|
60
examples/gltfutil/gltfuilconfig.h
Normal file
60
examples/gltfutil/gltfuilconfig.h
Normal file
@ -0,0 +1,60 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "texture_dumper.h"
|
||||
|
||||
namespace gltfutil {
|
||||
|
||||
enum class ui_mode { cli, interactive };
|
||||
enum class cli_action { not_set, help, dump };
|
||||
enum class FileType { Ascii, Binary, Unknown };
|
||||
|
||||
/// Probe inside the file, or check the extension to determine if we have to
|
||||
/// load a text file, or a binary file
|
||||
FileType detectType(const std::string& path) {
|
||||
// Quickly open the file as binary and chekc if there's the gltf binary magic
|
||||
// number
|
||||
{
|
||||
auto probe = std::ifstream(path, std::ios_base::binary);
|
||||
if (!probe) throw std::runtime_error("Could not open " + path);
|
||||
|
||||
std::array<char, 5> buffer;
|
||||
for (size_t i{0}; i < 4; ++i) probe >> buffer[i];
|
||||
buffer[4] = 0;
|
||||
|
||||
if (std::string("glTF") == std::string(buffer.data())) {
|
||||
std::cout
|
||||
<< "Detected binary file thanks to the magic number at the start!\n";
|
||||
return FileType::Binary;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have any better, check the file extension.
|
||||
auto extension = path.substr(path.find_last_of('.') + 1);
|
||||
std::transform(std::begin(extension), std::end(extension),
|
||||
std::begin(extension),
|
||||
[](char c) { return char(::tolower(int(c))); });
|
||||
if (extension == "gltf") return FileType::Ascii;
|
||||
if (extension == "glb") return FileType::Binary;
|
||||
|
||||
return FileType::Unknown;
|
||||
}
|
||||
|
||||
struct configuration {
|
||||
std::string input_path, output_dir;
|
||||
ui_mode mode;
|
||||
cli_action action = cli_action::not_set;
|
||||
texture_dumper::texture_output_format requested_format =
|
||||
texture_dumper::texture_output_format::not_specified;
|
||||
|
||||
bool has_output_dir;
|
||||
bool is_valid() {
|
||||
// TODO impl check
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gltfutil
|
123
examples/gltfutil/main.cc
Normal file
123
examples/gltfutil/main.cc
Normal file
@ -0,0 +1,123 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gltfuilconfig.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
namespace gltfutil {
|
||||
int usage(int ret = 0) {
|
||||
using std::cout;
|
||||
cout << "gltfutil: tool for manipulating gltf files\n"
|
||||
<< " usage information:\n\n"
|
||||
<< "\t gltfutil (-d|-h|) (-f [png|bmp|tga]) [path to .gltf/glb] (-o "
|
||||
"[path to output directory])\n\n"
|
||||
//<< "\t\t -i: start in interactive mode\n"
|
||||
<< "\t\t -d: dump enclosed content (image assets)\n"
|
||||
<< "\t\t -f: file format for image output"
|
||||
<< "\t\t -o: ouptput directory path"
|
||||
<< "\t\t -h: print this help\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
int arg_error() {
|
||||
(void)usage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int parse_args(int argc, char** argv) {
|
||||
gltfutil::configuration config;
|
||||
|
||||
for (size_t i = 1; i < size_t(argc); ++i) {
|
||||
char* arg = argv[i];
|
||||
if (arg[0] == '-') switch (arg[1]) {
|
||||
case 'h':
|
||||
return usage(0);
|
||||
break;
|
||||
case 'd':
|
||||
config.mode = ui_mode::cli;
|
||||
config.action = cli_action::dump;
|
||||
break;
|
||||
case 'i':
|
||||
config.mode = ui_mode::interactive;
|
||||
break;
|
||||
case 'o':
|
||||
i++;
|
||||
config.output_dir = argv[i];
|
||||
break;
|
||||
case 'f':
|
||||
i++;
|
||||
config.requested_format =
|
||||
texture_dumper::get_fromat_from_string(argv[i]);
|
||||
break;
|
||||
default:
|
||||
return arg_error();
|
||||
}
|
||||
else {
|
||||
// set the input path
|
||||
config.input_path = argv[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (config.is_valid()) {
|
||||
tinygltf::TinyGLTF loader;
|
||||
tinygltf::Model model;
|
||||
std::string error;
|
||||
bool state;
|
||||
switch (detectType(config.input_path)) {
|
||||
case FileType::Ascii:
|
||||
state = loader.LoadASCIIFromFile(&model, &error, config.input_path);
|
||||
break;
|
||||
case FileType::Binary:
|
||||
state = loader.LoadBinaryFromFile(&model, &error, config.input_path);
|
||||
break;
|
||||
case FileType::Unknown:
|
||||
default:
|
||||
return arg_error();
|
||||
break;
|
||||
}
|
||||
|
||||
std::cerr << "state is " << state << '\n';
|
||||
|
||||
if (config.mode == ui_mode::interactive) {
|
||||
// interactive usage now;
|
||||
// TODO impl
|
||||
} else {
|
||||
switch (config.action) {
|
||||
case cli_action::help:
|
||||
return usage();
|
||||
break;
|
||||
|
||||
case cli_action::dump: {
|
||||
texture_dumper dumper(model);
|
||||
if (config.requested_format !=
|
||||
texture_dumper::texture_output_format::not_specified)
|
||||
dumper.set_output_format(config.requested_format);
|
||||
|
||||
if (config.output_dir.empty())
|
||||
dumper.dump_to_folder();
|
||||
else
|
||||
dumper.dump_to_folder(config.output_dir);
|
||||
|
||||
} break;
|
||||
default:
|
||||
return arg_error();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return arg_error();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace gltfutil
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 1) return gltfutil::usage();
|
||||
if (argc > 1) return gltfutil::parse_args(argc, argv);
|
||||
}
|
1830
examples/gltfutil/stb_image_write.h
Normal file
1830
examples/gltfutil/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
67
examples/gltfutil/texture_dumper.cc
Normal file
67
examples/gltfutil/texture_dumper.cc
Normal file
@ -0,0 +1,67 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "stb_image_write.h"
|
||||
#include "texture_dumper.h"
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
using namespace gltfutil;
|
||||
using namespace tinygltf;
|
||||
using std::cout;
|
||||
|
||||
texture_dumper::texture_dumper(const Model& input)
|
||||
: model(input), configured_format(texture_output_format::png) {
|
||||
cout << "Texture dumper\n";
|
||||
}
|
||||
|
||||
void texture_dumper::dump_to_folder(const std::string& path) {
|
||||
cout << "dumping to folder " << path << '\n';
|
||||
cout << "model file has " << model.textures.size() << " textures.\n";
|
||||
size_t index = 0;
|
||||
|
||||
for (const auto& texture : model.textures) {
|
||||
index++;
|
||||
const auto& image = model.images[texture.source];
|
||||
cout << "image name is: \"" << image.name << "\"\n";
|
||||
cout << "image size is: " << image.width << 'x' << image.height << '\n';
|
||||
cout << "pixel channel count :" << image.component << '\n';
|
||||
std::string name = image.name.empty() ? std::to_string(index) : image.name;
|
||||
|
||||
switch (configured_format) {
|
||||
case texture_output_format::png:
|
||||
name = path + "/" + name + ".png";
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
stbi_write_png(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data(), 0);
|
||||
break;
|
||||
case texture_output_format::bmp:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".bmp";
|
||||
stbi_write_bmp(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
break;
|
||||
case texture_output_format::tga:
|
||||
std::cout << "Image will be written to " << name << '\n';
|
||||
name = path + "/" + name + ".tga";
|
||||
stbi_write_tga(name.c_str(), image.width, image.height, image.component,
|
||||
image.image.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void texture_dumper::set_output_format(texture_output_format format) {
|
||||
configured_format = format;
|
||||
}
|
||||
|
||||
texture_dumper::texture_output_format texture_dumper::get_fromat_from_string(
|
||||
const std::string& str) {
|
||||
std::string type = str;
|
||||
std::transform(str.begin(), str.end(), type.begin(), ::tolower);
|
||||
|
||||
if (type == "png") return texture_output_format::png;
|
||||
if (type == "bmp") return texture_output_format::bmp;
|
||||
if (type == "tga") return texture_output_format::tga;
|
||||
|
||||
return texture_output_format::not_specified;
|
||||
}
|
23
examples/gltfutil/texture_dumper.h
Normal file
23
examples/gltfutil/texture_dumper.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
namespace gltfutil {
|
||||
class texture_dumper {
|
||||
public:
|
||||
enum class texture_output_format { png, bmp, tga, not_specified };
|
||||
|
||||
private:
|
||||
const tinygltf::Model& model;
|
||||
texture_output_format configured_format;
|
||||
|
||||
public:
|
||||
texture_dumper(const tinygltf::Model& inputModel);
|
||||
void dump_to_folder(const std::string& path = "./");
|
||||
void set_output_format(texture_output_format format);
|
||||
|
||||
static texture_output_format get_fromat_from_string(const std::string& str);
|
||||
};
|
||||
} // namespace gltfutil
|
@ -2,7 +2,7 @@ Simple OpenGL viewer for glTF geometry.
|
||||
|
||||
## Requirements
|
||||
|
||||
* premake4 : Requires recent `premake4` for macosx and linux, `premake5` for windows.
|
||||
* premake5 : Requires recent `premake5`(alpha12 or later) for macosx and linux. `premake5` for windows is included in `$tinygltf/tools/window` directory.
|
||||
* GLEW
|
||||
* Ubuntu 16.04: sudo apt install libglew-dev
|
||||
* glfw3
|
||||
@ -19,7 +19,7 @@ Simple OpenGL viewer for glTF geometry.
|
||||
|
||||
### Windows(not tested well)
|
||||
|
||||
Edit glew and glfw path in `premake4.lua`, then
|
||||
Edit glew and glfw path in `premake5.lua`, then
|
||||
|
||||
> premake5.exe vs2013
|
||||
|
||||
|
@ -7,10 +7,10 @@ solution "glview"
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
cppdialect "C++11"
|
||||
files { "glview.cc", "trackball.cc" }
|
||||
includedirs { "./" }
|
||||
includedirs { "../../" }
|
||||
flags "c++11"
|
||||
|
||||
configuration { "linux" }
|
||||
linkoptions { "`pkg-config --libs glfw3`" }
|
||||
@ -34,9 +34,10 @@ solution "glview"
|
||||
|
||||
configuration "Debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols", "ExtraWarnings"}
|
||||
symbols "On"
|
||||
warnings "Extra"
|
||||
|
||||
configuration "Release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize", "ExtraWarnings"}
|
||||
|
||||
optimize "On"
|
||||
warnings "Extra"
|
@ -1,31 +1,128 @@
|
||||
# Raytrace example
|
||||
# NanoSG
|
||||
|
||||
Simple raytracing example with OpenGL preview
|
||||
Simple, minimal and header-only scene graph library for NanoRT.
|
||||
|
||||
## Status
|
||||
NanoSG itself shoud be compiled with C++-03 compiler, but demo code uses C++11 features.
|
||||
|
||||
Not working yet. Still in work in progress.
|
||||

|
||||
|
||||

|
||||
|
||||
## Build
|
||||
|
||||
### Linux or macOS
|
||||
|
||||
```
|
||||
$ premake5 gmake
|
||||
$ make
|
||||
```bash
|
||||
premake5 gmake
|
||||
make
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
$ premake5 vs2015
|
||||
```bash
|
||||
premake5 vs2015
|
||||
```
|
||||
|
||||
## Data structure
|
||||
|
||||
## Third party libraries and its icenses.
|
||||
### Node
|
||||
|
||||
Node represents scene graph node. Tansformation node or Mesh(shape) node.
|
||||
Node is interpreted as transformation node when passing `nullptr` to Node class constructure.
|
||||
|
||||
Node can contain multiple children.
|
||||
|
||||
### Scene
|
||||
|
||||
Scene contains root nodes and provides the method to find an intersection of nodes.
|
||||
|
||||
## User defined data structure
|
||||
|
||||
Following are required in user application.
|
||||
|
||||
### Mesh class
|
||||
|
||||
Current example code assumes mesh is all composed of triangle meshes.
|
||||
|
||||
Following method must be implemented for `Scene::Traversal`.
|
||||
|
||||
```cpp
|
||||
///
|
||||
/// Get the geometric normal and the shading normal at `face_idx' th face.
|
||||
///
|
||||
template<typename T>
|
||||
void GetNormal(T Ng[3], T Ns[3], const unsigned int face_idx, const T u, const T v) const;
|
||||
```
|
||||
|
||||
### Intersection class
|
||||
|
||||
Represents intersection(hit) information.
|
||||
|
||||
### Transform
|
||||
|
||||
Transformation is done in the following procedure.
|
||||
|
||||
`M' = parent_xform x local_xform x local_pivot`
|
||||
|
||||
## Memory management
|
||||
|
||||
`Scene` and `Node` does not create a copy of asset data(e.g. vertices, indices). Thus user must care about memory management of scene assets in user side.
|
||||
|
||||
## API
|
||||
|
||||
API is still subject to change.
|
||||
|
||||
### Node
|
||||
|
||||
```cpp
|
||||
void Node::SetName(const std::string &name);
|
||||
```
|
||||
|
||||
Set (unique) name for the node.
|
||||
|
||||
```cpp
|
||||
void Node::AddChild(const type &child);
|
||||
```
|
||||
|
||||
Add node as child node.
|
||||
|
||||
```cpp
|
||||
void Node::SetLocalXform(const T xform[4][4]) {
|
||||
```
|
||||
|
||||
Set local transformation matrix. Default is identity matrix.
|
||||
|
||||
### Scene
|
||||
|
||||
```cpp
|
||||
bool Scene::AddNode(const Node<T, M> &node);
|
||||
```
|
||||
|
||||
Add a node to the scene.
|
||||
|
||||
```cpp
|
||||
bool Scene::Commit() {
|
||||
```
|
||||
|
||||
Commit the scene. After adding nodes to the scene or changed transformation matrix, call this `Commit` before tracing rays.
|
||||
`Commit` triggers BVH build in each nodes and updates node's transformation matrix.
|
||||
|
||||
```cpp
|
||||
template<class H>
|
||||
bool Scene::Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const;
|
||||
```
|
||||
|
||||
Trace ray into the scene and find an intersection.
|
||||
Returns `true` when there is an intersection and hit information is stored in `isect`.
|
||||
|
||||
## TODO
|
||||
|
||||
* [ ] Compute pivot point of each node(mesh).
|
||||
|
||||
## Third party libraries and its icenses
|
||||
|
||||
* picojson : BSD license.
|
||||
* bt3gui : zlib license.
|
||||
* bt3gui : zlib license.
|
||||
* glew : BSD/MIT license.
|
||||
* tinyobjloader : MIT license.
|
||||
* glm : The Happy Bunny License (Modified MIT License). Copyright (c) 2005 - 2017 G-Truc Creation
|
||||
|
@ -1,9 +1,23 @@
|
||||
{ "gltf_filename" : "../../models/Cube/Cube.gltf",
|
||||
"scene_scale" : 1.0,
|
||||
"width" : 512,
|
||||
"height" : 512,
|
||||
"eye" : [0, 2.5, 15],
|
||||
"up" : [0, 1, 0],
|
||||
"look_at" : [0, 0, 0],
|
||||
"dummy" : 0
|
||||
{
|
||||
"commented_out_obj_filename": "cornellbox_suzanne.obj",
|
||||
"gltf_filename": "../../models/Cube/Cube.gltf",
|
||||
"scene_scale": 1.0,
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"eye": [
|
||||
0,
|
||||
2.5,
|
||||
15
|
||||
],
|
||||
"up": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
],
|
||||
"look_at": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"dummy": 0
|
||||
}
|
||||
|
1529
examples/raytrace/cornellbox_suzanne.obj
Normal file
1529
examples/raytrace/cornellbox_suzanne.obj
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,11 @@
|
||||
#include "gltf-loader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <memory> // c++11
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
namespace example {
|
||||
|
||||
static std::string GetFilePathExtension(const std::string &FileName) {
|
||||
if (FileName.find_last_of(".") != std::string::npos)
|
||||
return FileName.substr(FileName.find_last_of(".") + 1);
|
||||
@ -17,17 +15,17 @@ static std::string GetFilePathExtension(const std::string &FileName) {
|
||||
///
|
||||
/// Loads glTF 2.0 mesh
|
||||
///
|
||||
bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures)
|
||||
{
|
||||
|
||||
// TODO(syoyo): Implement
|
||||
bool LoadGLTF(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *materials,
|
||||
std::vector<Texture> *textures) {
|
||||
// TODO(syoyo): Texture
|
||||
// TODO(syoyo): Material
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string ext = GetFilePathExtension(filename);
|
||||
const std::string ext = GetFilePathExtension(filename);
|
||||
|
||||
bool ret = false;
|
||||
if (ext.compare("glb") == 0) {
|
||||
@ -46,8 +44,448 @@ bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float>
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cerr << "LoadGLTF() function is not yet implemented!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::cout << "loaded glTF file has:\n"
|
||||
<< model.accessors.size() << " accessors\n"
|
||||
<< model.animations.size() << " animations\n"
|
||||
<< model.buffers.size() << " buffers\n"
|
||||
<< model.bufferViews.size() << " bufferViews\n"
|
||||
<< model.materials.size() << " materials\n"
|
||||
<< model.meshes.size() << " meshes\n"
|
||||
<< model.nodes.size() << " nodes\n"
|
||||
<< model.textures.size() << " textures\n"
|
||||
<< model.images.size() << " images\n"
|
||||
<< model.skins.size() << " skins\n"
|
||||
<< model.samplers.size() << " samplers\n"
|
||||
<< model.cameras.size() << " cameras\n"
|
||||
<< model.scenes.size() << " scenes\n"
|
||||
<< model.lights.size() << " lights\n";
|
||||
|
||||
} // namespace example
|
||||
// Iterate through all the meshes in the glTF file
|
||||
for (const auto &gltfMesh : model.meshes) {
|
||||
std::cout << "Current mesh has " << gltfMesh.primitives.size()
|
||||
<< " primitives:\n";
|
||||
|
||||
// Create a mesh object
|
||||
Mesh<float> loadedMesh(sizeof(float) * 3);
|
||||
|
||||
// To store the min and max of the buffer (as 3D vector of floats)
|
||||
v3f pMin = {}, pMax = {};
|
||||
|
||||
// Store the name of the glTF mesh (if defined)
|
||||
loadedMesh.name = gltfMesh.name;
|
||||
|
||||
// For each primitive
|
||||
for (const auto &meshPrimitive : gltfMesh.primitives) {
|
||||
// Boolean used to check if we have converted the vertex buffer format
|
||||
bool convertedToTriangleList = false;
|
||||
// This permit to get a type agnostic way of reading the index buffer
|
||||
std::unique_ptr<intArrayBase> indicesArrayPtr = nullptr;
|
||||
{
|
||||
const auto &indicesAccessor = model.accessors[meshPrimitive.indices];
|
||||
const auto &bufferView = model.bufferViews[indicesAccessor.bufferView];
|
||||
const auto &buffer = model.buffers[bufferView.buffer];
|
||||
const auto dataAddress = buffer.data.data() + bufferView.byteOffset +
|
||||
indicesAccessor.byteOffset;
|
||||
const auto byteStride = indicesAccessor.ByteStride(bufferView);
|
||||
const auto count = indicesAccessor.count;
|
||||
|
||||
// Allocate the index array in the pointer-to-base declared in the
|
||||
// parent scope
|
||||
switch (indicesAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
indicesArrayPtr =
|
||||
std::unique_ptr<intArray<char> >(new intArray<char>(
|
||||
arrayAdapter<char>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned char> >(
|
||||
new intArray<unsigned char>(arrayAdapter<unsigned char>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
indicesArrayPtr =
|
||||
std::unique_ptr<intArray<short> >(new intArray<short>(
|
||||
arrayAdapter<short>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned short> >(
|
||||
new intArray<unsigned short>(arrayAdapter<unsigned short>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<int> >(new intArray<int>(
|
||||
arrayAdapter<int>(dataAddress, count, byteStride)));
|
||||
break;
|
||||
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
indicesArrayPtr = std::unique_ptr<intArray<unsigned int> >(
|
||||
new intArray<unsigned int>(arrayAdapter<unsigned int>(
|
||||
dataAddress, count, byteStride)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto &indices = *indicesArrayPtr;
|
||||
|
||||
if (indicesArrayPtr) {
|
||||
std::cout << "indices: ";
|
||||
for (size_t i(0); i < indicesArrayPtr->size(); ++i) {
|
||||
std::cout << indices[i] << " ";
|
||||
loadedMesh.faces.push_back(indices[i]);
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
switch (meshPrimitive.mode) {
|
||||
// We re-arrange the indices so that it describe a simple list of
|
||||
// triangles
|
||||
case TINYGLTF_MODE_TRIANGLE_FAN:
|
||||
if (!convertedToTriangleList) {
|
||||
std::cout << "TRIANGLE_FAN\n";
|
||||
// This only has to be done once per primitive
|
||||
convertedToTriangleList = true;
|
||||
|
||||
// We steal the guts of the vector
|
||||
auto triangleFan = std::move(loadedMesh.faces);
|
||||
loadedMesh.faces.clear();
|
||||
|
||||
// Push back the indices that describe just one triangle one by one
|
||||
for (size_t i{2}; i < triangleFan.size(); ++i) {
|
||||
loadedMesh.faces.push_back(triangleFan[0]);
|
||||
loadedMesh.faces.push_back(triangleFan[i - 1]);
|
||||
loadedMesh.faces.push_back(triangleFan[i]);
|
||||
}
|
||||
}
|
||||
case TINYGLTF_MODE_TRIANGLE_STRIP:
|
||||
if (!convertedToTriangleList) {
|
||||
std::cout << "TRIANGLE_STRIP\n";
|
||||
// This only has to be done once per primitive
|
||||
convertedToTriangleList = true;
|
||||
|
||||
auto triangleStrip = std::move(loadedMesh.faces);
|
||||
loadedMesh.faces.clear();
|
||||
|
||||
for (size_t i{2}; i < triangleStrip.size(); ++i) {
|
||||
loadedMesh.faces.push_back(triangleStrip[i - 2]);
|
||||
loadedMesh.faces.push_back(triangleStrip[i - 1]);
|
||||
loadedMesh.faces.push_back(triangleStrip[i]);
|
||||
}
|
||||
}
|
||||
case TINYGLTF_MODE_TRIANGLES: // this is the simpliest case to handle
|
||||
|
||||
{
|
||||
std::cout << "TRIANGLES\n";
|
||||
|
||||
for (const auto &attribute : meshPrimitive.attributes) {
|
||||
const auto attribAccessor = model.accessors[attribute.second];
|
||||
const auto &bufferView =
|
||||
model.bufferViews[attribAccessor.bufferView];
|
||||
const auto &buffer = model.buffers[bufferView.buffer];
|
||||
const auto dataPtr = buffer.data.data() + bufferView.byteOffset +
|
||||
attribAccessor.byteOffset;
|
||||
const auto byte_stride = attribAccessor.ByteStride(bufferView);
|
||||
const auto count = attribAccessor.count;
|
||||
|
||||
std::cout << "current attribute has count " << count
|
||||
<< " and stride " << byte_stride << " bytes\n";
|
||||
|
||||
std::cout << "attribute string is : " << attribute.first << '\n';
|
||||
if (attribute.first == "POSITION") {
|
||||
std::cout << "found position attribute\n";
|
||||
|
||||
// get the position min/max for computing the boundingbox
|
||||
pMin.x = attribAccessor.minValues[0];
|
||||
pMin.y = attribAccessor.minValues[1];
|
||||
pMin.z = attribAccessor.minValues[2];
|
||||
pMax.x = attribAccessor.maxValues[0];
|
||||
pMax.y = attribAccessor.maxValues[1];
|
||||
pMax.z = attribAccessor.maxValues[2];
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
std::cout << "Type is FLOAT\n";
|
||||
// 3D vector of float
|
||||
v3fArray positions(
|
||||
arrayAdapter<v3f>(dataPtr, count, byte_stride));
|
||||
|
||||
std::cout << "positions's size : " << positions.size()
|
||||
<< '\n';
|
||||
|
||||
for (size_t i{0}; i < positions.size(); ++i) {
|
||||
const auto v = positions[i];
|
||||
std::cout << "positions[" << i << "]: (" << v.x << ", "
|
||||
<< v.y << ", " << v.z << ")\n";
|
||||
|
||||
loadedMesh.vertices.push_back(v.x * scale);
|
||||
loadedMesh.vertices.push_back(v.y * scale);
|
||||
loadedMesh.vertices.push_back(v.z * scale);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "Type is DOUBLE\n";
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
v3dArray positions(
|
||||
arrayAdapter<v3d>(dataPtr, count, byte_stride));
|
||||
for (size_t i{0}; i < positions.size(); ++i) {
|
||||
const auto v = positions[i];
|
||||
std::cout << "positions[" << i << "]: (" << v.x
|
||||
<< ", " << v.y << ", " << v.z << ")\n";
|
||||
|
||||
loadedMesh.vertices.push_back(v.x * scale);
|
||||
loadedMesh.vertices.push_back(v.y * scale);
|
||||
loadedMesh.vertices.push_back(v.z * scale);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
// TODO Handle error
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
if (attribute.first == "NORMAL") {
|
||||
std::cout << "found normal attribute\n";
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC3: {
|
||||
std::cout << "Normal is VEC3\n";
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT: {
|
||||
std::cout << "Normal is FLOAT\n";
|
||||
v3fArray normals(
|
||||
arrayAdapter<v3f>(dataPtr, count, byte_stride));
|
||||
|
||||
// IMPORTANT: We need to reorder normals (and texture
|
||||
// coordinates into "facevarying" order) for each face
|
||||
|
||||
// For each triangle :
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the 3 normal vectors for that face
|
||||
v3f n0, n1, n2;
|
||||
n0 = normals[f0];
|
||||
n1 = normals[f1];
|
||||
n2 = normals[f2];
|
||||
|
||||
// Put them in the array in the correct order
|
||||
loadedMesh.facevarying_normals.push_back(n0.x);
|
||||
loadedMesh.facevarying_normals.push_back(n0.y);
|
||||
loadedMesh.facevarying_normals.push_back(n0.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n1.x);
|
||||
loadedMesh.facevarying_normals.push_back(n1.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n2.x);
|
||||
loadedMesh.facevarying_normals.push_back(n2.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
}
|
||||
} break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "Normal is DOUBLE\n";
|
||||
v3dArray normals(
|
||||
arrayAdapter<v3d>(dataPtr, count, byte_stride));
|
||||
|
||||
// IMPORTANT: We need to reorder normals (and texture
|
||||
// coordinates into "facevarying" order) for each face
|
||||
|
||||
// For each triangle :
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the 3 normal vectors for that face
|
||||
v3d n0, n1, n2;
|
||||
n0 = normals[f0];
|
||||
n1 = normals[f1];
|
||||
n2 = normals[f2];
|
||||
|
||||
// Put them in the array in the correct order
|
||||
loadedMesh.facevarying_normals.push_back(n0.x);
|
||||
loadedMesh.facevarying_normals.push_back(n0.y);
|
||||
loadedMesh.facevarying_normals.push_back(n0.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n1.x);
|
||||
loadedMesh.facevarying_normals.push_back(n1.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
|
||||
loadedMesh.facevarying_normals.push_back(n2.x);
|
||||
loadedMesh.facevarying_normals.push_back(n2.y);
|
||||
loadedMesh.facevarying_normals.push_back(n2.z);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "Unhandeled componant type for normal\n";
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "Unhandeled vector type for normal\n";
|
||||
}
|
||||
|
||||
// Face varying comment on the normals is also true for the UVs
|
||||
if (attribute.first == "TEXCOORD_0") {
|
||||
std::cout << "Found texture coordinates\n";
|
||||
|
||||
switch (attribAccessor.type) {
|
||||
case TINYGLTF_TYPE_VEC2: {
|
||||
std::cout << "TEXTCOORD is VEC2\n";
|
||||
switch (attribAccessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT: {
|
||||
std::cout << "TEXTCOORD is FLOAT\n";
|
||||
v2fArray uvs(
|
||||
arrayAdapter<v2f>(dataPtr, count, byte_stride));
|
||||
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
// get the texture coordinates for each triangle's
|
||||
// vertices
|
||||
v2f uv0, uv1, uv2;
|
||||
uv0 = uvs[f0];
|
||||
uv1 = uvs[f1];
|
||||
uv2 = uvs[f2];
|
||||
|
||||
// push them in order into the mesh data
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.y);
|
||||
}
|
||||
|
||||
} break;
|
||||
case TINYGLTF_COMPONENT_TYPE_DOUBLE: {
|
||||
std::cout << "TEXTCOORD is DOUBLE\n";
|
||||
v2dArray uvs(
|
||||
arrayAdapter<v2d>(dataPtr, count, byte_stride));
|
||||
|
||||
for (size_t i{0}; i < indices.size() / 3; ++i) {
|
||||
// get the i'th triange's indexes
|
||||
auto f0 = indices[3 * i + 0];
|
||||
auto f1 = indices[3 * i + 1];
|
||||
auto f2 = indices[3 * i + 2];
|
||||
|
||||
v2d uv0, uv1, uv2;
|
||||
uv0 = uvs[f0];
|
||||
uv1 = uvs[f1];
|
||||
uv2 = uvs[f2];
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv0.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv1.y);
|
||||
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.x);
|
||||
loadedMesh.facevarying_uvs.push_back(uv2.y);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "unrecognized vector type for UV";
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
std::cerr << "unreconized componant type for UV";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "primitive mode not implemented";
|
||||
break;
|
||||
|
||||
// These aren't triangles:
|
||||
case TINYGLTF_MODE_POINTS:
|
||||
case TINYGLTF_MODE_LINE:
|
||||
case TINYGLTF_MODE_LINE_LOOP:
|
||||
std::cerr << "primitive is not triangle based, ignoring";
|
||||
}
|
||||
}
|
||||
|
||||
// bbox :
|
||||
v3f bCenter;
|
||||
bCenter.x = 0.5f * (pMax.x - pMin.x) + pMin.x;
|
||||
bCenter.y = 0.5f * (pMax.y - pMin.y) + pMin.y;
|
||||
bCenter.z = 0.5f * (pMax.z - pMin.z) + pMin.z;
|
||||
|
||||
for (size_t v = 0; v < loadedMesh.vertices.size() / 3; v++) {
|
||||
loadedMesh.vertices[3 * v + 0] -= bCenter.x;
|
||||
loadedMesh.vertices[3 * v + 1] -= bCenter.y;
|
||||
loadedMesh.vertices[3 * v + 2] -= bCenter.z;
|
||||
}
|
||||
|
||||
loadedMesh.pivot_xform[0][0] = 1.0f;
|
||||
loadedMesh.pivot_xform[0][1] = 0.0f;
|
||||
loadedMesh.pivot_xform[0][2] = 0.0f;
|
||||
loadedMesh.pivot_xform[0][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[1][0] = 0.0f;
|
||||
loadedMesh.pivot_xform[1][1] = 1.0f;
|
||||
loadedMesh.pivot_xform[1][2] = 0.0f;
|
||||
loadedMesh.pivot_xform[1][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[2][0] = 0.0f;
|
||||
loadedMesh.pivot_xform[2][1] = 0.0f;
|
||||
loadedMesh.pivot_xform[2][2] = 1.0f;
|
||||
loadedMesh.pivot_xform[2][3] = 0.0f;
|
||||
|
||||
loadedMesh.pivot_xform[3][0] = bCenter.x;
|
||||
loadedMesh.pivot_xform[3][1] = bCenter.y;
|
||||
loadedMesh.pivot_xform[3][2] = bCenter.z;
|
||||
loadedMesh.pivot_xform[3][3] = 1.0f;
|
||||
|
||||
// TODO handle materials
|
||||
for (size_t i{0}; i < loadedMesh.faces.size(); ++i)
|
||||
loadedMesh.material_ids.push_back(materials->at(0).id);
|
||||
|
||||
meshes->push_back(loadedMesh);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through all texture declaration in glTF file
|
||||
for (const auto &gltfTexture : model.textures) {
|
||||
std::cout << "Found texture!";
|
||||
Texture loadedTexture;
|
||||
const auto &image = model.images[gltfTexture.source];
|
||||
loadedTexture.components = image.component;
|
||||
loadedTexture.width = image.width;
|
||||
loadedTexture.height = image.height;
|
||||
|
||||
const auto size =
|
||||
image.component * image.width * image.height * sizeof(unsigned char);
|
||||
loadedTexture.image = new unsigned char[size];
|
||||
memcpy(loadedTexture.image, image.image.data(), size);
|
||||
textures->push_back(loadedTexture);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace example
|
||||
|
@ -1,19 +1,166 @@
|
||||
#ifndef EXAMPLE_GLTF_LOADER_H_
|
||||
#define EXAMPLE_GLTF_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "material.h"
|
||||
#include "mesh.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
/// Adapts an array of bytes to an array of T. Will advace of byte_stride each
|
||||
/// elements.
|
||||
template <typename T>
|
||||
struct arrayAdapter {
|
||||
/// Pointer to the bytes
|
||||
const unsigned char *dataPtr;
|
||||
/// Number of elements in the array
|
||||
const size_t elemCount;
|
||||
/// Stride in bytes between two elements
|
||||
const size_t stride;
|
||||
|
||||
/// Construct an array adapter.
|
||||
/// \param ptr Pointer to the start of the data, with offset applied
|
||||
/// \param count Number of elements in the array
|
||||
/// \param byte_stride Stride betweens elements in the array
|
||||
arrayAdapter(const unsigned char *ptr, size_t count, size_t byte_stride)
|
||||
: dataPtr(ptr), elemCount(count), stride(byte_stride) {}
|
||||
|
||||
/// Returns a *copy* of a single element. Can't be used to modify it.
|
||||
T operator[](size_t pos) const {
|
||||
if (pos >= elemCount)
|
||||
throw std::out_of_range(
|
||||
"Tried to access beyond the last element of an array adapter with "
|
||||
"count " +
|
||||
std::to_string(elemCount) + " while getting elemnet number " +
|
||||
std::to_string(pos));
|
||||
return *(reinterpret_cast<const T *>(dataPtr + pos * stride));
|
||||
}
|
||||
};
|
||||
|
||||
/// Interface of any adapted array that returns ingeger data
|
||||
struct intArrayBase {
|
||||
virtual ~intArrayBase() = default;
|
||||
virtual unsigned int operator[](size_t) const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
};
|
||||
|
||||
/// Interface of any adapted array that returns float data
|
||||
struct floatArrayBase {
|
||||
virtual ~floatArrayBase() = default;
|
||||
virtual float operator[](size_t) const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
};
|
||||
|
||||
/// An array that loads interger types, returns them as int
|
||||
template <class T>
|
||||
struct intArray : public intArrayBase {
|
||||
arrayAdapter<T> adapter;
|
||||
|
||||
intArray(const arrayAdapter<T> &a) : adapter(a) {}
|
||||
unsigned int operator[](size_t position) const override {
|
||||
return static_cast<unsigned int>(adapter[position]);
|
||||
}
|
||||
|
||||
size_t size() const override { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct floatArray : public floatArrayBase {
|
||||
arrayAdapter<T> adapter;
|
||||
|
||||
floatArray(const arrayAdapter<T> &a) : adapter(a) {}
|
||||
float operator[](size_t position) const override {
|
||||
return static_cast<float>(adapter[position]);
|
||||
}
|
||||
|
||||
size_t size() const override { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
template <typename T>
|
||||
struct v2 {
|
||||
T x, y;
|
||||
};
|
||||
/// 3D vector of floats without padding
|
||||
template <typename T>
|
||||
struct v3 {
|
||||
T x, y, z;
|
||||
};
|
||||
|
||||
/// 4D vector of floats without padding
|
||||
template <typename T>
|
||||
struct v4 {
|
||||
T x, y, z, w;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
using v2f = v2<float>;
|
||||
using v3f = v3<float>;
|
||||
using v4f = v4<float>;
|
||||
using v2d = v2<double>;
|
||||
using v3d = v3<double>;
|
||||
using v4d = v4<double>;
|
||||
|
||||
struct v2fArray {
|
||||
arrayAdapter<v2f> adapter;
|
||||
v2fArray(const arrayAdapter<v2f> &a) : adapter(a) {}
|
||||
|
||||
v2f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v3fArray {
|
||||
arrayAdapter<v3f> adapter;
|
||||
v3fArray(const arrayAdapter<v3f> &a) : adapter(a) {}
|
||||
|
||||
v3f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v4fArray {
|
||||
arrayAdapter<v4f> adapter;
|
||||
v4fArray(const arrayAdapter<v4f> &a) : adapter(a) {}
|
||||
|
||||
v4f operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v2dArray {
|
||||
arrayAdapter<v2d> adapter;
|
||||
v2dArray(const arrayAdapter<v2d> &a) : adapter(a) {}
|
||||
|
||||
v2d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v3dArray {
|
||||
arrayAdapter<v3d> adapter;
|
||||
v3dArray(const arrayAdapter<v3d> &a) : adapter(a) {}
|
||||
|
||||
v3d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
struct v4dArray {
|
||||
arrayAdapter<v4d> adapter;
|
||||
v4dArray(const arrayAdapter<v4d> &a) : adapter(a) {}
|
||||
|
||||
v4d operator[](size_t position) const { return adapter[position]; }
|
||||
size_t size() const { return adapter.elemCount; }
|
||||
};
|
||||
|
||||
///
|
||||
/// Loads glTF 2.0 mesh
|
||||
///
|
||||
bool LoadGLTF(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
bool LoadGLTF(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
|
||||
}
|
||||
} // namespace example
|
||||
|
||||
#endif // EXAMPLE_GLTF_LOADER_H_
|
||||
#endif // EXAMPLE_GLTF_LOADER_H_
|
||||
|
BIN
examples/raytrace/images/nanosg-demo.png
Normal file
BIN
examples/raytrace/images/nanosg-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
@ -53,12 +53,13 @@ THE SOFTWARE.
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include <atomic> // C++11
|
||||
#include <chrono> // C++11
|
||||
@ -72,22 +73,23 @@ THE SOFTWARE.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
#include "glm/mat4x4.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
#include "glm/gtc/quaternion.hpp"
|
||||
#include "glm/gtc/type_ptr.hpp"
|
||||
#include "glm/mat4x4.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "gltf-loader.h"
|
||||
#include "nanosg.h"
|
||||
#include "obj-loader.h"
|
||||
#include "render-config.h"
|
||||
#include "render.h"
|
||||
#include "gltf-loader.h"
|
||||
#include "trackball.h"
|
||||
|
||||
#ifdef WIN32
|
||||
@ -96,19 +98,17 @@ THE SOFTWARE.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SHOW_BUFFER_COLOR (0)
|
||||
#define SHOW_BUFFER_NORMAL (1)
|
||||
#define SHOW_BUFFER_POSITION (2)
|
||||
#define SHOW_BUFFER_DEPTH (3)
|
||||
#define SHOW_BUFFER_TEXCOORD (4)
|
||||
#define SHOW_BUFFER_VARYCOORD (5)
|
||||
|
||||
b3gDefaultOpenGLWindow* window = 0;
|
||||
b3gDefaultOpenGLWindow *window = 0;
|
||||
int gWidth = 512;
|
||||
int gHeight = 512;
|
||||
int gMousePosX = -1, gMousePosY = -1;
|
||||
bool gMouseLeftDown = false;
|
||||
|
||||
// FIX issue when max passes is done - no modes is switched. pass must be set to
|
||||
// 0 when mode is changed
|
||||
int gShowBufferMode_prv = SHOW_BUFFER_COLOR;
|
||||
int gShowBufferMode = SHOW_BUFFER_COLOR;
|
||||
|
||||
bool gTabPressed = false;
|
||||
bool gShiftPressed = false;
|
||||
float gShowPositionScale = 1.0f;
|
||||
@ -128,8 +128,7 @@ std::atomic<bool> gSceneDirty;
|
||||
example::RenderConfig gRenderConfig;
|
||||
std::mutex gMutex;
|
||||
|
||||
struct RenderLayer
|
||||
{
|
||||
struct RenderLayer {
|
||||
std::vector<float> displayRGBA; // Accumurated image.
|
||||
std::vector<float> rgba;
|
||||
std::vector<float> auxRGBA; // Auxiliary buffer
|
||||
@ -143,14 +142,12 @@ struct RenderLayer
|
||||
|
||||
RenderLayer gRenderLayer;
|
||||
|
||||
struct Camera
|
||||
{
|
||||
struct Camera {
|
||||
glm::mat4 view;
|
||||
glm::mat4 projection;
|
||||
};
|
||||
|
||||
struct ManipConfig
|
||||
{
|
||||
struct ManipConfig {
|
||||
glm::vec3 snapTranslation;
|
||||
glm::vec3 snapRotation;
|
||||
glm::vec3 snapScale;
|
||||
@ -201,9 +198,12 @@ void RenderThread() {
|
||||
// gRenderCancel may be set to true in main loop.
|
||||
// Render() will repeatedly check this flag inside the rendering loop.
|
||||
|
||||
bool ret =
|
||||
example::Renderer::Render(&gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0), &gRenderLayer.sampleCounts.at(0),
|
||||
gCurrQuat, gScene, gAsset, gRenderConfig, gRenderCancel);
|
||||
bool ret = example::Renderer::Render(
|
||||
&gRenderLayer.rgba.at(0), &gRenderLayer.auxRGBA.at(0),
|
||||
&gRenderLayer.sampleCounts.at(0), gCurrQuat, gScene, gAsset,
|
||||
gRenderConfig, gRenderCancel,
|
||||
gShowBufferMode // added mode passing
|
||||
);
|
||||
|
||||
if (ret) {
|
||||
std::lock_guard<std::mutex> guard(gMutex);
|
||||
@ -219,16 +219,18 @@ void RenderThread() {
|
||||
}
|
||||
}
|
||||
|
||||
void InitRender(example::RenderConfig* rc) {
|
||||
void InitRender(example::RenderConfig *rc) {
|
||||
rc->pass = 0;
|
||||
|
||||
rc->max_passes = 128;
|
||||
|
||||
gRenderLayer.sampleCounts.resize(rc->width * rc->height);
|
||||
std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(), 0.0);
|
||||
std::fill(gRenderLayer.sampleCounts.begin(), gRenderLayer.sampleCounts.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.displayRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.displayRGBA.begin(), gRenderLayer.displayRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.rgba.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.rgba.begin(), gRenderLayer.rgba.end(), 0.0);
|
||||
@ -237,19 +239,23 @@ void InitRender(example::RenderConfig* rc) {
|
||||
std::fill(gRenderLayer.auxRGBA.begin(), gRenderLayer.auxRGBA.end(), 0.0);
|
||||
|
||||
gRenderLayer.normalRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.normalRGBA.begin(), gRenderLayer.normalRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.positionRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.positionRGBA.begin(), gRenderLayer.positionRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.depthRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.depthRGBA.begin(), gRenderLayer.depthRGBA.end(), 0.0);
|
||||
|
||||
gRenderLayer.texCoordRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.texCoordRGBA.begin(), gRenderLayer.texCoordRGBA.end(),
|
||||
0.0);
|
||||
|
||||
gRenderLayer.varyCoordRGBA.resize(rc->width * rc->height * 4);
|
||||
std::fill(gRenderLayer.varyCoordRGBA.begin(), gRenderLayer.varyCoordRGBA.end(), 0.0);
|
||||
std::fill(gRenderLayer.varyCoordRGBA.begin(),
|
||||
gRenderLayer.varyCoordRGBA.end(), 0.0);
|
||||
|
||||
rc->normalImage = &gRenderLayer.normalRGBA.at(0);
|
||||
rc->positionImage = &gRenderLayer.positionRGBA.at(0);
|
||||
@ -268,19 +274,18 @@ void checkErrors(std::string desc) {
|
||||
}
|
||||
}
|
||||
|
||||
static int CreateDisplayTextureGL(const float *data, int width, int height,
|
||||
int components) {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
static int CreateDisplayTextureGL(const float *data, int width,
|
||||
int height, int components) {
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
if (components == 1) {
|
||||
format = GL_LUMINANCE;
|
||||
@ -290,15 +295,15 @@ static int CreateDisplayTextureGL(const float *data, int width,
|
||||
format = GL_RGB;
|
||||
} else if (components == 4) {
|
||||
format = GL_RGBA;
|
||||
} else {
|
||||
assert(0); // "Invalid components"
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format,
|
||||
GL_FLOAT, data);
|
||||
|
||||
} else {
|
||||
assert(0); // "Invalid components"
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_FLOAT,
|
||||
data);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
|
||||
return static_cast<int>(id);
|
||||
}
|
||||
|
||||
@ -312,8 +317,10 @@ void keyboardCallback(int keycode, int state) {
|
||||
// reset.
|
||||
trackball(gCurrQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// clear buffer.
|
||||
memset(gRenderLayer.rgba.data(), 0, sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4);
|
||||
memset(gRenderLayer.sampleCounts.data(), 0, sizeof(int) * gRenderConfig.width * gRenderConfig.height);
|
||||
memset(gRenderLayer.rgba.data(), 0,
|
||||
sizeof(float) * gRenderConfig.width * gRenderConfig.height * 4);
|
||||
memset(gRenderLayer.sampleCounts.data(), 0,
|
||||
sizeof(int) * gRenderConfig.width * gRenderConfig.height);
|
||||
} else if (keycode == 9) {
|
||||
gTabPressed = (state == 1);
|
||||
} else if (keycode == B3G_SHIFT) {
|
||||
@ -330,9 +337,10 @@ void keyboardCallback(int keycode, int state) {
|
||||
}
|
||||
|
||||
void mouseMoveCallback(float x, float y) {
|
||||
|
||||
if (gMouseLeftDown) {
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
gSceneDirty = true;
|
||||
// RequestRender();
|
||||
} else {
|
||||
float w = static_cast<float>(gRenderConfig.width);
|
||||
float h = static_cast<float>(gRenderConfig.height);
|
||||
@ -371,31 +379,34 @@ void mouseButtonCallback(int button, int state, float x, float y) {
|
||||
(void)y;
|
||||
ImGui_ImplBtGui_SetMouseButtonState(button, (state == 1));
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.WantCaptureMouse || io.WantCaptureKeyboard) {
|
||||
return;
|
||||
}
|
||||
if (button == 0 && !state)
|
||||
gMouseLeftDown = false; // prevent sticky trackball after using gizmo
|
||||
|
||||
// left button
|
||||
if (button == 0) {
|
||||
if (state) {
|
||||
gMouseLeftDown = true;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
} else {
|
||||
trackball(gPrevQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
} else {
|
||||
gMouseLeftDown = false;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
if (io.WantCaptureMouse || io.WantCaptureKeyboard) {
|
||||
if (button == 0 && !state) {
|
||||
if (ImGuizmo::IsUsing()) {
|
||||
gSceneDirty = true;
|
||||
RequestRender();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// left button
|
||||
if (button == 0) {
|
||||
if (state) {
|
||||
gMouseLeftDown = true;
|
||||
if (ImGuizmo::IsOver() || ImGuizmo::IsUsing()) {
|
||||
} else {
|
||||
trackball(gPrevQuat, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resizeCallback(float width, float height) {
|
||||
//GLfloat h = (GLfloat)height / (GLfloat)width;
|
||||
// GLfloat h = (GLfloat)height / (GLfloat)width;
|
||||
GLfloat xmax, znear, zfar;
|
||||
|
||||
znear = 1.0f;
|
||||
@ -406,7 +417,7 @@ void resizeCallback(float width, float height) {
|
||||
gHeight = static_cast<int>(height);
|
||||
}
|
||||
|
||||
inline float pesudoColor(float v, int ch) {
|
||||
inline float pseudoColor(float v, int ch) {
|
||||
if (ch == 0) { // red
|
||||
if (v <= 0.5f)
|
||||
return 0.f;
|
||||
@ -471,7 +482,7 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) {
|
||||
for (size_t i = 0; i < buf.size(); i++) {
|
||||
float v = (gRenderLayer.depthRGBA[i] - d_min) / d_diff;
|
||||
if (gShowDepthPeseudoColor) {
|
||||
buf[i] = pesudoColor(v, i % 4);
|
||||
buf[i] = pseudoColor(v, i % 4);
|
||||
} else {
|
||||
buf[i] = v;
|
||||
}
|
||||
@ -491,31 +502,31 @@ void UpdateDisplayTextureGL(GLint tex_id, int width, int height) {
|
||||
disp.resize(width * height * 4);
|
||||
{
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)], sizeof(float) * 4 * width);
|
||||
memcpy(&disp[4 * (y * width)], &buf[4 * ((height - y - 1) * width)],
|
||||
sizeof(float) * 4 * width);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT, disp.data());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_FLOAT,
|
||||
disp.data());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
//glRasterPos2i(-1, -1);
|
||||
//glDrawPixels(width, height, GL_RGBA, GL_FLOAT,
|
||||
// glRasterPos2i(-1, -1);
|
||||
// glDrawPixels(width, height, GL_RGBA, GL_FLOAT,
|
||||
// static_cast<const GLvoid*>(&buf.at(0)));
|
||||
}
|
||||
|
||||
void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& matrix)
|
||||
{
|
||||
void EditTransform(const ManipConfig &config, const Camera &camera,
|
||||
glm::mat4 &matrix) {
|
||||
static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::ROTATE);
|
||||
static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::WORLD);
|
||||
if (ImGui::IsKeyPressed(90))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(69))
|
||||
mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
if (ImGui::IsKeyPressed(82)) // r Key
|
||||
if (ImGui::IsKeyPressed(90)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
if (ImGui::IsKeyPressed(69)) mCurrentGizmoOperation = ImGuizmo::ROTATE;
|
||||
if (ImGui::IsKeyPressed(82)) // r Key
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
if (ImGui::RadioButton("Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||
if (ImGui::RadioButton("Translate",
|
||||
mCurrentGizmoOperation == ImGuizmo::TRANSLATE))
|
||||
mCurrentGizmoOperation = ImGuizmo::TRANSLATE;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE))
|
||||
@ -524,14 +535,15 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m
|
||||
if (ImGui::RadioButton("Scale", mCurrentGizmoOperation == ImGuizmo::SCALE))
|
||||
mCurrentGizmoOperation = ImGuizmo::SCALE;
|
||||
float matrixTranslation[3], matrixRotation[3], matrixScale[3];
|
||||
ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation, matrixRotation, matrixScale);
|
||||
ImGuizmo::DecomposeMatrixToComponents(&matrix[0][0], matrixTranslation,
|
||||
matrixRotation, matrixScale);
|
||||
ImGui::InputFloat3("Tr", matrixTranslation, 3);
|
||||
ImGui::InputFloat3("Rt", matrixRotation, 3);
|
||||
ImGui::InputFloat3("Sc", matrixScale, 3);
|
||||
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation, matrixScale, &matrix[0][0]);
|
||||
ImGuizmo::RecomposeMatrixFromComponents(matrixTranslation, matrixRotation,
|
||||
matrixScale, &matrix[0][0]);
|
||||
|
||||
if (mCurrentGizmoOperation != ImGuizmo::SCALE)
|
||||
{
|
||||
if (mCurrentGizmoOperation != ImGuizmo::SCALE) {
|
||||
if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL))
|
||||
mCurrentGizmoMode = ImGuizmo::LOCAL;
|
||||
ImGui::SameLine();
|
||||
@ -539,33 +551,32 @@ void EditTransform(const ManipConfig &config, const Camera& camera, glm::mat4& m
|
||||
mCurrentGizmoMode = ImGuizmo::WORLD;
|
||||
}
|
||||
static bool useSnap(false);
|
||||
if (ImGui::IsKeyPressed(83))
|
||||
useSnap = !useSnap;
|
||||
if (ImGui::IsKeyPressed(83)) useSnap = !useSnap;
|
||||
ImGui::Checkbox("", &useSnap);
|
||||
ImGui::SameLine();
|
||||
glm::vec3 snap;
|
||||
switch (mCurrentGizmoOperation)
|
||||
{
|
||||
case ImGuizmo::TRANSLATE:
|
||||
snap = config.snapTranslation;
|
||||
ImGui::InputFloat3("Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::ROTATE:
|
||||
snap = config.snapRotation;
|
||||
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::SCALE:
|
||||
snap = config.snapScale;
|
||||
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||
break;
|
||||
switch (mCurrentGizmoOperation) {
|
||||
case ImGuizmo::TRANSLATE:
|
||||
snap = config.snapTranslation;
|
||||
ImGui::InputFloat3("Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::ROTATE:
|
||||
snap = config.snapRotation;
|
||||
ImGui::InputFloat("Angle Snap", &snap.x);
|
||||
break;
|
||||
case ImGuizmo::SCALE:
|
||||
snap = config.snapScale;
|
||||
ImGui::InputFloat("Scale Snap", &snap.x);
|
||||
break;
|
||||
}
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0], mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0], NULL, useSnap ? &snap.x : NULL);
|
||||
ImGuizmo::Manipulate(&camera.view[0][0], &camera.projection[0][0],
|
||||
mCurrentGizmoOperation, mCurrentGizmoMode, &matrix[0][0],
|
||||
NULL, useSnap ? &snap.x : NULL);
|
||||
}
|
||||
|
||||
void DrawMesh(const example::Mesh<float> *mesh)
|
||||
{
|
||||
void DrawMesh(const example::Mesh<float> *mesh) {
|
||||
// TODO(LTE): Use vertex array or use display list.
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
@ -579,20 +590,17 @@ void DrawMesh(const example::Mesh<float> *mesh)
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 0],
|
||||
mesh->facevarying_normals[9 * i + 1],
|
||||
mesh->facevarying_normals[9 * i + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0],
|
||||
mesh->vertices[3 * f0 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1],
|
||||
mesh->vertices[3 * f0 + 2]);
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 3],
|
||||
mesh->facevarying_normals[9 * i + 4],
|
||||
mesh->facevarying_normals[9 * i + 5]);
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0],
|
||||
mesh->vertices[3 * f1 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1],
|
||||
mesh->vertices[3 * f1 + 2]);
|
||||
glNormal3f(mesh->facevarying_normals[9 * i + 6],
|
||||
mesh->facevarying_normals[9 * i + 7],
|
||||
mesh->facevarying_normals[9 * i + 8]);
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0],
|
||||
mesh->vertices[3 * f2 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1],
|
||||
mesh->vertices[3 * f2 + 2]);
|
||||
}
|
||||
|
||||
@ -602,23 +610,19 @@ void DrawMesh(const example::Mesh<float> *mesh)
|
||||
unsigned int f1 = mesh->faces[3 * i + 1];
|
||||
unsigned int f2 = mesh->faces[3 * i + 2];
|
||||
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0],
|
||||
mesh->vertices[3 * f0 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f0 + 0], mesh->vertices[3 * f0 + 1],
|
||||
mesh->vertices[3 * f0 + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0],
|
||||
mesh->vertices[3 * f1 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f1 + 0], mesh->vertices[3 * f1 + 1],
|
||||
mesh->vertices[3 * f1 + 2]);
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0],
|
||||
mesh->vertices[3 * f2 + 1],
|
||||
glVertex3f(mesh->vertices[3 * f2 + 0], mesh->vertices[3 * f2 + 1],
|
||||
mesh->vertices[3 * f2 + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node)
|
||||
{
|
||||
void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node) {
|
||||
glPushMatrix();
|
||||
glMultMatrixf(node.GetLocalXformPtr());
|
||||
|
||||
@ -634,8 +638,8 @@ void DrawNode(const nanosg::Node<float, example::Mesh<float> > &node)
|
||||
}
|
||||
|
||||
// Draw scene with OpenGL
|
||||
void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const Camera &camera)
|
||||
{
|
||||
void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene,
|
||||
const Camera &camera) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
@ -649,11 +653,12 @@ void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const C
|
||||
const float light_diffuse[4] = {0.5f, 0.5f, 0.5f, 1.0f};
|
||||
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, &light0_pos[0]);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT1, GL_POSITION, &light1_pos[0]);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]);
|
||||
glLightfv(GL_LIGHT1, GL_DIFFUSE, &light_diffuse[0]);
|
||||
|
||||
const std::vector<nanosg::Node<float, example::Mesh<float> > > &root_nodes = scene.GetNodes();
|
||||
const std::vector<nanosg::Node<float, example::Mesh<float> > > &root_nodes =
|
||||
scene.GetNodes();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
@ -675,15 +680,12 @@ void DrawScene(const nanosg::Scene<float, example::Mesh<float> > &scene, const C
|
||||
glDisable(GL_LIGHT1);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
}
|
||||
|
||||
void BuildSceneItems(
|
||||
std::vector<std::string> *display_names,
|
||||
std::vector<std::string> *names,
|
||||
const nanosg::Node<float, example::Mesh<float> > &node,
|
||||
int indent)
|
||||
{
|
||||
void BuildSceneItems(std::vector<std::string> *display_names,
|
||||
std::vector<std::string> *names,
|
||||
const nanosg::Node<float, example::Mesh<float> > &node,
|
||||
int indent) {
|
||||
if (node.GetName().empty()) {
|
||||
// Skip a node with empty name.
|
||||
return;
|
||||
@ -699,14 +701,16 @@ void BuildSceneItems(
|
||||
|
||||
display_names->push_back(display_name);
|
||||
names->push_back(node.GetName());
|
||||
|
||||
|
||||
for (size_t i = 0; i < node.GetChildren().size(); i++) {
|
||||
BuildSceneItems(display_names, names, node.GetChildren()[i], indent + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// tigra: add default material
|
||||
example::Material default_material;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string config_filename = "config.json";
|
||||
|
||||
if (argc > 1) {
|
||||
@ -729,13 +733,47 @@ int main(int argc, char** argv) {
|
||||
std::vector<example::Material> materials;
|
||||
std::vector<example::Texture> textures;
|
||||
|
||||
bool ret = LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale, &meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load glTF [ " << gRenderConfig.gltf_filename << " ]" << std::endl;
|
||||
return -1;
|
||||
// tigra: set default material to 95% white diffuse
|
||||
default_material.diffuse[0] = 0.95f;
|
||||
default_material.diffuse[1] = 0.95f;
|
||||
default_material.diffuse[2] = 0.95f;
|
||||
|
||||
default_material.specular[0] = 0;
|
||||
default_material.specular[1] = 0;
|
||||
default_material.specular[2] = 0;
|
||||
|
||||
// Material pushed as first material on the list
|
||||
materials.push_back(default_material);
|
||||
|
||||
if (!gRenderConfig.obj_filename.empty()) {
|
||||
bool ret = LoadObj(gRenderConfig.obj_filename, gRenderConfig.scene_scale,
|
||||
&meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load .obj [ " << gRenderConfig.obj_filename
|
||||
<< " ]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gRenderConfig.gltf_filename.empty()) {
|
||||
std::cout << "Found gltf file : " << gRenderConfig.gltf_filename << "\n";
|
||||
|
||||
bool ret =
|
||||
LoadGLTF(gRenderConfig.gltf_filename, gRenderConfig.scene_scale,
|
||||
&meshes, &materials, &textures);
|
||||
if (!ret) {
|
||||
std::cerr << "Failed to load glTF file [ "
|
||||
<< gRenderConfig.gltf_filename << " ]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (textures.size() > 0) {
|
||||
materials[0].diffuse_texid = 0;
|
||||
}
|
||||
|
||||
gAsset.materials = materials;
|
||||
gAsset.default_material = default_material;
|
||||
gAsset.textures = textures;
|
||||
|
||||
for (size_t n = 0; n < meshes.size(); n++) {
|
||||
@ -744,12 +782,20 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < gAsset.meshes.size(); n++) {
|
||||
|
||||
nanosg::Node<float, example::Mesh<float> > node(&gAsset.meshes[n]);
|
||||
|
||||
// case where the name of a mesh isn't defined in the loaded file
|
||||
if (gAsset.meshes[n].name.empty()) {
|
||||
std::string generatedName = "unnamed_" + std::to_string(n);
|
||||
gAsset.meshes[n].name = generatedName;
|
||||
meshes[n].name = generatedName;
|
||||
}
|
||||
|
||||
node.SetName(meshes[n].name);
|
||||
node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform as node's local transform.
|
||||
node.SetLocalXform(meshes[n].pivot_xform); // Use mesh's pivot transform
|
||||
// as node's local transform.
|
||||
gNodes.push_back(node);
|
||||
|
||||
|
||||
gScene.AddNode(node);
|
||||
}
|
||||
|
||||
@ -761,11 +807,12 @@ int main(int argc, char** argv) {
|
||||
float bmin[3], bmax[3];
|
||||
gScene.GetBoundingBox(bmin, bmax);
|
||||
printf(" # of nodes : %d\n", int(gNodes.size()));
|
||||
printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
|
||||
printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
|
||||
|
||||
printf(" Scene Bmin : %f, %f, %f\n", bmin[0], bmin[1],
|
||||
bmin[2]);
|
||||
printf(" Scene Bmax : %f, %f, %f\n", bmax[0], bmax[1],
|
||||
bmax[2]);
|
||||
}
|
||||
|
||||
|
||||
std::vector<const char *> imgui_node_names;
|
||||
std::vector<std::string> display_node_names;
|
||||
std::vector<std::string> node_names;
|
||||
@ -773,13 +820,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < gScene.GetNodes().size(); i++) {
|
||||
BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i], /* indent */0);
|
||||
BuildSceneItems(&display_node_names, &node_names, gScene.GetNodes()[i],
|
||||
/* indent */ 0);
|
||||
}
|
||||
|
||||
// List of strings for imgui.
|
||||
// Assume nodes in the scene does not change.
|
||||
for (size_t i = 0; i < display_node_names.size(); i++) {
|
||||
//std::cout << "name : " << display_node_names[i] << std::endl;
|
||||
// std::cout << "name : " << display_node_names[i] << std::endl;
|
||||
imgui_node_names.push_back(display_node_names[i].c_str());
|
||||
}
|
||||
|
||||
@ -788,13 +836,13 @@ int main(int argc, char** argv) {
|
||||
nanosg::Node<float, example::Mesh<float> > *node;
|
||||
|
||||
if (gScene.FindNode(node_names[i], &node)) {
|
||||
//std::cout << "id : " << i << ", name : " << node_names[i] << std::endl;
|
||||
// std::cout << "id : " << i << ", name : " << node_names[i] <<
|
||||
// std::endl;
|
||||
node_map[i] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window = new b3gDefaultOpenGLWindow;
|
||||
b3gWindowConstructionInfo ci;
|
||||
#ifdef USE_OPENGL2
|
||||
@ -834,11 +882,12 @@ int main(int argc, char** argv) {
|
||||
window->setResizeCallback(resizeCallback);
|
||||
checkErrors("resize");
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui_ImplBtGui_Init(window);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
io.Fonts->AddFontDefault();
|
||||
//io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f);
|
||||
// io.Fonts->AddFontFromFileTTF("./DroidSans.ttf", 15.0f);
|
||||
|
||||
glm::mat4 projection(1.0f);
|
||||
glm::mat4 view(1.0f);
|
||||
@ -861,7 +910,7 @@ int main(int argc, char** argv) {
|
||||
ImGuizmo::BeginFrame();
|
||||
ImGuizmo::Enable(true);
|
||||
|
||||
//ImGuiIO &io = ImGui::GetIO();
|
||||
// ImGuiIO &io = ImGui::GetIO();
|
||||
ImGuizmo::SetRect(0, 0, io.DisplaySize.x, io.DisplaySize.y);
|
||||
|
||||
ImGui::Begin("UI");
|
||||
@ -897,7 +946,7 @@ int main(int argc, char** argv) {
|
||||
ImGui::InputFloat("show pos scale", &gShowPositionScale);
|
||||
|
||||
ImGui::InputFloat2("show depth range", gShowDepthRange);
|
||||
ImGui::Checkbox("show depth pesudo color", &gShowDepthPeseudoColor);
|
||||
ImGui::Checkbox("show depth pseudo color", &gShowDepthPeseudoColor);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
@ -908,38 +957,47 @@ int main(int argc, char** argv) {
|
||||
|
||||
checkErrors("clear");
|
||||
|
||||
// fix max passes issue
|
||||
if (gShowBufferMode_prv != gShowBufferMode) {
|
||||
gRenderConfig.pass = 0;
|
||||
gShowBufferMode_prv = gShowBufferMode;
|
||||
}
|
||||
|
||||
// Render display window
|
||||
{
|
||||
static GLint gl_texid = -1;
|
||||
if (gl_texid < 0) {
|
||||
gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width, gRenderConfig.height, 4);
|
||||
gl_texid = CreateDisplayTextureGL(NULL, gRenderConfig.width,
|
||||
gRenderConfig.height, 4);
|
||||
}
|
||||
|
||||
// Refresh texture until rendering finishes.
|
||||
if (gRenderConfig.pass < gRenderConfig.max_passes) {
|
||||
// FIXME(LTE): Do not update GL texture frequently.
|
||||
UpdateDisplayTextureGL(gl_texid, gRenderConfig.width, gRenderConfig.height);
|
||||
UpdateDisplayTextureGL(gl_texid, gRenderConfig.width,
|
||||
gRenderConfig.height);
|
||||
}
|
||||
|
||||
ImGui::Begin("Render");
|
||||
ImTextureID tex_id = reinterpret_cast<void *>(
|
||||
static_cast<intptr_t>(gl_texid));
|
||||
ImTextureID tex_id =
|
||||
reinterpret_cast<void *>(static_cast<intptr_t>(gl_texid));
|
||||
ImGui::Image(tex_id, ImVec2(256, 256), ImVec2(0, 0),
|
||||
ImVec2(1, 1));// Setup camera and draw imguizomo
|
||||
ImVec2(1, 1)); // Setup camera and draw imguizomo
|
||||
|
||||
ImGui::End();
|
||||
|
||||
}
|
||||
|
||||
// scene graph tree
|
||||
glm::mat4 node_matrix;
|
||||
static int node_selected = 0;
|
||||
static int node_selected_index = 0;
|
||||
{
|
||||
ImGui::Begin("Scene");
|
||||
|
||||
ImGui::ListBox("Node list", &node_selected, imgui_node_names.data(), imgui_node_names.size(), 16);
|
||||
node_matrix = glm::make_mat4(node_map[node_selected]->GetLocalXformPtr());
|
||||
ImGui::ListBox("Node list", &node_selected_index, imgui_node_names.data(),
|
||||
imgui_node_names.size(), 16);
|
||||
|
||||
auto node_selected = node_map.at(node_selected_index);
|
||||
node_matrix = glm::make_mat4(node_selected->GetLocalXformPtr());
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
@ -964,11 +1022,14 @@ int main(int argc, char** argv) {
|
||||
up[2] = gRenderConfig.up[2];
|
||||
|
||||
// NOTE(LTE): w, then (x,y,z) for glm::quat.
|
||||
glm::quat rot = glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]);
|
||||
glm::quat rot =
|
||||
glm::quat(gCurrQuat[3], gCurrQuat[0], gCurrQuat[1], gCurrQuat[2]);
|
||||
glm::mat4 rm = glm::mat4_cast(rot);
|
||||
|
||||
view = glm::lookAt(eye, lookat, up) * glm::inverse(glm::mat4_cast(rot));
|
||||
projection = glm::perspective (45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f, 1000.0f);
|
||||
projection = glm::perspective(
|
||||
45.0f, float(window->getWidth()) / float(window->getHeight()), 0.01f,
|
||||
1000.0f);
|
||||
|
||||
camera.view = view;
|
||||
camera.projection = projection;
|
||||
@ -978,10 +1039,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
float mat[4][4];
|
||||
memcpy(mat, &node_matrix[0][0], sizeof(float) * 16);
|
||||
node_map[node_selected]->SetLocalXform(mat);
|
||||
node_map[node_selected_index]->SetLocalXform(mat);
|
||||
|
||||
checkErrors("edit_transform");
|
||||
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,14 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace example {
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO(syoyo): Support PBR material.
|
||||
namespace example {
|
||||
|
||||
struct Material {
|
||||
// float ambient[3];
|
||||
@ -53,6 +58,7 @@ struct Texture {
|
||||
int width;
|
||||
int height;
|
||||
int components;
|
||||
int _pad_;
|
||||
unsigned char* image;
|
||||
|
||||
Texture() {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
namespace example {
|
||||
|
||||
@ -69,9 +70,13 @@ inline void calculate_normal(T Nn[3], const T v0[3], const T v1[3], const T v2[3
|
||||
template<typename T>
|
||||
class Mesh {
|
||||
public:
|
||||
explicit Mesh(const size_t vertex_stride) :
|
||||
stride(vertex_stride) {
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
std::vector<T> vertices; /// [xyz] * num_vertices
|
||||
std::vector<T> vertices; /// stride * num_vertices
|
||||
std::vector<T> facevarying_normals; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_tangents; /// [xyz] * 3(triangle) * num_faces
|
||||
std::vector<T> facevarying_binormals; /// [xyz] * 3(triangle) * num_faces
|
||||
@ -82,6 +87,7 @@ class Mesh {
|
||||
std::vector<unsigned int> material_ids; /// index x num_faces
|
||||
|
||||
T pivot_xform[4][4];
|
||||
size_t stride; /// stride for vertex data.
|
||||
|
||||
// --- Required methods in Scene::Traversal. ---
|
||||
|
||||
|
1
examples/raytrace/nanort.cc
Normal file
1
examples/raytrace/nanort.cc
Normal file
@ -0,0 +1 @@
|
||||
#include "nanort.h"
|
@ -44,6 +44,13 @@ THE SOFTWARE.
|
||||
|
||||
namespace nanort {
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#if __has_warning("-Wzero-as-null-pointer-constant")
|
||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Parallelized BVH build is not yet fully tested,
|
||||
// thus turn off if you face a problem when building BVH.
|
||||
#define NANORT_ENABLE_PARALLEL_BUILD (1)
|
||||
@ -301,9 +308,7 @@ class real3 {
|
||||
real3 operator/(const real3 &f2) const {
|
||||
return real3(x() / f2.x(), y() / f2.y(), z() / f2.z());
|
||||
}
|
||||
real3 operator-() const {
|
||||
return real3(-x(), -y(), -z());
|
||||
}
|
||||
real3 operator-() const { return real3(-x(), -y(), -z()); }
|
||||
T operator[](int i) const { return v[i]; }
|
||||
T &operator[](int i) { return v[i]; }
|
||||
|
||||
@ -330,8 +335,8 @@ template <typename T>
|
||||
inline real3<T> vnormalize(const real3<T> &rhs) {
|
||||
real3<T> v = rhs;
|
||||
T len = vlength(rhs);
|
||||
if (fabs(len) > 1.0e-6f) {
|
||||
float inv_len = 1.0f / len;
|
||||
if (std::fabs(len) > static_cast<T>(1.0e-6)) {
|
||||
T inv_len = static_cast<T>(1.0) / len;
|
||||
v.v[0] *= inv_len;
|
||||
v.v[1] *= inv_len;
|
||||
v.v[2] *= inv_len;
|
||||
@ -363,9 +368,7 @@ inline const real *get_vertex_addr(const real *p, const size_t idx,
|
||||
template <typename T = float>
|
||||
class Ray {
|
||||
public:
|
||||
Ray()
|
||||
: min_t(static_cast<T>(0.0))
|
||||
, max_t(std::numeric_limits<T>::max()) {
|
||||
Ray() : min_t(static_cast<T>(0.0)), max_t(std::numeric_limits<T>::max()) {
|
||||
org[0] = static_cast<T>(0.0);
|
||||
org[1] = static_cast<T>(0.0);
|
||||
org[2] = static_cast<T>(0.0);
|
||||
@ -374,11 +377,11 @@ class Ray {
|
||||
dir[2] = static_cast<T>(-1.0);
|
||||
}
|
||||
|
||||
T org[3]; // must set
|
||||
T dir[3]; // must set
|
||||
T min_t; // minium ray hit distance.
|
||||
T max_t; // maximum ray hit distance.
|
||||
T inv_dir[3]; // filled internally
|
||||
T org[3]; // must set
|
||||
T dir[3]; // must set
|
||||
T min_t; // minimum ray hit distance.
|
||||
T max_t; // maximum ray hit distance.
|
||||
T inv_dir[3]; // filled internally
|
||||
int dir_sign[3]; // filled internally
|
||||
};
|
||||
|
||||
@ -386,6 +389,38 @@ template <typename T = float>
|
||||
class BVHNode {
|
||||
public:
|
||||
BVHNode() {}
|
||||
BVHNode(const BVHNode &rhs) {
|
||||
bmin[0] = rhs.bmin[0];
|
||||
bmin[1] = rhs.bmin[1];
|
||||
bmin[2] = rhs.bmin[2];
|
||||
flag = rhs.flag;
|
||||
|
||||
bmax[0] = rhs.bmax[0];
|
||||
bmax[1] = rhs.bmax[1];
|
||||
bmax[2] = rhs.bmax[2];
|
||||
axis = rhs.axis;
|
||||
|
||||
data[0] = rhs.data[0];
|
||||
data[1] = rhs.data[1];
|
||||
}
|
||||
|
||||
BVHNode &operator=(const BVHNode &rhs) {
|
||||
bmin[0] = rhs.bmin[0];
|
||||
bmin[1] = rhs.bmin[1];
|
||||
bmin[2] = rhs.bmin[2];
|
||||
flag = rhs.flag;
|
||||
|
||||
bmax[0] = rhs.bmax[0];
|
||||
bmax[1] = rhs.bmax[1];
|
||||
bmax[2] = rhs.bmax[2];
|
||||
axis = rhs.axis;
|
||||
|
||||
data[0] = rhs.data[0];
|
||||
data[1] = rhs.data[1];
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~BVHNode() {}
|
||||
|
||||
T bmin[3];
|
||||
@ -480,14 +515,26 @@ class BBox {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class NodeHit
|
||||
{
|
||||
template <typename T>
|
||||
class NodeHit {
|
||||
public:
|
||||
NodeHit()
|
||||
: t_min(std::numeric_limits<T>::max())
|
||||
, t_max(-std::numeric_limits<T>::max())
|
||||
, node_id(static_cast<unsigned int>(-1)) {
|
||||
: t_min(std::numeric_limits<T>::max()),
|
||||
t_max(-std::numeric_limits<T>::max()),
|
||||
node_id(static_cast<unsigned int>(-1)) {}
|
||||
|
||||
NodeHit(const NodeHit<T> &rhs) {
|
||||
t_min = rhs.t_min;
|
||||
t_max = rhs.t_max;
|
||||
node_id = rhs.node_id;
|
||||
}
|
||||
|
||||
NodeHit &operator=(const NodeHit<T> &rhs) {
|
||||
t_min = rhs.t_min;
|
||||
t_max = rhs.t_max;
|
||||
node_id = rhs.node_id;
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
||||
~NodeHit() {}
|
||||
@ -497,9 +544,8 @@ class NodeHit
|
||||
unsigned int node_id;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class NodeHitComparator
|
||||
{
|
||||
template <typename T>
|
||||
class NodeHitComparator {
|
||||
public:
|
||||
inline bool operator()(const NodeHit<T> &a, const NodeHit<T> &b) {
|
||||
return a.t_min < b.t_min;
|
||||
@ -512,29 +558,37 @@ class BVHAccel {
|
||||
BVHAccel() : pad0_(0) { (void)pad0_; }
|
||||
~BVHAccel() {}
|
||||
|
||||
///
|
||||
/// Build BVH for input primitives.
|
||||
template<class P, class Pred>
|
||||
bool Build(const unsigned int num_primitives,
|
||||
const P &p, const Pred &pred, const BVHBuildOptions<T> &options = BVHBuildOptions<T>());
|
||||
///
|
||||
template <class P, class Pred>
|
||||
bool Build(const unsigned int num_primitives, const P &p, const Pred &pred,
|
||||
const BVHBuildOptions<T> &options = BVHBuildOptions<T>());
|
||||
|
||||
///
|
||||
/// Get statistics of built BVH tree. Valid after Build()
|
||||
///
|
||||
BVHBuildStatistics GetStatistics() const { return stats_; }
|
||||
|
||||
///
|
||||
/// Dump built BVH to the file.
|
||||
///
|
||||
bool Dump(const char *filename);
|
||||
|
||||
///
|
||||
/// Load BVH binary
|
||||
///
|
||||
bool Load(const char *filename);
|
||||
|
||||
void Debug();
|
||||
|
||||
///
|
||||
/// Traverse into BVH along ray and find closest hit point & primitive if
|
||||
/// found
|
||||
template<class I, class H>
|
||||
bool Traverse(const Ray<T> &ray,
|
||||
const I &intersector,
|
||||
H *isect,
|
||||
const BVHTraceOptions& options = BVHTraceOptions()) const;
|
||||
///
|
||||
template <class I, class H>
|
||||
bool Traverse(const Ray<T> &ray, const I &intersector, H *isect,
|
||||
const BVHTraceOptions &options = BVHTraceOptions()) const;
|
||||
|
||||
#if 0
|
||||
/// Multi-hit ray traversal
|
||||
@ -551,16 +605,17 @@ class BVHAccel {
|
||||
/// List up nodes which intersects along the ray.
|
||||
/// This function is useful for two-level BVH traversal.
|
||||
///
|
||||
template<class I>
|
||||
bool ListNodeIntersections(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
template <class I>
|
||||
bool ListNodeIntersections(const Ray<T> &ray, int max_intersections,
|
||||
const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const;
|
||||
|
||||
const std::vector<BVHNode<T> > &GetNodes() const { return nodes_; }
|
||||
const std::vector<unsigned int> &GetIndices() const { return indices_; }
|
||||
|
||||
///
|
||||
/// Returns bounding box of built BVH.
|
||||
///
|
||||
void BoundingBox(T bmin[3], T bmax[3]) const {
|
||||
if (nodes_.empty()) {
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<T>::max();
|
||||
@ -589,7 +644,7 @@ class BVHAccel {
|
||||
std::vector<ShallowNodeInfo> shallow_node_infos_;
|
||||
|
||||
/// Builds shallow BVH tree recursively.
|
||||
template<class P, class Pred>
|
||||
template <class P, class Pred>
|
||||
unsigned int BuildShallowTree(std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx,
|
||||
unsigned int depth,
|
||||
@ -598,22 +653,22 @@ class BVHAccel {
|
||||
#endif
|
||||
|
||||
/// Builds BVH tree recursively.
|
||||
template<class P, class Pred>
|
||||
template <class P, class Pred>
|
||||
unsigned int BuildTree(BVHBuildStatistics *out_stat,
|
||||
std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx,
|
||||
unsigned int depth, const P &p, const Pred &pred);
|
||||
|
||||
template<class I>
|
||||
template <class I>
|
||||
bool TestLeafNode(const BVHNode<T> &node, const Ray<T> &ray,
|
||||
const I &intersector) const;
|
||||
|
||||
template<class I>
|
||||
bool TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > *isect_pq) const;
|
||||
template <class I>
|
||||
bool TestLeafNodeIntersections(
|
||||
const BVHNode<T> &node, const Ray<T> &ray, const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> > *isect_pq) const;
|
||||
|
||||
#if 0
|
||||
template<class I, class H, class Comp>
|
||||
@ -663,7 +718,7 @@ class TriangleSAHPred {
|
||||
|
||||
T center = p0[axis] + p1[axis] + p2[axis];
|
||||
|
||||
return (center < pos * 3.0);
|
||||
return (center < pos * static_cast<T>(3.0));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -762,7 +817,7 @@ class TriangleIntersector {
|
||||
/// distance `t`,
|
||||
/// varycentric coordinate `u` and `v`.
|
||||
/// Returns true if there's intersection.
|
||||
bool Intersect(T *t_inout, unsigned int prim_index) const {
|
||||
bool Intersect(T *t_inout, const unsigned int prim_index) const {
|
||||
if ((prim_index < trace_options_.prim_ids_range[0]) ||
|
||||
(prim_index >= trace_options_.prim_ids_range[1])) {
|
||||
return false;
|
||||
@ -791,8 +846,13 @@ class TriangleIntersector {
|
||||
T V = Ax * Cy - Ay * Cx;
|
||||
T W = Bx * Ay - By * Ax;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
|
||||
// Fall back to test against edges using double precision.
|
||||
if (U == 0.0 || V == 0.0 || W == 0.0) {
|
||||
if (U == static_cast<T>(0.0) || V == static_cast<T>(0.0) || W == static_cast<T>(0.0)) {
|
||||
double CxBy = static_cast<double>(Cx) * static_cast<double>(By);
|
||||
double CyBx = static_cast<double>(Cy) * static_cast<double>(Bx);
|
||||
U = static_cast<T>(CxBy - CyBx);
|
||||
@ -807,15 +867,19 @@ class TriangleIntersector {
|
||||
}
|
||||
|
||||
if (trace_options_.cull_back_face) {
|
||||
if (U < 0.0 || V < 0.0 || W < 0.0) return false;
|
||||
if (U < static_cast<T>(0.0) || V < static_cast<T>(0.0) || W < static_cast<T>(0.0)) return false;
|
||||
} else {
|
||||
if ((U < 0.0 || V < 0.0 || W < 0.0) && (U > 0.0 || V > 0.0 || W > 0.0)) {
|
||||
if ((U < static_cast<T>(0.0) || V < static_cast<T>(0.0) || W < static_cast<T>(0.0)) && (U > static_cast<T>(0.0) || V > static_cast<T>(0.0) || W > static_cast<T>(0.0))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
T det = U + V + W;
|
||||
if (det == 0.0) return false;
|
||||
if (det == static_cast<T>(0.0)) return false;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
const T Az = ray_coeff_.Sz * A[ray_coeff_.kz];
|
||||
const T Bz = ray_coeff_.Sz * B[ray_coeff_.kz];
|
||||
@ -829,6 +893,10 @@ class TriangleIntersector {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tt < t_min_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*t_inout) = tt;
|
||||
// Use Thomas-Mueller style barycentric coord.
|
||||
// U + V + W = 1.0 and interp(p) = U * p0 + V * p1 + W * p2
|
||||
@ -884,6 +952,8 @@ class TriangleIntersector {
|
||||
|
||||
trace_options_ = trace_options;
|
||||
|
||||
t_min_ = ray.min_t;
|
||||
|
||||
u_ = 0.0f;
|
||||
v_ = 0.0f;
|
||||
}
|
||||
@ -901,19 +971,20 @@ class TriangleIntersector {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const T *vertices_;
|
||||
const unsigned int *faces_;
|
||||
const size_t vertex_stride_bytes_;
|
||||
|
||||
|
||||
mutable real3<T> ray_org_;
|
||||
mutable RayCoeff ray_coeff_;
|
||||
mutable BVHTraceOptions trace_options_;
|
||||
mutable T t_min_;
|
||||
|
||||
mutable T t_;
|
||||
mutable T u_;
|
||||
mutable T v_;
|
||||
mutable T t_;
|
||||
mutable T u_;
|
||||
mutable T v_;
|
||||
mutable unsigned int prim_id_;
|
||||
int _pad_;
|
||||
};
|
||||
|
||||
//
|
||||
@ -950,7 +1021,8 @@ struct BinBuffer {
|
||||
template <typename T>
|
||||
inline T CalculateSurfaceArea(const real3<T> &min, const real3<T> &max) {
|
||||
real3<T> box = max - min;
|
||||
return static_cast<T>(2.0) * (box[0] * box[1] + box[1] * box[2] + box[2] * box[0]);
|
||||
return static_cast<T>(2.0) *
|
||||
(box[0] * box[1] + box[1] * box[2] + box[2] * box[0]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -994,12 +1066,12 @@ inline void ContributeBinBuffer(BinBuffer *bins, // [out]
|
||||
real3<T> scene_size, scene_inv_size;
|
||||
scene_size = scene_max - scene_min;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
assert(scene_size[i] >= 0.0);
|
||||
assert(scene_size[i] >= static_cast<T>(0.0));
|
||||
|
||||
if (scene_size[i] > 0.0) {
|
||||
if (scene_size[i] > static_cast<T>(0.0)) {
|
||||
scene_inv_size[i] = bin_size / scene_size[i];
|
||||
} else {
|
||||
scene_inv_size[i] = 0.0;
|
||||
scene_inv_size[i] = static_cast<T>(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1057,7 +1129,8 @@ inline T SAH(size_t ns1, T leftArea, size_t ns2, T rightArea, T invS, T Taabb,
|
||||
T Ttri) {
|
||||
T sah;
|
||||
|
||||
sah = static_cast<T>(2.0) * Taabb + (leftArea * invS) * static_cast<T>(ns1) * Ttri +
|
||||
sah = static_cast<T>(2.0) * Taabb +
|
||||
(leftArea * invS) * static_cast<T>(ns1) * Ttri +
|
||||
(rightArea * invS) * static_cast<T>(ns2) * Ttri;
|
||||
|
||||
return sah;
|
||||
@ -1079,22 +1152,22 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
T pos;
|
||||
T minCost[3];
|
||||
|
||||
T costTtri = 1.0f - costTaabb;
|
||||
T costTtri = static_cast<T>(1.0) - costTaabb;
|
||||
|
||||
(*minCostAxis) = 0;
|
||||
|
||||
bsize = bmax - bmin;
|
||||
bstep = bsize * (1.0f / bins->bin_size);
|
||||
bstep = bsize * (static_cast<T>(1.0) / bins->bin_size);
|
||||
saTotal = CalculateSurfaceArea(bmin, bmax);
|
||||
|
||||
T invSaTotal = 0.0f;
|
||||
T invSaTotal = static_cast<T>(0.0);
|
||||
if (saTotal > kEPS) {
|
||||
invSaTotal = 1.0f / saTotal;
|
||||
invSaTotal = static_cast<T>(1.0) / saTotal;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
//
|
||||
// Compute SAH cost for right side of each cell of the bbox.
|
||||
// Compute SAH cost for the right side of each cell of the bbox.
|
||||
// Exclude both extreme side of the bbox.
|
||||
//
|
||||
// i: 0 1 2 3
|
||||
@ -1103,7 +1176,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
// +----+----+----+----+----+
|
||||
//
|
||||
|
||||
T minCostPos = bmin[j] + 0.5f * bstep[j];
|
||||
T minCostPos = bmin[j] + static_cast<T>(1.0) * bstep[j];
|
||||
minCost[j] = std::numeric_limits<T>::max();
|
||||
|
||||
left = 0;
|
||||
@ -1127,7 +1200,7 @@ inline bool FindCutFromBinBuffer(T *cut_pos, // [out] xyz
|
||||
// +1 for i since we want a position on right side of the cell.
|
||||
//
|
||||
|
||||
pos = bmin[j] + (i + 0.5f) * bstep[j];
|
||||
pos = bmin[j] + (i + static_cast<T>(1.0)) * bstep[j];
|
||||
bmaxLeft[j] = pos;
|
||||
bminRight[j] = pos;
|
||||
|
||||
@ -1280,11 +1353,14 @@ inline void GetBoundingBox(real3<T> *bmin, real3<T> *bmax,
|
||||
//
|
||||
|
||||
#if NANORT_ENABLE_PARALLEL_BUILD
|
||||
template <typename T> template<class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildShallowTree(
|
||||
std::vector<BVHNode<T> > *out_nodes, unsigned int left_idx,
|
||||
unsigned int right_idx, unsigned int depth, unsigned int max_shallow_depth,
|
||||
const P &p, const Pred &pred) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildShallowTree(std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx,
|
||||
unsigned int right_idx,
|
||||
unsigned int depth,
|
||||
unsigned int max_shallow_depth,
|
||||
const P &p, const Pred &pred) {
|
||||
assert(left_idx <= right_idx);
|
||||
|
||||
unsigned int offset = static_cast<unsigned int>(out_nodes->size());
|
||||
@ -1424,11 +1500,13 @@ unsigned int BVHAccel<T>::BuildShallowTree(
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> template<class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildTree(
|
||||
BVHBuildStatistics *out_stat, std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx, unsigned int right_idx, unsigned int depth,
|
||||
const P &p, const Pred &pred) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
unsigned int BVHAccel<T>::BuildTree(BVHBuildStatistics *out_stat,
|
||||
std::vector<BVHNode<T> > *out_nodes,
|
||||
unsigned int left_idx,
|
||||
unsigned int right_idx, unsigned int depth,
|
||||
const P &p, const Pred &pred) {
|
||||
assert(left_idx <= right_idx);
|
||||
|
||||
unsigned int offset = static_cast<unsigned int>(out_nodes->size());
|
||||
@ -1554,10 +1632,10 @@ unsigned int BVHAccel<T>::BuildTree(
|
||||
return offset;
|
||||
}
|
||||
|
||||
template <typename T> template<class P, class Pred>
|
||||
bool BVHAccel<T>::Build(unsigned int num_primitives,
|
||||
const P &p, const Pred &pred,
|
||||
const BVHBuildOptions<T> &options) {
|
||||
template <typename T>
|
||||
template <class P, class Pred>
|
||||
bool BVHAccel<T>::Build(unsigned int num_primitives, const P &p,
|
||||
const Pred &pred, const BVHBuildOptions<T> &options) {
|
||||
options_ = options;
|
||||
stats_ = BVHBuildStatistics();
|
||||
|
||||
@ -1566,6 +1644,10 @@ bool BVHAccel<T>::Build(unsigned int num_primitives,
|
||||
|
||||
assert(options_.bin_size > 1);
|
||||
|
||||
if (num_primitives == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int n = num_primitives;
|
||||
|
||||
//
|
||||
@ -1697,15 +1779,9 @@ void BVHAccel<T>::Debug() {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n",
|
||||
int(i),
|
||||
nodes_[i].bmin[0],
|
||||
nodes_[i].bmin[1],
|
||||
nodes_[i].bmin[1],
|
||||
nodes_[i].bmax[0],
|
||||
nodes_[i].bmax[1],
|
||||
nodes_[i].bmax[1]);
|
||||
|
||||
printf("node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n", int(i),
|
||||
nodes_[i].bmin[0], nodes_[i].bmin[1], nodes_[i].bmin[1],
|
||||
nodes_[i].bmax[0], nodes_[i].bmax[1], nodes_[i].bmax[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1713,7 +1789,7 @@ template <typename T>
|
||||
bool BVHAccel<T>::Dump(const char *filename) {
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
if (!fp) {
|
||||
//fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename);
|
||||
// fprintf(stderr, "[BVHAccel] Cannot write a file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1744,7 +1820,7 @@ template <typename T>
|
||||
bool BVHAccel<T>::Load(const char *filename) {
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
//fprintf(stderr, "Cannot open file: %s\n", filename);
|
||||
// fprintf(stderr, "Cannot open file: %s\n", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1815,10 +1891,10 @@ inline bool IntersectRayAABB(T *tminOut, // [out]
|
||||
return false; // no hit
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const I &intersector) const {
|
||||
template <typename T>
|
||||
template <class I>
|
||||
inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node, const Ray<T> &ray,
|
||||
const I &intersector) const {
|
||||
bool hit = false;
|
||||
|
||||
unsigned int num_primitives = node.data[0];
|
||||
@ -1841,20 +1917,18 @@ inline bool BVHAccel<T>::TestLeafNode(const BVHNode<T> &node,
|
||||
|
||||
T local_t = t;
|
||||
if (intersector.Intersect(&local_t, prim_idx)) {
|
||||
if (local_t > ray.min_t) {
|
||||
// Update isect state
|
||||
t = local_t;
|
||||
// Update isect state
|
||||
t = local_t;
|
||||
|
||||
intersector.Update(t, prim_idx);
|
||||
hit = true;
|
||||
}
|
||||
intersector.Update(t, prim_idx);
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Implement
|
||||
#if 0 // TODO(LTE): Implement
|
||||
template <typename T> template<class I, class H, class Comp>
|
||||
bool BVHAccel<T>::MultiHitTestLeafNode(
|
||||
std::priority_queue<H, std::vector<H>, Comp> *isect_pq,
|
||||
@ -1928,11 +2002,10 @@ bool BVHAccel<T>::MultiHitTestLeafNode(
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> template<class I, class H>
|
||||
bool BVHAccel<T>::Traverse(const Ray<T> &ray,
|
||||
const I &intersector,
|
||||
H *isect,
|
||||
const BVHTraceOptions &options) const {
|
||||
template <typename T>
|
||||
template <class I, class H>
|
||||
bool BVHAccel<T>::Traverse(const Ray<T> &ray, const I &intersector, H *isect,
|
||||
const BVHTraceOptions &options) const {
|
||||
const int kMaxStackDepth = 512;
|
||||
|
||||
T hit_t = ray.max_t;
|
||||
@ -1999,13 +2072,14 @@ bool BVHAccel<T>::Traverse(const Ray<T> &ray,
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
const Ray<T> &ray,
|
||||
const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > *isect_pq) const {
|
||||
|
||||
template <typename T>
|
||||
template <class I>
|
||||
inline bool BVHAccel<T>::TestLeafNodeIntersections(
|
||||
const BVHNode<T> &node, const Ray<T> &ray, const int max_intersections,
|
||||
const I &intersector,
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> > *isect_pq) const {
|
||||
bool hit = false;
|
||||
|
||||
unsigned int num_primitives = node.data[0];
|
||||
@ -2043,7 +2117,6 @@ inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
isect_pq->pop();
|
||||
|
||||
isect_pq->push(isect);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2052,11 +2125,11 @@ inline bool BVHAccel<T>::TestLeafNodeIntersections(const BVHNode<T> &node,
|
||||
return hit;
|
||||
}
|
||||
|
||||
template <typename T> template<class I>
|
||||
bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const {
|
||||
template <typename T>
|
||||
template <class I>
|
||||
bool BVHAccel<T>::ListNodeIntersections(
|
||||
const Ray<T> &ray, int max_intersections, const I &intersector,
|
||||
StackVector<NodeHit<T>, 128> *hits) const {
|
||||
const int kMaxStackDepth = 512;
|
||||
|
||||
T hit_t = ray.max_t;
|
||||
@ -2066,14 +2139,19 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
node_stack[0] = 0;
|
||||
|
||||
// Stores furthest intersection at top
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >, NodeHitComparator<T> > isect_pq;
|
||||
std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
|
||||
NodeHitComparator<T> >
|
||||
isect_pq;
|
||||
|
||||
(*hits)->clear();
|
||||
|
||||
int dir_sign[3];
|
||||
dir_sign[0] = ray.dir[0] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[1] = ray.dir[1] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[2] = ray.dir[2] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
dir_sign[0] =
|
||||
ray.dir[0] < static_cast<T>(0.0) ? 1 : 0;
|
||||
dir_sign[1] =
|
||||
ray.dir[1] < static_cast<T>(0.0) ? 1 : 0;
|
||||
dir_sign[2] =
|
||||
ray.dir[2] < static_cast<T>(0.0) ? 1 : 0;
|
||||
|
||||
// @fixme { Check edge case; i.e., 1/0 }
|
||||
real3<T> ray_inv_dir;
|
||||
@ -2108,7 +2186,8 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
|
||||
} else { // leaf node
|
||||
if (hit) {
|
||||
TestLeafNodeIntersections(node, ray, max_intersections, intersector, &isect_pq);
|
||||
TestLeafNodeIntersections(node, ray, max_intersections, intersector,
|
||||
&isect_pq);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2132,7 +2211,7 @@ bool BVHAccel<T>::ListNodeIntersections(const Ray<T> &ray,
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Implement
|
||||
#if 0 // TODO(LTE): Implement
|
||||
template <typename T> template<class I, class H, class Comp>
|
||||
bool BVHAccel<T>::MultiHitTraverse(const Ray<T> &ray,
|
||||
int max_intersections,
|
||||
@ -2225,6 +2304,10 @@ bool BVHAccel<T>::MultiHitTraverse(const Ray<T> &ray,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace nanort
|
||||
|
||||
#endif // NANORT_H_
|
||||
|
@ -31,35 +31,36 @@ THE SOFTWARE.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "nanort.h"
|
||||
|
||||
namespace nanosg {
|
||||
|
||||
template<class T>
|
||||
template <class T>
|
||||
class PrimitiveInterface;
|
||||
|
||||
template<class T>
|
||||
class PrimitiveInterface{
|
||||
public:
|
||||
void print(){ static_cast<T &>(this)->print(); }
|
||||
template <class T>
|
||||
class PrimitiveInterface {
|
||||
public:
|
||||
void print() { static_cast<T &>(this)->print(); }
|
||||
};
|
||||
|
||||
class SpherePrimitive : PrimitiveInterface<SpherePrimitive> {
|
||||
public:
|
||||
void print(){ std::cout << "Sphere" << std::endl; }
|
||||
public:
|
||||
void print() { std::cout << "Sphere" << std::endl; }
|
||||
};
|
||||
|
||||
// 4x4 matrix
|
||||
template <typename T> class Matrix {
|
||||
public:
|
||||
template <typename T>
|
||||
class Matrix {
|
||||
public:
|
||||
Matrix();
|
||||
~Matrix();
|
||||
|
||||
static void Print(T m[4][4]) {
|
||||
static void Print(const T m[4][4]) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
printf("m[%d] = %f, %f, %f, %f\n", i, m[i][0], m[i][1], m[i][2], m[i][3]);
|
||||
}
|
||||
@ -232,18 +233,15 @@ public:
|
||||
dst[1] = tmp[1];
|
||||
dst[2] = tmp[2];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//typedef Matrix<float> Matrixf;
|
||||
//typedef Matrix<double> Matrixd;
|
||||
|
||||
template<typename T>
|
||||
static void XformBoundingBox(T xbmin[3], // out
|
||||
T xbmax[3], // out
|
||||
T bmin[3], T bmax[3],
|
||||
T m[4][4]) {
|
||||
// typedef Matrix<float> Matrixf;
|
||||
// typedef Matrix<double> Matrixd;
|
||||
|
||||
template <typename T>
|
||||
static void XformBoundingBox(T xbmin[3], // out
|
||||
T xbmax[3], // out
|
||||
T bmin[3], T bmax[3], T m[4][4]) {
|
||||
// create bounding vertex from (bmin, bmax)
|
||||
T b[8][3];
|
||||
|
||||
@ -286,7 +284,6 @@ static void XformBoundingBox(T xbmin[3], // out
|
||||
xbmax[2] = xb[0][2];
|
||||
|
||||
for (int i = 1; i < 8; i++) {
|
||||
|
||||
xbmin[0] = std::min(xb[i][0], xbmin[0]);
|
||||
xbmin[1] = std::min(xb[i][1], xbmin[1]);
|
||||
xbmin[2] = std::min(xb[i][2], xbmin[2]);
|
||||
@ -297,48 +294,45 @@ static void XformBoundingBox(T xbmin[3], // out
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Intersection
|
||||
{
|
||||
template <typename T>
|
||||
struct Intersection {
|
||||
// required fields.
|
||||
T t; // hit distance
|
||||
unsigned int prim_id; // primitive ID of the hit
|
||||
float u;
|
||||
float v;
|
||||
T t; // hit distance
|
||||
unsigned int prim_id; // primitive ID of the hit
|
||||
float u;
|
||||
float v;
|
||||
|
||||
unsigned int node_id; // node ID of the hit.
|
||||
nanort::real3<T> P; // intersection point
|
||||
nanort::real3<T> Ns; // shading normal
|
||||
nanort::real3<T> Ng; // geometric normal
|
||||
unsigned int node_id; // node ID of the hit.
|
||||
nanort::real3<T> P; // intersection point
|
||||
nanort::real3<T> Ns; // shading normal
|
||||
nanort::real3<T> Ng; // geometric normal
|
||||
};
|
||||
|
||||
///
|
||||
/// Renderable node
|
||||
///
|
||||
template<typename T, class M>
|
||||
class Node
|
||||
{
|
||||
template <typename T, class M>
|
||||
class Node {
|
||||
public:
|
||||
typedef Node<T, M> type;
|
||||
|
||||
explicit Node(const M *mesh)
|
||||
: mesh_(mesh)
|
||||
{
|
||||
xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits<T>::max();
|
||||
xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits<T>::max();
|
||||
explicit Node(const M *mesh) : mesh_(mesh) {
|
||||
xbmin_[0] = xbmin_[1] = xbmin_[2] = std::numeric_limits<T>::max();
|
||||
xbmax_[0] = xbmax_[1] = xbmax_[2] = -std::numeric_limits<T>::max();
|
||||
|
||||
lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits<T>::max();
|
||||
lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits<T>::max();
|
||||
lbmin_[0] = lbmin_[1] = lbmin_[2] = std::numeric_limits<T>::max();
|
||||
lbmax_[0] = lbmax_[1] = lbmax_[2] = -std::numeric_limits<T>::max();
|
||||
|
||||
Matrix<T>::Identity(local_xform_);
|
||||
Matrix<T>::Identity(xform_);
|
||||
Matrix<T>::Identity(inv_xform_);
|
||||
Matrix<T>::Identity(inv_xform33_); inv_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_transpose_xform33_); inv_transpose_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_xform33_);
|
||||
inv_xform33_[3][3] = static_cast<T>(0.0);
|
||||
Matrix<T>::Identity(inv_transpose_xform33_);
|
||||
inv_transpose_xform33_[3][3] = static_cast<T>(0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~Node() {}
|
||||
~Node() {}
|
||||
|
||||
void Copy(const type &rhs) {
|
||||
Matrix<T>::Copy(local_xform_, rhs.local_xform_);
|
||||
@ -369,53 +363,44 @@ class Node
|
||||
children_ = rhs.children_;
|
||||
}
|
||||
|
||||
Node(const type &rhs) {
|
||||
Copy(rhs);
|
||||
}
|
||||
Node(const type &rhs) { Copy(rhs); }
|
||||
|
||||
const type &operator=(const type &rhs) {
|
||||
Copy(rhs);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void SetName(const std::string &name) {
|
||||
name_ = name;
|
||||
}
|
||||
void SetName(const std::string &name) { name_ = name; }
|
||||
|
||||
const std::string &GetName() const {
|
||||
return name_;
|
||||
}
|
||||
const std::string &GetName() const { return name_; }
|
||||
|
||||
///
|
||||
/// Add child node.
|
||||
///
|
||||
void AddChild(const type &child) {
|
||||
children_.push_back(child);
|
||||
}
|
||||
void AddChild(const type &child) { children_.push_back(child); }
|
||||
|
||||
///
|
||||
/// Get chidren
|
||||
///
|
||||
const std::vector<type> &GetChildren() const {
|
||||
return children_;
|
||||
}
|
||||
const std::vector<type> &GetChildren() const { return children_; }
|
||||
|
||||
std::vector<type> &GetChildren() {
|
||||
return children_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Update internal state.
|
||||
///
|
||||
void Update(const T parent_xform[4][4]) {
|
||||
|
||||
if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) && (mesh_->faces.size() >= 3)) {
|
||||
std::vector<type> &GetChildren() { return children_; }
|
||||
|
||||
///
|
||||
/// Update internal state.
|
||||
///
|
||||
void Update(const T parent_xform[4][4]) {
|
||||
if (!accel_.IsValid() && mesh_ && (mesh_->vertices.size() > 3) &&
|
||||
(mesh_->faces.size() >= 3)) {
|
||||
// Assume mesh is composed of triangle faces only.
|
||||
nanort::TriangleMesh<float> triangle_mesh(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
||||
nanort::TriangleSAHPred<float> triangle_pred(mesh_->vertices.data(), mesh_->faces.data(), sizeof(float) * 3);
|
||||
nanort::TriangleMesh<float> triangle_mesh(
|
||||
mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride);
|
||||
nanort::TriangleSAHPred<float> triangle_pred(
|
||||
mesh_->vertices.data(), mesh_->faces.data(), mesh_->stride);
|
||||
|
||||
bool ret = accel_.Build(int(mesh_->faces.size()) / 3, triangle_mesh, triangle_pred);
|
||||
bool ret =
|
||||
accel_.Build(static_cast<unsigned int>(mesh_->faces.size()) / 3,
|
||||
triangle_mesh, triangle_pred);
|
||||
|
||||
// Update local bbox.
|
||||
if (ret) {
|
||||
@ -433,7 +418,7 @@ class Node
|
||||
Matrix<T>::Copy(inv_xform_, xform_);
|
||||
Matrix<T>::Inverse(inv_xform_);
|
||||
|
||||
// Clear translation, then inverse(xform)
|
||||
// Clear translation, then inverse(xform)
|
||||
Matrix<T>::Copy(inv_xform33_, xform_);
|
||||
inv_xform33_[3][0] = static_cast<T>(0.0);
|
||||
inv_xform33_[3][1] = static_cast<T>(0.0);
|
||||
@ -448,67 +433,61 @@ class Node
|
||||
for (size_t i = 0; i < children_.size(); i++) {
|
||||
children_[i].Update(xform_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Set local transformation.
|
||||
///
|
||||
///
|
||||
/// Set local transformation.
|
||||
///
|
||||
void SetLocalXform(const T xform[4][4]) {
|
||||
memcpy(local_xform_, xform, sizeof(float) * 16);
|
||||
}
|
||||
|
||||
const T *GetLocalXformPtr() const {
|
||||
return &local_xform_[0][0];
|
||||
const T *GetLocalXformPtr() const { return &local_xform_[0][0]; }
|
||||
|
||||
const T *GetXformPtr() const { return &xform_[0][0]; }
|
||||
|
||||
const M *GetMesh() const { return mesh_; }
|
||||
|
||||
const nanort::BVHAccel<T> &GetAccel() const { return accel_; }
|
||||
|
||||
inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = xbmin_[0];
|
||||
bmin[1] = xbmin_[1];
|
||||
bmin[2] = xbmin_[2];
|
||||
|
||||
bmax[0] = xbmax_[0];
|
||||
bmax[1] = xbmax_[1];
|
||||
bmax[2] = xbmax_[2];
|
||||
}
|
||||
|
||||
const T *GetXformPtr() const {
|
||||
return &xform_[0][0];
|
||||
inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = lbmin_[0];
|
||||
bmin[1] = lbmin_[1];
|
||||
bmin[2] = lbmin_[2];
|
||||
|
||||
bmax[0] = lbmax_[0];
|
||||
bmax[1] = lbmax_[1];
|
||||
bmax[2] = lbmax_[2];
|
||||
}
|
||||
|
||||
const M *GetMesh() const {
|
||||
return mesh_;
|
||||
}
|
||||
|
||||
const nanort::BVHAccel<T> &GetAccel() const {
|
||||
return accel_;
|
||||
}
|
||||
|
||||
inline void GetWorldBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = xbmin_[0];
|
||||
bmin[1] = xbmin_[1];
|
||||
bmin[2] = xbmin_[2];
|
||||
|
||||
bmax[0] = xbmax_[0];
|
||||
bmax[1] = xbmax_[1];
|
||||
bmax[2] = xbmax_[2];
|
||||
}
|
||||
|
||||
inline void GetLocalBoundingBox(T bmin[3], T bmax[3]) const {
|
||||
bmin[0] = lbmin_[0];
|
||||
bmin[1] = lbmin_[1];
|
||||
bmin[2] = lbmin_[2];
|
||||
|
||||
bmax[0] = lbmax_[0];
|
||||
bmax[1] = lbmax_[1];
|
||||
bmax[2] = lbmax_[2];
|
||||
}
|
||||
|
||||
T local_xform_[4][4]; // Node's local transformation matrix.
|
||||
T xform_[4][4]; // Parent xform x local_xform.
|
||||
T inv_xform_[4][4]; // inverse(xform). world -> local
|
||||
T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for transforming direction vector)
|
||||
T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left 3x3 elements only(for transforming normal vector)
|
||||
T local_xform_[4][4]; // Node's local transformation matrix.
|
||||
T xform_[4][4]; // Parent xform x local_xform.
|
||||
T inv_xform_[4][4]; // inverse(xform). world -> local
|
||||
T inv_xform33_[4][4]; // inverse(xform0 with upper-left 3x3 elemets only(for
|
||||
// transforming direction vector)
|
||||
T inv_transpose_xform33_[4][4]; // inverse(transpose(xform)) with upper-left
|
||||
// 3x3 elements only(for transforming normal
|
||||
// vector)
|
||||
|
||||
private:
|
||||
// bounding box(local space)
|
||||
T lbmin_[3];
|
||||
T lbmax_[3];
|
||||
|
||||
// bounding box(local space)
|
||||
T lbmin_[3];
|
||||
T lbmax_[3];
|
||||
// bounding box after xform(world space)
|
||||
T xbmin_[3];
|
||||
T xbmax_[3];
|
||||
|
||||
// bounding box after xform(world space)
|
||||
T xbmin_[3];
|
||||
T xbmax_[3];
|
||||
|
||||
nanort::BVHAccel<T> accel_;
|
||||
|
||||
std::string name_;
|
||||
@ -516,16 +495,16 @@ class Node
|
||||
const M *mesh_;
|
||||
|
||||
std::vector<type> children_;
|
||||
|
||||
};
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
// Predefined SAH predicator for cube.
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxPred {
|
||||
public:
|
||||
NodeBBoxPred(const std::vector<Node<T, M> >* nodes) : axis_(0), pos_(0.0f), nodes_(nodes) {}
|
||||
NodeBBoxPred(const std::vector<Node<T, M> > *nodes)
|
||||
: axis_(0), pos_(0.0f), nodes_(nodes) {}
|
||||
|
||||
void Set(int axis, float pos) const {
|
||||
axis_ = axis;
|
||||
@ -538,8 +517,8 @@ class NodeBBoxPred {
|
||||
|
||||
T bmin[3], bmax[3];
|
||||
|
||||
(*nodes_)[i].GetWorldBoundingBox(bmin, bmax);
|
||||
|
||||
(*nodes_)[i].GetWorldBoundingBox(bmin, bmax);
|
||||
|
||||
T center = bmax[axis] - bmin[axis];
|
||||
|
||||
return (center < pos);
|
||||
@ -551,15 +530,15 @@ class NodeBBoxPred {
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxGeometry {
|
||||
public:
|
||||
NodeBBoxGeometry(const std::vector<Node<T, M> >* nodes)
|
||||
: nodes_(nodes) {}
|
||||
NodeBBoxGeometry(const std::vector<Node<T, M> > *nodes) : nodes_(nodes) {}
|
||||
|
||||
/// Compute bounding box for `prim_index`th cube.
|
||||
/// This function is called for each primitive in BVH build.
|
||||
void BoundingBox(nanort::real3<T>* bmin, nanort::real3<T>* bmax, unsigned int prim_index) const {
|
||||
void BoundingBox(nanort::real3<T> *bmin, nanort::real3<T> *bmax,
|
||||
unsigned int prim_index) const {
|
||||
T a[3], b[3];
|
||||
(*nodes_)[prim_index].GetWorldBoundingBox(a, b);
|
||||
(*bmin)[0] = a[0];
|
||||
@ -570,10 +549,11 @@ class NodeBBoxGeometry {
|
||||
(*bmax)[2] = b[2];
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> >* nodes_;
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
mutable nanort::real3<T> ray_org_;
|
||||
mutable nanort::real3<T> ray_dir_;
|
||||
mutable nanort::BVHTraceOptions trace_options_;
|
||||
int _pad_;
|
||||
};
|
||||
|
||||
class NodeBBoxIntersection {
|
||||
@ -587,14 +567,13 @@ class NodeBBoxIntersection {
|
||||
unsigned int prim_id;
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
template <typename T, class M>
|
||||
class NodeBBoxIntersector {
|
||||
public:
|
||||
NodeBBoxIntersector(const std::vector<Node<T, M> >* nodes)
|
||||
: nodes_(nodes) {}
|
||||
|
||||
bool Intersect(float* out_t_min, float *out_t_max, unsigned int prim_index) const {
|
||||
NodeBBoxIntersector(const std::vector<Node<T, M> > *nodes) : nodes_(nodes) {}
|
||||
|
||||
bool Intersect(float *out_t_min, float *out_t_max,
|
||||
unsigned int prim_index) const {
|
||||
T bmin[3], bmax[3];
|
||||
|
||||
(*nodes_)[prim_index].GetWorldBoundingBox(bmin, bmax);
|
||||
@ -634,7 +613,7 @@ class NodeBBoxIntersector {
|
||||
|
||||
/// Prepare BVH traversal(e.g. compute inverse ray direction)
|
||||
/// This function is called only once in BVH traversal.
|
||||
void PrepareTraversal(const nanort::Ray<float>& ray) const {
|
||||
void PrepareTraversal(const nanort::Ray<float> &ray) const {
|
||||
ray_org_[0] = ray.org[0];
|
||||
ray_org_[1] = ray.org[1];
|
||||
ray_org_[2] = ray.org[2];
|
||||
@ -648,40 +627,37 @@ class NodeBBoxIntersector {
|
||||
ray_inv_dir_[1] = static_cast<T>(1.0) / ray.dir[1];
|
||||
ray_inv_dir_[2] = static_cast<T>(1.0) / ray.dir[2];
|
||||
|
||||
ray_dir_sign_[0] = ray.dir[0] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
ray_dir_sign_[0] = ray.dir[0] < static_cast<T>(0.0) ? 1 : 0;
|
||||
ray_dir_sign_[1] = ray.dir[1] < static_cast<T>(0.0) ? 1 : 0;
|
||||
ray_dir_sign_[2] = ray.dir[2] < static_cast<T>(0.0) ? 1 : 0;
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> >* nodes_;
|
||||
const std::vector<Node<T, M> > *nodes_;
|
||||
mutable nanort::real3<T> ray_org_;
|
||||
mutable nanort::real3<T> ray_dir_;
|
||||
mutable nanort::real3<T> ray_inv_dir_;
|
||||
mutable int ray_dir_sign_[3];
|
||||
};
|
||||
|
||||
template<typename T, class M>
|
||||
class Scene
|
||||
{
|
||||
template <typename T, class M>
|
||||
class Scene {
|
||||
public:
|
||||
Scene() {
|
||||
Scene() {
|
||||
bmin_[0] = bmin_[1] = bmin_[2] = std::numeric_limits<T>::max();
|
||||
bmax_[0] = bmax_[1] = bmax_[2] = -std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
~Scene() {};
|
||||
~Scene() {}
|
||||
|
||||
///
|
||||
/// Add intersectable node to the scene.
|
||||
///
|
||||
bool AddNode(const Node<T, M> &node) {
|
||||
bool AddNode(const Node<T, M> &node) {
|
||||
nodes_.push_back(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<Node<T, M> > &GetNodes() const {
|
||||
return nodes_;
|
||||
}
|
||||
const std::vector<Node<T, M> > &GetNodes() const { return nodes_; }
|
||||
|
||||
bool FindNode(const std::string &name, Node<T, M> **found_node) {
|
||||
if (!found_node) {
|
||||
@ -702,11 +678,15 @@ class Scene
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Commit the scene. Must be called before tracing rays into the scene.
|
||||
///
|
||||
bool Commit() {
|
||||
// the scene should contains something
|
||||
if (nodes_.size() == 0) {
|
||||
std::cerr << "You are attempting to commit an empty scene!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update nodes.
|
||||
for (size_t i = 0; i < nodes_.size(); i++) {
|
||||
@ -719,21 +699,26 @@ class Scene
|
||||
// Build toplevel BVH.
|
||||
NodeBBoxGeometry<T, M> geom(&nodes_);
|
||||
NodeBBoxPred<T, M> pred(&nodes_);
|
||||
|
||||
// FIXME(LTE): Limit one leaf contains one node bbox primitive. This would work, but would be inefficient.
|
||||
// e.g. will miss some node when constructed BVH depth is larger than the value of BVHBuildOptions.
|
||||
// Implement more better and efficient BVH build and traverse for Toplevel BVH.
|
||||
|
||||
// FIXME(LTE): Limit one leaf contains one node bbox primitive. This would
|
||||
// work, but would be inefficient.
|
||||
// e.g. will miss some node when constructed BVH depth is larger than the
|
||||
// value of BVHBuildOptions.
|
||||
// Implement more better and efficient BVH build and traverse for Toplevel
|
||||
// BVH.
|
||||
nanort::BVHBuildOptions<T> build_options;
|
||||
build_options.min_leaf_primitives = 1;
|
||||
|
||||
bool ret = toplevel_accel_.Build(static_cast<unsigned int>(nodes_.size()), geom, pred, build_options);
|
||||
|
||||
bool ret = toplevel_accel_.Build(static_cast<unsigned int>(nodes_.size()),
|
||||
geom, pred, build_options);
|
||||
|
||||
nanort::BVHBuildStatistics stats = toplevel_accel_.GetStatistics();
|
||||
(void)stats;
|
||||
|
||||
//toplevel_accel_.Debug();
|
||||
// toplevel_accel_.Debug();
|
||||
|
||||
if (ret) {
|
||||
toplevel_accel_.BoundingBox(bmin_, bmax_);
|
||||
toplevel_accel_.BoundingBox(bmin_, bmax_);
|
||||
} else {
|
||||
// Set invalid bbox value.
|
||||
bmin_[0] = std::numeric_limits<T>::max();
|
||||
@ -766,51 +751,54 @@ class Scene
|
||||
/// First find the intersection of nodes' bounding box using toplevel BVH.
|
||||
/// Then, trace into the hit node to find the intersection of the primitive.
|
||||
///
|
||||
template<class H>
|
||||
bool Traverse(nanort::Ray<T> &ray, H *isect, const bool cull_back_face = false) const {
|
||||
|
||||
template <class H>
|
||||
bool Traverse(nanort::Ray<T> &ray, H *isect,
|
||||
const bool cull_back_face = false) const {
|
||||
if (!toplevel_accel_.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int kMaxIntersections = 64;
|
||||
const int kMaxIntersections = 64;
|
||||
|
||||
bool has_hit = false;
|
||||
|
||||
|
||||
NodeBBoxIntersector<T, M> isector(&nodes_);
|
||||
nanort::StackVector<nanort::NodeHit<T>, 128> node_hits;
|
||||
bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections, isector, &node_hits);
|
||||
bool may_hit = toplevel_accel_.ListNodeIntersections(ray, kMaxIntersections,
|
||||
isector, &node_hits);
|
||||
|
||||
if (may_hit) {
|
||||
|
||||
T t_max = std::numeric_limits<T>::max();
|
||||
T t_nearest = t_max;
|
||||
if (may_hit) {
|
||||
T t_max = std::numeric_limits<T>::max();
|
||||
T t_nearest = t_max;
|
||||
|
||||
nanort::BVHTraceOptions trace_options;
|
||||
trace_options.cull_back_face = cull_back_face;
|
||||
|
||||
// Find actual intersection point.
|
||||
for (size_t i = 0; i < node_hits->size(); i++) {
|
||||
|
||||
// Early cull test.
|
||||
// Find actual intersection point.
|
||||
for (size_t i = 0; i < node_hits->size(); i++) {
|
||||
// Early cull test.
|
||||
if (t_nearest < node_hits[i].t_min) {
|
||||
//printf("near: %f, t_min: %f, t_max: %f\n", t_nearest, node_hits[i].t_min, node_hits[i].t_max);
|
||||
// printf("near: %f, t_min: %f, t_max: %f\n", t_nearest,
|
||||
// node_hits[i].t_min, node_hits[i].t_max);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(node_hits[i].node_id < nodes_.size());
|
||||
const Node<T, M> &node = nodes_[node_hits[i].node_id];
|
||||
|
||||
// Transform ray into node's local space
|
||||
// Transform ray into node's local space
|
||||
// TODO(LTE): Set ray tmin and tmax
|
||||
nanort::Ray<T> local_ray;
|
||||
Matrix<T>::MultV(local_ray.org, node.inv_xform_, ray.org);
|
||||
Matrix<T>::MultV(local_ray.dir, node.inv_xform33_, ray.dir);
|
||||
|
||||
nanort::TriangleIntersector<T, H> triangle_intersector(node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(), sizeof(T) * 3);
|
||||
nanort::TriangleIntersector<T, H> triangle_intersector(
|
||||
node.GetMesh()->vertices.data(), node.GetMesh()->faces.data(),
|
||||
node.GetMesh()->stride);
|
||||
H local_isect;
|
||||
|
||||
bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector, &local_isect);
|
||||
bool hit = node.GetAccel().Traverse(local_ray, triangle_intersector,
|
||||
&local_isect);
|
||||
|
||||
if (hit) {
|
||||
// Calulcate hit distance in world coordiante.
|
||||
@ -828,6 +816,7 @@ class Scene
|
||||
po[2] = world_P[2] - ray.org[2];
|
||||
|
||||
float t_world = vlength(po);
|
||||
// printf("tworld %f, tnear %f\n", t_world, t_nearest);
|
||||
|
||||
if (t_world < t_nearest) {
|
||||
t_nearest = t_world;
|
||||
@ -839,36 +828,30 @@ class Scene
|
||||
isect->v = local_isect.v;
|
||||
|
||||
// TODO(LTE): Implement
|
||||
T Ng[3], Ns[3]; // geometric normal, shading normal.
|
||||
T Ng[3], Ns[3]; // geometric normal, shading normal.
|
||||
|
||||
node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u,
|
||||
isect->v);
|
||||
|
||||
node.GetMesh()->GetNormal(Ng, Ns, isect->prim_id, isect->u, isect->v);
|
||||
|
||||
// Convert position and normal into world coordinate.
|
||||
isect->t = t_world;
|
||||
Matrix<T>::MultV(isect->P, node.xform_, local_P);
|
||||
Matrix<T>::MultV(isect->Ng, node.inv_transpose_xform33_,
|
||||
Ng);
|
||||
Matrix<T>::MultV(isect->Ns, node.inv_transpose_xform33_,
|
||||
Ns);
|
||||
}
|
||||
|
||||
Matrix<T>::MultV(isect->Ng, node.inv_transpose_xform33_, Ng);
|
||||
Matrix<T>::MultV(isect->Ns, node.inv_transpose_xform33_, Ns);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return has_hit;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
///
|
||||
/// Find a node by name.
|
||||
///
|
||||
bool FindNodeRecursive(const std::string &name, Node<T, M> *root, Node<T, M> **found_node) {
|
||||
|
||||
///
|
||||
bool FindNodeRecursive(const std::string &name, Node<T, M> *root,
|
||||
Node<T, M> **found_node) {
|
||||
if (root->GetName().compare(name) == 0) {
|
||||
(*found_node) = root;
|
||||
return true;
|
||||
@ -882,19 +865,18 @@ class Scene
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Scene bounding box.
|
||||
// Valid after calling `Commit()`.
|
||||
T bmin_[3];
|
||||
T bmax_[3];
|
||||
|
||||
|
||||
// Toplevel BVH accel.
|
||||
nanort::BVHAccel<T> toplevel_accel_;
|
||||
std::vector<Node<T, M> > nodes_;
|
||||
std::vector<Node<T, M> > nodes_;
|
||||
};
|
||||
|
||||
} // namespace nanosg
|
||||
} // namespace nanosg
|
||||
|
||||
#endif // NANOSG_H_
|
||||
#endif // NANOSG_H_
|
||||
|
458
examples/raytrace/obj-loader.cc
Normal file
458
examples/raytrace/obj-loader.cc
Normal file
@ -0,0 +1,458 @@
|
||||
#include "obj-loader.h"
|
||||
#include "nanort.h" // for float3
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
|
||||
#pragma clang diagnostic ignored "-Wcast-align"
|
||||
#pragma clang diagnostic ignored "-Wpadded"
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
||||
#pragma clang diagnostic ignored "-Wvariadic-macros"
|
||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#if __has_warning("-Wdouble-promotion")
|
||||
#pragma clang diagnostic ignored "-Wdouble-promotion"
|
||||
#endif
|
||||
#if __has_warning("-Wcomma")
|
||||
#pragma clang diagnostic ignored "-Wcomma"
|
||||
#endif
|
||||
#if __has_warning("-Wcast-qual")
|
||||
#pragma clang diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "stb_image.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
#include <unordered_map>
|
||||
#else
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
#define USE_TEX_CACHE 1
|
||||
|
||||
namespace example {
|
||||
|
||||
typedef nanort::real3<float> float3;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
// TODO(LTE): Remove global static definition.
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
static std::unordered_map<std::string, int> hashed_tex;
|
||||
#else
|
||||
static std::map<std::string, int> hashed_tex;
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
inline void CalcNormal(float3 &N, float3 v0, float3 v1, float3 v2) {
|
||||
float3 v10 = v1 - v0;
|
||||
float3 v20 = v2 - v0;
|
||||
|
||||
N = vcross(v20, v10);
|
||||
N = vnormalize(N);
|
||||
}
|
||||
|
||||
static std::string GetBaseDir(const std::string &filepath) {
|
||||
if (filepath.find_last_of("/\\") != std::string::npos)
|
||||
return filepath.substr(0, filepath.find_last_of("/\\"));
|
||||
return "";
|
||||
}
|
||||
|
||||
static int LoadTexture(const std::string &filename,
|
||||
std::vector<Texture> *textures) {
|
||||
int idx;
|
||||
|
||||
if (filename.empty()) return -1;
|
||||
|
||||
std::cout << " Loading texture : " << filename << std::endl;
|
||||
Texture texture;
|
||||
|
||||
// tigra: find in cache. get index
|
||||
if (USE_TEX_CACHE) {
|
||||
if (hashed_tex.find(filename) != hashed_tex.end()) {
|
||||
puts("from cache");
|
||||
return hashed_tex[filename];
|
||||
}
|
||||
}
|
||||
|
||||
int w, h, n;
|
||||
unsigned char *data = stbi_load(filename.c_str(), &w, &h, &n, 0);
|
||||
if (data) {
|
||||
texture.width = w;
|
||||
texture.height = h;
|
||||
texture.components = n;
|
||||
|
||||
size_t n_elem = size_t(w * h * n);
|
||||
texture.image = new unsigned char[n_elem];
|
||||
for (size_t i = 0; i < n_elem; i++) {
|
||||
texture.image[i] = data[i];
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
textures->push_back(texture);
|
||||
|
||||
idx = int(textures->size()) - 1;
|
||||
|
||||
// tigra: store index to cache
|
||||
if (USE_TEX_CACHE) {
|
||||
hashed_tex[filename] = idx;
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
std::cout << " Failed to load : " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ComputeBoundingBoxOfMesh(float bmin[3], float bmax[3],
|
||||
const example::Mesh<float> &mesh) {
|
||||
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
|
||||
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
|
||||
|
||||
for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
|
||||
bmin[0] = std::min(bmin[0], mesh.vertices[3 * i + 0]);
|
||||
bmin[1] = std::min(bmin[1], mesh.vertices[3 * i + 1]);
|
||||
bmin[2] = std::min(bmin[1], mesh.vertices[3 * i + 2]);
|
||||
|
||||
bmax[0] = std::max(bmax[0], mesh.vertices[3 * i + 0]);
|
||||
bmax[1] = std::max(bmax[1], mesh.vertices[3 * i + 1]);
|
||||
bmax[2] = std::max(bmax[2], mesh.vertices[3 * i + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadObj(const std::string &filename, float scale,
|
||||
std::vector<Mesh<float> > *meshes,
|
||||
std::vector<Material> *out_materials,
|
||||
std::vector<Texture> *out_textures) {
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
|
||||
std::string basedir = GetBaseDir(filename) + "/";
|
||||
const char *basepath = (basedir.compare("/") == 0) ? NULL : basedir.c_str();
|
||||
|
||||
// auto t_start = std::chrono::system_clock::now();
|
||||
|
||||
bool ret =
|
||||
tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
|
||||
basepath, /* triangulate */ true);
|
||||
|
||||
// auto t_end = std::chrono::system_clock::now();
|
||||
// std::chrono::duration<double, std::milli> ms = t_end - t_start;
|
||||
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// std::cout << "[LoadOBJ] Parse time : " << ms.count() << " [msecs]"
|
||||
// << std::endl;
|
||||
|
||||
std::cout << "[LoadOBJ] # of shapes in .obj : " << shapes.size() << std::endl;
|
||||
std::cout << "[LoadOBJ] # of materials in .obj : " << materials.size()
|
||||
<< std::endl;
|
||||
|
||||
{
|
||||
size_t total_num_vertices = 0;
|
||||
size_t total_num_faces = 0;
|
||||
|
||||
total_num_vertices = attrib.vertices.size() / 3;
|
||||
std::cout << " vertices : " << attrib.vertices.size() / 3 << std::endl;
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
std::cout << " shape[" << i << "].name : " << shapes[i].name
|
||||
<< std::endl;
|
||||
std::cout << " shape[" << i
|
||||
<< "].indices : " << shapes[i].mesh.indices.size() << std::endl;
|
||||
assert((shapes[i].mesh.indices.size() % 3) == 0);
|
||||
|
||||
total_num_faces += shapes[i].mesh.indices.size() / 3;
|
||||
|
||||
// tigra: empty name convert to _id
|
||||
if (shapes[i].name.length() == 0) {
|
||||
#ifdef NANOSG_USE_CXX11
|
||||
shapes[i].name = "_" + std::to_string(i);
|
||||
#else
|
||||
std::stringstream ss;
|
||||
ss << i;
|
||||
shapes[i].name = "_" + ss.str();
|
||||
#endif
|
||||
std::cout << " EMPTY shape[" << i << "].name, new : " << shapes[i].name
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "[LoadOBJ] # of faces: " << total_num_faces << std::endl;
|
||||
std::cout << "[LoadOBJ] # of vertices: " << total_num_vertices << std::endl;
|
||||
}
|
||||
|
||||
// TODO(LTE): Implement tangents and binormals
|
||||
|
||||
for (size_t i = 0; i < shapes.size(); i++) {
|
||||
Mesh<float> mesh(/* stride */ sizeof(float) * 3);
|
||||
|
||||
mesh.name = shapes[i].name;
|
||||
|
||||
const size_t num_faces = shapes[i].mesh.indices.size() / 3;
|
||||
mesh.faces.resize(num_faces * 3);
|
||||
mesh.material_ids.resize(num_faces);
|
||||
mesh.facevarying_normals.resize(num_faces * 3 * 3);
|
||||
mesh.facevarying_uvs.resize(num_faces * 3 * 2);
|
||||
mesh.vertices.resize(num_faces * 3 * 3);
|
||||
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
// reorder vertices. may create duplicated vertices.
|
||||
size_t f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
size_t f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
size_t f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
mesh.vertices[9 * f + 0] = scale * attrib.vertices[3 * f0 + 0];
|
||||
mesh.vertices[9 * f + 1] = scale * attrib.vertices[3 * f0 + 1];
|
||||
mesh.vertices[9 * f + 2] = scale * attrib.vertices[3 * f0 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 3] = scale * attrib.vertices[3 * f1 + 0];
|
||||
mesh.vertices[9 * f + 4] = scale * attrib.vertices[3 * f1 + 1];
|
||||
mesh.vertices[9 * f + 5] = scale * attrib.vertices[3 * f1 + 2];
|
||||
|
||||
mesh.vertices[9 * f + 6] = scale * attrib.vertices[3 * f2 + 0];
|
||||
mesh.vertices[9 * f + 7] = scale * attrib.vertices[3 * f2 + 1];
|
||||
mesh.vertices[9 * f + 8] = scale * attrib.vertices[3 * f2 + 2];
|
||||
|
||||
mesh.faces[3 * f + 0] = static_cast<unsigned int>(3 * f + 0);
|
||||
mesh.faces[3 * f + 1] = static_cast<unsigned int>(3 * f + 1);
|
||||
mesh.faces[3 * f + 2] = static_cast<unsigned int>(3 * f + 2);
|
||||
|
||||
mesh.material_ids[f] =
|
||||
static_cast<unsigned int>(shapes[i].mesh.material_ids[f]);
|
||||
}
|
||||
|
||||
if (attrib.normals.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].normal_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].normal_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].normal_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float n0[3], n1[3], n2[3];
|
||||
|
||||
n0[0] = attrib.normals[3 * f0 + 0];
|
||||
n0[1] = attrib.normals[3 * f0 + 1];
|
||||
n0[2] = attrib.normals[3 * f0 + 2];
|
||||
|
||||
n1[0] = attrib.normals[3 * f1 + 0];
|
||||
n1[1] = attrib.normals[3 * f1 + 1];
|
||||
n1[2] = attrib.normals[3 * f1 + 2];
|
||||
|
||||
n2[0] = attrib.normals[3 * f2 + 0];
|
||||
n2[1] = attrib.normals[3 * f2 + 1];
|
||||
n2[2] = attrib.normals[3 * f2 + 2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = n0[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = n0[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = n1[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = n1[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = n2[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = n2[2];
|
||||
} else { // face contains invalid normal index. calc geometric normal.
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// calc geometric normal
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
|
||||
|
||||
float3 v0, v1, v2;
|
||||
|
||||
v0[0] = attrib.vertices[3 * f0 + 0];
|
||||
v0[1] = attrib.vertices[3 * f0 + 1];
|
||||
v0[2] = attrib.vertices[3 * f0 + 2];
|
||||
|
||||
v1[0] = attrib.vertices[3 * f1 + 0];
|
||||
v1[1] = attrib.vertices[3 * f1 + 1];
|
||||
v1[2] = attrib.vertices[3 * f1 + 2];
|
||||
|
||||
v2[0] = attrib.vertices[3 * f2 + 0];
|
||||
v2[1] = attrib.vertices[3 * f2 + 1];
|
||||
v2[2] = attrib.vertices[3 * f2 + 2];
|
||||
|
||||
float3 N;
|
||||
CalcNormal(N, v0, v1, v2);
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
|
||||
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
|
||||
mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
|
||||
}
|
||||
}
|
||||
|
||||
if (attrib.texcoords.size() > 0) {
|
||||
for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
|
||||
size_t f0, f1, f2;
|
||||
|
||||
f0 = size_t(shapes[i].mesh.indices[3 * f + 0].texcoord_index);
|
||||
f1 = size_t(shapes[i].mesh.indices[3 * f + 1].texcoord_index);
|
||||
f2 = size_t(shapes[i].mesh.indices[3 * f + 2].texcoord_index);
|
||||
|
||||
if (f0 > 0 && f1 > 0 && f2 > 0) {
|
||||
float3 n0, n1, n2;
|
||||
|
||||
n0[0] = attrib.texcoords[2 * f0 + 0];
|
||||
n0[1] = attrib.texcoords[2 * f0 + 1];
|
||||
|
||||
n1[0] = attrib.texcoords[2 * f1 + 0];
|
||||
n1[1] = attrib.texcoords[2 * f1 + 1];
|
||||
|
||||
n2[0] = attrib.texcoords[2 * f2 + 0];
|
||||
n2[1] = attrib.texcoords[2 * f2 + 1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 0] = n0[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 0) + 1] = n0[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 0] = n1[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 1) + 1] = n1[1];
|
||||
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 0] = n2[0];
|
||||
mesh.facevarying_uvs[2 * (3 * f + 2) + 1] = n2[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute pivot translation and add offset to the vertices.
|
||||
float bmin[3], bmax[3];
|
||||
ComputeBoundingBoxOfMesh(bmin, bmax, mesh);
|
||||
|
||||
float bcenter[3];
|
||||
bcenter[0] = 0.5f * (bmax[0] - bmin[0]) + bmin[0];
|
||||
bcenter[1] = 0.5f * (bmax[1] - bmin[1]) + bmin[1];
|
||||
bcenter[2] = 0.5f * (bmax[2] - bmin[2]) + bmin[2];
|
||||
|
||||
for (size_t v = 0; v < mesh.vertices.size() / 3; v++) {
|
||||
mesh.vertices[3 * v + 0] -= bcenter[0];
|
||||
mesh.vertices[3 * v + 1] -= bcenter[1];
|
||||
mesh.vertices[3 * v + 2] -= bcenter[2];
|
||||
}
|
||||
|
||||
mesh.pivot_xform[0][0] = 1.0f;
|
||||
mesh.pivot_xform[0][1] = 0.0f;
|
||||
mesh.pivot_xform[0][2] = 0.0f;
|
||||
mesh.pivot_xform[0][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[1][0] = 0.0f;
|
||||
mesh.pivot_xform[1][1] = 1.0f;
|
||||
mesh.pivot_xform[1][2] = 0.0f;
|
||||
mesh.pivot_xform[1][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[2][0] = 0.0f;
|
||||
mesh.pivot_xform[2][1] = 0.0f;
|
||||
mesh.pivot_xform[2][2] = 1.0f;
|
||||
mesh.pivot_xform[2][3] = 0.0f;
|
||||
|
||||
mesh.pivot_xform[3][0] = bcenter[0];
|
||||
mesh.pivot_xform[3][1] = bcenter[1];
|
||||
mesh.pivot_xform[3][2] = bcenter[2];
|
||||
mesh.pivot_xform[3][3] = 1.0f;
|
||||
|
||||
meshes->push_back(mesh);
|
||||
}
|
||||
|
||||
// material_t -> Material and Texture
|
||||
out_materials->resize(materials.size());
|
||||
out_textures->resize(0);
|
||||
for (size_t i = 0; i < materials.size(); i++) {
|
||||
(*out_materials)[i].diffuse[0] = materials[i].diffuse[0];
|
||||
(*out_materials)[i].diffuse[1] = materials[i].diffuse[1];
|
||||
(*out_materials)[i].diffuse[2] = materials[i].diffuse[2];
|
||||
(*out_materials)[i].specular[0] = materials[i].specular[0];
|
||||
(*out_materials)[i].specular[1] = materials[i].specular[1];
|
||||
(*out_materials)[i].specular[2] = materials[i].specular[2];
|
||||
|
||||
(*out_materials)[i].id = int(i);
|
||||
|
||||
// map_Kd
|
||||
(*out_materials)[i].diffuse_texid =
|
||||
LoadTexture(materials[i].diffuse_texname, out_textures);
|
||||
// map_Ks
|
||||
(*out_materials)[i].specular_texid =
|
||||
LoadTexture(materials[i].specular_texname, out_textures);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace example
|
19
examples/raytrace/obj-loader.h
Normal file
19
examples/raytrace/obj-loader.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef EXAMPLE_OBJ_LOADER_H_
|
||||
#define EXAMPLE_OBJ_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "material.h"
|
||||
|
||||
namespace example {
|
||||
|
||||
///
|
||||
/// Loads wavefront .obj mesh
|
||||
///
|
||||
bool LoadObj(const std::string &filename, float scale, std::vector<Mesh<float> > *meshes, std::vector<Material> *materials, std::vector<Texture> *textures);
|
||||
|
||||
}
|
||||
|
||||
#endif // EXAMPLE_OBJ_LOADER_H_
|
@ -1,12 +1,19 @@
|
||||
newoption {
|
||||
trigger = "with-gtk3nfd",
|
||||
description = "Build with native file dialog support(GTK3 required. Linux only)"
|
||||
}
|
||||
|
||||
newoption {
|
||||
trigger = "asan",
|
||||
description = "Enable Address Sanitizer(gcc5+ ang clang only)"
|
||||
}
|
||||
|
||||
sources = {
|
||||
"stbi-impl.cc",
|
||||
"main.cc",
|
||||
"render.cc",
|
||||
"render-config.cc",
|
||||
"obj-loader.cc",
|
||||
"gltf-loader.cc",
|
||||
"matrix.cc",
|
||||
"../common/trackball.cc",
|
||||
@ -16,7 +23,7 @@ sources = {
|
||||
"../common/imgui/ImGuizmo.cpp",
|
||||
}
|
||||
|
||||
solution "RaytraceSolution"
|
||||
solution "NanoSGSolution"
|
||||
configurations { "Release", "Debug" }
|
||||
|
||||
if os.is("Windows") then
|
||||
@ -53,7 +60,6 @@ solution "RaytraceSolution"
|
||||
end
|
||||
|
||||
if os.is("Windows") then
|
||||
flags { "FatalCompileWarnings" }
|
||||
warnings "Extra" -- /W4
|
||||
|
||||
defines { "NOMINMAX" }
|
||||
|
@ -29,12 +29,24 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) {
|
||||
|
||||
picojson::object o = v.get<picojson::object>();
|
||||
|
||||
if (o.find("obj_filename") != o.end()) {
|
||||
if (o["obj_filename"].is<std::string>()) {
|
||||
config->obj_filename = o["obj_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (o.find("gltf_filename") != o.end()) {
|
||||
if (o["gltf_filename"].is<std::string>()) {
|
||||
config->gltf_filename = o["gltf_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
if (o.find("eson_filename") != o.end()) {
|
||||
if (o["eson_filename"].is<std::string>()) {
|
||||
config->eson_filename = o["eson_filename"].get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
config->scene_scale = 1.0f;
|
||||
if (o.find("scene_scale") != o.end()) {
|
||||
if (o["scene_scale"].is<double>()) {
|
||||
@ -107,4 +119,4 @@ bool LoadRenderConfig(example::RenderConfig* config, const char* filename) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // namespace example
|
||||
|
@ -28,7 +28,9 @@ typedef struct {
|
||||
float *varycoordImage;
|
||||
|
||||
// Scene input info
|
||||
std::string obj_filename;
|
||||
std::string gltf_filename;
|
||||
std::string eson_filename;
|
||||
float scene_scale;
|
||||
|
||||
} RenderConfig;
|
||||
|
@ -200,6 +200,7 @@ void BuildCameraFrame(float3* origin, float3* corner, float3* u, float3* v,
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO(LTE): Not used method. Delete.
|
||||
nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
|
||||
const float3& du, const float3& dv, float u,
|
||||
float v) {
|
||||
@ -217,9 +218,12 @@ nanort::Ray<float> GenerateRay(const float3& origin, const float3& corner,
|
||||
ray.org[1] = origin[1];
|
||||
ray.org[2] = origin[2];
|
||||
ray.dir[0] = dir[0];
|
||||
ray.dir[1] = dir[1];
|
||||
ray.dir[2] = dir[2];
|
||||
|
||||
return ray;
|
||||
}
|
||||
#endif
|
||||
|
||||
void FetchTexture(const Texture &texture, float u, float v, float* col) {
|
||||
int tx = u * texture.width;
|
||||
@ -235,10 +239,15 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
const nanosg::Scene<float, example::Mesh<float>> &scene,
|
||||
const example::Asset &asset,
|
||||
const RenderConfig& config,
|
||||
std::atomic<bool>& cancelFlag) {
|
||||
std::atomic<bool>& cancelFlag,
|
||||
int &_showBufferMode
|
||||
) {
|
||||
//if (!gAccel.IsValid()) {
|
||||
// return false;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
int width = config.width;
|
||||
int height = config.height;
|
||||
@ -300,6 +309,19 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
float u1 = pcg32_random(&rng);
|
||||
|
||||
float3 dir;
|
||||
|
||||
//for modes not a "color"
|
||||
if(_showBufferMode != SHOW_BUFFER_COLOR)
|
||||
{
|
||||
//only one pass
|
||||
if(config.pass > 0)
|
||||
continue;
|
||||
|
||||
//to the center of pixel
|
||||
u0 = 0.5f;
|
||||
u1 = 0.5f;
|
||||
}
|
||||
|
||||
dir = corner + (float(x) + u0) * u +
|
||||
(float(config.height - y - 1) + u1) * v;
|
||||
dir = vnormalize(dir);
|
||||
@ -320,6 +342,9 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
const std::vector<Material> &materials = asset.materials;
|
||||
const std::vector<Texture> &textures = asset.textures;
|
||||
const Mesh<float> &mesh = asset.meshes[isect.node_id];
|
||||
|
||||
//tigra: add default material
|
||||
const Material &default_material = asset.default_material;
|
||||
|
||||
float3 p;
|
||||
p[0] =
|
||||
@ -410,26 +435,49 @@ bool Renderer::Render(float* rgba, float* aux_rgba, int* sample_counts,
|
||||
// Fetch texture
|
||||
unsigned int material_id =
|
||||
mesh.material_ids[isect.prim_id];
|
||||
|
||||
//printf("material_id=%d materials=%lld\n", material_id, materials.size());
|
||||
|
||||
float diffuse_col[3];
|
||||
int diffuse_texid = materials[material_id].diffuse_texid;
|
||||
if (diffuse_texid >= 0) {
|
||||
FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col);
|
||||
} else {
|
||||
diffuse_col[0] = materials[material_id].diffuse[0];
|
||||
diffuse_col[1] = materials[material_id].diffuse[1];
|
||||
diffuse_col[2] = materials[material_id].diffuse[2];
|
||||
}
|
||||
|
||||
float specular_col[3];
|
||||
int specular_texid = materials[material_id].specular_texid;
|
||||
if (specular_texid >= 0) {
|
||||
FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col);
|
||||
} else {
|
||||
specular_col[0] = materials[material_id].specular[0];
|
||||
specular_col[1] = materials[material_id].specular[1];
|
||||
specular_col[2] = materials[material_id].specular[2];
|
||||
}
|
||||
|
||||
//tigra: material_id is ok
|
||||
if(material_id<materials.size())
|
||||
{
|
||||
//printf("ok mat\n");
|
||||
|
||||
int diffuse_texid = materials[material_id].diffuse_texid;
|
||||
if (diffuse_texid >= 0) {
|
||||
FetchTexture(textures[diffuse_texid], UV[0], UV[1], diffuse_col);
|
||||
} else {
|
||||
diffuse_col[0] = materials[material_id].diffuse[0];
|
||||
diffuse_col[1] = materials[material_id].diffuse[1];
|
||||
diffuse_col[2] = materials[material_id].diffuse[2];
|
||||
}
|
||||
|
||||
int specular_texid = materials[material_id].specular_texid;
|
||||
if (specular_texid >= 0) {
|
||||
FetchTexture(textures[specular_texid], UV[0], UV[1], specular_col);
|
||||
} else {
|
||||
specular_col[0] = materials[material_id].specular[0];
|
||||
specular_col[1] = materials[material_id].specular[1];
|
||||
specular_col[2] = materials[material_id].specular[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
//tigra: wrong material_id, use default_material
|
||||
{
|
||||
|
||||
//printf("default_material\n");
|
||||
|
||||
diffuse_col[0] = default_material.diffuse[0];
|
||||
diffuse_col[1] = default_material.diffuse[1];
|
||||
diffuse_col[2] = default_material.diffuse[2];
|
||||
specular_col[0] = default_material.specular[0];
|
||||
specular_col[1] = default_material.specular[1];
|
||||
specular_col[2] = default_material.specular[2];
|
||||
}
|
||||
|
||||
// Simple shading
|
||||
float NdotV = fabsf(vdot(N, dir));
|
||||
|
@ -3,6 +3,15 @@
|
||||
|
||||
#include <atomic> // C++11
|
||||
|
||||
//mode definitions now here
|
||||
|
||||
#define SHOW_BUFFER_COLOR (0)
|
||||
#define SHOW_BUFFER_NORMAL (1)
|
||||
#define SHOW_BUFFER_POSITION (2)
|
||||
#define SHOW_BUFFER_DEPTH (3)
|
||||
#define SHOW_BUFFER_TEXCOORD (4)
|
||||
#define SHOW_BUFFER_VARYCOORD (5)
|
||||
|
||||
#include "render-config.h"
|
||||
#include "nanosg.h"
|
||||
#include "mesh.h"
|
||||
@ -13,6 +22,9 @@ namespace example {
|
||||
struct Asset {
|
||||
std::vector<Mesh<float> > meshes;
|
||||
std::vector<Material> materials;
|
||||
|
||||
//tigra: add default material
|
||||
Material default_material;
|
||||
std::vector<Texture> textures;
|
||||
};
|
||||
|
||||
@ -23,7 +35,10 @@ class Renderer {
|
||||
|
||||
/// Returns false when the rendering was canceled.
|
||||
static bool Render(float* rgba, float* aux_rgba, int *sample_counts, float quat[4],
|
||||
const nanosg::Scene<float, Mesh<float>> &scene, const Asset &asset, const RenderConfig& config, std::atomic<bool>& cancel_flag);
|
||||
const nanosg::Scene<float, Mesh<float>> &scene, const Asset &asset, const RenderConfig& config,
|
||||
std::atomic<bool>& cancel_flag,
|
||||
int& _showBufferMode
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
3
examples/raytrace/stbi-impl.cc
Normal file
3
examples/raytrace/stbi-impl.cc
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
357
examples/raytrace/viwewer.make
Normal file
357
examples/raytrace/viwewer.make
Normal file
@ -0,0 +1,357 @@
|
||||
# GNU Make project makefile autogenerated by Premake
|
||||
|
||||
ifndef config
|
||||
config=release_native
|
||||
endif
|
||||
|
||||
ifndef verbose
|
||||
SILENT = @
|
||||
endif
|
||||
|
||||
.PHONY: clean prebuild prelink
|
||||
|
||||
ifeq ($(config),release_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/native/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x64/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),release_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Release
|
||||
TARGET = $(TARGETDIR)/view
|
||||
OBJDIR = obj/x32/Release
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -O2 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_native)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/native/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/native/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x64)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x64/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x64/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m64 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m64 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
ifeq ($(config),debug_x32)
|
||||
RESCOMP = windres
|
||||
TARGETDIR = bin/x32/Debug
|
||||
TARGET = $(TARGETDIR)/view_debug
|
||||
OBJDIR = obj/x32/Debug
|
||||
DEFINES += -DGLEW_INIT_OPENGL11_FUNCTIONS=1 -DGLEW_STATIC -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS=1 -DDEBUG
|
||||
INCLUDES += -I../common/ThirdPartyLibs/Glew -I. -I../.. -I../common -I../common/imgui -I../common/glm
|
||||
FORCE_INCLUDE +=
|
||||
ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP $(DEFINES) $(INCLUDES)
|
||||
ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) -m32 -g
|
||||
ALL_CXXFLAGS += $(CXXFLAGS) $(ALL_CPPFLAGS) -m32 -g -std=c++11
|
||||
ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)
|
||||
LIBS += -lX11 -lpthread -ldl
|
||||
LDDEPS +=
|
||||
ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32
|
||||
LINKCMD = $(CXX) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)
|
||||
define PREBUILDCMDS
|
||||
endef
|
||||
define PRELINKCMDS
|
||||
endef
|
||||
define POSTBUILDCMDS
|
||||
endef
|
||||
all: prebuild prelink $(TARGET)
|
||||
@:
|
||||
|
||||
endif
|
||||
|
||||
OBJECTS := \
|
||||
$(OBJDIR)/X11OpenGLWindow.o \
|
||||
$(OBJDIR)/glew.o \
|
||||
$(OBJDIR)/ImGuizmo.o \
|
||||
$(OBJDIR)/imgui.o \
|
||||
$(OBJDIR)/imgui_draw.o \
|
||||
$(OBJDIR)/imgui_impl_btgui.o \
|
||||
$(OBJDIR)/trackball.o \
|
||||
$(OBJDIR)/gltf-loader.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/matrix.o \
|
||||
$(OBJDIR)/obj-loader.o \
|
||||
$(OBJDIR)/render-config.o \
|
||||
$(OBJDIR)/render.o \
|
||||
$(OBJDIR)/stbi-impl.o \
|
||||
|
||||
RESOURCES := \
|
||||
|
||||
CUSTOMFILES := \
|
||||
|
||||
SHELLTYPE := msdos
|
||||
ifeq (,$(ComSpec)$(COMSPEC))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
ifeq (/bin,$(findstring /bin,$(SHELL)))
|
||||
SHELLTYPE := posix
|
||||
endif
|
||||
|
||||
$(TARGET): $(GCH) ${CUSTOMFILES} $(OBJECTS) $(LDDEPS) $(RESOURCES)
|
||||
@echo Linking viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(TARGETDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(TARGETDIR))
|
||||
endif
|
||||
$(SILENT) $(LINKCMD)
|
||||
$(POSTBUILDCMDS)
|
||||
|
||||
clean:
|
||||
@echo Cleaning viwewer
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) rm -f $(TARGET)
|
||||
$(SILENT) rm -rf $(OBJDIR)
|
||||
else
|
||||
$(SILENT) if exist $(subst /,\\,$(TARGET)) del $(subst /,\\,$(TARGET))
|
||||
$(SILENT) if exist $(subst /,\\,$(OBJDIR)) rmdir /s /q $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
|
||||
prebuild:
|
||||
$(PREBUILDCMDS)
|
||||
|
||||
prelink:
|
||||
$(PRELINKCMDS)
|
||||
|
||||
ifneq (,$(PCH))
|
||||
$(OBJECTS): $(GCH) $(PCH)
|
||||
$(GCH): $(PCH)
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) -x c++-header $(ALL_CXXFLAGS) -o "$@" -MF "$(@:%.gch=%.d)" -c "$<"
|
||||
endif
|
||||
|
||||
$(OBJDIR)/X11OpenGLWindow.o: ../common/OpenGLWindow/X11OpenGLWindow.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/glew.o: ../common/ThirdPartyLibs/Glew/glew.c
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CC) $(ALL_CFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/ImGuizmo.o: ../common/imgui/ImGuizmo.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui.o: ../common/imgui/imgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_draw.o: ../common/imgui/imgui_draw.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/imgui_impl_btgui.o: ../common/imgui/imgui_impl_btgui.cpp
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/trackball.o: ../common/trackball.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/gltf-loader.o: gltf-loader.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/main.o: main.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/matrix.o: matrix.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/obj-loader.o: obj-loader.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render-config.o: render-config.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/render.o: render.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
$(OBJDIR)/stbi-impl.o: stbi-impl.cc
|
||||
@echo $(notdir $<)
|
||||
ifeq (posix,$(SHELLTYPE))
|
||||
$(SILENT) mkdir -p $(OBJDIR)
|
||||
else
|
||||
$(SILENT) mkdir $(subst /,\\,$(OBJDIR))
|
||||
endif
|
||||
$(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"
|
||||
|
||||
-include $(OBJECTS:%.o=%.d)
|
||||
ifneq (,$(PCH))
|
||||
-include $(OBJDIR)/$(notdir $(PCH)).d
|
||||
endif
|
2
examples/saver/Makefile.dev
Normal file
2
examples/saver/Makefile.dev
Normal file
@ -0,0 +1,2 @@
|
||||
all:
|
||||
clang++ -std=c++11 -I../../ -g -O1 -o saver main.cc
|
1
examples/saver/README.md
Normal file
1
examples/saver/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Simple serialization API sample.
|
33
examples/saver/main.cc
Normal file
33
examples/saver/main.cc
Normal file
@ -0,0 +1,33 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define TINYGLTF_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "tiny_gltf.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
std::cout << "Needs input.gltf output.gltf" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
std::string err;
|
||||
std::string input_filename(argv[1]);
|
||||
std::string output_filename(argv[2]);
|
||||
|
||||
// assume ascii glTF.
|
||||
bool ret = loader.LoadASCIIFromFile(&model, &err, input_filename.c_str());
|
||||
if (!ret) {
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
loader.WriteGltfSceneToFile(&model, output_filename);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
}
|
469
tiny_gltf.h
469
tiny_gltf.h
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user