Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Courses
Scotty3D
Commits
c2535f0f
Commit
c2535f0f
authored
Sep 26, 2020
by
TheNumbat
Browse files
upstream changes
parent
8b8ee1f1
Changes
93
Hide whitespace changes
Inline
Side-by-side
src/scene/object.h
View file @
c2535f0f
#pragma once
#pragma once
#include "../platform/gl.h"
#include "../geometry/halfedge.h"
#include "../geometry/halfedge.h"
#include "../platform/gl.h"
#include "../rays/shapes.h"
#include "../rays/shapes.h"
#include "pose.h"
#include "material.h"
#include "material.h"
#include "pose.h"
#include "skeleton.h"
#include "skeleton.h"
using
Scene_ID
=
unsigned
int
;
using
Scene_ID
=
unsigned
int
;
class
Scene_Object
{
class
Scene_Object
{
public:
public:
Scene_Object
()
=
default
;
Scene_Object
()
=
default
;
Scene_Object
(
Scene_ID
id
,
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
=
{});
Scene_Object
(
Scene_ID
id
,
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
=
{});
Scene_Object
(
Scene_ID
id
,
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
=
{});
Scene_Object
(
Scene_ID
id
,
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
=
{});
Scene_Object
(
const
Scene_Object
&
src
)
=
delete
;
Scene_Object
(
const
Scene_Object
&
src
)
=
delete
;
Scene_Object
(
Scene_Object
&&
src
)
=
default
;
Scene_Object
(
Scene_Object
&&
src
)
=
default
;
~
Scene_Object
()
=
default
;
~
Scene_Object
()
=
default
;
void
operator
=
(
const
Scene_Object
&
src
)
=
delete
;
void
operator
=
(
const
Scene_Object
&
src
)
=
delete
;
Scene_Object
&
operator
=
(
Scene_Object
&&
src
)
=
default
;
Scene_Object
&
operator
=
(
Scene_Object
&&
src
)
=
default
;
Scene_ID
id
()
const
{
return
_id
;}
Scene_ID
id
()
const
{
return
_id
;
}
void
sync_mesh
();
void
sync_mesh
();
void
sync_anim_mesh
();
void
sync_anim_mesh
();
void
set_time
(
float
time
);
void
set_time
(
float
time
);
const
GL
::
Mesh
&
mesh
()
{
sync_mesh
();
return
_mesh
;}
const
GL
::
Mesh
&
mesh
()
{
const
GL
::
Mesh
&
posed_mesh
();
sync_mesh
();
return
_mesh
;
void
render
(
const
Mat4
&
view
,
bool
solid
=
false
,
bool
depth_only
=
false
,
bool
posed
=
true
,
bool
anim
=
true
);
}
const
GL
::
Mesh
&
posed_mesh
();
Halfedge_Mesh
&
get_mesh
();
const
Halfedge_Mesh
&
get_mesh
()
const
;
void
render
(
const
Mat4
&
view
,
bool
solid
=
false
,
bool
depth_only
=
false
,
bool
posed
=
true
,
void
copy_mesh
(
Halfedge_Mesh
&
out
);
bool
anim
=
true
);
void
take_mesh
(
Halfedge_Mesh
&&
in
);
void
set_mesh
(
Halfedge_Mesh
&
in
);
Halfedge_Mesh
&
get_mesh
();
Halfedge_Mesh
::
ElementRef
set_mesh
(
Halfedge_Mesh
&
in
,
unsigned
int
eid
);
const
Halfedge_Mesh
&
get_mesh
()
const
;
void
copy_mesh
(
Halfedge_Mesh
&
out
);
BBox
bbox
();
void
take_mesh
(
Halfedge_Mesh
&&
in
);
bool
is_editable
()
const
;
void
set_mesh
(
Halfedge_Mesh
&
in
);
bool
is_shape
()
const
;
Halfedge_Mesh
::
ElementRef
set_mesh
(
Halfedge_Mesh
&
in
,
unsigned
int
eid
);
void
try_make_editable
(
PT
::
Shape_Type
prev
=
PT
::
Shape_Type
::
none
);
BBox
bbox
();
void
set_mesh_dirty
();
bool
is_editable
()
const
;
void
set_skel_dirty
();
bool
is_shape
()
const
;
void
set_pose_dirty
();
void
try_make_editable
(
PT
::
Shape_Type
prev
=
PT
::
Shape_Type
::
none
);
static
const
inline
int
max_name_len
=
256
;
void
set_mesh_dirty
();
struct
Options
{
void
set_skel_dirty
();
char
name
[
max_name_len
]
=
{};
void
set_pose_dirty
();
bool
wireframe
=
false
;
bool
smooth_normals
=
false
;
static
const
inline
int
max_name_len
=
256
;
PT
::
Shape_Type
shape_type
=
PT
::
Shape_Type
::
none
;
struct
Options
{
PT
::
Shape
shape
;
char
name
[
max_name_len
]
=
{};
};
bool
wireframe
=
false
;
bool
smooth_normals
=
false
;
Options
opt
;
PT
::
Shape_Type
shape_type
=
PT
::
Shape_Type
::
none
;
Pose
pose
;
PT
::
Shape
shape
;
Anim_Pose
anim
;
};
Skeleton
armature
;
Material
material
;
Options
opt
;
Pose
pose
;
mutable
bool
rig_dirty
=
false
;
Anim_Pose
anim
;
Skeleton
armature
;
Material
material
;
mutable
bool
rig_dirty
=
false
;
private:
private:
Scene_ID
_id
=
0
;
Scene_ID
_id
=
0
;
Halfedge_Mesh
halfedge
;
Halfedge_Mesh
halfedge
;
mutable
GL
::
Mesh
_mesh
,
_anim_mesh
;
mutable
GL
::
Mesh
_mesh
,
_anim_mesh
;
mutable
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>
vertex_joints
;
mutable
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>
vertex_joints
;
mutable
bool
editable
=
true
;
mutable
bool
editable
=
true
;
mutable
bool
mesh_dirty
=
false
;
mutable
bool
mesh_dirty
=
false
;
mutable
bool
skel_dirty
=
false
,
pose_dirty
=
false
;
mutable
bool
skel_dirty
=
false
,
pose_dirty
=
false
;
};
};
bool
operator
!=
(
const
Scene_Object
::
Options
&
l
,
const
Scene_Object
::
Options
&
r
);
bool
operator
!=
(
const
Scene_Object
::
Options
&
l
,
const
Scene_Object
::
Options
&
r
);
src/scene/pose.cpp
View file @
c2535f0f
#include "pose.h"
#include "pose.h"
Mat4
Pose
::
transform
()
const
{
Mat4
Pose
::
transform
()
const
{
return
Mat4
::
translate
(
pos
)
*
rotation_mat
()
*
Mat4
::
scale
(
scale
);
}
return
Mat4
::
translate
(
pos
)
*
rotation_mat
()
*
Mat4
::
scale
(
scale
);
}
Mat4
Pose
::
rotation_mat
()
const
{
Mat4
Pose
::
rotation_mat
()
const
{
return
Mat4
::
euler
(
euler
);
}
return
Mat4
::
euler
(
euler
);
}
Quat
Pose
::
rotation_quat
()
const
{
Quat
Pose
::
rotation_quat
()
const
{
return
Quat
::
euler
(
euler
);
}
return
Quat
::
euler
(
euler
);
}
bool
Pose
::
valid
()
const
{
bool
Pose
::
valid
()
const
{
return
pos
.
valid
()
&&
euler
.
valid
()
&&
scale
.
valid
();
}
return
pos
.
valid
()
&&
euler
.
valid
()
&&
scale
.
valid
();
}
void
Pose
::
clamp_euler
()
{
void
Pose
::
clamp_euler
()
{
if
(
!
valid
())
return
;
if
(
!
valid
())
while
(
euler
.
x
<
0
)
euler
.
x
+=
360.0
f
;
return
;
while
(
euler
.
x
>=
360.0
f
)
euler
.
x
-=
360.0
f
;
while
(
euler
.
x
<
0
)
while
(
euler
.
y
<
0
)
euler
.
y
+=
360.0
f
;
euler
.
x
+=
360.0
f
;
while
(
euler
.
y
>=
360.0
f
)
euler
.
y
-=
360.0
f
;
while
(
euler
.
x
>=
360.0
f
)
while
(
euler
.
z
<
0
)
euler
.
z
+=
360.0
f
;
euler
.
x
-=
360.0
f
;
while
(
euler
.
z
>=
360.0
f
)
euler
.
z
-=
360.0
f
;
while
(
euler
.
y
<
0
)
euler
.
y
+=
360.0
f
;
while
(
euler
.
y
>=
360.0
f
)
euler
.
y
-=
360.0
f
;
while
(
euler
.
z
<
0
)
euler
.
z
+=
360.0
f
;
while
(
euler
.
z
>=
360.0
f
)
euler
.
z
-=
360.0
f
;
}
}
Pose
Pose
::
rotated
(
Vec3
angles
)
{
Pose
Pose
::
rotated
(
Vec3
angles
)
{
return
Pose
{
Vec3
{},
angles
,
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
return
Pose
{
Vec3
{},
angles
,
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
Pose
Pose
::
moved
(
Vec3
t
)
{
Pose
Pose
::
moved
(
Vec3
t
)
{
return
Pose
{
t
,
Vec3
{},
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
return
Pose
{
t
,
Vec3
{},
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
Pose
Pose
::
scaled
(
Vec3
s
)
{
Pose
Pose
::
scaled
(
Vec3
s
)
{
return
Pose
{
Vec3
{},
Vec3
{},
s
};
}
return
Pose
{
Vec3
{},
Vec3
{},
s
};
}
Pose
Pose
::
id
()
{
Pose
Pose
::
id
()
{
return
Pose
{
Vec3
{},
Vec3
{},
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
return
Pose
{
Vec3
{},
Vec3
{},
Vec3
{
1.0
f
,
1.0
f
,
1.0
f
}};
}
bool
operator
==
(
const
Pose
&
l
,
const
Pose
&
r
)
{
bool
operator
==
(
const
Pose
&
l
,
const
Pose
&
r
)
{
return
l
.
pos
==
r
.
pos
&&
l
.
euler
==
r
.
euler
&&
l
.
scale
==
r
.
scale
;
return
l
.
pos
==
r
.
pos
&&
l
.
euler
==
r
.
euler
&&
l
.
scale
==
r
.
scale
;
}
}
bool
operator
!=
(
const
Pose
&
l
,
const
Pose
&
r
)
{
bool
operator
!=
(
const
Pose
&
l
,
const
Pose
&
r
)
{
return
l
.
pos
!=
r
.
pos
||
l
.
euler
!=
r
.
euler
||
l
.
scale
!=
r
.
scale
;
return
l
.
pos
!=
r
.
pos
||
l
.
euler
!=
r
.
euler
||
l
.
scale
!=
r
.
scale
;
}
}
Pose
Anim_Pose
::
at
(
float
t
)
const
{
Pose
Anim_Pose
::
at
(
float
t
)
const
{
auto
[
p
,
r
,
s
]
=
splines
.
at
(
t
);
auto
[
p
,
r
,
s
]
=
splines
.
at
(
t
);
return
Pose
{
p
,
r
.
to_euler
(),
s
};
return
Pose
{
p
,
r
.
to_euler
(),
s
};
}
void
Anim_Pose
::
set
(
float
t
,
Pose
p
)
{
splines
.
set
(
t
,
p
.
pos
,
Quat
::
euler
(
p
.
euler
),
p
.
scale
);
}
}
void
Anim_Pose
::
set
(
float
t
,
Pose
p
)
{
splines
.
set
(
t
,
p
.
pos
,
Quat
::
euler
(
p
.
euler
),
p
.
scale
);
}
src/scene/pose.h
View file @
c2535f0f
#pragma once
#pragma once
#include <set>
#include "../lib/mathlib.h"
#include "../geometry/spline.h"
#include "../geometry/spline.h"
#include "../lib/mathlib.h"
#include <set>
struct
Pose
{
struct
Pose
{
Vec3
pos
;
Vec3
pos
;
Vec3
euler
;
Vec3
euler
;
Vec3
scale
=
Vec3
{
1
.
0
f
};
Vec3
scale
=
Vec3
{
1
.
0
f
};
Mat4
transform
()
const
;
Mat4
transform
()
const
;
Mat4
rotation_mat
()
const
;
Mat4
rotation_mat
()
const
;
Quat
rotation_quat
()
const
;
Quat
rotation_quat
()
const
;
void
clamp_euler
();
void
clamp_euler
();
bool
valid
()
const
;
bool
valid
()
const
;
static
Pose
rotated
(
Vec3
angles
);
static
Pose
rotated
(
Vec3
angles
);
static
Pose
moved
(
Vec3
t
);
static
Pose
moved
(
Vec3
t
);
static
Pose
scaled
(
Vec3
s
);
static
Pose
scaled
(
Vec3
s
);
static
Pose
id
();
static
Pose
id
();
};
};
bool
operator
==
(
const
Pose
&
l
,
const
Pose
&
r
);
bool
operator
==
(
const
Pose
&
l
,
const
Pose
&
r
);
bool
operator
!=
(
const
Pose
&
l
,
const
Pose
&
r
);
bool
operator
!=
(
const
Pose
&
l
,
const
Pose
&
r
);
struct
Anim_Pose
{
struct
Anim_Pose
{
Pose
at
(
float
t
)
const
;
Pose
at
(
float
t
)
const
;
void
set
(
float
t
,
Pose
p
);
void
set
(
float
t
,
Pose
p
);
Splines
<
Vec3
,
Quat
,
Vec3
>
splines
;
Splines
<
Vec3
,
Quat
,
Vec3
>
splines
;
};
};
src/scene/renderer.cpp
View file @
c2535f0f
#include <imgui/imgui.h>
#include <imgui/imgui.h>
#include "../geometry/util.h"
#include "../gui/manager.h"
#include "../gui/manager.h"
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
#include "../geometry/util.h"
#include "renderer.h"
#include "renderer.h"
#include "scene.h"
#include "scene.h"
static
const
int
DEFAULT_SAMPLES
=
4
;
static
const
int
DEFAULT_SAMPLES
=
4
;
Renderer
::
Renderer
(
Vec2
dim
)
:
Renderer
::
Renderer
(
Vec2
dim
)
framebuffer
(
2
,
dim
,
DEFAULT_SAMPLES
,
true
),
:
framebuffer
(
2
,
dim
,
DEFAULT_SAMPLES
,
true
),
id_resolve
(
1
,
dim
,
1
,
false
),
id_resolve
(
1
,
dim
,
1
,
false
),
save_buffer
(
1
,
dim
,
DEFAULT_SAMPLES
,
true
),
save_output
(
1
,
dim
,
1
,
false
),
save_buffer
(
1
,
dim
,
DEFAULT_SAMPLES
,
true
),
mesh_shader
(
GL
::
Shaders
::
mesh_v
,
GL
::
Shaders
::
mesh_f
),
save_output
(
1
,
dim
,
1
,
false
),
line_shader
(
GL
::
Shaders
::
line_v
,
GL
::
Shaders
::
line_f
),
mesh_shader
(
GL
::
Shaders
::
mesh_v
,
GL
::
Shaders
::
mesh_f
),
inst_shader
(
GL
::
Shaders
::
inst_v
,
GL
::
Shaders
::
mesh_f
),
line_shader
(
GL
::
Shaders
::
line_v
,
GL
::
Shaders
::
line_f
),
dome_shader
(
GL
::
Shaders
::
dome_v
,
GL
::
Shaders
::
dome_f
),
_sphere
(
Util
::
sphere_mesh
(
1.0
f
,
3
)),
inst_shader
(
GL
::
Shaders
::
inst_v
,
GL
::
Shaders
::
mesh_f
),
_cyl
(
Util
::
cyl_mesh
(
1.0
f
,
1.0
f
,
64
,
false
)),
_hemi
(
Util
::
hemi_mesh
(
1.0
f
)),
dome_shader
(
GL
::
Shaders
::
dome_v
,
GL
::
Shaders
::
dome_f
),
samples
(
DEFAULT_SAMPLES
),
window_dim
(
dim
),
_sphere
(
Util
::
sphere_mesh
(
1.0
f
,
3
)),
id_buffer
(
new
GLubyte
[(
int
)
dim
.
x
*
(
int
)
dim
.
y
*
4
])
{}
_cyl
(
Util
::
cyl_mesh
(
1.0
f
,
1.0
f
,
64
,
false
)),
_hemi
(
Util
::
hemi_mesh
(
1.0
f
)),
samples
(
DEFAULT_SAMPLES
),
window_dim
(
dim
),
id_buffer
(
new
GLubyte
[(
int
)
dim
.
x
*
(
int
)
dim
.
y
*
4
])
{}
Renderer
::~
Renderer
()
{
Renderer
::~
Renderer
()
{
delete
[]
id_buffer
;
delete
[]
id_buffer
;
id_buffer
=
nullptr
;
id_buffer
=
nullptr
;
}
}
Renderer
&
Renderer
::
get
()
{
Renderer
&
Renderer
::
get
()
{
assert
(
data
);
assert
(
data
);
return
*
data
;
return
*
data
;
}
}
void
Renderer
::
setup
(
Vec2
dim
)
{
void
Renderer
::
setup
(
Vec2
dim
)
{
data
=
new
Renderer
(
dim
);
}
data
=
new
Renderer
(
dim
);
}
void
Renderer
::
update_dim
(
Vec2
dim
)
{
void
Renderer
::
update_dim
(
Vec2
dim
)
{
window_dim
=
dim
;
window_dim
=
dim
;
delete
[]
id_buffer
;
delete
[]
id_buffer
;
id_buffer
=
new
GLubyte
[(
int
)
dim
.
x
*
(
int
)
dim
.
y
*
4
]();
id_buffer
=
new
GLubyte
[(
int
)
dim
.
x
*
(
int
)
dim
.
y
*
4
]();
framebuffer
.
resize
(
dim
,
samples
);
framebuffer
.
resize
(
dim
,
samples
);
save_buffer
.
resize
(
dim
,
save_buffer
.
samples
());
save_buffer
.
resize
(
dim
,
save_buffer
.
samples
());
id_resolve
.
resize
(
dim
);
id_resolve
.
resize
(
dim
);
save_output
.
resize
(
dim
);
save_output
.
resize
(
dim
);
}
}
void
Renderer
::
shutdown
()
{
void
Renderer
::
shutdown
()
{
delete
data
;
delete
data
;
data
=
nullptr
;
data
=
nullptr
;
}
}
void
Renderer
::
proj
(
const
Mat4
&
proj
)
{
void
Renderer
::
proj
(
const
Mat4
&
proj
)
{
_proj
=
proj
;
}
_proj
=
proj
;
}
void
Renderer
::
complete
()
{
void
Renderer
::
complete
()
{
framebuffer
.
blit_to
(
1
,
id_resolve
,
false
);
framebuffer
.
blit_to
(
1
,
id_resolve
,
false
);
if
(
!
id_resolve
.
can_read_at
())
if
(
!
id_resolve
.
can_read_at
())
id_resolve
.
read
(
0
,
id_buffer
);
id_resolve
.
read
(
0
,
id_buffer
);
framebuffer
.
blit_to_screen
(
0
,
window_dim
);
framebuffer
.
blit_to_screen
(
0
,
window_dim
);
}
}
void
Renderer
::
begin
()
{
void
Renderer
::
begin
()
{
framebuffer
.
clear
(
0
,
Vec4
(
Gui
::
Color
::
background
,
1.0
f
));
framebuffer
.
clear
(
0
,
Vec4
(
Gui
::
Color
::
background
,
1.0
f
));
framebuffer
.
clear
(
1
,
Vec4
{
0.0
f
,
0.0
f
,
0.0
f
,
1.0
f
});
framebuffer
.
clear
(
1
,
Vec4
{
0.0
f
,
0.0
f
,
0.0
f
,
1.0
f
});
framebuffer
.
clear_d
();
framebuffer
.
clear_d
();
framebuffer
.
bind
();
framebuffer
.
bind
();
GL
::
viewport
(
window_dim
);
GL
::
viewport
(
window_dim
);
}
}
void
Renderer
::
save
(
Scene
&
scene
,
const
Camera
&
cam
,
int
w
,
int
h
,
int
s
)
{
void
Renderer
::
save
(
Scene
&
scene
,
const
Camera
&
cam
,
int
w
,
int
h
,
int
s
)
{
Vec2
dim
((
float
)
w
,
(
float
)
h
);
Vec2
dim
((
float
)
w
,
(
float
)
h
);
save_buffer
.
resize
(
dim
,
s
);
save_buffer
.
resize
(
dim
,
s
);
save_output
.
resize
(
dim
);
save_output
.
resize
(
dim
);
save_buffer
.
clear
(
0
,
Vec4
{
0.0
f
,
0.0
f
,
0.0
f
,
1.0
f
});
save_buffer
.
clear
(
0
,
Vec4
{
0.0
f
,
0.0
f
,
0.0
f
,
1.0
f
});
save_buffer
.
bind
();
save_buffer
.
bind
();
GL
::
viewport
(
dim
);
GL
::
viewport
(
dim
);
Mat4
view
=
cam
.
get_view
();
Mat4
view
=
cam
.
get_view
();
scene
.
for_items
([
&
](
Scene_Item
&
item
)
{
scene
.
for_items
([
&
](
Scene_Item
&
item
)
{
if
(
item
.
is
<
Scene_Light
>
())
return
;
if
(
item
.
is
<
Scene_Light
>
())
item
.
render
(
view
);
return
;
});
item
.
render
(
view
);
});
save_buffer
.
blit_to
(
0
,
save_output
,
true
);
save_buffer
.
blit_to
(
0
,
save_output
,
true
);
framebuffer
.
bind
();
framebuffer
.
bind
();
GL
::
viewport
(
window_dim
);
GL
::
viewport
(
window_dim
);
}
}
void
Renderer
::
saved
(
std
::
vector
<
unsigned
char
>
&
out
)
const
{
void
Renderer
::
saved
(
std
::
vector
<
unsigned
char
>
&
out
)
const
{
save_output
.
flush
();
save_output
.
flush
();
out
.
resize
(
save_output
.
bytes
());
out
.
resize
(
save_output
.
bytes
());
save_output
.
read
(
0
,
out
.
data
());
save_output
.
read
(
0
,
out
.
data
());
}
}
GLuint
Renderer
::
saved
()
const
{
GLuint
Renderer
::
saved
()
const
{
save_output
.
flush
();
save_output
.
flush
();
return
save_output
.
get_output
(
0
);
return
save_output
.
get_output
(
0
);
}
}
void
Renderer
::
lines
(
const
GL
::
Lines
&
lines
,
const
Mat4
&
view
,
const
Mat4
&
model
,
float
alpha
)
{
void
Renderer
::
lines
(
const
GL
::
Lines
&
lines
,
const
Mat4
&
view
,
const
Mat4
&
model
,
float
alpha
)
{
Mat4
mvp
=
_proj
*
view
*
model
;
Mat4
mvp
=
_proj
*
view
*
model
;
line_shader
.
bind
();
line_shader
.
bind
();
line_shader
.
uniform
(
"mvp"
,
mvp
);
line_shader
.
uniform
(
"mvp"
,
mvp
);
line_shader
.
uniform
(
"alpha"
,
alpha
);
line_shader
.
uniform
(
"alpha"
,
alpha
);
lines
.
render
(
framebuffer
.
is_multisampled
());
lines
.
render
(
framebuffer
.
is_multisampled
());
}
}
void
Renderer
::
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
,
const
GL
::
Tex2D
&
tex
)
{
void
Renderer
::
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
,
const
GL
::
Tex2D
&
tex
)
{
tex
.
bind
();
tex
.
bind
();
dome_shader
.
bind
();
dome_shader
.
bind
();
dome_shader
.
uniform
(
"tex"
,
0
);
dome_shader
.
uniform
(
"tex"
,
0
);
dome_shader
.
uniform
(
"use_texture"
,
true
);
dome_shader
.
uniform
(
"use_texture"
,
true
);
dome_shader
.
uniform
(
"color"
,
color
);
dome_shader
.
uniform
(
"color"
,
color
);
dome_shader
.
uniform
(
"cosine"
,
cosine
);
dome_shader
.
uniform
(
"cosine"
,
cosine
);
dome_shader
.
uniform
(
"transform"
,
_proj
*
rotation
);
dome_shader
.
uniform
(
"transform"
,
_proj
*
rotation
);
_sphere
.
render
();
_sphere
.
render
();
}
}
void
Renderer
::
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
)
{
void
Renderer
::
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
)
{
dome_shader
.
bind
();
dome_shader
.
bind
();
dome_shader
.
uniform
(
"use_texture"
,
false
);
dome_shader
.
uniform
(
"use_texture"
,
false
);
dome_shader
.
uniform
(
"color"
,
color
);
dome_shader
.
uniform
(
"color"
,
color
);
dome_shader
.
uniform
(
"cosine"
,
cosine
);
dome_shader
.
uniform
(
"cosine"
,
cosine
);
dome_shader
.
uniform
(
"transform"
,
_proj
*
rotation
);
dome_shader
.
uniform
(
"transform"
,
_proj
*
rotation
);
_sphere
.
render
();
_sphere
.
render
();
}
}
void
Renderer
::
sphere
(
MeshOpt
opt
)
{
void
Renderer
::
sphere
(
MeshOpt
opt
)
{
mesh
(
_sphere
,
opt
);
}
mesh
(
_sphere
,
opt
);
}
void
Renderer
::
capsule
(
MeshOpt
opt
,
const
Mat4
&
mdl
,
float
height
,
float
rad
,
BBox
&
box
)
{
void
Renderer
::
capsule
(
MeshOpt
opt
,
const
Mat4
&
mdl
,
float
height
,
float
rad
,
BBox
&
box
)
{
Mat4
T
=
opt
.
modelview
;
Mat4
T
=
opt
.
modelview
;
Mat4
cyl
=
mdl
*
Mat4
::
scale
(
Vec3
{
rad
,
height
,
rad
});
Mat4
cyl
=
mdl
*
Mat4
::
scale
(
Vec3
{
rad
,
height
,
rad
});
Mat4
bot
=
mdl
*
Mat4
::
scale
(
Vec3
{
rad
});
Mat4
bot
=
mdl
*
Mat4
::
scale
(
Vec3
{
rad
});
Mat4
top
=
mdl
*
Mat4
::
translate
(
Vec3
{
0.0
f
,
height
,
0.0
f
})
*
Mat4
::
euler
(
Vec3
{
180.0
f
,
0.0
f
,
0.0
f
})
*
Mat4
::
scale
(
Vec3
{
rad
});
Mat4
top
=
mdl
*
Mat4
::
translate
(
Vec3
{
0.0
f
,
height
,
0.0
f
})
*
Mat4
::
euler
(
Vec3
{
180.0
f
,
0.0
f
,
0.0
f
})
*
Mat4
::
scale
(
Vec3
{
rad
});
opt
.
modelview
=
T
*
cyl
;
opt
.
modelview
=
T
*
cyl
;
mesh
(
_cyl
,
opt
);
mesh
(
_cyl
,
opt
);
opt
.
modelview
=
T
*
bot
;
opt
.
modelview
=
T
*
bot
;
mesh
(
_hemi
,
opt
);
mesh
(
_hemi
,
opt
);
opt
.
modelview
=
T
*
top
;
opt
.
modelview
=
T
*
top
;
mesh
(
_hemi
,
opt
);
mesh
(
_hemi
,
opt
);
BBox
b
=
_cyl
.
bbox
();
BBox
b
=
_cyl
.
bbox
();
b
.
transform
(
cyl
);
b
.
transform
(
cyl
);
box
.
enclose
(
b
);
box
.
enclose
(
b
);
b
=
_hemi
.
bbox
();
b
=
_hemi
.
bbox
();
b
.
transform
(
bot
);
b
.
transform
(
bot
);
box
.
enclose
(
b
);
box
.
enclose
(
b
);
b
=
_hemi
.
bbox
();
b
=
_hemi
.
bbox
();
b
.
transform
(
top
);
b
.
transform
(
top
);
box
.
enclose
(
b
);
box
.
enclose
(
b
);
}
}
void
Renderer
::
capsule
(
MeshOpt
opt
,
float
height
,
float
rad
)
{
void
Renderer
::
capsule
(
MeshOpt
opt
,
float
height
,
float
rad
)
{
BBox
box
;
BBox
box
;
capsule
(
opt
,
Mat4
::
I
,
height
,
rad
,
box
);
capsule
(
opt
,
Mat4
::
I
,
height
,
rad
,
box
);
}
}
void
Renderer
::
mesh
(
GL
::
Mesh
&
mesh
,
Renderer
::
MeshOpt
opt
)
{
void
Renderer
::
mesh
(
GL
::
Mesh
&
mesh
,
Renderer
::
MeshOpt
opt
)
{
mesh_shader
.
bind
();
mesh_shader
.
bind
();
mesh_shader
.
uniform
(
"use_v_id"
,
opt
.
per_vert_id
);
mesh_shader
.
uniform
(
"use_v_id"
,
opt
.
per_vert_id
);
mesh_shader
.
uniform
(
"id"
,
opt
.
id
);
mesh_shader
.
uniform
(
"id"
,
opt
.
id
);
mesh_shader
.
uniform
(
"alpha"
,
opt
.
alpha
);
mesh_shader
.
uniform
(
"alpha"
,
opt
.
alpha
);
mesh_shader
.
uniform
(
"mvp"
,
_proj
*
opt
.
modelview
);
mesh_shader
.
uniform
(
"mvp"
,
_proj
*
opt
.
modelview
);
mesh_shader
.
uniform
(
"normal"
,
Mat4
::
transpose
(
Mat4
::
inverse
(
opt
.
modelview
)));
mesh_shader
.
uniform
(
"normal"
,
Mat4
::
transpose
(
Mat4
::
inverse
(
opt
.
modelview
)));
mesh_shader
.
uniform
(
"solid"
,
opt
.
solid_color
);
mesh_shader
.
uniform
(
"solid"
,
opt
.
solid_color
);
mesh_shader
.
uniform
(
"sel_color"
,
opt
.
sel_color
);
mesh_shader
.
uniform
(
"sel_color"
,
opt
.
sel_color
);
mesh_shader
.
uniform
(
"sel_id"
,
opt
.
sel_id
);
mesh_shader
.
uniform
(
"sel_id"
,
opt
.
sel_id
);
mesh_shader
.
uniform
(
"hov_color"
,
opt
.
hov_color
);
mesh_shader
.
uniform
(
"hov_color"
,
opt
.
hov_color
);
mesh_shader
.
uniform
(
"hov_id"
,
opt
.
hov_id
);
mesh_shader
.
uniform
(
"hov_id"
,
opt
.
hov_id
);
if
(
opt
.
depth_only
)
GL
::
color_mask
(
false
);
if
(
opt
.
depth_only
)
GL
::
color_mask
(
false
);
if
(
opt
.
wireframe
)
{
mesh_shader
.
uniform
(
"color"
,
Vec3
());
if
(
opt
.
wireframe
)
{
GL
::
enable
(
GL
::
Opt
::
wireframe
);
mesh_shader
.
uniform
(
"color"
,
Vec3
());
mesh
.
render
();
GL
::
enable
(
GL
::
Opt
::
wireframe
);
GL
::
disable
(
GL
::
Opt
::
wireframe
);
mesh
.
render
();
}
GL
::
disable
(
GL
::
Opt
::
wireframe
);
}
mesh_shader
.
uniform
(
"color"
,
opt
.
color
);
mesh
.
render
();
mesh_shader
.
uniform
(
"color"
,
opt
.
color
);
mesh
.
render
();
if
(
opt
.
depth_only
)
GL
::
color_mask
(
true
);
if
(
opt
.
depth_only
)
GL
::
color_mask
(
true
);
}
}
void
Renderer
::
set_samples
(
int
s
)
{
void
Renderer
::
set_samples
(
int
s
)
{
samples
=
s
;
samples
=
s
;
framebuffer
.
resize
(
window_dim
,
samples
);
framebuffer
.
resize
(
window_dim
,
samples
);
}
}
Scene_ID
Renderer
::
read_id
(
Vec2
pos
)
{
Scene_ID
Renderer
::
read_id
(
Vec2
pos
)
{
int
x
=
(
int
)
pos
.
x
;
int
x
=
(
int
)
pos
.
x
;
int
y
=
(
int
)(
window_dim
.
y
-
pos
.
y
-
1
);
int
y
=
(
int
)(
window_dim
.
y
-
pos
.
y
-
1
);
if
(
id_resolve
.
can_read_at
())
{
if
(
id_resolve
.
can_read_at
())
{
GLubyte
read
[
4
]
=
{};
GLubyte
read
[
4
]
=
{};
id_resolve
.
read_at
(
0
,
x
,
y
,
read
);
id_resolve
.
read_at
(
0
,
x
,
y
,
read
);
return
(
int
)
read
[
0
]
|
(
int
)
read
[
1
]
<<
8
|
(
int
)
read
[
2
]
<<
16
;
return
(
int
)
read
[
0
]
|
(
int
)
read
[
1
]
<<
8
|
(
int
)
read
[
2
]
<<
16
;
}
else
{
}
else
{
int
idx
=
y
*
(
int
)
window_dim
.
x
*
4
+
x
*
4
;
assert
(
id_buffer
&&
idx
>
0
&&
idx
<=
window_dim
.
x
*
window_dim
.
y
*
4
);
int
a
=
id_buffer
[
idx
];
int
b
=
id_buffer
[
idx
+
1
];
int
c
=
id_buffer
[
idx
+
2
];
return
a
|
b
<<
8
|
c
<<
16
;
int
idx
=
y
*
(
int
)
window_dim
.
x
*
4
+
x
*
4
;
}
assert
(
id_buffer
&&
idx
>
0
&&
idx
<=
window_dim
.
x
*
window_dim
.
y
*
4
);
}
void
Renderer
::
reset_depth
()
{
int
a
=
id_buffer
[
idx
];
framebuffer
.
clear_d
()
;
int
b
=
id_buffer
[
idx
+
1
]
;
}
int
c
=
id_buffer
[
idx
+
2
];
void
Renderer
::
begin_outline
()
{
return
a
|
b
<<
8
|
c
<<
16
;
framebuffer
.
clear_d
();
}
}
}
void
Renderer
::
end_outline
(
const
Mat4
&
view
,
BBox
box
)
{
void
Renderer
::
reset_depth
()
{
framebuffer
.
clear_d
();
}
void
Renderer
::
begin_outline
()
{
framebuffer
.
clear_d
();
}
void
Renderer
::
end_outline
(
const
Mat4
&
view
,
BBox
box
)
{
Mat4
viewproj
=
_proj
*
view
;
Mat4
viewproj
=
_proj
*
view
;
Vec2
min
,
max
;
Vec2
min
,
max
;
box
.
screen_rect
(
viewproj
,
min
,
max
);
box
.
screen_rect
(
viewproj
,
min
,
max
);
Vec2
thickness
=
Vec2
(
3.0
f
/
window_dim
.
x
,
3.0
f
/
window_dim
.
y
);
Vec2
thickness
=
Vec2
(
3.0
f
/
window_dim
.
x
,
3.0
f
/
window_dim
.
y
);
GL
::
Effects
::
outline
(
framebuffer
,
framebuffer
,
Gui
::
Color
::
outline
,
GL
::
Effects
::
outline
(
framebuffer
,
framebuffer
,
Gui
::
Color
::
outline
,
min
-
thickness
,
min
-
thickness
,
max
+
thickness
);
max
+
thickness
);
}
}
void
Renderer
::
outline
(
const
Mat4
&
view
,
Scene_Item
&
obj
)
{
void
Renderer
::
outline
(
const
Mat4
&
view
,
Scene_Item
&
obj
)
{
Mat4
viewproj
=
_proj
*
view
;
Mat4
viewproj
=
_proj
*
view
;
framebuffer
.
clear_d
();
framebuffer
.
clear_d
();
obj
.
render
(
view
,
false
,
true
);
obj
.
render
(
view
,
false
,
true
);
Vec2
min
,
max
;
Vec2
min
,
max
;
obj
.
bbox
().
screen_rect
(
viewproj
,
min
,
max
);
obj
.
bbox
().
screen_rect
(
viewproj
,
min
,
max
);
Vec2
thickness
=
Vec2
(
3.0
f
/
window_dim
.
x
,
3.0
f
/
window_dim
.
y
);
Vec2
thickness
=
Vec2
(
3.0
f
/
window_dim
.
x
,
3.0
f
/
window_dim
.
y
);
GL
::
Effects
::
outline
(
framebuffer
,
framebuffer
,
Gui
::
Color
::
outline
,
GL
::
Effects
::
outline
(
framebuffer
,
framebuffer
,
Gui
::
Color
::
outline
,
min
-
thickness
,
min
-
thickness
,
max
+
thickness
);
max
+
thickness
);
}
}
void
Renderer
::
halfedge_editor
(
Renderer
::
HalfedgeOpt
opt
)
{
void
Renderer
::
halfedge_editor
(
Renderer
::
HalfedgeOpt
opt
)
{
auto
[
faces
,
spheres
,
cylinders
,
arrows
]
=
opt
.
editor
.
shapes
();
auto
[
faces
,
spheres
,
cylinders
,
arrows
]
=
opt
.
editor
.
shapes
();
MeshOpt
fopt
=
MeshOpt
();
MeshOpt
fopt
=
MeshOpt
();
fopt
.
modelview
=
opt
.
modelview
;
fopt
.
modelview
=
opt
.
modelview
;
fopt
.
color
=
opt
.
color
;
fopt
.
color
=
opt
.
color
;
fopt
.
per_vert_id
=
true
;
fopt
.
per_vert_id
=
true
;
fopt
.
sel_color
=
Gui
::
Color
::
outline
;
fopt
.
sel_color
=
Gui
::
Color
::
outline
;
fopt
.
sel_id
=
opt
.
editor
.
select_id
();
fopt
.
sel_id
=
opt
.
editor
.
select_id
();
fopt
.
hov_color
=
Gui
::
Color
::
hover
;
fopt
.
hov_color
=
Gui
::
Color
::
hover
;
fopt
.
hov_id
=
opt
.
editor
.
hover_id
();
fopt
.
hov_id
=
opt
.
editor
.
hover_id
();
Renderer
::
mesh
(
faces
,
fopt
);
Renderer
::
mesh
(
faces
,
fopt
);
inst_shader
.
bind
();
inst_shader
.
bind
();
inst_shader
.
uniform
(
"use_v_id"
,
true
);
inst_shader
.
uniform
(
"use_v_id"
,
true
);
inst_shader
.
uniform
(
"use_i_id"
,
true
);
inst_shader
.
uniform
(
"use_i_id"
,
true
);
inst_shader
.
uniform
(
"solid"
,
false
);
inst_shader
.
uniform
(
"solid"
,
false
);
inst_shader
.
uniform
(
"proj"
,
_proj
);
inst_shader
.
uniform
(
"proj"
,
_proj
);
inst_shader
.
uniform
(
"modelview"
,
opt
.
modelview
);
inst_shader
.
uniform
(
"modelview"
,
opt
.
modelview
);
inst_shader
.
uniform
(
"color"
,
opt
.
color
);
inst_shader
.
uniform
(
"color"
,
opt
.
color
);
inst_shader
.
uniform
(
"alpha"
,
fopt
.
alpha
);
inst_shader
.
uniform
(
"alpha"
,
fopt
.
alpha
);
inst_shader
.
uniform
(
"sel_color"
,
Gui
::
Color
::
outline
);
inst_shader
.
uniform
(
"sel_color"
,
Gui
::
Color
::
outline
);
inst_shader
.
uniform
(
"hov_color"
,
Gui
::
Color
::
hover
);
inst_shader
.
uniform
(
"hov_color"
,
Gui
::
Color
::
hover
);
inst_shader
.
uniform
(
"sel_id"
,
fopt
.
sel_id
);
inst_shader
.
uniform
(
"sel_id"
,
fopt
.
sel_id
);
inst_shader
.
uniform
(
"hov_id"
,
fopt
.
hov_id
);
inst_shader
.
uniform
(
"hov_id"
,
fopt
.
hov_id
);
spheres
.
render
();
spheres
.
render
();
cylinders
.
render
();
cylinders
.
render
();
arrows
.
render
();
arrows
.
render
();
}
}
src/scene/renderer.h
View file @
c2535f0f
...
@@ -3,26 +3,28 @@
...
@@ -3,26 +3,28 @@
#include <variant>
#include <variant>
#include "scene.h"
#include "../platform/gl.h"
#include "../lib/bbox.h"
#include "../lib/bbox.h"
#include "../platform/gl.h"
#include "scene.h"
namespace
Gui
{
class
Model
;
}
namespace
Gui
{
class
Model
;
}
// Singleton
// Singleton
class
Renderer
{
class
Renderer
{
public:
public:
static
void
setup
(
Vec2
dim
);
static
void
setup
(
Vec2
dim
);
static
void
shutdown
();
static
void
shutdown
();
static
Renderer
&
get
();
static
Renderer
&
get
();
void
begin
();
void
begin
();
void
complete
();
void
complete
();
void
reset_depth
();
void
reset_depth
();
void
proj
(
const
Mat4
&
proj
);
void
proj
(
const
Mat4
&
proj
);
void
update_dim
(
Vec2
dim
);
void
update_dim
(
Vec2
dim
);
void
settings_gui
(
bool
*
open
);
void
settings_gui
(
bool
*
open
);
void
set_samples
(
int
samples
);
void
set_samples
(
int
samples
);
unsigned
int
read_id
(
Vec2
pos
);
unsigned
int
read_id
(
Vec2
pos
);
...
@@ -36,47 +38,48 @@ public:
...
@@ -36,47 +38,48 @@ public:
bool
solid_color
=
false
;
bool
solid_color
=
false
;
bool
depth_only
=
false
;
bool
depth_only
=
false
;
bool
per_vert_id
=
false
;
bool
per_vert_id
=
false
;
};
};
struct
HalfedgeOpt
{
struct
HalfedgeOpt
{
HalfedgeOpt
(
Gui
::
Model
&
e
)
:
editor
(
e
)
{}
HalfedgeOpt
(
Gui
::
Model
&
e
)
:
editor
(
e
)
{}
Gui
::
Model
&
editor
;
Gui
::
Model
&
editor
;
Mat4
modelview
;
Mat4
modelview
;
Vec3
color
;
Vec3
color
;
};
};
// NOTE(max): updates & uses the indices in mesh for selection/traversal
// NOTE(max): updates & uses the indices in mesh for selection/traversal
void
halfedge_editor
(
HalfedgeOpt
opt
);
void
halfedge_editor
(
HalfedgeOpt
opt
);
void
mesh
(
GL
::
Mesh
&
mesh
,
MeshOpt
opt
);
void
mesh
(
GL
::
Mesh
&
mesh
,
MeshOpt
opt
);
void
lines
(
const
GL
::
Lines
&
lines
,
const
Mat4
&
view
,
const
Mat4
&
model
=
Mat4
::
I
,
float
alpha
=
1.0
f
);
void
lines
(
const
GL
::
Lines
&
lines
,
const
Mat4
&
view
,
const
Mat4
&
model
=
Mat4
::
I
,
float
alpha
=
1.0
f
);
void
outline
(
const
Mat4
&
view
,
Scene_Item
&
obj
);
void
outline
(
const
Mat4
&
view
,
Scene_Item
&
obj
);
void
begin_outline
();
void
begin_outline
();
void
end_outline
(
const
Mat4
&
view
,
BBox
box
);
void
end_outline
(
const
Mat4
&
view
,
BBox
box
);
void
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
);
void
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
);
void
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
,
const
GL
::
Tex2D
&
tex
);
void
skydome
(
const
Mat4
&
rotation
,
Vec3
color
,
float
cosine
,
const
GL
::
Tex2D
&
tex
);
void
sphere
(
MeshOpt
opt
);
void
sphere
(
MeshOpt
opt
);
void
capsule
(
MeshOpt
opt
,
float
height
,
float
rad
);
void
capsule
(
MeshOpt
opt
,
float
height
,
float
rad
);
void
capsule
(
MeshOpt
opt
,
const
Mat4
&
mdl
,
float
height
,
float
rad
,
BBox
&
box
);
void
capsule
(
MeshOpt
opt
,
const
Mat4
&
mdl
,
float
height
,
float
rad
,
BBox
&
box
);
GLuint
saved
()
const
;
GLuint
saved
()
const
;
void
saved
(
std
::
vector
<
unsigned
char
>
&
data
)
const
;
void
saved
(
std
::
vector
<
unsigned
char
>
&
data
)
const
;
void
save
(
Scene
&
scene
,
const
Camera
&
cam
,
int
w
,
int
h
,
int
samples
);
void
save
(
Scene
&
scene
,
const
Camera
&
cam
,
int
w
,
int
h
,
int
samples
);
private:
private:
Renderer
(
Vec2
dim
);
Renderer
(
Vec2
dim
);
~
Renderer
();
~
Renderer
();
static
inline
Renderer
*
data
=
nullptr
;
static
inline
Renderer
*
data
=
nullptr
;
GL
::
Framebuffer
framebuffer
,
id_resolve
,
save_buffer
,
save_output
;
GL
::
Framebuffer
framebuffer
,
id_resolve
,
save_buffer
,
save_output
;
GL
::
Shader
mesh_shader
,
line_shader
,
inst_shader
,
dome_shader
;
GL
::
Shader
mesh_shader
,
line_shader
,
inst_shader
,
dome_shader
;
GL
::
Mesh
_sphere
,
_cyl
,
_hemi
;
GL
::
Mesh
_sphere
,
_cyl
,
_hemi
;
int
samples
;
int
samples
;
Vec2
window_dim
;
Vec2
window_dim
;
GLubyte
*
id_buffer
;
GLubyte
*
id_buffer
;
Mat4
_proj
;
Mat4
_proj
;
};
};
src/scene/scene.cpp
View file @
c2535f0f
#include <sstream>
#include <assimp/Importer.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <assimp/scene.h>
#include <sstream>
#include "../lib/log.h"
#include "../gui/manager.h"
#include "../gui/manager.h"
#include "../gui/render.h"
#include "../gui/render.h"
#include "../lib/log.h"
#include "scene.h"
#include "renderer.h"
#include "renderer.h"
#include "scene.h"
#include "undo.h"
#include "undo.h"
namespace
std
{
namespace
std
{
template
<
typename
T1
,
typename
T2
>
template
<
typename
T1
,
typename
T2
>
struct
hash
<
pair
<
T1
,
T2
>>
{
struct
hash
<
pair
<
T1
,
T2
>>
{
uint64_t
operator
()(
const
pair
<
T1
,
T2
>
&
p
)
const
{
uint64_t
operator
()(
const
pair
<
T1
,
T2
>&
p
)
const
{
static
const
hash
<
T1
>
h1
;
static
const
hash
<
T1
>
h1
;
static
const
hash
<
T2
>
h2
;
static
const
hash
<
T2
>
h2
;
return
h1
(
p
.
first
)
^
h2
(
p
.
second
);
return
h1
(
p
.
first
)
^
h2
(
p
.
second
);
}
}
};
};
};
};
// namespace std
Scene_Item
::
Scene_Item
(
Scene_Object
&&
obj
)
:
Scene_Item
::
Scene_Item
(
Scene_Object
&&
obj
)
:
data
(
std
::
move
(
obj
))
{}
data
(
std
::
move
(
obj
))
{}
Scene_Item
::
Scene_Item
(
Scene_Light
&&
light
)
:
Scene_Item
::
Scene_Item
(
Scene_Light
&&
light
)
:
data
(
std
::
move
(
light
))
{}
data
(
std
::
move
(
light
))
{}
Scene_Item
::
Scene_Item
(
Scene_Item
&&
src
)
:
data
(
std
::
move
(
src
.
data
))
Scene_Item
::
Scene_Item
(
Scene_Item
&&
src
)
:
data
(
std
::
move
(
src
.
data
))
{}
{}
Scene_Item
&
Scene_Item
::
operator
=
(
Scene_Item
&&
src
)
{
Scene_Item
&
Scene_Item
::
operator
=
(
Scene_Item
&&
src
)
{
data
=
std
::
move
(
src
.
data
);
data
=
std
::
move
(
src
.
data
);
return
*
this
;
return
*
this
;
}
}
void
Scene_Item
::
set_time
(
float
time
)
{
void
Scene_Item
::
set_time
(
float
time
)
{
return
std
::
visit
(
overloaded
{
return
std
::
visit
(
overloaded
{[
time
](
Scene_Object
&
obj
)
{
obj
.
set_time
(
time
);
},
[
time
](
Scene_Object
&
obj
)
{
[
time
](
Scene_Light
&
light
)
{
light
.
set_time
(
time
);
}},
obj
.
set_time
(
time
);
data
);
},
[
time
](
Scene_Light
&
light
)
{
light
.
set_time
(
time
);
}
},
data
);
}
}
BBox
Scene_Item
::
bbox
()
{
BBox
Scene_Item
::
bbox
()
{
return
std
::
visit
(
overloaded
{
return
std
::
visit
(
overloaded
{[](
Scene_Object
&
obj
)
{
return
obj
.
bbox
();
},
[](
Scene_Object
&
obj
)
{
[](
Scene_Light
&
light
)
{
return
light
.
bbox
();
}},
return
obj
.
bbox
();
data
);
},
[](
Scene_Light
&
light
)
{
return
light
.
bbox
();
}
},
data
);
}
}
void
Scene_Item
::
render
(
const
Mat4
&
view
,
bool
solid
,
bool
depth_only
,
bool
posed
)
{
void
Scene_Item
::
render
(
const
Mat4
&
view
,
bool
solid
,
bool
depth_only
,
bool
posed
)
{
std
::
visit
(
overloaded
{
std
::
visit
(
overloaded
{[
&
](
Scene_Object
&
obj
)
{
obj
.
render
(
view
,
solid
,
depth_only
,
posed
);
},
[
&
](
Scene_Object
&
obj
)
{
[
&
](
Scene_Light
&
light
)
{
light
.
render
(
view
,
depth_only
,
posed
);
}},
obj
.
render
(
view
,
solid
,
depth_only
,
posed
);
data
);
},
[
&
](
Scene_Light
&
light
)
{
light
.
render
(
view
,
depth_only
,
posed
);
}
},
data
);
}
}
Scene_ID
Scene_Item
::
id
()
const
{
Scene_ID
Scene_Item
::
id
()
const
{
return
std
::
visit
(
overloaded
{
return
std
::
visit
(
overloaded
{[](
const
Scene_Object
&
obj
)
{
return
obj
.
id
();
},
[](
const
Scene_Object
&
obj
)
{
[](
const
Scene_Light
&
light
)
{
return
light
.
id
();
}},
return
obj
.
id
();
data
);
},
[](
const
Scene_Light
&
light
)
{
return
light
.
id
();
}
},
data
);
}
}
Anim_Pose
&
Scene_Item
::
animation
()
{
Anim_Pose
&
Scene_Item
::
animation
()
{
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
o
->
anim
;
if
(
o
)
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
o
->
anim
;
if
(
l
)
return
l
->
anim
;
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
l
->
anim
;
assert
(
false
);
assert
(
false
);
return
l
->
anim
;
return
l
->
anim
;
}
}
const
Anim_Pose
&
Scene_Item
::
animation
()
const
{
const
Anim_Pose
&
Scene_Item
::
animation
()
const
{
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
o
->
anim
;
if
(
o
)
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
o
->
anim
;
if
(
l
)
return
l
->
anim
;
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
l
->
anim
;
assert
(
false
);
assert
(
false
);
return
l
->
anim
;
return
l
->
anim
;
}
}
Pose
&
Scene_Item
::
pose
()
{
Pose
&
Scene_Item
::
pose
()
{
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
o
->
pose
;
if
(
o
)
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
o
->
pose
;
if
(
l
)
return
l
->
pose
;
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
l
->
pose
;
assert
(
false
);
assert
(
false
);
return
l
->
pose
;
return
l
->
pose
;
}
}
const
Pose
&
Scene_Item
::
pose
()
const
{
const
Pose
&
Scene_Item
::
pose
()
const
{
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
o
->
pose
;
if
(
o
)
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
o
->
pose
;
if
(
l
)
return
l
->
pose
;
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
l
->
pose
;
assert
(
false
);
assert
(
false
);
return
l
->
pose
;
return
l
->
pose
;
}
}
std
::
pair
<
char
*
,
int
>
Scene_Item
::
name
()
{
std
::
pair
<
char
*
,
int
>
Scene_Item
::
name
()
{
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
{
o
->
opt
.
name
,
Scene_Object
::
max_name_len
};
if
(
o
)
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
{
o
->
opt
.
name
,
Scene_Object
::
max_name_len
};
if
(
l
)
return
{
l
->
opt
.
name
,
Scene_Light
::
max_name_len
};
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
{
l
->
opt
.
name
,
Scene_Light
::
max_name_len
};
assert
(
false
);
assert
(
false
);
return
{
l
->
opt
.
name
,
Scene_Object
::
max_name_len
};
return
{
l
->
opt
.
name
,
Scene_Object
::
max_name_len
};
}
}
std
::
string
Scene_Item
::
name
()
const
{
std
::
string
Scene_Item
::
name
()
const
{
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
const
Scene_Object
*
o
=
std
::
get_if
<
Scene_Object
>
(
&
data
);
if
(
o
)
return
std
::
string
(
o
->
opt
.
name
);
if
(
o
)
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
return
std
::
string
(
o
->
opt
.
name
);
if
(
l
)
return
std
::
string
(
l
->
opt
.
name
);
const
Scene_Light
*
l
=
std
::
get_if
<
Scene_Light
>
(
&
data
);
if
(
l
)
return
std
::
string
(
l
->
opt
.
name
);
assert
(
false
);
assert
(
false
);
return
std
::
string
(
l
->
opt
.
name
);
return
std
::
string
(
l
->
opt
.
name
);
}
}
Scene
::
Scene
(
Scene_ID
start
)
:
Scene
::
Scene
(
Scene_ID
start
)
:
next_id
(
start
),
first_id
(
start
)
{}
next_id
(
start
),
first_id
(
start
)
{
}
Scene_ID
Scene
::
used_ids
()
{
Scene_ID
Scene
::
used_ids
()
{
return
next_id
;
}
return
next_id
;
}
Scene_ID
Scene
::
reserve_id
()
{
Scene_ID
Scene
::
reserve_id
()
{
return
next_id
++
;
}
return
next_id
++
;
}
Scene_ID
Scene
::
add
(
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
,
Scene_ID
id
)
{
Scene_ID
Scene
::
add
(
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
,
Scene_ID
id
)
{
if
(
!
id
)
id
=
next_id
++
;
if
(
!
id
)
assert
(
objs
.
find
(
id
)
==
objs
.
end
());
id
=
next_id
++
;
objs
.
emplace
(
std
::
make_pair
(
id
,
Scene_Object
(
id
,
pose
,
std
::
move
(
mesh
),
n
)));
assert
(
objs
.
find
(
id
)
==
objs
.
end
());
return
id
;
objs
.
emplace
(
std
::
make_pair
(
id
,
Scene_Object
(
id
,
pose
,
std
::
move
(
mesh
),
n
)));
return
id
;
}
}
Scene_ID
Scene
::
add
(
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
,
Scene_ID
id
)
{
Scene_ID
Scene
::
add
(
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
,
Scene_ID
id
)
{
if
(
!
id
)
id
=
next_id
++
;
if
(
!
id
)
assert
(
objs
.
find
(
id
)
==
objs
.
end
());
id
=
next_id
++
;
objs
.
emplace
(
std
::
make_pair
(
id
,
Scene_Object
(
id
,
pose
,
std
::
move
(
mesh
),
n
)));
assert
(
objs
.
find
(
id
)
==
objs
.
end
());
return
id
;
objs
.
emplace
(
std
::
make_pair
(
id
,
Scene_Object
(
id
,
pose
,
std
::
move
(
mesh
),
n
)));
return
id
;
}
}
std
::
string
Scene
::
set_env_map
(
std
::
string
file
)
{
std
::
string
Scene
::
set_env_map
(
std
::
string
file
)
{
Scene_ID
id
=
0
;
Scene_ID
id
=
0
;
for_items
([
&
id
](
const
Scene_Item
&
item
)
{
for_items
([
&
id
](
const
Scene_Item
&
item
)
{
if
(
item
.
is
<
Scene_Light
>
()
&&
item
.
get
<
Scene_Light
>
().
is_env
())
if
(
item
.
is
<
Scene_Light
>
()
&&
item
.
get
<
Scene_Light
>
().
is_env
())
id
=
item
.
id
();
id
=
item
.
id
();
});
});
Scene_Light
l
(
Light_Type
::
sphere
,
reserve_id
(),
{},
"env_map"
);
Scene_Light
l
(
Light_Type
::
sphere
,
reserve_id
(),
{},
"env_map"
);
std
::
string
err
=
l
.
emissive_load
(
file
);
std
::
string
err
=
l
.
emissive_load
(
file
);
if
(
err
.
empty
())
{
if
(
err
.
empty
())
{
if
(
id
)
erase
(
id
);
if
(
id
)
add
(
std
::
move
(
l
));
erase
(
id
);
}
add
(
std
::
move
(
l
));
return
err
;
}
return
err
;
}
}
bool
Scene
::
has_env_light
()
const
{
bool
Scene
::
has_env_light
()
const
{
bool
ret
=
false
;
bool
ret
=
false
;
for_items
([
&
ret
](
const
Scene_Item
&
item
)
{
for_items
([
&
ret
](
const
Scene_Item
&
item
)
{
ret
=
ret
||
(
item
.
is
<
Scene_Light
>
()
&&
item
.
get
<
Scene_Light
>
().
is_env
());
ret
=
ret
||
(
item
.
is
<
Scene_Light
>
()
&&
item
.
get
<
Scene_Light
>
().
is_env
());
});
});
return
ret
;
return
ret
;
}
}
Scene_ID
Scene
::
add
(
Scene_Light
&&
obj
)
{
Scene_ID
Scene
::
add
(
Scene_Light
&&
obj
)
{
assert
(
objs
.
find
(
obj
.
id
())
==
objs
.
end
());
assert
(
objs
.
find
(
obj
.
id
())
==
objs
.
end
());
objs
.
emplace
(
std
::
make_pair
(
obj
.
id
(),
std
::
move
(
obj
)));
objs
.
emplace
(
std
::
make_pair
(
obj
.
id
(),
std
::
move
(
obj
)));
return
obj
.
id
();
return
obj
.
id
();
}
}
Scene_ID
Scene
::
add
(
Scene_Object
&&
obj
)
{
Scene_ID
Scene
::
add
(
Scene_Object
&&
obj
)
{
assert
(
objs
.
find
(
obj
.
id
())
==
objs
.
end
());
assert
(
objs
.
find
(
obj
.
id
())
==
objs
.
end
());
objs
.
emplace
(
std
::
make_pair
(
obj
.
id
(),
std
::
move
(
obj
)));
objs
.
emplace
(
std
::
make_pair
(
obj
.
id
(),
std
::
move
(
obj
)));
return
obj
.
id
();
return
obj
.
id
();
}
}
void
Scene
::
restore
(
Scene_ID
id
)
{
void
Scene
::
restore
(
Scene_ID
id
)
{
if
(
objs
.
find
(
id
)
!=
objs
.
end
())
return
;
if
(
objs
.
find
(
id
)
!=
objs
.
end
())
assert
(
erased
.
find
(
id
)
!=
erased
.
end
());
return
;
objs
.
insert
({
id
,
std
::
move
(
erased
[
id
])});
assert
(
erased
.
find
(
id
)
!=
erased
.
end
());
erased
.
erase
(
id
);
objs
.
insert
({
id
,
std
::
move
(
erased
[
id
])});
erased
.
erase
(
id
);
}
}
void
Scene
::
erase
(
Scene_ID
id
)
{
void
Scene
::
erase
(
Scene_ID
id
)
{
assert
(
erased
.
find
(
id
)
==
erased
.
end
());
assert
(
erased
.
find
(
id
)
==
erased
.
end
());
assert
(
objs
.
find
(
id
)
!=
objs
.
end
());
assert
(
objs
.
find
(
id
)
!=
objs
.
end
());
erased
.
insert
({
id
,
std
::
move
(
objs
[
id
])});
erased
.
insert
({
id
,
std
::
move
(
objs
[
id
])});
objs
.
erase
(
id
);
objs
.
erase
(
id
);
}
}
void
Scene
::
for_items
(
std
::
function
<
void
(
const
Scene_Item
&
)
>
func
)
const
{
void
Scene
::
for_items
(
std
::
function
<
void
(
const
Scene_Item
&
)
>
func
)
const
{
for
(
const
auto
&
obj
:
objs
)
{
for
(
const
auto
&
obj
:
objs
)
{
func
(
obj
.
second
);
func
(
obj
.
second
);
}
}
}
}
void
Scene
::
for_items
(
std
::
function
<
void
(
Scene_Item
&
)
>
func
)
{
void
Scene
::
for_items
(
std
::
function
<
void
(
Scene_Item
&
)
>
func
)
{
for
(
auto
&
obj
:
objs
)
{
for
(
auto
&
obj
:
objs
)
{
func
(
obj
.
second
);
func
(
obj
.
second
);
}
}
}
}
size_t
Scene
::
size
()
{
size_t
Scene
::
size
()
{
return
objs
.
size
();
}
return
objs
.
size
();
}
bool
Scene
::
empty
()
{
bool
Scene
::
empty
()
{
return
objs
.
size
()
==
0
;
}
return
objs
.
size
()
==
0
;
}
Scene_Maybe
Scene
::
get
(
Scene_ID
id
)
{
Scene_Maybe
Scene
::
get
(
Scene_ID
id
)
{
auto
entry
=
objs
.
find
(
id
);
auto
entry
=
objs
.
find
(
id
);
if
(
entry
==
objs
.
end
())
return
std
::
nullopt
;
if
(
entry
==
objs
.
end
())
return
entry
->
second
;
return
std
::
nullopt
;
return
entry
->
second
;
}
}
Scene_Light
&
Scene
::
get_light
(
Scene_ID
id
)
{
Scene_Light
&
Scene
::
get_light
(
Scene_ID
id
)
{
auto
entry
=
objs
.
find
(
id
);
auto
entry
=
objs
.
find
(
id
);
assert
(
entry
!=
objs
.
end
());
assert
(
entry
!=
objs
.
end
());
assert
(
entry
->
second
.
is
<
Scene_Light
>
());
assert
(
entry
->
second
.
is
<
Scene_Light
>
());
return
entry
->
second
.
get
<
Scene_Light
>
();
return
entry
->
second
.
get
<
Scene_Light
>
();
}
}
Scene_Object
&
Scene
::
get_obj
(
Scene_ID
id
)
{
Scene_Object
&
Scene
::
get_obj
(
Scene_ID
id
)
{
auto
entry
=
objs
.
find
(
id
);
auto
entry
=
objs
.
find
(
id
);
assert
(
entry
!=
objs
.
end
());
assert
(
entry
!=
objs
.
end
());
assert
(
entry
->
second
.
is
<
Scene_Object
>
());
assert
(
entry
->
second
.
is
<
Scene_Object
>
());
return
entry
->
second
.
get
<
Scene_Object
>
();
return
entry
->
second
.
get
<
Scene_Object
>
();
}
}
void
Scene
::
clear
(
Undo
&
undo
)
{
void
Scene
::
clear
(
Undo
&
undo
)
{
next_id
=
first_id
;
next_id
=
first_id
;
objs
.
clear
();
objs
.
clear
();
erased
.
clear
();
erased
.
clear
();
undo
.
reset
();
undo
.
reset
();
}
}
static
const
std
::
string
FAKE_NAME
=
"FAKE-S3D-FAKE-MESH"
;
static
const
std
::
string
FAKE_NAME
=
"FAKE-S3D-FAKE-MESH"
;
static
aiVector3D
vecVec
(
Vec3
v
)
{
static
aiVector3D
vecVec
(
Vec3
v
)
{
return
aiVector3D
(
v
.
x
,
v
.
y
,
v
.
z
);
}
return
aiVector3D
(
v
.
x
,
v
.
y
,
v
.
z
);
}
static
Quat
aiQuat
(
aiQuaternion
aiv
)
{
static
Quat
aiQuat
(
aiQuaternion
aiv
)
{
return
Quat
(
aiv
.
x
,
aiv
.
y
,
aiv
.
z
,
aiv
.
w
);
}
return
Quat
(
aiv
.
x
,
aiv
.
y
,
aiv
.
z
,
aiv
.
w
);
}
static
Vec3
aiVec
(
aiVector3D
aiv
)
{
static
Vec3
aiVec
(
aiVector3D
aiv
)
{
return
Vec3
(
aiv
.
x
,
aiv
.
y
,
aiv
.
z
);
}
return
Vec3
(
aiv
.
x
,
aiv
.
y
,
aiv
.
z
);
}
static
Spectrum
aiSpec
(
aiColor3D
aiv
)
{
static
Spectrum
aiSpec
(
aiColor3D
aiv
)
{
return
Spectrum
(
aiv
.
r
,
aiv
.
g
,
aiv
.
b
);
}
return
Spectrum
(
aiv
.
r
,
aiv
.
g
,
aiv
.
b
);
}
static
aiMatrix4x4
matMat
(
const
Mat4
&
T
)
{
static
aiMatrix4x4
matMat
(
const
Mat4
&
T
)
{
return
{
T
[
0
][
0
],
T
[
1
][
0
],
T
[
2
][
0
],
T
[
3
][
0
],
return
{
T
[
0
][
0
],
T
[
1
][
0
],
T
[
2
][
0
],
T
[
3
][
0
],
T
[
0
][
1
],
T
[
1
][
1
],
T
[
2
][
1
],
T
[
3
][
1
],
T
[
0
][
1
],
T
[
1
][
1
],
T
[
2
][
1
],
T
[
3
][
1
],
T
[
0
][
2
],
T
[
1
][
2
],
T
[
2
][
2
],
T
[
3
][
2
],
T
[
0
][
3
],
T
[
1
][
3
],
T
[
2
][
3
],
T
[
3
][
3
]};
T
[
0
][
2
],
T
[
1
][
2
],
T
[
2
][
2
],
T
[
3
][
2
],
T
[
0
][
3
],
T
[
1
][
3
],
T
[
2
][
3
],
T
[
3
][
3
]};
}
}
static
Mat4
aiMat
(
aiMatrix4x4
T
)
{
static
Mat4
aiMat
(
aiMatrix4x4
T
)
{
return
Mat4
{
Vec4
{
T
[
0
][
0
],
T
[
1
][
0
],
T
[
2
][
0
],
T
[
3
][
0
]},
return
Mat4
{
Vec4
{
T
[
0
][
0
],
T
[
1
][
0
],
T
[
2
][
0
],
T
[
3
][
0
]},
Vec4
{
T
[
0
][
1
],
T
[
1
][
1
],
T
[
2
][
1
],
T
[
3
][
1
]},
Vec4
{
T
[
0
][
1
],
T
[
1
][
1
],
T
[
2
][
1
],
T
[
3
][
1
]},
Vec4
{
T
[
0
][
2
],
T
[
1
][
2
],
T
[
2
][
2
],
T
[
3
][
2
]},
Vec4
{
T
[
0
][
3
],
T
[
1
][
3
],
T
[
2
][
3
],
T
[
3
][
3
]}};
Vec4
{
T
[
0
][
2
],
T
[
1
][
2
],
T
[
2
][
2
],
T
[
3
][
2
]},
Vec4
{
T
[
0
][
3
],
T
[
1
][
3
],
T
[
2
][
3
],
T
[
3
][
3
]}};
}
}
static
aiMatrix4x4
node_transform
(
const
aiNode
*
node
)
{
static
aiMatrix4x4
node_transform
(
const
aiNode
*
node
)
{
aiMatrix4x4
T
;
aiMatrix4x4
T
;
while
(
node
)
{
while
(
node
)
{
T
=
T
*
node
->
mTransformation
;
T
=
T
*
node
->
mTransformation
;
node
=
node
->
mParent
;
node
=
node
->
mParent
;
}
}
return
T
;
return
T
;
}
}
static
void
load_node
(
Scene
&
scobj
,
std
::
vector
<
std
::
string
>&
errors
,
static
void
load_node
(
Scene
&
scobj
,
std
::
vector
<
std
::
string
>
&
errors
,
std
::
unordered_map
<
aiNode
*
,
Scene_ID
>&
node_to_obj
,
std
::
unordered_map
<
aiNode
*
,
Scene_ID
>
&
node_to_obj
,
std
::
unordered_map
<
aiNode
*
,
Joint
*>&
node_to_bone
,
std
::
unordered_map
<
aiNode
*
,
Joint
*>
&
node_to_bone
,
const
aiScene
*
scene
,
const
aiScene
*
scene
,
aiNode
*
node
,
aiMatrix4x4
transform
)
{
aiNode
*
node
,
aiMatrix4x4
transform
)
{
transform
=
transform
*
node
->
mTransformation
;
transform
=
transform
*
node
->
mTransformation
;
for
(
unsigned
int
i
=
0
;
i
<
node
->
mNumMeshes
;
i
++
)
{
for
(
unsigned
int
i
=
0
;
i
<
node
->
mNumMeshes
;
i
++
)
{
const
aiMesh
*
mesh
=
scene
->
mMeshes
[
node
->
mMeshes
[
i
]];
const
aiMesh
*
mesh
=
scene
->
mMeshes
[
node
->
mMeshes
[
i
]];
std
::
string
name
;
std
::
string
name
;
bool
do_flip
=
false
,
do_smooth
=
false
;
bool
do_flip
=
false
,
do_smooth
=
false
;
if
(
mesh
->
mName
.
length
)
{
if
(
mesh
->
mName
.
length
)
{
name
=
std
::
string
(
mesh
->
mName
.
C_Str
());
name
=
std
::
string
(
mesh
->
mName
.
C_Str
());
if
(
name
.
find
(
FAKE_NAME
)
!=
std
::
string
::
npos
)
continue
;
if
(
name
.
find
(
FAKE_NAME
)
!=
std
::
string
::
npos
)
continue
;
size_t
special
=
name
.
find
(
"-S3D-"
);
if
(
special
!=
std
::
string
::
npos
)
{
size_t
special
=
name
.
find
(
"-S3D-"
);
if
(
name
.
find
(
"FLIPPED"
)
!=
std
::
string
::
npos
)
do_flip
=
true
;
if
(
special
!=
std
::
string
::
npos
)
{
if
(
name
.
find
(
"SMOOTHED"
)
!=
std
::
string
::
npos
)
do_smooth
=
true
;
if
(
name
.
find
(
"FLIPPED"
)
!=
std
::
string
::
npos
)
name
=
name
.
substr
(
0
,
special
);
do_flip
=
true
;
std
::
replace
(
name
.
begin
(),
name
.
end
(),
'_'
,
' '
);
if
(
name
.
find
(
"SMOOTHED"
)
!=
std
::
string
::
npos
)
}
do_smooth
=
true
;
}
name
=
name
.
substr
(
0
,
special
);
std
::
replace
(
name
.
begin
(),
name
.
end
(),
'_'
,
' '
);
if
(
!
mesh
->
HasNormals
())
{
}
errors
.
push_back
(
"Mesh has no normals."
);
}
continue
;
}
if
(
!
mesh
->
HasNormals
())
{
errors
.
push_back
(
"Mesh has no normals."
);
std
::
vector
<
Vec3
>
verts
;
continue
;
}
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumVertices
;
j
++
)
{
const
aiVector3D
&
pos
=
mesh
->
mVertices
[
j
];
std
::
vector
<
Vec3
>
verts
;
verts
.
push_back
(
Vec3
(
pos
.
x
,
pos
.
y
,
pos
.
z
));
}
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumVertices
;
j
++
)
{
const
aiVector3D
&
pos
=
mesh
->
mVertices
[
j
];
std
::
vector
<
std
::
vector
<
Halfedge_Mesh
::
Index
>>
polys
;
verts
.
push_back
(
Vec3
(
pos
.
x
,
pos
.
y
,
pos
.
z
));
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumFaces
;
j
++
)
{
}
const
aiFace
&
face
=
mesh
->
mFaces
[
j
];
std
::
vector
<
std
::
vector
<
Halfedge_Mesh
::
Index
>>
polys
;
std
::
vector
<
Halfedge_Mesh
::
Index
>
poly
;
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumFaces
;
j
++
)
{
for
(
unsigned
int
k
=
0
;
k
<
face
.
mNumIndices
;
k
++
)
{
const
aiFace
&
face
=
mesh
->
mFaces
[
j
];
poly
.
push_back
(
face
.
mIndices
[
k
]);
}
std
::
vector
<
Halfedge_Mesh
::
Index
>
poly
;
polys
.
push_back
(
poly
);
for
(
unsigned
int
k
=
0
;
k
<
face
.
mNumIndices
;
k
++
)
{
}
poly
.
push_back
(
face
.
mIndices
[
k
]);
}
aiVector3D
ascale
,
arot
,
apos
;
polys
.
push_back
(
poly
);
transform
.
Decompose
(
ascale
,
arot
,
apos
);
}
Vec3
pos
=
aiVec
(
apos
);
Vec3
rot
=
aiVec
(
arot
);
aiVector3D
ascale
,
arot
,
apos
;
Vec3
scale
=
aiVec
(
ascale
);
transform
.
Decompose
(
ascale
,
arot
,
apos
);
Pose
p
=
{
pos
,
Degrees
(
rot
).
range
(
0.0
f
,
360.0
f
),
scale
};
Vec3
pos
=
aiVec
(
apos
);
Vec3
rot
=
aiVec
(
arot
);
Material
::
Options
material
;
Vec3
scale
=
aiVec
(
ascale
);
const
aiMaterial
&
ai_mat
=
*
scene
->
mMaterials
[
mesh
->
mMaterialIndex
];
Pose
p
=
{
pos
,
Degrees
(
rot
).
range
(
0.0
f
,
360.0
f
),
scale
};
aiColor3D
albedo
;
Material
::
Options
material
;
ai_mat
.
Get
(
AI_MATKEY_COLOR_DIFFUSE
,
albedo
);
const
aiMaterial
&
ai_mat
=
*
scene
->
mMaterials
[
mesh
->
mMaterialIndex
];
material
.
albedo
=
aiSpec
(
albedo
);
aiColor3D
albedo
;
aiColor3D
emissive
;
ai_mat
.
Get
(
AI_MATKEY_COLOR_DIFFUSE
,
albedo
);
ai_mat
.
Get
(
AI_MATKEY_COLOR_EMISSIVE
,
emissive
);
material
.
albedo
=
aiSpec
(
albedo
);
material
.
emissive
=
aiSpec
(
emissive
);
aiColor3D
emissive
;
aiColor3D
reflectance
;
ai_mat
.
Get
(
AI_MATKEY_COLOR_EMISSIVE
,
emissive
);
ai_mat
.
Get
(
AI_MATKEY_COLOR_REFLECTIVE
,
reflectance
);
material
.
emissive
=
aiSpec
(
emissive
);
material
.
reflectance
=
aiSpec
(
reflectance
);
aiColor3D
reflectance
;
aiColor3D
transmittance
;
ai_mat
.
Get
(
AI_MATKEY_COLOR_REFLECTIVE
,
reflectance
);
ai_mat
.
Get
(
AI_MATKEY_COLOR_TRANSPARENT
,
transmittance
);
material
.
reflectance
=
aiSpec
(
reflectance
);
material
.
transmittance
=
aiSpec
(
transmittance
);
aiColor3D
transmittance
;
ai_mat
.
Get
(
AI_MATKEY_REFRACTI
,
material
.
ior
);
ai_mat
.
Get
(
AI_MATKEY_COLOR_TRANSPARENT
,
transmittance
);
ai_mat
.
Get
(
AI_MATKEY_SHININESS
,
material
.
intensity
);
material
.
transmittance
=
aiSpec
(
transmittance
);
aiString
ai_type
;
ai_mat
.
Get
(
AI_MATKEY_REFRACTI
,
material
.
ior
);
ai_mat
.
Get
(
AI_MATKEY_NAME
,
ai_type
);
ai_mat
.
Get
(
AI_MATKEY_SHININESS
,
material
.
intensity
);
std
::
string
type
(
ai_type
.
C_Str
());
aiString
ai_type
;
if
(
type
.
find
(
"lambertian"
)
!=
std
::
string
::
npos
)
{
ai_mat
.
Get
(
AI_MATKEY_NAME
,
ai_type
);
material
.
type
=
Material_Type
::
lambertian
;
std
::
string
type
(
ai_type
.
C_Str
());
}
else
if
(
type
.
find
(
"mirror"
)
!=
std
::
string
::
npos
)
{
material
.
type
=
Material_Type
::
mirror
;
if
(
type
.
find
(
"lambertian"
)
!=
std
::
string
::
npos
)
{
}
else
if
(
type
.
find
(
"refract"
)
!=
std
::
string
::
npos
)
{
material
.
type
=
Material_Type
::
lambertian
;
material
.
type
=
Material_Type
::
refract
;
}
else
if
(
type
.
find
(
"mirror"
)
!=
std
::
string
::
npos
)
{
}
else
if
(
type
.
find
(
"glass"
)
!=
std
::
string
::
npos
)
{
material
.
type
=
Material_Type
::
mirror
;
material
.
type
=
Material_Type
::
glass
;
}
else
if
(
type
.
find
(
"refract"
)
!=
std
::
string
::
npos
)
{
}
else
if
(
type
.
find
(
"diffuse_light"
)
!=
std
::
string
::
npos
)
{
material
.
type
=
Material_Type
::
refract
;
material
.
type
=
Material_Type
::
diffuse_light
;
}
else
if
(
type
.
find
(
"glass"
)
!=
std
::
string
::
npos
)
{
}
else
{
material
.
type
=
Material_Type
::
glass
;
material
=
Material
::
Options
();
}
else
if
(
type
.
find
(
"diffuse_light"
)
!=
std
::
string
::
npos
)
{
}
material
.
type
=
Material_Type
::
diffuse_light
;
material
.
emissive
*=
1.0
f
/
material
.
intensity
;
}
else
{
material
=
Material
::
Options
();
Scene_Object
new_obj
;
}
material
.
emissive
*=
1.0
f
/
material
.
intensity
;
// Horrible hack
if
(
type
.
find
(
"SPHERESHAPE"
)
!=
std
::
string
::
npos
)
{
Scene_Object
new_obj
;
aiColor3D
specular
;
// Horrible hack
ai_mat
.
Get
(
AI_MATKEY_COLOR_SPECULAR
,
specular
);
if
(
type
.
find
(
"SPHERESHAPE"
)
!=
std
::
string
::
npos
)
{
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
GL
::
Mesh
());
obj
.
material
.
opt
=
material
;
aiColor3D
specular
;
obj
.
opt
.
shape_type
=
PT
::
Shape_Type
::
sphere
;
ai_mat
.
Get
(
AI_MATKEY_COLOR_SPECULAR
,
specular
);
obj
.
opt
.
shape
=
PT
::
Shape
(
PT
::
Sphere
(
specular
.
r
));
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
GL
::
Mesh
());
new_obj
=
std
::
move
(
obj
);
obj
.
material
.
opt
=
material
;
obj
.
opt
.
shape_type
=
PT
::
Shape_Type
::
sphere
;
}
else
{
obj
.
opt
.
shape
=
PT
::
Shape
(
PT
::
Sphere
(
specular
.
r
));
new_obj
=
std
::
move
(
obj
);
Halfedge_Mesh
hemesh
;
std
::
string
err
=
hemesh
.
from_poly
(
polys
,
verts
);
}
else
{
if
(
!
err
.
empty
())
{
Halfedge_Mesh
hemesh
;
std
::
vector
<
GL
::
Mesh
::
Vert
>
mesh_verts
;
std
::
string
err
=
hemesh
.
from_poly
(
polys
,
verts
);
std
::
vector
<
GL
::
Mesh
::
Index
>
mesh_inds
;
if
(
!
err
.
empty
())
{
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumVertices
;
j
++
)
{
std
::
vector
<
GL
::
Mesh
::
Vert
>
mesh_verts
;
const
aiVector3D
&
vpos
=
mesh
->
mVertices
[
j
];
std
::
vector
<
GL
::
Mesh
::
Index
>
mesh_inds
;
const
aiVector3D
&
vnorm
=
mesh
->
mNormals
[
j
];
mesh_verts
.
push_back
({
aiVec
(
vpos
),
aiVec
(
vnorm
),
0
});
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumVertices
;
j
++
)
{
}
const
aiVector3D
&
vpos
=
mesh
->
mVertices
[
j
];
const
aiVector3D
&
vnorm
=
mesh
->
mNormals
[
j
];
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumFaces
;
j
++
)
{
mesh_verts
.
push_back
({
aiVec
(
vpos
),
aiVec
(
vnorm
),
0
});
const
aiFace
&
face
=
mesh
->
mFaces
[
j
];
}
unsigned
int
start
=
face
.
mIndices
[
0
];
for
(
size_t
k
=
1
;
k
<=
face
.
mNumIndices
-
2
;
k
++
)
{
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumFaces
;
j
++
)
{
mesh_inds
.
push_back
(
start
);
const
aiFace
&
face
=
mesh
->
mFaces
[
j
];
mesh_inds
.
push_back
(
face
.
mIndices
[
k
]);
unsigned
int
start
=
face
.
mIndices
[
0
];
mesh_inds
.
push_back
(
face
.
mIndices
[
k
+
1
]);
for
(
size_t
k
=
1
;
k
<=
face
.
mNumIndices
-
2
;
k
++
)
{
}
mesh_inds
.
push_back
(
start
);
}
mesh_inds
.
push_back
(
face
.
mIndices
[
k
]);
mesh_inds
.
push_back
(
face
.
mIndices
[
k
+
1
]);
errors
.
push_back
(
err
);
}
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
GL
::
Mesh
(
std
::
move
(
mesh_verts
),
std
::
move
(
mesh_inds
)),
name
);
}
obj
.
material
.
opt
=
material
;
new_obj
=
std
::
move
(
obj
);
errors
.
push_back
(
err
);
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
}
else
{
GL
::
Mesh
(
std
::
move
(
mesh_verts
),
std
::
move
(
mesh_inds
)),
name
);
obj
.
material
.
opt
=
material
;
if
(
do_flip
)
hemesh
.
flip
();
new_obj
=
std
::
move
(
obj
);
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
std
::
move
(
hemesh
),
name
);
obj
.
material
.
opt
=
material
;
}
else
{
obj
.
opt
.
smooth_normals
=
do_smooth
;
new_obj
=
std
::
move
(
obj
);
if
(
do_flip
)
}
hemesh
.
flip
();
}
Scene_Object
obj
(
scobj
.
reserve_id
(),
p
,
std
::
move
(
hemesh
),
name
);
obj
.
material
.
opt
=
material
;
if
(
mesh
->
mNumBones
)
{
obj
.
opt
.
smooth_normals
=
do_smooth
;
new_obj
=
std
::
move
(
obj
);
Skeleton
&
skeleton
=
new_obj
.
armature
;
}
aiNode
*
arm_node
=
mesh
->
mBones
[
0
]
->
mArmature
;
}
{
aiVector3D
t
,
r
,
s
;
if
(
mesh
->
mNumBones
)
{
arm_node
->
mTransformation
.
Decompose
(
s
,
r
,
t
);
skeleton
.
base
()
=
aiVec
(
t
);
Skeleton
&
skeleton
=
new_obj
.
armature
;
}
aiNode
*
arm_node
=
mesh
->
mBones
[
0
]
->
mArmature
;
{
std
::
unordered_map
<
aiNode
*
,
aiBone
*>
node_to_aibone
;
aiVector3D
t
,
r
,
s
;
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumBones
;
j
++
)
{
arm_node
->
mTransformation
.
Decompose
(
s
,
r
,
t
);
node_to_aibone
[
mesh
->
mBones
[
j
]
->
mNode
]
=
mesh
->
mBones
[
j
];
skeleton
.
base
()
=
aiVec
(
t
);
}
}
std
::
function
<
void
(
Joint
*
,
aiNode
*
)
>
build_tree
;
std
::
unordered_map
<
aiNode
*
,
aiBone
*>
node_to_aibone
;
build_tree
=
[
&
](
Joint
*
p
,
aiNode
*
node
)
{
for
(
unsigned
int
j
=
0
;
j
<
mesh
->
mNumBones
;
j
++
)
{
aiBone
*
bone
=
node_to_aibone
[
node
];
node_to_aibone
[
mesh
->
mBones
[
j
]
->
mNode
]
=
mesh
->
mBones
[
j
];
aiVector3D
t
,
r
,
s
;
}
bone
->
mOffsetMatrix
.
Decompose
(
s
,
r
,
t
);
Joint
*
c
=
skeleton
.
add_child
(
p
,
aiVec
(
t
));
std
::
function
<
void
(
Joint
*
,
aiNode
*
)
>
build_tree
;
node_to_bone
[
node
]
=
c
;
build_tree
=
[
&
](
Joint
*
p
,
aiNode
*
node
)
{
c
->
pose
=
aiVec
(
r
);
aiBone
*
bone
=
node_to_aibone
[
node
];
c
->
radius
=
bone
->
mWeights
[
0
].
mWeight
;
aiVector3D
t
,
r
,
s
;
for
(
unsigned
int
j
=
0
;
j
<
node
->
mNumChildren
;
j
++
)
bone
->
mOffsetMatrix
.
Decompose
(
s
,
r
,
t
);
build_tree
(
c
,
node
->
mChildren
[
j
]);
Joint
*
c
=
skeleton
.
add_child
(
p
,
aiVec
(
t
));
};
node_to_bone
[
node
]
=
c
;
for
(
unsigned
int
j
=
0
;
j
<
arm_node
->
mNumChildren
;
j
++
)
{
c
->
pose
=
aiVec
(
r
);
aiNode
*
root_node
=
arm_node
->
mChildren
[
j
];
c
->
radius
=
bone
->
mWeights
[
0
].
mWeight
;
aiBone
*
root_bone
=
node_to_aibone
[
root_node
];
for
(
unsigned
int
j
=
0
;
j
<
node
->
mNumChildren
;
j
++
)
aiVector3D
t
,
r
,
s
;
build_tree
(
c
,
node
->
mChildren
[
j
]);
root_bone
->
mOffsetMatrix
.
Decompose
(
s
,
r
,
t
);
};
Joint
*
root
=
skeleton
.
add_root
(
aiVec
(
t
));
for
(
unsigned
int
j
=
0
;
j
<
arm_node
->
mNumChildren
;
j
++
)
{
node_to_bone
[
root_node
]
=
root
;
aiNode
*
root_node
=
arm_node
->
mChildren
[
j
];
root
->
pose
=
aiVec
(
r
);
aiBone
*
root_bone
=
node_to_aibone
[
root_node
];
root
->
radius
=
root_bone
->
mWeights
[
0
].
mWeight
;
aiVector3D
t
,
r
,
s
;
for
(
unsigned
int
k
=
0
;
k
<
root_node
->
mNumChildren
;
k
++
)
root_bone
->
mOffsetMatrix
.
Decompose
(
s
,
r
,
t
);
build_tree
(
root
,
root_node
->
mChildren
[
k
]);
Joint
*
root
=
skeleton
.
add_root
(
aiVec
(
t
));
}
node_to_bone
[
root_node
]
=
root
;
}
root
->
pose
=
aiVec
(
r
);
root
->
radius
=
root_bone
->
mWeights
[
0
].
mWeight
;
node_to_obj
[
node
]
=
new_obj
.
id
();
for
(
unsigned
int
k
=
0
;
k
<
root_node
->
mNumChildren
;
k
++
)
scobj
.
add
(
std
::
move
(
new_obj
));
build_tree
(
root
,
root_node
->
mChildren
[
k
]);
}
}
}
for
(
unsigned
int
i
=
0
;
i
<
node
->
mNumChildren
;
i
++
)
{
load_node
(
scobj
,
errors
,
node_to_obj
,
node_to_bone
,
scene
,
node
->
mChildren
[
i
],
transform
);
node_to_obj
[
node
]
=
new_obj
.
id
();
}
scobj
.
add
(
std
::
move
(
new_obj
));
}
for
(
unsigned
int
i
=
0
;
i
<
node
->
mNumChildren
;
i
++
)
{
load_node
(
scobj
,
errors
,
node_to_obj
,
node_to_bone
,
scene
,
node
->
mChildren
[
i
],
transform
);
}
}
}
std
::
string
Scene
::
load
(
bool
new_scene
,
Undo
&
undo
,
Gui
::
Manager
&
gui
,
std
::
string
file
)
{
std
::
string
Scene
::
load
(
bool
new_scene
,
Undo
&
undo
,
Gui
::
Manager
&
gui
,
std
::
string
file
)
{
if
(
new_scene
)
{
if
(
new_scene
)
{
clear
(
undo
);
clear
(
undo
);
gui
.
get_animate
().
clear
();
gui
.
get_animate
().
clear
();
gui
.
get_rig
().
clear
();
gui
.
get_rig
().
clear
();
}
}
Assimp
::
Importer
importer
;
Assimp
::
Importer
importer
;
const
aiScene
*
scene
=
importer
.
ReadFile
(
file
.
c_str
(),
const
aiScene
*
scene
=
importer
.
ReadFile
(
aiProcess_GenSmoothNormals
|
file
.
c_str
(),
aiProcess_GenSmoothNormals
|
aiProcess_PopulateArmatureData
|
aiProcess_PopulateArmatureData
|
aiProcess_ValidateDataStructure
|
aiProcess_OptimizeMeshes
|
aiProcess_ValidateDataStructure
|
aiProcess_FindInstances
|
aiProcess_FindDegenerates
|
aiProcess_OptimizeMeshes
|
aiProcess_JoinIdenticalVertices
|
aiProcess_FindInvalidData
);
aiProcess_FindInstances
|
aiProcess_FindDegenerates
|
if
(
!
scene
)
{
aiProcess_JoinIdenticalVertices
|
return
"Parsing scene "
+
file
+
": "
+
std
::
string
(
importer
.
GetErrorString
());
aiProcess_FindInvalidData
);
}
if
(
!
scene
)
{
std
::
vector
<
std
::
string
>
errors
;
return
"Parsing scene "
+
file
+
": "
+
std
::
string
(
importer
.
GetErrorString
());
std
::
unordered_map
<
aiNode
*
,
Scene_ID
>
node_to_obj
;
}
std
::
unordered_map
<
aiNode
*
,
Joint
*>
node_to_bone
;
scene
->
mRootNode
->
mTransformation
=
aiMatrix4x4
();
std
::
vector
<
std
::
string
>
errors
;
std
::
unordered_map
<
aiNode
*
,
Scene_ID
>
node_to_obj
;
// Load objects
std
::
unordered_map
<
aiNode
*
,
Joint
*>
node_to_bone
;
load_node
(
*
this
,
errors
,
node_to_obj
,
node_to_bone
,
scene
,
scene
->
mRootNode
,
aiMatrix4x4
());
scene
->
mRootNode
->
mTransformation
=
aiMatrix4x4
();
// Load camera
// Load objects
if
(
new_scene
&&
scene
->
mNumCameras
)
{
load_node
(
*
this
,
errors
,
node_to_obj
,
node_to_bone
,
scene
,
scene
->
mRootNode
,
aiMatrix4x4
());
const
aiCamera
&
aiCam
=
*
scene
->
mCameras
[
0
];
Mat4
cam_transform
=
aiMat
(
node_transform
(
scene
->
mRootNode
->
FindNode
(
aiCam
.
mName
)));
// Load camera
Vec3
pos
=
cam_transform
*
aiVec
(
aiCam
.
mPosition
);
if
(
new_scene
&&
scene
->
mNumCameras
)
{
Vec3
center
=
cam_transform
*
aiVec
(
aiCam
.
mLookAt
);
const
aiCamera
&
aiCam
=
*
scene
->
mCameras
[
0
];
gui
.
get_render
().
load_cam
(
pos
,
center
,
aiCam
.
mAspect
,
aiCam
.
mHorizontalFOV
);
Mat4
cam_transform
=
aiMat
(
node_transform
(
scene
->
mRootNode
->
FindNode
(
aiCam
.
mName
)));
}
Vec3
pos
=
cam_transform
*
aiVec
(
aiCam
.
mPosition
);
Vec3
center
=
cam_transform
*
aiVec
(
aiCam
.
mLookAt
);
// Load lights
gui
.
get_render
().
load_cam
(
pos
,
center
,
aiCam
.
mAspect
,
aiCam
.
mHorizontalFOV
);
for
(
unsigned
int
i
=
0
;
i
<
scene
->
mNumLights
;
i
++
)
{
}
const
aiLight
&
ailight
=
*
scene
->
mLights
[
i
];
// Load lights
const
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
ailight
.
mName
);
for
(
unsigned
int
i
=
0
;
i
<
scene
->
mNumLights
;
i
++
)
{
Mat4
trans
=
aiMat
(
node_transform
(
node
));
const
aiLight
&
ailight
=
*
scene
->
mLights
[
i
];
Vec3
pos
=
trans
*
aiVec
(
ailight
.
mPosition
);
const
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
ailight
.
mName
);
Vec3
dir
=
trans
.
rotate
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
Mat4
trans
=
aiMat
(
node_transform
(
node
));
Pose
p
;
Vec3
pos
=
trans
*
aiVec
(
ailight
.
mPosition
);
p
.
pos
=
pos
;
Vec3
dir
=
trans
.
rotate
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
p
.
euler
=
Mat4
::
rotate_to
(
dir
).
to_euler
();
Pose
p
;
bool
was_exported_from_s3d
=
false
;
p
.
pos
=
pos
;
float
export_power
=
1.0
f
;
p
.
euler
=
Mat4
::
rotate_to
(
dir
).
to_euler
();
bool
is_sphere
=
false
,
is_hemisphere
=
false
,
is_area
=
false
;
bool
was_exported_from_s3d
=
false
;
std
::
string
name
=
std
::
string
(
node
->
mName
.
C_Str
());
float
export_power
=
1.0
f
;
bool
is_sphere
=
false
,
is_hemisphere
=
false
,
is_area
=
false
;
size_t
special
=
name
.
find
(
"-S3D-"
);
if
(
special
!=
std
::
string
::
npos
)
{
std
::
string
name
=
std
::
string
(
node
->
mName
.
C_Str
());
was_exported_from_s3d
=
true
;
size_t
special
=
name
.
find
(
"-S3D-"
);
export_power
=
ailight
.
mAttenuationQuadratic
;
if
(
special
!=
std
::
string
::
npos
)
{
std
::
string
left
=
name
.
substr
(
special
+
4
);
was_exported_from_s3d
=
true
;
name
=
name
.
substr
(
0
,
special
);
export_power
=
ailight
.
mAttenuationQuadratic
;
std
::
replace
(
name
.
begin
(),
name
.
end
(),
'_'
,
' '
);
std
::
string
left
=
name
.
substr
(
special
+
4
);
if
(
left
.
find
(
"HEMISPHERE"
)
!=
std
::
string
::
npos
)
name
=
name
.
substr
(
0
,
special
);
is_hemisphere
=
true
;
std
::
replace
(
name
.
begin
(),
name
.
end
(),
'_'
,
' '
);
else
if
(
left
.
find
(
"SPHERE"
)
!=
std
::
string
::
npos
)
is_sphere
=
true
;
if
(
left
.
find
(
"HEMISPHERE"
)
!=
std
::
string
::
npos
)
is_hemisphere
=
true
;
else
if
(
left
.
find
(
"AREA"
)
!=
std
::
string
::
npos
)
else
if
(
left
.
find
(
"SPHERE"
)
!=
std
::
string
::
npos
)
is_sphere
=
true
;
is_area
=
true
;
else
if
(
left
.
find
(
"AREA"
)
!=
std
::
string
::
npos
)
is_area
=
true
;
}
}
aiColor3D
color
;
aiColor3D
color
;
Scene_Light
light
(
Light_Type
::
point
,
reserve_id
(),
p
,
name
);
Scene_Light
light
(
Light_Type
::
point
,
reserve_id
(),
p
,
name
);
switch
(
ailight
.
mType
)
{
switch
(
ailight
.
mType
)
{
case
aiLightSource_DIRECTIONAL
:
{
case
aiLightSource_DIRECTIONAL
:
{
light
.
opt
.
type
=
Light_Type
::
directional
;
light
.
opt
.
type
=
Light_Type
::
directional
;
color
=
ailight
.
mColorDiffuse
;
color
=
ailight
.
mColorDiffuse
;
}
break
;
}
break
;
case
aiLightSource_POINT
:
{
case
aiLightSource_POINT
:
{
light
.
opt
.
type
=
Light_Type
::
point
;
light
.
opt
.
type
=
Light_Type
::
point
;
color
=
ailight
.
mColorDiffuse
;
color
=
ailight
.
mColorDiffuse
;
}
break
;
}
break
;
case
aiLightSource_SPOT
:
{
case
aiLightSource_SPOT
:
{
light
.
opt
.
type
=
Light_Type
::
spot
;
light
.
opt
.
type
=
Light_Type
::
spot
;
light
.
opt
.
angle_bounds
.
x
=
ailight
.
mAngleInnerCone
;
light
.
opt
.
angle_bounds
.
x
=
ailight
.
mAngleInnerCone
;
light
.
opt
.
angle_bounds
.
y
=
ailight
.
mAngleOuterCone
;
light
.
opt
.
angle_bounds
.
y
=
ailight
.
mAngleOuterCone
;
color
=
ailight
.
mColorDiffuse
;
color
=
ailight
.
mColorDiffuse
;
}
break
;
}
break
;
case
aiLightSource_AMBIENT
:
{
case
aiLightSource_AMBIENT
:
{
if
(
is_hemisphere
)
if
(
is_hemisphere
)
light
.
opt
.
type
=
Light_Type
::
hemisphere
;
light
.
opt
.
type
=
Light_Type
::
hemisphere
;
else
if
(
is_sphere
)
{
else
if
(
is_sphere
)
{
light
.
opt
.
type
=
Light_Type
::
sphere
;
light
.
opt
.
type
=
Light_Type
::
sphere
;
if
(
ailight
.
mEnvMap
.
length
)
{
if
(
ailight
.
mEnvMap
.
length
)
{
light
.
opt
.
has_emissive_map
=
true
;
light
.
opt
.
has_emissive_map
=
true
;
light
.
emissive_load
(
std
::
string
(
ailight
.
mEnvMap
.
C_Str
()));
light
.
emissive_load
(
std
::
string
(
ailight
.
mEnvMap
.
C_Str
()));
}
}
}
else
if
(
is_area
)
{
}
else
if
(
is_area
)
{
light
.
opt
.
type
=
Light_Type
::
rectangle
;
light
.
opt
.
type
=
Light_Type
::
rectangle
;
light
.
opt
.
size
.
x
=
ailight
.
mAttenuationConstant
;
light
.
opt
.
size
.
x
=
ailight
.
mAttenuationConstant
;
light
.
opt
.
size
.
y
=
ailight
.
mAttenuationLinear
;
light
.
opt
.
size
.
y
=
ailight
.
mAttenuationLinear
;
}
}
color
=
ailight
.
mColorAmbient
;
color
=
ailight
.
mColorAmbient
;
}
break
;
}
break
;
case
aiLightSource_AREA
:
{
case
aiLightSource_AREA
:
{
light
.
opt
.
type
=
Light_Type
::
rectangle
;
light
.
opt
.
type
=
Light_Type
::
rectangle
;
light
.
opt
.
size
.
x
=
ailight
.
mSize
.
x
;
light
.
opt
.
size
.
x
=
ailight
.
mSize
.
x
;
light
.
opt
.
size
.
y
=
ailight
.
mSize
.
y
;
light
.
opt
.
size
.
y
=
ailight
.
mSize
.
y
;
color
=
ailight
.
mColorDiffuse
;
color
=
ailight
.
mColorDiffuse
;
}
break
;
}
break
;
default:
continue
;
default:
}
continue
;
}
float
power
=
std
::
max
(
color
.
r
,
std
::
max
(
color
.
g
,
color
.
b
));
light
.
opt
.
spectrum
=
Spectrum
(
color
.
r
,
color
.
g
,
color
.
b
)
*
(
1.0
f
/
power
);
float
power
=
std
::
max
(
color
.
r
,
std
::
max
(
color
.
g
,
color
.
b
));
light
.
opt
.
intensity
=
power
;
light
.
opt
.
spectrum
=
Spectrum
(
color
.
r
,
color
.
g
,
color
.
b
)
*
(
1.0
f
/
power
);
light
.
opt
.
intensity
=
power
;
if
(
was_exported_from_s3d
)
{
float
factor
=
power
/
export_power
;
if
(
was_exported_from_s3d
)
{
light
.
opt
.
spectrum
*=
factor
;
float
factor
=
power
/
export_power
;
light
.
opt
.
intensity
=
export_power
;
light
.
opt
.
spectrum
*=
factor
;
}
light
.
opt
.
intensity
=
export_power
;
}
if
(
!
light
.
is_env
()
||
!
has_env_light
())
{
if
(
!
light
.
is_env
()
||
!
has_env_light
())
{
node_to_obj
[(
aiNode
*
)
node
]
=
light
.
id
();
node_to_obj
[(
aiNode
*
)
node
]
=
light
.
id
();
std
::
string
anim_name
=
std
::
string
(
node
->
mName
.
C_Str
())
+
"-LIGHT_ANIM_NODE"
;
aiNode
*
anim_node
=
scene
->
mRootNode
->
FindNode
(
aiString
(
anim_name
));
std
::
string
anim_name
=
std
::
string
(
node
->
mName
.
C_Str
())
+
"-LIGHT_ANIM_NODE"
;
node_to_obj
[
anim_node
]
=
light
.
id
();
aiNode
*
anim_node
=
scene
->
mRootNode
->
FindNode
(
aiString
(
anim_name
));
node_to_obj
[
anim_node
]
=
light
.
id
();
add
(
std
::
move
(
light
));
}
add
(
std
::
move
(
light
));
}
}
}
// animations
for
(
unsigned
int
i
=
0
;
i
<
scene
->
mNumAnimations
;
i
++
)
{
// animations
for
(
unsigned
int
i
=
0
;
i
<
scene
->
mNumAnimations
;
i
++
)
{
aiAnimation
&
anim
=
*
scene
->
mAnimations
[
i
];
for
(
unsigned
int
j
=
0
;
j
<
anim
.
mNumChannels
;
j
++
)
{
aiAnimation
&
anim
=
*
scene
->
mAnimations
[
i
];
aiNodeAnim
&
node_anim
=
*
anim
.
mChannels
[
j
];
for
(
unsigned
int
j
=
0
;
j
<
anim
.
mNumChannels
;
j
++
)
{
aiNodeAnim
&
node_anim
=
*
anim
.
mChannels
[
j
];
if
(
node_anim
.
mNodeName
==
aiString
(
"camera_node"
))
{
if
(
node_anim
.
mNodeName
==
aiString
(
"camera_node"
))
{
Gui
::
Anim_Camera
&
cam
=
gui
.
get_animate
().
camera
();
unsigned
int
keys
=
std
::
min
(
node_anim
.
mNumPositionKeys
,
Gui
::
Anim_Camera
&
cam
=
gui
.
get_animate
().
camera
();
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
unsigned
int
keys
=
std
::
min
(
node_anim
.
mNumPositionKeys
,
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
Vec3
pos
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
Vec3
v
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
Vec3
pos
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
cam
.
splines
.
set
(
t
,
pos
,
rot
,
v
.
x
,
v
.
y
);
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
}
Vec3
v
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
cam
.
splines
.
set
(
t
,
pos
,
rot
,
v
.
x
,
v
.
y
);
}
else
if
(
std
::
string
(
node_anim
.
mNodeName
.
C_Str
()).
find
(
"LIGHT_ANIM_NODE"
)
!=
std
::
string
::
npos
)
{
}
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
node_anim
.
mNodeName
);
}
else
if
(
std
::
string
(
node_anim
.
mNodeName
.
C_Str
()).
find
(
"LIGHT_ANIM_NODE"
)
!=
auto
entry
=
node_to_obj
.
find
(
node
);
std
::
string
::
npos
)
{
if
(
entry
!=
node_to_obj
.
end
())
{
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
node_anim
.
mNodeName
);
Scene_Light
&
l
=
get_light
(
entry
->
second
);
auto
entry
=
node_to_obj
.
find
(
node
);
Scene_Light
::
Anim_Light
&
light
=
l
.
lanim
;
if
(
entry
!=
node_to_obj
.
end
())
{
unsigned
int
keys
=
std
::
min
(
node_anim
.
mNumPositionKeys
,
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
Scene_Light
&
l
=
get_light
(
entry
->
second
);
Scene_Light
::
Anim_Light
&
light
=
l
.
lanim
;
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
unsigned
int
keys
=
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
std
::
min
(
node_anim
.
mNumPositionKeys
,
Vec3
spec
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
Vec3
angle
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
).
to_euler
();
Vec3
inten_sz
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
light
.
splines
.
set
(
t
,
Spectrum
{
spec
.
x
,
spec
.
y
,
spec
.
z
},
inten_sz
.
x
-
1.0
f
,
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
Vec2
{
angle
.
x
,
angle
.
z
},
Vec2
{
inten_sz
.
y
-
1.0
f
,
inten_sz
.
z
-
1.0
f
});
Vec3
spec
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
}
Vec3
angle
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
).
to_euler
();
}
Vec3
inten_sz
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
light
.
splines
.
set
(
t
,
Spectrum
{
spec
.
x
,
spec
.
y
,
spec
.
z
},
inten_sz
.
x
-
1.0
f
,
}
else
{
Vec2
{
angle
.
x
,
angle
.
z
},
Vec2
{
inten_sz
.
y
-
1.0
f
,
inten_sz
.
z
-
1.0
f
});
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
node_anim
.
mNodeName
);
}
auto
jentry
=
node_to_bone
.
find
(
node
);
}
if
(
jentry
!=
node_to_bone
.
end
())
{
}
else
{
Joint
*
jt
=
jentry
->
second
;
unsigned
int
keys
=
node_anim
.
mNumRotationKeys
;
aiNode
*
node
=
scene
->
mRootNode
->
FindNode
(
node_anim
.
mNodeName
);
auto
jentry
=
node_to_bone
.
find
(
node
);
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
if
(
jentry
!=
node_to_bone
.
end
())
{
float
t
=
(
float
)
node_anim
.
mRotationKeys
[
k
].
mTime
;
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
Joint
*
jt
=
jentry
->
second
;
jt
->
anim
.
set
(
t
,
rot
);
unsigned
int
keys
=
node_anim
.
mNumRotationKeys
;
}
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
}
else
{
float
t
=
(
float
)
node_anim
.
mRotationKeys
[
k
].
mTime
;
auto
entry
=
node_to_obj
.
find
(
node
);
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
if
(
entry
!=
node_to_obj
.
end
())
{
jt
->
anim
.
set
(
t
,
rot
);
}
Scene_Item
&
item
=
*
get
(
entry
->
second
);
Anim_Pose
&
pose
=
item
.
animation
();
}
else
{
unsigned
int
keys
=
std
::
min
(
node_anim
.
mNumPositionKeys
,
auto
entry
=
node_to_obj
.
find
(
node
);
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
if
(
entry
!=
node_to_obj
.
end
())
{
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
Scene_Item
&
item
=
*
get
(
entry
->
second
);
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
Anim_Pose
&
pose
=
item
.
animation
();
Vec3
pos
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
unsigned
int
keys
=
std
::
min
(
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
node_anim
.
mNumPositionKeys
,
Vec3
scl
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
std
::
min
(
node_anim
.
mNumRotationKeys
,
node_anim
.
mNumScalingKeys
));
pose
.
splines
.
set
(
t
,
pos
,
rot
,
scl
);
}
for
(
unsigned
int
k
=
0
;
k
<
keys
;
k
++
)
{
}
float
t
=
(
float
)
node_anim
.
mPositionKeys
[
k
].
mTime
;
}
Vec3
pos
=
aiVec
(
node_anim
.
mPositionKeys
[
k
].
mValue
);
}
Quat
rot
=
aiQuat
(
node_anim
.
mRotationKeys
[
k
].
mValue
);
}
Vec3
scl
=
aiVec
(
node_anim
.
mScalingKeys
[
k
].
mValue
);
pose
.
splines
.
set
(
t
,
pos
,
rot
,
scl
);
if
(
anim
.
mDuration
>
0.0
f
)
{
}
gui
.
get_animate
().
set
((
int
)
std
::
ceil
(
anim
.
mDuration
),
(
int
)
std
::
round
(
anim
.
mTicksPerSecond
));
}
}
}
gui
.
get_animate
().
refresh
(
*
this
);
}
}
}
std
::
stringstream
stream
;
if
(
anim
.
mDuration
>
0.0
f
)
{
if
(
errors
.
size
())
{
gui
.
get_animate
().
set
((
int
)
std
::
ceil
(
anim
.
mDuration
),
stream
<<
"Meshes with errors may not be edit-able in the model mode."
<<
std
::
endl
<<
std
::
endl
;
(
int
)
std
::
round
(
anim
.
mTicksPerSecond
));
}
}
for
(
size_t
i
=
0
;
i
<
errors
.
size
();
i
++
)
{
gui
.
get_animate
().
refresh
(
*
this
);
stream
<<
"Loading mesh "
<<
i
<<
": "
<<
errors
[
i
]
<<
std
::
endl
;
}
}
return
stream
.
str
();
std
::
stringstream
stream
;
if
(
errors
.
size
())
{
stream
<<
"Meshes with errors may not be edit-able in the model mode."
<<
std
::
endl
<<
std
::
endl
;
}
for
(
size_t
i
=
0
;
i
<
errors
.
size
();
i
++
)
{
stream
<<
"Loading mesh "
<<
i
<<
": "
<<
errors
[
i
]
<<
std
::
endl
;
}
return
stream
.
str
();
}
}
std
::
string
Scene
::
write
(
std
::
string
file
,
const
Camera
&
render_cam
,
const
Gui
::
Animate
&
animation
)
{
std
::
string
Scene
::
write
(
std
::
string
file
,
const
Camera
&
render_cam
,
const
Gui
::
Animate
&
animation
)
{
bool
no_real_meshes
=
false
;
bool
no_real_meshes
=
false
;
size_t
n_meshes
=
0
,
n_lights
=
0
,
n_anims
=
0
;
size_t
n_armatures
=
0
;
size_t
n_meshes
=
0
,
n_lights
=
0
,
n_anims
=
0
;
for_items
([
&
](
Scene_Item
&
item
)
{
size_t
n_armatures
=
0
;
if
(
item
.
is
<
Scene_Object
>
())
{
for_items
([
&
](
Scene_Item
&
item
)
{
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
if
(
item
.
is
<
Scene_Object
>
())
{
n_meshes
++
;
Scene_Object
&
obj
=
item
.
get
<
Scene_Object
>
();
if
(
obj
.
anim
.
splines
.
any
())
n_anims
++
;
n_meshes
++
;
if
(
obj
.
armature
.
has_bones
())
n_armatures
++
;
if
(
obj
.
anim
.
splines
.
any
())
obj
.
armature
.
for_joints
([
&
](
Joint
*
j
)
{
n_anims
++
;
if
(
j
->
anim
.
any
())
n_anims
++
;
if
(
obj
.
armature
.
has_bones
())
});
n_armatures
++
;
}
else
if
(
item
.
is
<
Scene_Light
>
())
{
obj
.
armature
.
for_joints
([
&
](
Joint
*
j
)
{
if
(
item
.
animation
().
splines
.
any
())
n_anims
++
;
if
(
j
->
anim
.
any
())
if
(
item
.
get
<
Scene_Light
>
().
lanim
.
splines
.
any
())
n_anims
++
;
n_anims
++
;
n_lights
++
;
});
}
}
else
if
(
item
.
is
<
Scene_Light
>
())
{
});
if
(
item
.
animation
().
splines
.
any
())
n_anims
++
;
size_t
camera_anim
=
n_anims
;
if
(
item
.
get
<
Scene_Light
>
().
lanim
.
splines
.
any
())
if
(
animation
.
camera
().
splines
.
any
())
n_anims
++
;
n_anims
++
;
n_lights
++
;
if
(
!
n_meshes
)
{
}
no_real_meshes
=
true
;
});
n_meshes
=
1
;
}
size_t
camera_anim
=
n_anims
;
if
(
animation
.
camera
().
splines
.
any
())
aiScene
scene
;
n_anims
++
;
scene
.
mRootNode
=
new
aiNode
();
if
(
!
n_meshes
)
{
// materials
no_real_meshes
=
true
;
scene
.
mMaterials
=
new
aiMaterial
*
[
n_meshes
]();
n_meshes
=
1
;
scene
.
mNumMaterials
=
(
unsigned
int
)
n_meshes
;
}
// camera
aiScene
scene
;
const
Gui
::
Anim_Camera
&
anim_cam
=
animation
.
camera
();
scene
.
mRootNode
=
new
aiNode
();
Camera
cam
=
render_cam
;
if
(
anim_cam
.
splines
.
any
())
{
// materials
cam
=
animation
.
camera
().
at
(
0.0
f
);
scene
.
mMaterials
=
new
aiMaterial
*
[
n_meshes
]();
}
scene
.
mNumMaterials
=
(
unsigned
int
)
n_meshes
;
scene
.
mCameras
=
new
aiCamera
*
[
1
]();
scene
.
mCameras
[
0
]
=
new
aiCamera
();
// camera
scene
.
mCameras
[
0
]
->
mAspect
=
cam
.
get_ar
();
const
Gui
::
Anim_Camera
&
anim_cam
=
animation
.
camera
();
scene
.
mCameras
[
0
]
->
mClipPlaneNear
=
cam
.
get_near
();
Camera
cam
=
render_cam
;
scene
.
mCameras
[
0
]
->
mClipPlaneFar
=
100.0
f
;
if
(
anim_cam
.
splines
.
any
())
{
scene
.
mCameras
[
0
]
->
mLookAt
=
aiVector3D
(
0.0
f
,
0.0
f
,
-
1.0
f
);
cam
=
animation
.
camera
().
at
(
0.0
f
);
scene
.
mCameras
[
0
]
->
mHorizontalFOV
=
Radians
(
cam
.
get_h_fov
());
}
scene
.
mCameras
[
0
]
->
mName
=
aiString
(
"camera_node"
);
scene
.
mCameras
=
new
aiCamera
*
[
1
]();
scene
.
mNumCameras
=
1
;
scene
.
mCameras
[
0
]
=
new
aiCamera
();
scene
.
mCameras
[
0
]
->
mAspect
=
cam
.
get_ar
();
// nodes
scene
.
mCameras
[
0
]
->
mClipPlaneNear
=
cam
.
get_near
();
size_t
cam_idx
=
n_meshes
+
n_armatures
+
n_lights
*
2
;
scene
.
mCameras
[
0
]
->
mClipPlaneFar
=
100.0
f
;
size_t
n_nodes
=
cam_idx
+
1
;
scene
.
mCameras
[
0
]
->
mLookAt
=
aiVector3D
(
0.0
f
,
0.0
f
,
-
1.0
f
);
scene
.
mCameras
[
0
]
->
mHorizontalFOV
=
Radians
(
cam
.
get_h_fov
());
scene
.
mRootNode
->
mNumMeshes
=
0
;
scene
.
mCameras
[
0
]
->
mName
=
aiString
(
"camera_node"
);
scene
.
mRootNode
->
mNumChildren
=
(
unsigned
int
)(
n_nodes
);
scene
.
mNumCameras
=
1
;
scene
.
mRootNode
->
mChildren
=
new
aiNode
*
[
n_nodes
]();
// nodes
// camera node
size_t
cam_idx
=
n_meshes
+
n_armatures
+
n_lights
*
2
;
Mat4
view
=
cam
.
get_view
().
inverse
();
size_t
n_nodes
=
cam_idx
+
1
;
scene
.
mRootNode
->
mChildren
[
cam_idx
]
=
new
aiNode
();
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mNumMeshes
=
0
;
scene
.
mRootNode
->
mNumMeshes
=
0
;
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mName
=
aiString
(
"camera_node"
);
scene
.
mRootNode
->
mNumChildren
=
(
unsigned
int
)(
n_nodes
);
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mTransformation
=
matMat
(
view
);
scene
.
mRootNode
->
mChildren
=
new
aiNode
*
[
n_nodes
]();
// meshes
// camera node
scene
.
mMeshes
=
new
aiMesh
*
[
n_meshes
]();
Mat4
view
=
cam
.
get_view
().
inverse
();
scene
.
mNumMeshes
=
(
unsigned
int
)
n_meshes
;
scene
.
mRootNode
->
mChildren
[
cam_idx
]
=
new
aiNode
();
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mNumMeshes
=
0
;
// lights
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mName
=
aiString
(
"camera_node"
);
scene
.
mLights
=
new
aiLight
*
[
n_lights
]();
scene
.
mRootNode
->
mChildren
[
cam_idx
]
->
mTransformation
=
matMat
(
view
);
scene
.
mNumLights
=
(
unsigned
int
)
n_lights
;
// meshes
size_t
mesh_idx
=
0
,
light_idx
=
0
,
node_idx
=
0
;
scene
.
mMeshes
=
new
aiMesh
*
[
n_meshes
]();
scene
.
mNumMeshes
=
(
unsigned
int
)
n_meshes
;
if
(
no_real_meshes
)
{
aiMesh
*
ai_mesh
=
new
aiMesh
();
// lights
aiNode
*
ai_node
=
new
aiNode
();
scene
.
mLights
=
new
aiLight
*
[
n_lights
]();
scene
.
mMeshes
[
mesh_idx
++
]
=
ai_mesh
;
scene
.
mNumLights
=
(
unsigned
int
)
n_lights
;
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
ai_node
->
mNumMeshes
=
1
;
size_t
mesh_idx
=
0
,
light_idx
=
0
,
node_idx
=
0
;
ai_node
->
mMeshes
=
new
unsigned
int
((
unsigned
int
)
0
);
if
(
no_real_meshes
)
{
ai_mesh
->
mVertices
=
new
aiVector3D
[
3
];
aiMesh
*
ai_mesh
=
new
aiMesh
();
ai_mesh
->
mNormals
=
new
aiVector3D
[
3
];
aiNode
*
ai_node
=
new
aiNode
();
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
3
;
scene
.
mMeshes
[
mesh_idx
++
]
=
ai_mesh
;
ai_mesh
->
mVertices
[
0
]
=
vecVec
(
Vec3
{
1.0
f
,
0.0
f
,
0.0
f
});
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
ai_mesh
->
mVertices
[
1
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_node
->
mNumMeshes
=
1
;
ai_mesh
->
mVertices
[
2
]
=
vecVec
(
Vec3
{
0.0
f
,
0.0
f
,
1.0
f
});
ai_node
->
mMeshes
=
new
unsigned
int
((
unsigned
int
)
0
);
ai_mesh
->
mNormals
[
0
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mNormals
[
1
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mVertices
=
new
aiVector3D
[
3
];
ai_mesh
->
mNormals
[
2
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mNormals
=
new
aiVector3D
[
3
];
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
3
;
ai_mesh
->
mFaces
=
new
aiFace
[
1
];
ai_mesh
->
mVertices
[
0
]
=
vecVec
(
Vec3
{
1.0
f
,
0.0
f
,
0.0
f
});
ai_mesh
->
mNumFaces
=
1u
;
ai_mesh
->
mVertices
[
1
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mVertices
[
2
]
=
vecVec
(
Vec3
{
0.0
f
,
0.0
f
,
1.0
f
});
ai_mesh
->
mFaces
[
0
].
mIndices
=
new
unsigned
int
[
3
];
ai_mesh
->
mNormals
[
0
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mFaces
[
0
].
mNumIndices
=
3
;
ai_mesh
->
mNormals
[
1
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mFaces
[
0
].
mIndices
[
0
]
=
0
;
ai_mesh
->
mNormals
[
2
]
=
vecVec
(
Vec3
{
0.0
f
,
1.0
f
,
0.0
f
});
ai_mesh
->
mFaces
[
0
].
mIndices
[
1
]
=
1
;
ai_mesh
->
mFaces
[
0
].
mIndices
[
2
]
=
2
;
ai_mesh
->
mFaces
=
new
aiFace
[
1
];
ai_mesh
->
mNumFaces
=
1u
;
ai_mesh
->
mName
=
aiString
(
FAKE_NAME
);
ai_node
->
mName
=
aiString
(
FAKE_NAME
);
ai_mesh
->
mFaces
[
0
].
mIndices
=
new
unsigned
int
[
3
];
scene
.
mMaterials
[
0
]
=
new
aiMaterial
();
ai_mesh
->
mFaces
[
0
].
mNumIndices
=
3
;
}
ai_mesh
->
mFaces
[
0
].
mIndices
[
0
]
=
0
;
ai_mesh
->
mFaces
[
0
].
mIndices
[
1
]
=
1
;
std
::
unordered_map
<
Scene_ID
,
aiNode
*>
item_nodes
;
ai_mesh
->
mFaces
[
0
].
mIndices
[
2
]
=
2
;
std
::
unordered_map
<
std
::
pair
<
Scene_ID
,
Scene_ID
>
,
aiNode
*>
bone_nodes
;
ai_mesh
->
mName
=
aiString
(
FAKE_NAME
);
for
(
auto
&
entry
:
objs
)
{
ai_node
->
mName
=
aiString
(
FAKE_NAME
);
scene
.
mMaterials
[
0
]
=
new
aiMaterial
();
if
(
entry
.
second
.
is
<
Scene_Object
>
())
{
}
Scene_Object
&
obj
=
entry
.
second
.
get
<
Scene_Object
>
();
std
::
unordered_map
<
Scene_ID
,
aiNode
*>
item_nodes
;
std
::
unordered_map
<
std
::
pair
<
Scene_ID
,
Scene_ID
>
,
aiNode
*>
bone_nodes
;
if
(
obj
.
is_shape
())
{
obj
.
try_make_editable
(
obj
.
opt
.
shape_type
);
for
(
auto
&
entry
:
objs
)
{
}
if
(
entry
.
second
.
is
<
Scene_Object
>
())
{
aiMesh
*
ai_mesh
=
new
aiMesh
();
aiNode
*
ai_node
=
new
aiNode
();
Scene_Object
&
obj
=
entry
.
second
.
get
<
Scene_Object
>
();
aiMaterial
*
ai_mat
=
new
aiMaterial
();
if
(
obj
.
is_shape
())
{
size_t
idx
=
mesh_idx
++
;
obj
.
try_make_editable
(
obj
.
opt
.
shape_type
);
scene
.
mMaterials
[
idx
]
=
ai_mat
;
}
scene
.
mMeshes
[
idx
]
=
ai_mesh
;
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
aiMesh
*
ai_mesh
=
new
aiMesh
();
aiNode
*
ai_node
=
new
aiNode
();
ai_mesh
->
mMaterialIndex
=
(
unsigned
int
)
idx
;
aiMaterial
*
ai_mat
=
new
aiMaterial
();
ai_node
->
mNumMeshes
=
1
;
ai_node
->
mMeshes
=
new
unsigned
int
((
unsigned
int
)
idx
);
size_t
idx
=
mesh_idx
++
;
scene
.
mMaterials
[
idx
]
=
ai_mat
;
if
(
obj
.
is_editable
())
{
scene
.
mMeshes
[
idx
]
=
ai_mesh
;
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
Halfedge_Mesh
&
mesh
=
obj
.
get_mesh
();
size_t
n_verts
=
mesh
.
n_vertices
();
ai_mesh
->
mMaterialIndex
=
(
unsigned
int
)
idx
;
size_t
n_faces
=
mesh
.
n_faces
();
ai_node
->
mNumMeshes
=
1
;
ai_node
->
mMeshes
=
new
unsigned
int
((
unsigned
int
)
idx
);
ai_mesh
->
mVertices
=
new
aiVector3D
[
n_verts
];
ai_mesh
->
mNormals
=
new
aiVector3D
[
n_verts
];
if
(
obj
.
is_editable
())
{
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
n_verts
;
Halfedge_Mesh
&
mesh
=
obj
.
get_mesh
();
ai_mesh
->
mFaces
=
new
aiFace
[
n_faces
];
size_t
n_verts
=
mesh
.
n_vertices
();
ai_mesh
->
mNumFaces
=
(
unsigned
int
)(
n_faces
);
size_t
n_faces
=
mesh
.
n_faces
();
std
::
unordered_map
<
size_t
,
size_t
>
id_to_idx
;
ai_mesh
->
mVertices
=
new
aiVector3D
[
n_verts
];
ai_mesh
->
mNormals
=
new
aiVector3D
[
n_verts
];
size_t
vert_idx
=
0
;
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
n_verts
;
for
(
auto
v
=
mesh
.
vertices_begin
();
v
!=
mesh
.
vertices_end
();
v
++
)
{
id_to_idx
[
v
->
id
()]
=
vert_idx
;
ai_mesh
->
mFaces
=
new
aiFace
[
n_faces
];
Vec3
n
=
mesh
.
flipped
()
?
-
v
->
normal
()
:
v
->
normal
();
ai_mesh
->
mNumFaces
=
(
unsigned
int
)(
n_faces
);
ai_mesh
->
mVertices
[
vert_idx
]
=
vecVec
(
v
->
pos
);
ai_mesh
->
mNormals
[
vert_idx
]
=
vecVec
(
n
);
std
::
unordered_map
<
size_t
,
size_t
>
id_to_idx
;
vert_idx
++
;
}
size_t
vert_idx
=
0
;
for
(
auto
v
=
mesh
.
vertices_begin
();
v
!=
mesh
.
vertices_end
();
v
++
)
{
size_t
face_idx
=
0
;
id_to_idx
[
v
->
id
()]
=
vert_idx
;
for
(
auto
f
=
mesh
.
faces_begin
();
f
!=
mesh
.
faces_end
();
f
++
)
{
Vec3
n
=
mesh
.
flipped
()
?
-
v
->
normal
()
:
v
->
normal
();
ai_mesh
->
mVertices
[
vert_idx
]
=
vecVec
(
v
->
pos
);
aiFace
&
face
=
ai_mesh
->
mFaces
[
face_idx
];
ai_mesh
->
mNormals
[
vert_idx
]
=
vecVec
(
n
);
face
.
mIndices
=
new
unsigned
int
[
f
->
degree
()];
vert_idx
++
;
face
.
mNumIndices
=
f
->
degree
();
}
size_t
i_idx
=
0
;
size_t
face_idx
=
0
;
auto
h
=
f
->
halfedge
();
for
(
auto
f
=
mesh
.
faces_begin
();
f
!=
mesh
.
faces_end
();
f
++
)
{
do
{
face
.
mIndices
[
i_idx
]
=
(
unsigned
int
)
id_to_idx
[
h
->
vertex
()
->
id
()];
aiFace
&
face
=
ai_mesh
->
mFaces
[
face_idx
];
h
=
h
->
next
();
face
.
mIndices
=
new
unsigned
int
[
f
->
degree
()];
i_idx
++
;
face
.
mNumIndices
=
f
->
degree
();
}
while
(
h
!=
f
->
halfedge
());
size_t
i_idx
=
0
;
face_idx
++
;
auto
h
=
f
->
halfedge
();
}
do
{
face
.
mIndices
[
i_idx
]
=
(
unsigned
int
)
id_to_idx
[
h
->
vertex
()
->
id
()];
}
else
{
h
=
h
->
next
();
i_idx
++
;
const
auto
&
verts
=
obj
.
mesh
().
verts
();
}
while
(
h
!=
f
->
halfedge
());
const
auto
&
elems
=
obj
.
mesh
().
indices
();
face_idx
++
;
ai_mesh
->
mVertices
=
new
aiVector3D
[
verts
.
size
()];
}
ai_mesh
->
mNormals
=
new
aiVector3D
[
verts
.
size
()];
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
verts
.
size
();
}
else
{
int
j
=
0
;
const
auto
&
verts
=
obj
.
mesh
().
verts
();
for
(
GL
::
Mesh
::
Vert
v
:
verts
)
{
const
auto
&
elems
=
obj
.
mesh
().
indices
();
ai_mesh
->
mVertices
[
j
]
=
vecVec
(
v
.
pos
);
ai_mesh
->
mNormals
[
j
]
=
vecVec
(
v
.
norm
);
ai_mesh
->
mVertices
=
new
aiVector3D
[
verts
.
size
()];
j
++
;
ai_mesh
->
mNormals
=
new
aiVector3D
[
verts
.
size
()];
}
ai_mesh
->
mNumVertices
=
(
unsigned
int
)
verts
.
size
();
ai_mesh
->
mFaces
=
new
aiFace
[
elems
.
size
()
/
3
];
int
j
=
0
;
ai_mesh
->
mNumFaces
=
(
unsigned
int
)(
elems
.
size
()
/
3
);
for
(
GL
::
Mesh
::
Vert
v
:
verts
)
{
ai_mesh
->
mVertices
[
j
]
=
vecVec
(
v
.
pos
);
for
(
size_t
i
=
0
;
i
<
elems
.
size
();
i
+=
3
)
{
ai_mesh
->
mNormals
[
j
]
=
vecVec
(
v
.
norm
);
aiFace
&
face
=
ai_mesh
->
mFaces
[
i
/
3
];
j
++
;
face
.
mIndices
=
new
unsigned
int
[
3
];
}
face
.
mNumIndices
=
3
;
face
.
mIndices
[
0
]
=
elems
[
i
];
ai_mesh
->
mFaces
=
new
aiFace
[
elems
.
size
()
/
3
];
face
.
mIndices
[
1
]
=
elems
[
i
+
1
];
ai_mesh
->
mNumFaces
=
(
unsigned
int
)(
elems
.
size
()
/
3
);
face
.
mIndices
[
2
]
=
elems
[
i
+
2
];
}
for
(
size_t
i
=
0
;
i
<
elems
.
size
();
i
+=
3
)
{
}
aiFace
&
face
=
ai_mesh
->
mFaces
[
i
/
3
];
face
.
mIndices
=
new
unsigned
int
[
3
];
std
::
string
name
(
obj
.
opt
.
name
);
face
.
mNumIndices
=
3
;
std
::
replace
(
name
.
begin
(),
name
.
end
(),
' '
,
'_'
);
face
.
mIndices
[
0
]
=
elems
[
i
];
name
+=
"-S3D-"
+
std
::
to_string
(
obj
.
id
());
face
.
mIndices
[
1
]
=
elems
[
i
+
1
];
face
.
mIndices
[
2
]
=
elems
[
i
+
2
];
if
(
obj
.
get_mesh
().
flipped
())
name
+=
"-FLIPPED"
;
}
if
(
obj
.
opt
.
smooth_normals
)
name
+=
"-SMOOTHED"
;
}
ai_mesh
->
mName
=
aiString
(
name
);
std
::
string
name
(
obj
.
opt
.
name
);
std
::
replace
(
name
.
begin
(),
name
.
end
(),
' '
,
'_'
);
Mat4
trans
=
obj
.
pose
.
transform
();
name
+=
"-S3D-"
+
std
::
to_string
(
obj
.
id
());
item_nodes
[
obj
.
id
()]
=
ai_node
;
if
(
obj
.
get_mesh
().
flipped
())
ai_node
->
mName
=
aiString
(
name
);
name
+=
"-FLIPPED"
;
ai_node
->
mTransformation
=
matMat
(
trans
);
if
(
obj
.
opt
.
smooth_normals
)
name
+=
"-SMOOTHED"
;
const
Material
::
Options
&
opt
=
obj
.
material
.
opt
;
std
::
string
mat_name
;
ai_mesh
->
mName
=
aiString
(
name
);
switch
(
opt
.
type
)
{
Mat4
trans
=
obj
.
pose
.
transform
();
case
Material_Type
::
lambertian
:
{
mat_name
=
"lambertian"
;
item_nodes
[
obj
.
id
()]
=
ai_node
;
}
break
;
ai_node
->
mName
=
aiString
(
name
);
case
Material_Type
::
mirror
:
{
ai_node
->
mTransformation
=
matMat
(
trans
);
mat_name
=
"mirror"
;
}
break
;
const
Material
::
Options
&
opt
=
obj
.
material
.
opt
;
case
Material_Type
::
refract
:
{
std
::
string
mat_name
;
mat_name
=
"refract"
;
}
break
;
switch
(
opt
.
type
)
{
case
Material_Type
::
glass
:
{
case
Material_Type
::
lambertian
:
{
mat_name
=
"glass"
;
mat_name
=
"lambertian"
;
}
break
;
}
break
;
case
Material_Type
::
diffuse_light
:
{
case
Material_Type
::
mirror
:
{
mat_name
=
"diffuse_light"
;
mat_name
=
"mirror"
;
}
break
;
}
break
;
default:
break
;
case
Material_Type
::
refract
:
{
}
mat_name
=
"refract"
;
}
break
;
// Horrible hack
case
Material_Type
::
glass
:
{
if
(
obj
.
opt
.
shape_type
==
PT
::
Shape_Type
::
sphere
)
{
mat_name
=
"glass"
;
mat_name
+=
"-SPHERESHAPE"
;
}
break
;
ai_mat
->
AddProperty
(
new
aiColor3D
(
obj
.
opt
.
shape
.
get
<
PT
::
Sphere
>
().
radius
),
1
,
AI_MATKEY_COLOR_SPECULAR
);
case
Material_Type
::
diffuse_light
:
{
}
mat_name
=
"diffuse_light"
;
}
break
;
Spectrum
emissive
=
obj
.
material
.
emissive
();
default:
break
;
// diffuse -> albedo
}
// reflective -> reflectance
// transparent -> transmittance
// Horrible hack
// emissive -> emissive
if
(
obj
.
opt
.
shape_type
==
PT
::
Shape_Type
::
sphere
)
{
// refracti -> index of refraction
mat_name
+=
"-SPHERESHAPE"
;
// shininess -> intensity
ai_mat
->
AddProperty
(
new
aiColor3D
(
obj
.
opt
.
shape
.
get
<
PT
::
Sphere
>
().
radius
),
1
,
ai_mat
->
AddProperty
(
new
aiString
(
mat_name
),
AI_MATKEY_NAME
);
AI_MATKEY_COLOR_SPECULAR
);
ai_mat
->
AddProperty
(
new
aiColor3D
(
opt
.
albedo
.
r
,
opt
.
albedo
.
g
,
opt
.
albedo
.
b
),
1
,
AI_MATKEY_COLOR_DIFFUSE
);
}
ai_mat
->
AddProperty
(
new
aiColor3D
(
opt
.
reflectance
.
r
,
opt
.
reflectance
.
g
,
opt
.
reflectance
.
b
),
1
,
AI_MATKEY_COLOR_REFLECTIVE
);
ai_mat
->
AddProperty
(
new
aiColor3D
(
opt
.
transmittance
.
r
,
opt
.
transmittance
.
g
,
opt
.
transmittance
.
b
),
1
,
AI_MATKEY_COLOR_TRANSPARENT
);
Spectrum
emissive
=
obj
.
material
.
emissive
();
ai_mat
->
AddProperty
(
new
aiColor3D
(
emissive
.
r
,
emissive
.
g
,
emissive
.
b
),
1
,
AI_MATKEY_COLOR_EMISSIVE
);
ai_mat
->
AddProperty
(
new
float
(
opt
.
ior
),
1
,
AI_MATKEY_REFRACTI
);
// diffuse -> albedo
ai_mat
->
AddProperty
(
new
float
(
opt
.
intensity
),
1
,
AI_MATKEY_SHININESS
);
// reflective -> reflectance
// transparent -> transmittance
if
(
obj
.
armature
.
has_bones
())
{
// emissive -> emissive
ai_mesh
->
mNumBones
=
obj
.
armature
.
n_bones
();
// refracti -> index of refraction
ai_mesh
->
mBones
=
new
aiBone
*
[
ai_mesh
->
mNumBones
];
// shininess -> intensity
ai_mat
->
AddProperty
(
new
aiString
(
mat_name
),
AI_MATKEY_NAME
);
size_t
bone_idx
=
0
;
ai_mat
->
AddProperty
(
new
aiColor3D
(
opt
.
albedo
.
r
,
opt
.
albedo
.
g
,
opt
.
albedo
.
b
),
1
,
std
::
string
prefix
=
"S3D-joint-"
+
std
::
to_string
(
obj
.
id
())
+
"-"
;
AI_MATKEY_COLOR_DIFFUSE
);
ai_mat
->
AddProperty
(
aiNode
*
arm_node
=
new
aiNode
();
new
aiColor3D
(
opt
.
reflectance
.
r
,
opt
.
reflectance
.
g
,
opt
.
reflectance
.
b
),
1
,
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
arm_node
;
AI_MATKEY_COLOR_REFLECTIVE
);
arm_node
->
mName
=
aiString
(
prefix
+
"armature"
);
ai_mat
->
AddProperty
(
arm_node
->
mTransformation
=
matMat
(
Mat4
::
translate
(
obj
.
armature
.
base_pos
));
new
aiColor3D
(
opt
.
transmittance
.
r
,
opt
.
transmittance
.
g
,
opt
.
transmittance
.
b
),
1
,
arm_node
->
mNumChildren
=
(
unsigned
int
)
obj
.
armature
.
roots
.
size
();
AI_MATKEY_COLOR_TRANSPARENT
);
arm_node
->
mChildren
=
new
aiNode
*
[
obj
.
armature
.
roots
.
size
()];
ai_mat
->
AddProperty
(
new
aiColor3D
(
emissive
.
r
,
emissive
.
g
,
emissive
.
b
),
1
,
AI_MATKEY_COLOR_EMISSIVE
);
std
::
unordered_map
<
Joint
*
,
aiNode
*>
j_to_node
;
ai_mat
->
AddProperty
(
new
float
(
opt
.
ior
),
1
,
AI_MATKEY_REFRACTI
);
ai_mat
->
AddProperty
(
new
float
(
opt
.
intensity
),
1
,
AI_MATKEY_SHININESS
);
std
::
function
<
void
(
std
::
string
,
aiNode
*
,
Joint
*
)
>
joint_tree
;
joint_tree
=
[
&
joint_tree
,
&
j_to_node
](
std
::
string
n
,
aiNode
*
node
,
Joint
*
j
)
{
if
(
obj
.
armature
.
has_bones
())
{
std
::
string
name
=
n
+
std
::
to_string
(
j
->
_id
);
ai_mesh
->
mNumBones
=
obj
.
armature
.
n_bones
();
node
->
mName
=
aiString
(
name
);
ai_mesh
->
mBones
=
new
aiBone
*
[
ai_mesh
->
mNumBones
];
j_to_node
[
j
]
=
node
;
if
(
j
->
children
.
size
())
{
size_t
bone_idx
=
0
;
node
->
mNumChildren
=
(
unsigned
int
)
j
->
children
.
size
();
std
::
string
prefix
=
"S3D-joint-"
+
std
::
to_string
(
obj
.
id
())
+
"-"
;
node
->
mChildren
=
new
aiNode
*
[
j
->
children
.
size
()];
size_t
i
=
0
;
aiNode
*
arm_node
=
new
aiNode
();
for
(
Joint
*
c
:
j
->
children
)
{
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
arm_node
;
node
->
mChildren
[
i
]
=
new
aiNode
();
arm_node
->
mName
=
aiString
(
prefix
+
"armature"
);
joint_tree
(
n
,
node
->
mChildren
[
i
],
c
);
arm_node
->
mTransformation
=
matMat
(
Mat4
::
translate
(
obj
.
armature
.
base_pos
));
i
++
;
arm_node
->
mNumChildren
=
(
unsigned
int
)
obj
.
armature
.
roots
.
size
();
}
arm_node
->
mChildren
=
new
aiNode
*
[
obj
.
armature
.
roots
.
size
()];
}
};
std
::
unordered_map
<
Joint
*
,
aiNode
*>
j_to_node
;
size_t
i
=
0
;
std
::
function
<
void
(
std
::
string
,
aiNode
*
,
Joint
*
)
>
joint_tree
;
for
(
Joint
*
j
:
obj
.
armature
.
roots
)
{
joint_tree
=
[
&
joint_tree
,
&
j_to_node
](
std
::
string
n
,
aiNode
*
node
,
Joint
*
j
)
{
aiNode
*
root_node
=
new
aiNode
();
std
::
string
name
=
n
+
std
::
to_string
(
j
->
_id
);
arm_node
->
mChildren
[
i
]
=
root_node
;
node
->
mName
=
aiString
(
name
);
j_to_node
[
j
]
=
root_node
;
j_to_node
[
j
]
=
node
;
joint_tree
(
prefix
,
root_node
,
j
);
if
(
j
->
children
.
size
())
{
i
++
;
node
->
mNumChildren
=
(
unsigned
int
)
j
->
children
.
size
();
}
node
->
mChildren
=
new
aiNode
*
[
j
->
children
.
size
()];
size_t
i
=
0
;
for
(
auto
[
j
,
n
]
:
j_to_node
)
{
for
(
Joint
*
c
:
j
->
children
)
{
bone_nodes
.
insert
({{
obj
.
id
(),
j
->
_id
},
n
});
node
->
mChildren
[
i
]
=
new
aiNode
();
}
joint_tree
(
n
,
node
->
mChildren
[
i
],
c
);
i
++
;
obj
.
armature
.
for_joints
([
&
](
Joint
*
j
)
{
}
aiBone
*
bone
=
new
aiBone
();
}
ai_mesh
->
mBones
[
bone_idx
++
]
=
bone
;
};
bone
->
mOffsetMatrix
=
matMat
(
Mat4
::
translate
(
j
->
extent
)
*
Mat4
::
euler
(
j
->
pose
));
bone
->
mNode
=
j_to_node
[
j
];
size_t
i
=
0
;
std
::
string
name
=
prefix
+
std
::
to_string
(
j
->
_id
);
for
(
Joint
*
j
:
obj
.
armature
.
roots
)
{
bone
->
mName
=
aiString
(
name
);
aiNode
*
root_node
=
new
aiNode
();
bone
->
mNumWeights
=
1
;
arm_node
->
mChildren
[
i
]
=
root_node
;
bone
->
mWeights
=
new
aiVertexWeight
[
1
];
j_to_node
[
j
]
=
root_node
;
bone
->
mWeights
[
0
].
mWeight
=
j
->
radius
;
joint_tree
(
prefix
,
root_node
,
j
);
});
i
++
;
}
}
}
else
if
(
entry
.
second
.
is
<
Scene_Light
>
())
{
for
(
auto
[
j
,
n
]
:
j_to_node
)
{
bone_nodes
.
insert
({{
obj
.
id
(),
j
->
_id
},
n
});
const
Scene_Light
&
light
=
entry
.
second
.
get
<
Scene_Light
>
();
}
std
::
string
name
(
light
.
opt
.
name
);
obj
.
armature
.
for_joints
([
&
](
Joint
*
j
)
{
std
::
replace
(
name
.
begin
(),
name
.
end
(),
' '
,
'_'
);
aiBone
*
bone
=
new
aiBone
();
ai_mesh
->
mBones
[
bone_idx
++
]
=
bone
;
aiLight
*
ai_light
=
new
aiLight
();
bone
->
mOffsetMatrix
=
matMat
(
Mat4
::
translate
(
j
->
extent
)
*
Mat4
::
euler
(
j
->
pose
));
aiNode
*
ai_node
=
new
aiNode
();
bone
->
mNode
=
j_to_node
[
j
];
aiNode
*
ai_node_light
=
new
aiNode
();
std
::
string
name
=
prefix
+
std
::
to_string
(
j
->
_id
);
bone
->
mName
=
aiString
(
name
);
scene
.
mLights
[
light_idx
++
]
=
ai_light
;
bone
->
mNumWeights
=
1
;
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
bone
->
mWeights
=
new
aiVertexWeight
[
1
];
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node_light
;
bone
->
mWeights
[
0
].
mWeight
=
j
->
radius
;
});
switch
(
light
.
opt
.
type
)
{
}
case
Light_Type
::
directional
:
{
ai_light
->
mType
=
aiLightSource_DIRECTIONAL
;
}
else
if
(
entry
.
second
.
is
<
Scene_Light
>
())
{
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
}
break
;
const
Scene_Light
&
light
=
entry
.
second
.
get
<
Scene_Light
>
();
case
Light_Type
::
sphere
:
{
ai_light
->
mType
=
aiLightSource_AMBIENT
;
std
::
string
name
(
light
.
opt
.
name
);
name
+=
"-S3D-SPHERE-"
+
std
::
to_string
(
light
.
id
());
std
::
replace
(
name
.
begin
(),
name
.
end
(),
' '
,
'_'
);
if
(
light
.
opt
.
has_emissive_map
)
{
ai_light
->
mEnvMap
=
aiString
(
light
.
emissive_loaded
());
aiLight
*
ai_light
=
new
aiLight
();
}
aiNode
*
ai_node
=
new
aiNode
();
}
break
;
aiNode
*
ai_node_light
=
new
aiNode
();
case
Light_Type
::
hemisphere
:
{
ai_light
->
mType
=
aiLightSource_AMBIENT
;
scene
.
mLights
[
light_idx
++
]
=
ai_light
;
name
+=
"-S3D-HEMISPHERE-"
+
std
::
to_string
(
light
.
id
());
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node
;
}
break
;
scene
.
mRootNode
->
mChildren
[
node_idx
++
]
=
ai_node_light
;
case
Light_Type
::
point
:
{
ai_light
->
mType
=
aiLightSource_POINT
;
switch
(
light
.
opt
.
type
)
{
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
case
Light_Type
::
directional
:
{
}
break
;
ai_light
->
mType
=
aiLightSource_DIRECTIONAL
;
case
Light_Type
::
spot
:
{
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
ai_light
->
mType
=
aiLightSource_SPOT
;
}
break
;
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
case
Light_Type
::
sphere
:
{
}
break
;
ai_light
->
mType
=
aiLightSource_AMBIENT
;
case
Light_Type
::
rectangle
:
{
name
+=
"-S3D-SPHERE-"
+
std
::
to_string
(
light
.
id
());
// the collada exporter literally just ignores area lights ????????
if
(
light
.
opt
.
has_emissive_map
)
{
ai_light
->
mType
=
aiLightSource_AMBIENT
;
ai_light
->
mEnvMap
=
aiString
(
light
.
emissive_loaded
());
name
+=
"-S3D-AREA-"
+
std
::
to_string
(
light
.
id
());
}
ai_light
->
mAttenuationConstant
=
light
.
opt
.
size
.
x
;
}
break
;
ai_light
->
mAttenuationLinear
=
light
.
opt
.
size
.
y
;
case
Light_Type
::
hemisphere
:
{
}
break
;
ai_light
->
mType
=
aiLightSource_AMBIENT
;
default:
break
;
name
+=
"-S3D-HEMISPHERE-"
+
std
::
to_string
(
light
.
id
());
}
}
break
;
case
Light_Type
::
point
:
{
Spectrum
r
=
light
.
radiance
();
ai_light
->
mType
=
aiLightSource_POINT
;
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
ai_light
->
mName
=
aiString
(
name
);
}
break
;
ai_light
->
mPosition
=
aiVector3D
(
0.0
f
,
0.0
f
,
0.0
f
);
case
Light_Type
::
spot
:
{
ai_light
->
mDirection
=
aiVector3D
(
0.0
f
,
1.0
f
,
0.0
f
);
ai_light
->
mType
=
aiLightSource_SPOT
;
ai_light
->
mUp
=
aiVector3D
(
0.0
f
,
1.0
f
,
0.0
f
);
name
+=
"-S3D-"
+
std
::
to_string
(
light
.
id
());
ai_light
->
mSize
=
aiVector2D
(
light
.
opt
.
size
.
x
,
light
.
opt
.
size
.
y
);
}
break
;
ai_light
->
mAngleInnerCone
=
light
.
opt
.
angle_bounds
.
x
;
case
Light_Type
::
rectangle
:
{
ai_light
->
mAngleOuterCone
=
light
.
opt
.
angle_bounds
.
y
;
// the collada exporter literally just ignores area lights ????????
ai_light
->
mColorDiffuse
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
ai_light
->
mType
=
aiLightSource_AMBIENT
;
ai_light
->
mColorAmbient
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
name
+=
"-S3D-AREA-"
+
std
::
to_string
(
light
.
id
());
ai_light
->
mColorDiffuse
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
ai_light
->
mAttenuationConstant
=
light
.
opt
.
size
.
x
;
ai_light
->
mAttenuationQuadratic
=
light
.
opt
.
intensity
;
ai_light
->
mAttenuationLinear
=
light
.
opt
.
size
.
y
;
}
break
;
Mat4
T
=
light
.
pose
.
transform
();
default:
item_nodes
[
light
.
id
()]
=
ai_node
;
break
;
ai_node
->
mName
=
aiString
(
name
);
}
ai_node
->
mNumMeshes
=
0
;
ai_node
->
mMeshes
=
nullptr
;
Spectrum
r
=
light
.
radiance
();
ai_node
->
mTransformation
=
matMat
(
T
);
ai_light
->
mName
=
aiString
(
name
);
ai_node_light
->
mName
=
aiString
(
name
+
"-LIGHT_ANIM_NODE"
);
ai_light
->
mPosition
=
aiVector3D
(
0.0
f
,
0.0
f
,
0.0
f
);
ai_node_light
->
mNumMeshes
=
0
;
ai_light
->
mDirection
=
aiVector3D
(
0.0
f
,
1.0
f
,
0.0
f
);
ai_node_light
->
mMeshes
=
nullptr
;
ai_light
->
mUp
=
aiVector3D
(
0.0
f
,
1.0
f
,
0.0
f
);
ai_node_light
->
mTransformation
=
aiMatrix4x4
();
ai_light
->
mSize
=
aiVector2D
(
light
.
opt
.
size
.
x
,
light
.
opt
.
size
.
y
);
}
ai_light
->
mAngleInnerCone
=
light
.
opt
.
angle_bounds
.
x
;
}
ai_light
->
mAngleOuterCone
=
light
.
opt
.
angle_bounds
.
y
;
{
ai_light
->
mColorDiffuse
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
scene
.
mNumAnimations
=
1
;
ai_light
->
mColorAmbient
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
scene
.
mAnimations
=
new
aiAnimation
*
[
1
];
ai_light
->
mColorDiffuse
=
aiColor3D
(
r
.
r
,
r
.
g
,
r
.
b
);
scene
.
mAnimations
[
0
]
=
new
aiAnimation
();
ai_light
->
mAttenuationQuadratic
=
light
.
opt
.
intensity
;
aiAnimation
&
ai_anim
=
*
scene
.
mAnimations
[
0
];
Mat4
T
=
light
.
pose
.
transform
();
ai_anim
.
mName
=
aiString
(
"Scotty3D-animate"
);
item_nodes
[
light
.
id
()]
=
ai_node
;
ai_anim
.
mDuration
=
(
double
)
animation
.
n_frames
();
ai_node
->
mName
=
aiString
(
name
);
ai_anim
.
mTicksPerSecond
=
(
double
)
animation
.
fps
();
ai_node
->
mNumMeshes
=
0
;
ai_anim
.
mNumChannels
=
(
unsigned
int
)
n_anims
;
ai_node
->
mMeshes
=
nullptr
;
ai_anim
.
mChannels
=
new
aiNodeAnim
*
[
n_anims
];
ai_node
->
mTransformation
=
matMat
(
T
);
auto
write_keyframes
=
[](
aiNodeAnim
*
node
,
std
::
string
name
,
auto
pt
,
auto
rot
,
auto
scl
)
{
ai_node_light
->
mName
=
aiString
(
name
+
"-LIGHT_ANIM_NODE"
);
node
->
mNodeName
=
aiString
(
name
);
ai_node_light
->
mNumMeshes
=
0
;
node
->
mNumPositionKeys
=
(
unsigned
int
)
pt
.
size
();
ai_node_light
->
mMeshes
=
nullptr
;
node
->
mNumRotationKeys
=
(
unsigned
int
)
rot
.
size
();
ai_node_light
->
mTransformation
=
aiMatrix4x4
();
node
->
mNumScalingKeys
=
(
unsigned
int
)
scl
.
size
();
}
node
->
mPositionKeys
=
new
aiVectorKey
[
pt
.
size
()];
}
node
->
mRotationKeys
=
new
aiQuatKey
[
rot
.
size
()];
{
node
->
mScalingKeys
=
new
aiVectorKey
[
scl
.
size
()];
scene
.
mNumAnimations
=
1
;
size_t
i
=
0
;
scene
.
mAnimations
=
new
aiAnimation
*
[
1
];
for
(
auto
&
e
:
pt
)
{
scene
.
mAnimations
[
0
]
=
new
aiAnimation
();
node
->
mPositionKeys
[
i
]
=
aiVectorKey
(
e
.
first
,
vecVec
(
e
.
second
));
aiAnimation
&
ai_anim
=
*
scene
.
mAnimations
[
0
];
i
++
;
}
ai_anim
.
mName
=
aiString
(
"Scotty3D-animate"
);
i
=
0
;
ai_anim
.
mDuration
=
(
double
)
animation
.
n_frames
();
for
(
auto
&
e
:
rot
)
{
ai_anim
.
mTicksPerSecond
=
(
double
)
animation
.
fps
();
node
->
mRotationKeys
[
i
]
=
aiQuatKey
(
e
.
first
,
aiQuaternion
(
e
.
second
.
w
,
e
.
second
.
x
,
e
.
second
.
y
,
e
.
second
.
z
));
ai_anim
.
mNumChannels
=
(
unsigned
int
)
n_anims
;
i
++
;
ai_anim
.
mChannels
=
new
aiNodeAnim
*
[
n_anims
];
}
i
=
0
;
auto
write_keyframes
=
[](
aiNodeAnim
*
node
,
std
::
string
name
,
auto
pt
,
auto
rot
,
auto
scl
)
{
for
(
auto
&
e
:
scl
)
{
node
->
mNodeName
=
aiString
(
name
);
node
->
mScalingKeys
[
i
]
=
aiVectorKey
(
e
.
first
,
vecVec
(
e
.
second
));
node
->
mNumPositionKeys
=
(
unsigned
int
)
pt
.
size
();
i
++
;
node
->
mNumRotationKeys
=
(
unsigned
int
)
rot
.
size
();
}
node
->
mNumScalingKeys
=
(
unsigned
int
)
scl
.
size
();
};
node
->
mPositionKeys
=
new
aiVectorKey
[
pt
.
size
()];
node
->
mRotationKeys
=
new
aiQuatKey
[
rot
.
size
()];
if
(
anim_cam
.
splines
.
any
())
{
node
->
mScalingKeys
=
new
aiVectorKey
[
scl
.
size
()];
ai_anim
.
mChannels
[
camera_anim
]
=
new
aiNodeAnim
();
size_t
i
=
0
;
for
(
auto
&
e
:
pt
)
{
std
::
set
<
float
>
keys
=
anim_cam
.
splines
.
keys
();
node
->
mPositionKeys
[
i
]
=
aiVectorKey
(
e
.
first
,
vecVec
(
e
.
second
));
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
i
++
;
std
::
unordered_map
<
float
,
Quat
>
rotations
;
}
for
(
float
k
:
keys
)
{
i
=
0
;
auto
[
p
,
r
,
fov
,
ar
]
=
anim_cam
.
splines
.
at
(
k
);
for
(
auto
&
e
:
rot
)
{
points
[
k
]
=
p
;
node
->
mRotationKeys
[
i
]
=
aiQuatKey
(
rotations
[
k
]
=
r
;
e
.
first
,
aiQuaternion
(
e
.
second
.
w
,
e
.
second
.
x
,
e
.
second
.
y
,
e
.
second
.
z
));
scales
[
k
]
=
Vec3
{
fov
,
ar
,
1.0
f
};
i
++
;
}
}
write_keyframes
(
ai_anim
.
mChannels
[
camera_anim
],
"camera_node"
,
points
,
rotations
,
scales
);
i
=
0
;
}
for
(
auto
&
e
:
scl
)
{
node
->
mScalingKeys
[
i
]
=
aiVectorKey
(
e
.
first
,
vecVec
(
e
.
second
));
size_t
anim_idx
=
0
;
i
++
;
for
(
auto
&
entry
:
objs
)
{
}
};
Scene_Item
&
item
=
entry
.
second
;
const
Anim_Pose
&
pose
=
item
.
animation
();
if
(
anim_cam
.
splines
.
any
())
{
ai_anim
.
mChannels
[
camera_anim
]
=
new
aiNodeAnim
();
if
(
pose
.
splines
.
any
())
{
std
::
set
<
float
>
keys
=
pose
.
splines
.
keys
();
std
::
set
<
float
>
keys
=
anim_cam
.
splines
.
keys
();
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
std
::
unordered_map
<
float
,
Quat
>
rotations
;
std
::
unordered_map
<
float
,
Quat
>
rotations
;
for
(
float
k
:
keys
)
{
for
(
float
k
:
keys
)
{
auto
[
p
,
r
,
s
]
=
pose
.
splines
.
at
(
k
);
auto
[
p
,
r
,
fov
,
ar
]
=
anim_cam
.
splines
.
at
(
k
);
points
[
k
]
=
p
;
points
[
k
]
=
p
;
rotations
[
k
]
=
r
;
rotations
[
k
]
=
r
;
scales
[
k
]
=
s
;
scales
[
k
]
=
Vec3
{
fov
,
ar
,
1.0
f
};
}
}
write_keyframes
(
ai_anim
.
mChannels
[
camera_anim
],
"camera_node"
,
points
,
rotations
,
aiNode
*
node
=
item_nodes
[
item
.
id
()];
scales
);
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
}
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
std
::
string
(
node
->
mName
.
C_Str
()),
points
,
rotations
,
scales
);
size_t
anim_idx
=
0
;
anim_idx
++
;
for
(
auto
&
entry
:
objs
)
{
}
Scene_Item
&
item
=
entry
.
second
;
if
(
item
.
is
<
Scene_Object
>
())
{
const
Anim_Pose
&
pose
=
item
.
animation
();
Skeleton
&
skel
=
item
.
get
<
Scene_Object
>
().
armature
;
if
(
pose
.
splines
.
any
())
{
if
(
skel
.
has_keyframes
())
{
std
::
set
<
float
>
keys
=
pose
.
splines
.
keys
();
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
skel
.
for_joints
([
&
](
Joint
*
j
)
{
std
::
unordered_map
<
float
,
Quat
>
rotations
;
for
(
float
k
:
keys
)
{
std
::
set
<
float
>
keys
=
j
->
anim
.
keys
();
auto
[
p
,
r
,
s
]
=
pose
.
splines
.
at
(
k
);
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
points
[
k
]
=
p
;
std
::
unordered_map
<
float
,
Quat
>
rotations
;
rotations
[
k
]
=
r
;
scales
[
k
]
=
s
;
for
(
float
k
:
keys
)
{
}
points
[
k
]
=
Vec3
{
0.0
f
};
rotations
[
k
]
=
j
->
anim
.
at
(
k
);
aiNode
*
node
=
item_nodes
[
item
.
id
()];
scales
[
k
]
=
Vec3
{
1.0
f
};
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
}
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
std
::
string
(
node
->
mName
.
C_Str
()),
points
,
rotations
,
scales
);
aiNode
*
node
=
bone_nodes
[{
item
.
id
(),
j
->
_id
}];
anim_idx
++
;
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
}
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
std
::
string
(
node
->
mName
.
C_Str
()),
points
,
rotations
,
scales
);
if
(
item
.
is
<
Scene_Object
>
())
{
anim_idx
++
;
});
Skeleton
&
skel
=
item
.
get
<
Scene_Object
>
().
armature
;
}
if
(
skel
.
has_keyframes
())
{
}
else
if
(
item
.
is
<
Scene_Light
>
())
{
skel
.
for_joints
([
&
](
Joint
*
j
)
{
std
::
set
<
float
>
keys
=
j
->
anim
.
keys
();
aiNode
*
node
=
item_nodes
[
item
.
id
()];
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
std
::
string
name
(
node
->
mName
.
C_Str
());
std
::
unordered_map
<
float
,
Quat
>
rotations
;
name
+=
"-LIGHT_ANIM_NODE"
;
for
(
float
k
:
keys
)
{
const
Scene_Light
::
Anim_Light
&
light
=
item
.
get
<
Scene_Light
>
().
lanim
;
points
[
k
]
=
Vec3
{
0.0
f
};
rotations
[
k
]
=
j
->
anim
.
at
(
k
);
if
(
light
.
splines
.
any
())
{
scales
[
k
]
=
Vec3
{
1.0
f
};
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
}
std
::
unordered_map
<
float
,
Quat
>
rotations
;
std
::
set
<
float
>
keys
=
light
.
splines
.
keys
();
aiNode
*
node
=
bone_nodes
[{
item
.
id
(),
j
->
_id
}];
for
(
float
k
:
keys
)
{
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
auto
[
spec
,
inten
,
angle
,
size
]
=
light
.
splines
.
at
(
k
);
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
points
[
k
]
=
Vec3
{
spec
.
r
,
spec
.
g
,
spec
.
b
};
std
::
string
(
node
->
mName
.
C_Str
()),
points
,
rotations
,
rotations
[
k
]
=
Quat
::
euler
(
Vec3
{
angle
.
x
,
0.0
f
,
angle
.
y
});
scales
);
scales
[
k
]
=
Vec3
{
inten
+
1.0
f
,
size
.
x
+
1.0
f
,
size
.
y
+
1.0
f
};
anim_idx
++
;
}
});
}
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
name
,
points
,
rotations
,
scales
);
}
else
if
(
item
.
is
<
Scene_Light
>
())
{
anim_idx
++
;
}
aiNode
*
node
=
item_nodes
[
item
.
id
()];
}
std
::
string
name
(
node
->
mName
.
C_Str
());
}
name
+=
"-LIGHT_ANIM_NODE"
;
}
const
Scene_Light
::
Anim_Light
&
light
=
item
.
get
<
Scene_Light
>
().
lanim
;
// Note: exporter/scene destructor should free everything
if
(
light
.
splines
.
any
())
{
Assimp
::
Exporter
exporter
;
std
::
unordered_map
<
float
,
Vec3
>
points
,
scales
;
if
(
exporter
.
Export
(
&
scene
,
"collada"
,
file
.
c_str
()))
{
std
::
unordered_map
<
float
,
Quat
>
rotations
;
return
std
::
string
(
exporter
.
GetErrorString
());
std
::
set
<
float
>
keys
=
light
.
splines
.
keys
();
}
for
(
float
k
:
keys
)
{
return
{};
auto
[
spec
,
inten
,
angle
,
size
]
=
light
.
splines
.
at
(
k
);
points
[
k
]
=
Vec3
{
spec
.
r
,
spec
.
g
,
spec
.
b
};
rotations
[
k
]
=
Quat
::
euler
(
Vec3
{
angle
.
x
,
0.0
f
,
angle
.
y
});
scales
[
k
]
=
Vec3
{
inten
+
1.0
f
,
size
.
x
+
1.0
f
,
size
.
y
+
1.0
f
};
}
ai_anim
.
mChannels
[
anim_idx
]
=
new
aiNodeAnim
();
write_keyframes
(
ai_anim
.
mChannels
[
anim_idx
],
name
,
points
,
rotations
,
scales
);
anim_idx
++
;
}
}
}
}
// Note: exporter/scene destructor should free everything
Assimp
::
Exporter
exporter
;
if
(
exporter
.
Export
(
&
scene
,
"collada"
,
file
.
c_str
()))
{
return
std
::
string
(
exporter
.
GetErrorString
());
}
return
{};
}
}
src/scene/scene.h
View file @
c2535f0f
#pragma once
#pragma once
#include <functional>
#include <map>
#include <map>
#include <optional>
#include <optional>
#include <functional>
#include "../geometry/halfedge.h"
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
#include "../util/camera.h"
#include "../platform/gl.h"
#include "../platform/gl.h"
#include "../
geometry/halfedge
.h"
#include "../
util/camera
.h"
#include "light.h"
#include "light.h"
#include "object.h"
#include "object.h"
class
Undo
;
class
Undo
;
class
Halfedge_Editor
;
class
Halfedge_Editor
;
namespace
Gui
{
class
Manager
;
class
Animate
;
}
namespace
Gui
{
class
Manager
;
class
Animate
;
}
// namespace Gui
class
Scene_Item
{
class
Scene_Item
{
public:
public:
Scene_Item
()
=
default
;
Scene_Item
()
=
default
;
Scene_Item
(
Scene_Object
&&
obj
);
Scene_Item
(
Scene_Object
&&
obj
);
Scene_Item
(
Scene_Light
&&
light
);
Scene_Item
(
Scene_Light
&&
light
);
Scene_Item
(
Scene_Item
&&
src
);
Scene_Item
(
Scene_Item
&&
src
);
Scene_Item
(
const
Scene_Item
&
src
)
=
delete
;
Scene_Item
(
const
Scene_Item
&
src
)
=
delete
;
Scene_Item
&
operator
=
(
Scene_Item
&&
src
);
Scene_Item
&
operator
=
(
Scene_Item
&&
src
);
Scene_Item
&
operator
=
(
const
Scene_Item
&
src
)
=
delete
;
Scene_Item
&
operator
=
(
const
Scene_Item
&
src
)
=
delete
;
BBox
bbox
();
BBox
bbox
();
void
render
(
const
Mat4
&
view
,
bool
solid
=
false
,
bool
depth_only
=
false
,
bool
posed
=
true
);
void
render
(
const
Mat4
&
view
,
bool
solid
=
false
,
bool
depth_only
=
false
,
bool
posed
=
true
);
Scene_ID
id
()
const
;
Scene_ID
id
()
const
;
Pose
&
pose
();
Pose
&
pose
();
const
Pose
&
pose
()
const
;
const
Pose
&
pose
()
const
;
Anim_Pose
&
animation
();
Anim_Pose
&
animation
();
const
Anim_Pose
&
animation
()
const
;
const
Anim_Pose
&
animation
()
const
;
void
set_time
(
float
time
);
void
set_time
(
float
time
);
std
::
string
name
()
const
;
std
::
string
name
()
const
;
std
::
pair
<
char
*
,
int
>
name
();
std
::
pair
<
char
*
,
int
>
name
();
template
<
typename
T
>
template
<
typename
T
>
bool
is
()
const
{
return
std
::
holds_alternative
<
T
>
(
data
);
}
bool
is
()
const
{
template
<
typename
T
>
T
&
get
()
{
return
std
::
get
<
T
>
(
data
);
}
return
std
::
holds_alternative
<
T
>
(
data
);
template
<
typename
T
>
const
T
&
get
()
const
{
return
std
::
get
<
T
>
(
data
);
}
}
template
<
typename
T
>
T
&
get
()
{
return
std
::
get
<
T
>
(
data
);
}
template
<
typename
T
>
const
T
&
get
()
const
{
return
std
::
get
<
T
>
(
data
);
}
private:
private:
std
::
variant
<
Scene_Object
,
Scene_Light
>
data
;
std
::
variant
<
Scene_Object
,
Scene_Light
>
data
;
};
};
using
Scene_Maybe
=
std
::
optional
<
std
::
reference_wrapper
<
Scene_Item
>>
;
using
Scene_Maybe
=
std
::
optional
<
std
::
reference_wrapper
<
Scene_Item
>>
;
...
@@ -66,34 +60,34 @@ public:
...
@@ -66,34 +60,34 @@ public:
Scene
(
Scene_ID
start
);
Scene
(
Scene_ID
start
);
~
Scene
()
=
default
;
~
Scene
()
=
default
;
std
::
string
write
(
std
::
string
file
,
const
Camera
&
cam
,
const
Gui
::
Animate
&
animation
);
std
::
string
write
(
std
::
string
file
,
const
Camera
&
cam
,
const
Gui
::
Animate
&
animation
);
std
::
string
load
(
bool
new_scene
,
Undo
&
undo
,
Gui
::
Manager
&
gui
,
std
::
string
file
);
std
::
string
load
(
bool
new_scene
,
Undo
&
undo
,
Gui
::
Manager
&
gui
,
std
::
string
file
);
void
clear
(
Undo
&
undo
);
void
clear
(
Undo
&
undo
);
bool
empty
();
bool
empty
();
size_t
size
();
size_t
size
();
Scene_ID
add
(
Scene_Object
&&
obj
);
Scene_ID
add
(
Scene_Object
&&
obj
);
Scene_ID
add
(
Scene_Light
&&
obj
);
Scene_ID
add
(
Scene_Light
&&
obj
);
Scene_ID
add
(
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
=
{},
Scene_ID
id
=
0
);
Scene_ID
add
(
Pose
pose
,
GL
::
Mesh
&&
mesh
,
std
::
string
n
=
{},
Scene_ID
id
=
0
);
Scene_ID
add
(
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
=
{},
Scene_ID
id
=
0
);
Scene_ID
add
(
Pose
pose
,
Halfedge_Mesh
&&
mesh
,
std
::
string
n
=
{},
Scene_ID
id
=
0
);
Scene_ID
reserve_id
();
Scene_ID
reserve_id
();
Scene_ID
used_ids
();
Scene_ID
used_ids
();
void
erase
(
Scene_ID
id
);
void
erase
(
Scene_ID
id
);
void
restore
(
Scene_ID
id
);
void
restore
(
Scene_ID
id
);
void
for_items
(
std
::
function
<
void
(
Scene_Item
&
)
>
func
);
void
for_items
(
std
::
function
<
void
(
Scene_Item
&
)
>
func
);
void
for_items
(
std
::
function
<
void
(
const
Scene_Item
&
)
>
func
)
const
;
void
for_items
(
std
::
function
<
void
(
const
Scene_Item
&
)
>
func
)
const
;
Scene_Maybe
get
(
Scene_ID
id
);
Scene_Maybe
get
(
Scene_ID
id
);
Scene_Object
&
get_obj
(
Scene_ID
id
);
Scene_Object
&
get_obj
(
Scene_ID
id
);
Scene_Light
&
get_light
(
Scene_ID
id
);
Scene_Light
&
get_light
(
Scene_ID
id
);
std
::
string
set_env_map
(
std
::
string
file
);
std
::
string
set_env_map
(
std
::
string
file
);
bool
has_env_light
()
const
;
bool
has_env_light
()
const
;
private:
private:
std
::
map
<
Scene_ID
,
Scene_Item
>
objs
;
std
::
map
<
Scene_ID
,
Scene_Item
>
objs
;
std
::
map
<
Scene_ID
,
Scene_Item
>
erased
;
std
::
map
<
Scene_ID
,
Scene_Item
>
erased
;
Scene_ID
next_id
,
first_id
;
Scene_ID
next_id
,
first_id
;
};
};
src/scene/skeleton.cpp
View file @
c2535f0f
#include "skeleton.h"
#include "skeleton.h"
#include "renderer.h"
#include "../gui/manager.h"
#include "../gui/manager.h"
#include "renderer.h"
bool
Joint
::
is_root
()
const
{
bool
Joint
::
is_root
()
const
{
return
!
parent
;
}
return
!
parent
;
}
void
Joint
::
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
)
{
void
Joint
::
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
)
{
func
(
this
);
func
(
this
);
for
(
Joint
*
j
:
children
)
j
->
for_joints
(
func
);
for
(
Joint
*
j
:
children
)
j
->
for_joints
(
func
);
}
}
Skeleton
::
Skeleton
()
{
Skeleton
::
Skeleton
()
{
root_id
=
Gui
::
n_Widget_IDs
;
root_id
=
Gui
::
n_Widget_IDs
;
next_id
=
Gui
::
n_Widget_IDs
+
1
;
next_id
=
Gui
::
n_Widget_IDs
+
1
;
}
}
Skeleton
::
Skeleton
(
unsigned
int
obj_id
)
{
Skeleton
::
Skeleton
(
unsigned
int
obj_id
)
{
root_id
=
obj_id
+
1
;
root_id
=
obj_id
+
1
;
next_id
=
root_id
+
1
;
next_id
=
root_id
+
1
;
}
}
Skeleton
::~
Skeleton
()
{
Skeleton
::~
Skeleton
()
{
for
(
Joint
*
j
:
roots
)
delete
j
;
for
(
Joint
*
j
:
roots
)
for
(
Joint
*
j
:
erased
)
delete
j
;
delete
j
;
for
(
Joint
*
j
:
erased
)
delete
j
;
}
}
bool
Skeleton
::
set_time
(
float
time
)
{
bool
Skeleton
::
set_time
(
float
time
)
{
bool
ret
=
false
;
bool
ret
=
false
;
for_joints
([
&
ret
,
time
](
Joint
*
j
)
{
for_joints
([
&
ret
,
time
](
Joint
*
j
)
{
if
(
j
->
anim
.
any
())
{
if
(
j
->
anim
.
any
())
{
j
->
pose
=
j
->
anim
.
at
(
time
).
to_euler
();
j
->
pose
=
j
->
anim
.
at
(
time
).
to_euler
();
ret
=
true
;
ret
=
true
;
}
}
...
@@ -38,13 +39,14 @@ bool Skeleton::set_time(float time) {
...
@@ -38,13 +39,14 @@ bool Skeleton::set_time(float time) {
return
ret
;
return
ret
;
}
}
void
Skeleton
::
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
)
{
void
Skeleton
::
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
)
{
for
(
Joint
*
r
:
roots
)
r
->
for_joints
(
func
);
for
(
Joint
*
r
:
roots
)
r
->
for_joints
(
func
);
}
}
Joint
*
Skeleton
::
add_root
(
Vec3
extent
)
{
Joint
*
Skeleton
::
add_root
(
Vec3
extent
)
{
Joint
*
j
=
new
Joint
(
next_id
++
,
nullptr
,
extent
);
Joint
*
j
=
new
Joint
(
next_id
++
,
nullptr
,
extent
);
for
(
float
f
:
keys
())
{
for
(
float
f
:
keys
())
{
j
->
anim
.
set
(
f
,
Quat
{});
j
->
anim
.
set
(
f
,
Quat
{});
}
}
roots
.
insert
(
j
);
roots
.
insert
(
j
);
...
@@ -52,40 +54,39 @@ Joint* Skeleton::add_root(Vec3 extent) {
...
@@ -52,40 +54,39 @@ Joint* Skeleton::add_root(Vec3 extent) {
}
}
void
Skeleton
::
crop
(
float
t
)
{
void
Skeleton
::
crop
(
float
t
)
{
for_joints
([
t
](
Joint
*
j
)
{
for_joints
([
t
](
Joint
*
j
)
{
j
->
anim
.
crop
(
t
);
});
j
->
anim
.
crop
(
t
);
});
}
}
Joint
*
Skeleton
::
get_joint
(
unsigned
int
id
)
{
Joint
*
Skeleton
::
get_joint
(
unsigned
int
id
)
{
Joint
*
j
=
nullptr
;
Joint
*
j
=
nullptr
;
for_joints
([
&
](
Joint
*
jt
)
{
for_joints
([
&
](
Joint
*
jt
)
{
if
(
jt
->
_id
==
id
)
j
=
jt
;
if
(
jt
->
_id
==
id
)
j
=
jt
;
});
});
return
j
;
return
j
;
}
}
void
Skeleton
::
render
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
unsigned
int
offset
)
{
void
Skeleton
::
render
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
unsigned
int
offset
)
{
Renderer
&
R
=
Renderer
::
get
();
Renderer
&
R
=
Renderer
::
get
();
Mat4
V
=
view
*
Mat4
::
translate
(
base_pos
);
Mat4
V
=
view
*
Mat4
::
translate
(
base_pos
);
for_joints
([
&
](
Joint
*
j
)
{
for_joints
([
&
](
Joint
*
j
)
{
Renderer
::
MeshOpt
opt
;
Renderer
::
MeshOpt
opt
;
opt
.
modelview
=
V
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
opt
.
modelview
=
Mat4
::
rotate_to
(
j
->
extent
);
V
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
Mat4
::
rotate_to
(
j
->
extent
);
opt
.
id
=
j
->
_id
+
offset
;
opt
.
id
=
j
->
_id
+
offset
;
opt
.
alpha
=
0.8
f
;
opt
.
alpha
=
0.8
f
;
opt
.
color
=
Gui
::
Color
::
hover
;
opt
.
color
=
Gui
::
Color
::
hover
;
R
.
capsule
(
opt
,
j
->
extent
.
norm
(),
j
->
radius
);
R
.
capsule
(
opt
,
j
->
extent
.
norm
(),
j
->
radius
);
});
});
if
(
select
)
{
if
(
select
)
{
R
.
begin_outline
();
R
.
begin_outline
();
Mat4
model
=
Mat4
::
translate
(
base_pos
)
*
Mat4
model
=
Mat4
::
translate
(
base_pos
)
*
(
posed
?
select
->
joint_to_posed
()
:
select
->
joint_to_bind
())
*
(
posed
?
select
->
joint_to_posed
()
:
select
->
joint_to_bind
())
*
Mat4
::
rotate_to
(
select
->
extent
);
Mat4
::
rotate_to
(
select
->
extent
);
Renderer
::
MeshOpt
opt
;
Renderer
::
MeshOpt
opt
;
opt
.
modelview
=
view
;
opt
.
modelview
=
view
;
...
@@ -104,24 +105,25 @@ void Skeleton::render(const Mat4& view, Joint* select, bool root, bool posed, un
...
@@ -104,24 +105,25 @@ void Skeleton::render(const Mat4& view, Joint* select, bool root, bool posed, un
opt
.
color
=
root
?
Gui
::
Color
::
outline
:
Gui
::
Color
::
hover
;
opt
.
color
=
root
?
Gui
::
Color
::
outline
:
Gui
::
Color
::
hover
;
R
.
sphere
(
opt
);
R
.
sphere
(
opt
);
for_joints
([
&
](
Joint
*
j
)
{
for_joints
([
&
](
Joint
*
j
)
{
Renderer
::
MeshOpt
opt
;
Renderer
::
MeshOpt
opt
;
opt
.
modelview
=
V
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
opt
.
modelview
=
V
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
Mat4
::
translate
(
j
->
extent
)
*
Mat4
::
scale
(
Vec3
{
j
->
radius
*
0.25
f
});
Mat4
::
translate
(
j
->
extent
)
*
Mat4
::
scale
(
Vec3
{
j
->
radius
*
0.25
f
});
opt
.
id
=
j
->
_id
+
offset
;
opt
.
id
=
j
->
_id
+
offset
;
opt
.
color
=
select
==
j
?
Gui
::
Color
::
outline
:
Gui
::
Color
::
hover
;
opt
.
color
=
select
==
j
?
Gui
::
Color
::
outline
:
Gui
::
Color
::
hover
;
R
.
sphere
(
opt
);
R
.
sphere
(
opt
);
});
});
}
}
void
Skeleton
::
outline
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
BBox
&
box
,
unsigned
int
offset
)
{
void
Skeleton
::
outline
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
BBox
&
box
,
unsigned
int
offset
)
{
Renderer
&
R
=
Renderer
::
get
();
Renderer
&
R
=
Renderer
::
get
();
Mat4
base_t
=
Mat4
::
translate
(
base_pos
);
Mat4
base_t
=
Mat4
::
translate
(
base_pos
);
for_joints
([
&
](
Joint
*
j
)
{
for_joints
([
&
](
Joint
*
j
)
{
Mat4
model
=
base_t
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
Mat4
model
=
base_t
*
(
posed
?
j
->
joint_to_posed
()
:
j
->
joint_to_bind
())
*
Mat4
::
rotate_to
(
j
->
extent
);
Mat4
::
rotate_to
(
j
->
extent
);
Renderer
::
MeshOpt
opt
;
Renderer
::
MeshOpt
opt
;
opt
.
modelview
=
view
;
opt
.
modelview
=
view
;
opt
.
id
=
j
->
_id
+
offset
;
opt
.
id
=
j
->
_id
+
offset
;
...
@@ -131,39 +133,31 @@ void Skeleton::outline(const Mat4& view, Joint* select, bool root, bool posed, B
...
@@ -131,39 +133,31 @@ void Skeleton::outline(const Mat4& view, Joint* select, bool root, bool posed, B
});
});
}
}
bool
Skeleton
::
is_root_id
(
unsigned
int
id
)
{
bool
Skeleton
::
is_root_id
(
unsigned
int
id
)
{
return
id
==
root_id
;
}
return
id
==
root_id
;
}
Joint
*
Skeleton
::
parent
(
Joint
*
j
)
{
Joint
*
Skeleton
::
parent
(
Joint
*
j
)
{
return
j
->
parent
;
}
return
j
->
parent
;
}
bool
Skeleton
::
has_bones
()
const
{
bool
Skeleton
::
has_bones
()
const
{
return
!
roots
.
empty
();
}
return
!
roots
.
empty
();
}
unsigned
int
Skeleton
::
n_bones
()
{
unsigned
int
Skeleton
::
n_bones
()
{
unsigned
int
n
=
0
;
unsigned
int
n
=
0
;
for_joints
([
&
n
](
Joint
*
)
{
n
++
;
});
for_joints
([
&
n
](
Joint
*
)
{
n
++
;
});
return
n
;
return
n
;
}
}
Vec3
&
Skeleton
::
base
()
{
Vec3
&
Skeleton
::
base
()
{
return
base_pos
;
}
return
base_pos
;
}
Joint
*
Skeleton
::
add_child
(
Joint
*
j
,
Vec3
e
)
{
Joint
*
Skeleton
::
add_child
(
Joint
*
j
,
Vec3
e
)
{
Joint
*
c
=
new
Joint
(
next_id
++
,
j
,
e
);
Joint
*
c
=
new
Joint
(
next_id
++
,
j
,
e
);
for
(
float
f
:
keys
())
{
for
(
float
f
:
keys
())
{
c
->
anim
.
set
(
f
,
Quat
{});
c
->
anim
.
set
(
f
,
Quat
{});
}
}
j
->
children
.
insert
(
c
);
j
->
children
.
insert
(
c
);
return
c
;
return
c
;
}
}
void
Skeleton
::
restore
(
Joint
*
j
)
{
void
Skeleton
::
restore
(
Joint
*
j
)
{
if
(
j
->
parent
)
{
if
(
j
->
parent
)
{
j
->
parent
->
children
.
insert
(
j
);
j
->
parent
->
children
.
insert
(
j
);
}
else
{
}
else
{
roots
.
insert
(
j
);
roots
.
insert
(
j
);
...
@@ -171,8 +165,8 @@ void Skeleton::restore(Joint* j) {
...
@@ -171,8 +165,8 @@ void Skeleton::restore(Joint* j) {
erased
.
erase
(
j
);
erased
.
erase
(
j
);
}
}
void
Skeleton
::
erase
(
Joint
*
j
)
{
void
Skeleton
::
erase
(
Joint
*
j
)
{
if
(
j
->
parent
)
{
if
(
j
->
parent
)
{
j
->
parent
->
children
.
erase
(
j
);
j
->
parent
->
children
.
erase
(
j
);
}
else
{
}
else
{
roots
.
erase
(
j
);
roots
.
erase
(
j
);
...
@@ -180,45 +174,33 @@ void Skeleton::erase(Joint* j) {
...
@@ -180,45 +174,33 @@ void Skeleton::erase(Joint* j) {
erased
.
insert
(
j
);
erased
.
insert
(
j
);
}
}
Vec3
Skeleton
::
posed_base_of
(
Joint
*
j
)
{
Vec3
Skeleton
::
posed_base_of
(
Joint
*
j
)
{
return
j
->
is_root
()
?
base
()
:
posed_end_of
(
parent
(
j
));
}
return
j
->
is_root
()
?
base
()
:
posed_end_of
(
parent
(
j
));
}
Vec3
Skeleton
::
base_of
(
Joint
*
j
)
{
Vec3
Skeleton
::
base_of
(
Joint
*
j
)
{
return
j
->
is_root
()
?
base
()
:
end_of
(
parent
(
j
));
}
return
j
->
is_root
()
?
base
()
:
end_of
(
parent
(
j
));
}
void
Skeleton
::
set
(
float
t
)
{
void
Skeleton
::
set
(
float
t
)
{
for_joints
([
t
](
Joint
*
j
)
{
for_joints
([
t
](
Joint
*
j
)
{
j
->
anim
.
set
(
t
,
Quat
::
euler
(
j
->
pose
));
});
j
->
anim
.
set
(
t
,
Quat
::
euler
(
j
->
pose
));
});
}
}
void
Skeleton
::
erase
(
float
t
)
{
void
Skeleton
::
erase
(
float
t
)
{
for_joints
([
t
](
Joint
*
j
)
{
for_joints
([
t
](
Joint
*
j
)
{
j
->
anim
.
erase
(
t
);
});
j
->
anim
.
erase
(
t
);
});
}
}
bool
Skeleton
::
has_keyframes
()
{
bool
Skeleton
::
has_keyframes
()
{
bool
frame
=
false
;
bool
frame
=
false
;
for_joints
([
&
frame
](
Joint
*
j
)
{
for_joints
([
&
frame
](
Joint
*
j
)
{
frame
=
frame
||
j
->
anim
.
any
();
});
frame
=
frame
||
j
->
anim
.
any
();
});
return
frame
;
return
frame
;
}
}
std
::
unordered_map
<
unsigned
int
,
Vec3
>
Skeleton
::
now
()
{
std
::
unordered_map
<
unsigned
int
,
Vec3
>
Skeleton
::
now
()
{
std
::
unordered_map
<
unsigned
int
,
Vec3
>
ret
;
std
::
unordered_map
<
unsigned
int
,
Vec3
>
ret
;
for_joints
([
&
ret
](
Joint
*
j
)
{
for_joints
([
&
ret
](
Joint
*
j
)
{
ret
[
j
->
_id
]
=
j
->
pose
;
});
ret
[
j
->
_id
]
=
j
->
pose
;
});
return
ret
;
return
ret
;
}
}
std
::
set
<
float
>
Skeleton
::
keys
()
{
std
::
set
<
float
>
Skeleton
::
keys
()
{
std
::
set
<
float
>
ret
;
std
::
set
<
float
>
ret
;
for_joints
([
&
ret
](
Joint
*
j
)
{
for_joints
([
&
ret
](
Joint
*
j
)
{
std
::
set
<
float
>
k
=
j
->
anim
.
keys
();
std
::
set
<
float
>
k
=
j
->
anim
.
keys
();
ret
.
insert
(
k
.
begin
(),
k
.
end
());
ret
.
insert
(
k
.
begin
(),
k
.
end
());
});
});
...
@@ -227,14 +209,10 @@ std::set<float> Skeleton::keys() {
...
@@ -227,14 +209,10 @@ std::set<float> Skeleton::keys() {
std
::
unordered_map
<
unsigned
int
,
Vec3
>
Skeleton
::
at
(
float
t
)
{
std
::
unordered_map
<
unsigned
int
,
Vec3
>
Skeleton
::
at
(
float
t
)
{
std
::
unordered_map
<
unsigned
int
,
Vec3
>
ret
;
std
::
unordered_map
<
unsigned
int
,
Vec3
>
ret
;
for_joints
([
&
ret
,
t
](
Joint
*
j
)
{
for_joints
([
&
ret
,
t
](
Joint
*
j
)
{
ret
[
j
->
_id
]
=
j
->
anim
.
at
(
t
).
to_euler
();
});
ret
[
j
->
_id
]
=
j
->
anim
.
at
(
t
).
to_euler
();
});
return
ret
;
return
ret
;
}
}
void
Skeleton
::
set
(
float
t
,
const
std
::
unordered_map
<
unsigned
int
,
Vec3
>&
data
)
{
void
Skeleton
::
set
(
float
t
,
const
std
::
unordered_map
<
unsigned
int
,
Vec3
>
&
data
)
{
for_joints
([
&
data
,
t
](
Joint
*
j
)
{
for_joints
([
&
data
,
t
](
Joint
*
j
)
{
j
->
anim
.
set
(
t
,
Quat
::
euler
(
data
.
at
(
j
->
_id
)));
});
j
->
anim
.
set
(
t
,
Quat
::
euler
(
data
.
at
(
j
->
_id
)));
});
}
}
src/scene/skeleton.h
View file @
c2535f0f
#pragma once
#pragma once
#include <functional>
#include <set>
#include <set>
#include <vector>
#include <unordered_map>
#include <unordered_map>
#include <unordered_set>
#include <unordered_set>
#include <
functional
>
#include <
vector
>
#include "../lib/mathlib.h"
#include "../geometry/spline.h"
#include "../geometry/spline.h"
#include "../lib/mathlib.h"
#include "../platform/gl.h"
#include "../platform/gl.h"
class
Joint
{
class
Joint
{
public:
public:
Joint
(
unsigned
int
id
)
:
_id
(
id
)
{}
Joint
(
unsigned
int
id
)
:
_id
(
id
)
{}
Joint
(
unsigned
int
id
,
Joint
*
parent
,
Vec3
extent
)
:
_id
(
id
),
parent
(
parent
),
extent
(
extent
)
{}
Joint
(
unsigned
int
id
,
Joint
*
parent
,
Vec3
extent
)
:
_id
(
id
),
parent
(
parent
),
extent
(
extent
)
{}
~
Joint
()
{
for
(
Joint
*
j
:
children
)
delete
j
;
}
~
Joint
()
{
for
(
Joint
*
j
:
children
)
delete
j
;
}
Joint
(
const
Joint
&
src
)
=
delete
;
Joint
(
const
Joint
&
src
)
=
delete
;
Joint
(
Joint
&&
src
)
=
default
;
Joint
(
Joint
&&
src
)
=
default
;
void
operator
=
(
const
Joint
&
src
)
=
delete
;
void
operator
=
(
const
Joint
&
src
)
=
delete
;
Joint
&
operator
=
(
Joint
&&
src
)
=
default
;
Joint
&
operator
=
(
Joint
&&
src
)
=
default
;
unsigned
int
id
()
const
{
return
_id
;
}
unsigned
int
id
()
const
{
return
_id
;
}
// Checks if this joint is a root node
// Checks if this joint is a root node
bool
is_root
()
const
;
bool
is_root
()
const
;
// Euler angles representing the current joint rotation
// Euler angles representing the current joint rotation
Vec3
pose
;
Vec3
pose
;
// The vector representing the direction and length of the bone.
// The vector representing the direction and length of the bone.
// This is specified in Joint space, and defines the origin of child bones.
// This is specified in Joint space, and defines the origin of child bones.
Vec3
extent
=
Vec3
(
0.0
f
,
1.0
f
,
0.0
f
);
Vec3
extent
=
Vec3
(
0.0
f
,
1.0
f
,
0.0
f
);
// The distance at which the joint segment should stop effecting vertices
// The distance at which the joint segment should stop effecting vertices
float
radius
=
0.25
f
;
float
radius
=
0.25
f
;
...
@@ -51,12 +54,12 @@ private:
...
@@ -51,12 +54,12 @@ private:
Mat4
joint_to_posed
()
const
;
Mat4
joint_to_posed
()
const
;
// Pointer to parent joint in the joint heirarchy
// Pointer to parent joint in the joint heirarchy
Joint
*
parent
=
nullptr
;
Joint
*
parent
=
nullptr
;
// Set of child joints - owned by this joint (could be shared_ptr and everything else weak_ptr)
// Set of child joints - owned by this joint (could be shared_ptr and everything else weak_ptr)
std
::
unordered_set
<
Joint
*>
children
;
std
::
unordered_set
<
Joint
*>
children
;
void
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
);
void
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
);
unsigned
int
_id
=
0
;
unsigned
int
_id
=
0
;
Spline
<
Quat
>
anim
;
Spline
<
Quat
>
anim
;
...
@@ -71,39 +74,42 @@ public:
...
@@ -71,39 +74,42 @@ public:
Skeleton
(
unsigned
int
obj_id
);
Skeleton
(
unsigned
int
obj_id
);
~
Skeleton
();
~
Skeleton
();
Skeleton
(
const
Skeleton
&
src
)
=
delete
;
Skeleton
(
const
Skeleton
&
src
)
=
delete
;
Skeleton
(
Skeleton
&&
src
)
=
default
;
Skeleton
(
Skeleton
&&
src
)
=
default
;
void
operator
=
(
const
Skeleton
&
src
)
=
delete
;
void
operator
=
(
const
Skeleton
&
src
)
=
delete
;
Skeleton
&
operator
=
(
Skeleton
&&
src
)
=
default
;
Skeleton
&
operator
=
(
Skeleton
&&
src
)
=
default
;
Vec3
&
base
();
Vec3
&
base
();
bool
has_bones
()
const
;
bool
has_bones
()
const
;
unsigned
int
n_bones
();
unsigned
int
n_bones
();
Joint
*
parent
(
Joint
*
j
);
Joint
*
parent
(
Joint
*
j
);
Joint
*
get_joint
(
unsigned
int
id
);
Joint
*
get_joint
(
unsigned
int
id
);
void
erase
(
Joint
*
j
);
void
erase
(
Joint
*
j
);
void
restore
(
Joint
*
j
);
void
restore
(
Joint
*
j
);
Vec3
end_of
(
Joint
*
j
);
Vec3
end_of
(
Joint
*
j
);
Vec3
base_of
(
Joint
*
j
);
Vec3
base_of
(
Joint
*
j
);
Vec3
posed_end_of
(
Joint
*
j
);
Vec3
posed_end_of
(
Joint
*
j
);
Vec3
posed_base_of
(
Joint
*
j
);
Vec3
posed_base_of
(
Joint
*
j
);
void
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
);
void
for_joints
(
std
::
function
<
void
(
Joint
*
)
>
func
);
Mat4
joint_to_bind
(
const
Joint
*
j
)
const
;
Mat4
joint_to_bind
(
const
Joint
*
j
)
const
;
Mat4
joint_to_posed
(
const
Joint
*
j
)
const
;
Mat4
joint_to_posed
(
const
Joint
*
j
)
const
;
Joint
*
add_root
(
Vec3
extent
);
Joint
*
add_root
(
Vec3
extent
);
Joint
*
add_child
(
Joint
*
j
,
Vec3
extent
);
Joint
*
add_child
(
Joint
*
j
,
Vec3
extent
);
bool
is_root_id
(
unsigned
int
id
);
bool
is_root_id
(
unsigned
int
id
);
bool
set_time
(
float
time
);
bool
set_time
(
float
time
);
void
render
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
unsigned
int
offset
=
0
);
void
render
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
unsigned
int
offset
=
0
);
void
outline
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
BBox
&
box
,
unsigned
int
offset
=
0
);
void
outline
(
const
Mat4
&
view
,
Joint
*
select
,
bool
root
,
bool
posed
,
BBox
&
box
,
void
find_joints
(
const
GL
::
Mesh
&
src
,
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>&
map
);
unsigned
int
offset
=
0
);
void
skin
(
const
GL
::
Mesh
&
input
,
GL
::
Mesh
&
output
,
const
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>&
map
);
void
find_joints
(
const
GL
::
Mesh
&
src
,
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>
&
map
);
void
skin
(
const
GL
::
Mesh
&
input
,
GL
::
Mesh
&
output
,
const
std
::
unordered_map
<
unsigned
int
,
std
::
vector
<
Joint
*>>
&
map
);
void
set
(
float
t
);
void
set
(
float
t
);
void
crop
(
float
t
);
void
crop
(
float
t
);
...
@@ -112,11 +118,11 @@ public:
...
@@ -112,11 +118,11 @@ public:
std
::
set
<
float
>
keys
();
std
::
set
<
float
>
keys
();
std
::
unordered_map
<
unsigned
int
,
Vec3
>
now
();
std
::
unordered_map
<
unsigned
int
,
Vec3
>
now
();
std
::
unordered_map
<
unsigned
int
,
Vec3
>
at
(
float
t
);
std
::
unordered_map
<
unsigned
int
,
Vec3
>
at
(
float
t
);
void
set
(
float
t
,
const
std
::
unordered_map
<
unsigned
int
,
Vec3
>
&
data
);
void
set
(
float
t
,
const
std
::
unordered_map
<
unsigned
int
,
Vec3
>
&
data
);
private:
private:
Vec3
base_pos
;
Vec3
base_pos
;
unsigned
int
root_id
,
next_id
;
unsigned
int
root_id
,
next_id
;
std
::
unordered_set
<
Joint
*>
roots
,
erased
;
std
::
unordered_set
<
Joint
*>
roots
,
erased
;
friend
class
Scene
;
friend
class
Scene
;
};
};
src/scene/undo.cpp
View file @
c2535f0f
#include "undo.h"
#include "undo.h"
#include "../gui/manager.h"
#include "../gui/animate.h"
#include "../gui/animate.h"
#include "../gui/manager.h"
#include "../gui/rig.h"
#include "../gui/rig.h"
Undo
::
Undo
(
Scene
&
sc
,
Gui
::
Manager
&
man
)
Undo
::
Undo
(
Scene
&
sc
,
Gui
::
Manager
&
man
)
:
scene
(
sc
),
gui
(
man
)
{}
:
scene
(
sc
),
gui
(
man
)
{}
void
Undo
::
reset
()
{
void
Undo
::
reset
()
{
undos
=
{};
undos
=
{};
redos
=
{};
redos
=
{};
}
}
template
<
typename
R
,
typename
U
>
template
<
typename
R
,
typename
U
>
class
Action
:
public
Action_Base
{
class
Action
:
public
Action_Base
{
public:
public:
Action
(
R
&&
r
,
U
&&
u
)
:
_undo
(
std
::
forward
<
decltype
(
u
)
>
(
u
)),
_redo
(
std
::
forward
<
decltype
(
r
)
>
(
r
))
{};
Action
(
R
&&
r
,
U
&&
u
)
:
_undo
(
std
::
forward
<
decltype
(
u
)
>
(
u
)),
_redo
(
std
::
forward
<
decltype
(
r
)
>
(
r
)){};
~
Action
()
{}
~
Action
()
{}
private:
private:
U
_undo
;
U
_undo
;
R
_redo
;
R
_redo
;
void
undo
()
{
_undo
();}
void
undo
()
{
_undo
();
}
void
redo
()
{
_redo
();}
void
redo
()
{
_redo
();
}
};
};
template
<
typename
R
,
typename
U
>
template
<
typename
R
,
typename
U
>
void
Undo
::
action
(
R
&&
redo
,
U
&&
undo
)
{
void
Undo
::
action
(
R
&&
redo
,
U
&&
undo
)
{
action
(
std
::
make_unique
<
Action
<
R
,
U
>>
(
std
::
move
(
redo
),
std
::
move
(
undo
)));
action
(
std
::
make_unique
<
Action
<
R
,
U
>>
(
std
::
move
(
redo
),
std
::
move
(
undo
)));
}
}
void
Undo
::
update_mesh_full
(
Scene_ID
id
,
Halfedge_Mesh
&&
old_mesh
)
{
void
Undo
::
update_mesh_full
(
Scene_ID
id
,
Halfedge_Mesh
&&
old_mesh
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Halfedge_Mesh
new_mesh
;
Halfedge_Mesh
new_mesh
;
obj
.
copy_mesh
(
new_mesh
);
obj
.
copy_mesh
(
new_mesh
);
action
([
id
,
this
,
nm
=
std
::
move
(
new_mesh
)]()
mutable
{
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
id
,
this
,
nm
=
std
::
move
(
new_mesh
)]()
mutable
{
obj
.
set_mesh
(
nm
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
[
id
,
this
,
om
=
std
::
move
(
old_mesh
)]()
mutable
{
obj
.
set_mesh
(
nm
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
set_mesh
(
om
);
[
id
,
this
,
om
=
std
::
move
(
old_mesh
)]()
mutable
{
});
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_mesh
(
om
);
});
}
}
void
Undo
::
move_root
(
Scene_ID
id
,
Vec3
old
)
{
void
Undo
::
move_root
(
Scene_ID
id
,
Vec3
old
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Vec3
np
=
obj
.
armature
.
base
();
Vec3
np
=
obj
.
armature
.
base
();
action
([
this
,
id
,
np
]()
{
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
this
,
id
,
np
]()
{
obj
.
armature
.
base
()
=
np
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_skel_dirty
();
obj
.
armature
.
base
()
=
np
;
},
[
this
,
id
,
op
=
old
](){
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
armature
.
base
()
=
op
;
[
this
,
id
,
op
=
old
]()
{
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
obj
.
armature
.
base
()
=
op
;
obj
.
set_skel_dirty
();
});
}
}
void
Undo
::
del_bone
(
Scene_ID
id
,
Joint
*
j
)
{
void
Undo
::
del_bone
(
Scene_ID
id
,
Joint
*
j
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
armature
.
erase
(
j
);
obj
.
armature
.
erase
(
j
);
obj
.
set_skel_dirty
();
obj
.
set_skel_dirty
();
action
([
this
,
id
,
j
]()
{
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
this
,
id
,
j
]()
{
obj
.
armature
.
erase
(
j
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
gui
.
get_rig
().
invalidate
(
j
);
obj
.
armature
.
erase
(
j
);
obj
.
set_skel_dirty
();
gui
.
get_rig
().
invalidate
(
j
);
},
[
this
,
id
,
j
](){
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
armature
.
restore
(
j
);
[
this
,
id
,
j
]()
{
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
obj
.
armature
.
restore
(
j
);
obj
.
set_skel_dirty
();
});
}
}
void
Undo
::
move_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
)
{
void
Undo
::
move_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
)
{
action
([
this
,
id
,
j
,
ne
=
j
->
extent
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
this
,
id
,
j
,
ne
=
j
->
extent
]()
{
j
->
extent
=
ne
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_skel_dirty
();
j
->
extent
=
ne
;
},
[
this
,
id
,
j
,
oe
=
old
](){
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
j
->
extent
=
oe
;
[
this
,
id
,
j
,
oe
=
old
]()
{
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
j
->
extent
=
oe
;
obj
.
set_skel_dirty
();
});
}
}
void
Undo
::
pose_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
)
{
void
Undo
::
pose_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
)
{
action
([
this
,
id
,
j
,
ne
=
j
->
pose
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
this
,
id
,
j
,
ne
=
j
->
pose
]()
{
j
->
pose
=
ne
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_pose_dirty
();
j
->
pose
=
ne
;
},
[
this
,
id
,
j
,
oe
=
old
](){
obj
.
set_pose_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
j
->
pose
=
oe
;
[
this
,
id
,
j
,
oe
=
old
]()
{
obj
.
set_pose_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
j
->
pose
=
oe
;
obj
.
set_pose_dirty
();
});
}
}
void
Undo
::
add_bone
(
Scene_ID
id
,
Joint
*
j
)
{
void
Undo
::
add_bone
(
Scene_ID
id
,
Joint
*
j
)
{
action
([
this
,
id
,
j
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
this
,
id
,
j
]()
{
obj
.
armature
.
restore
(
j
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_skel_dirty
();
obj
.
armature
.
restore
(
j
);
},
[
this
,
id
,
j
]()
{
obj
.
set_skel_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
armature
.
erase
(
j
);
[
this
,
id
,
j
]()
{
gui
.
get_rig
().
invalidate
(
j
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_skel_dirty
();
obj
.
armature
.
erase
(
j
);
});
gui
.
get_rig
().
invalidate
(
j
);
obj
.
set_skel_dirty
();
});
}
}
void
Undo
::
del_obj
(
Scene_ID
id
)
{
void
Undo
::
del_obj
(
Scene_ID
id
)
{
scene
.
erase
(
id
);
scene
.
erase
(
id
);
gui
.
invalidate_obj
(
id
);
gui
.
invalidate_obj
(
id
);
action
(
[
id
,
this
](){
action
(
scene
.
erase
(
id
);
[
id
,
this
]()
{
gui
.
invalidate_obj
(
id
);
scene
.
erase
(
id
);
},
[
id
,
this
](){
gui
.
invalidate_obj
(
id
);
scene
.
restore
(
id
);
},
});
[
id
,
this
]()
{
scene
.
restore
(
id
);
});
}
}
Scene_Object
&
Undo
::
add_obj
(
GL
::
Mesh
&&
mesh
,
std
::
string
name
)
{
Scene_Object
&
Undo
::
add_obj
(
GL
::
Mesh
&&
mesh
,
std
::
string
name
)
{
Scene_ID
id
=
scene
.
add
({},
std
::
move
(
mesh
),
name
);
Scene_ID
id
=
scene
.
add
({},
std
::
move
(
mesh
),
name
);
scene
.
restore
(
id
);
scene
.
restore
(
id
);
action
([
id
,
this
](){
action
([
id
,
this
]()
{
scene
.
restore
(
id
);
},
scene
.
restore
(
id
);
[
id
,
this
]()
{
},
[
id
,
this
](){
scene
.
erase
(
id
);
scene
.
erase
(
id
);
gui
.
invalidate_obj
(
id
);
gui
.
invalidate_obj
(
id
);
});
});
return
scene
.
get_obj
(
id
);
return
scene
.
get_obj
(
id
);
}
}
Scene_Object
&
Undo
::
add_obj
(
Halfedge_Mesh
&&
mesh
,
std
::
string
name
)
{
Scene_Object
&
Undo
::
add_obj
(
Halfedge_Mesh
&&
mesh
,
std
::
string
name
)
{
Scene_ID
id
=
scene
.
add
({},
std
::
move
(
mesh
),
name
);
Scene_ID
id
=
scene
.
add
({},
std
::
move
(
mesh
),
name
);
scene
.
restore
(
id
);
scene
.
restore
(
id
);
action
([
id
,
this
](){
action
([
id
,
this
]()
{
scene
.
restore
(
id
);
},
scene
.
restore
(
id
);
[
id
,
this
]()
{
},
[
id
,
this
](){
scene
.
erase
(
id
);
scene
.
erase
(
id
);
gui
.
invalidate_obj
(
id
);
gui
.
invalidate_obj
(
id
);
});
});
return
scene
.
get_obj
(
id
);
return
scene
.
get_obj
(
id
);
}
}
void
Undo
::
add_light
(
Scene_Light
&&
light
)
{
void
Undo
::
add_light
(
Scene_Light
&&
light
)
{
Scene_ID
id
=
scene
.
add
(
std
::
move
(
light
));
Scene_ID
id
=
scene
.
add
(
std
::
move
(
light
));
scene
.
restore
(
id
);
scene
.
restore
(
id
);
action
([
id
,
this
](){
action
([
id
,
this
]()
{
scene
.
restore
(
id
);
},
scene
.
restore
(
id
);
[
id
,
this
]()
{
},
[
id
,
this
](){
scene
.
erase
(
id
);
scene
.
erase
(
id
);
gui
.
invalidate_obj
(
id
);
gui
.
invalidate_obj
(
id
);
});
});
}
}
void
Undo
::
update_light
(
Scene_ID
id
,
Scene_Light
::
Options
old
)
{
void
Undo
::
update_light
(
Scene_ID
id
,
Scene_Light
::
Options
old
)
{
Scene_Light
&
light
=
scene
.
get_light
(
id
);
Scene_Light
&
light
=
scene
.
get_light
(
id
);
action
([
id
,
this
,
no
=
light
.
opt
](){
action
(
Scene_Light
&
light
=
scene
.
get_light
(
id
);
[
id
,
this
,
no
=
light
.
opt
]()
{
light
.
opt
=
no
;
Scene_Light
&
light
=
scene
.
get_light
(
id
);
light
.
dirty
();
light
.
opt
=
no
;
},
[
id
,
this
,
oo
=
old
](){
light
.
dirty
();
Scene_Light
&
light
=
scene
.
get_light
(
id
);
},
light
.
opt
=
oo
;
[
id
,
this
,
oo
=
old
]()
{
light
.
dirty
();
Scene_Light
&
light
=
scene
.
get_light
(
id
);
});
light
.
opt
=
oo
;
light
.
dirty
();
});
}
}
void
Undo
::
update_material
(
Scene_ID
id
,
Material
::
Options
old
)
{
void
Undo
::
update_material
(
Scene_ID
id
,
Material
::
Options
old
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
action
([
id
,
this
,
nm
=
obj
.
material
.
opt
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
id
,
this
,
nm
=
obj
.
material
.
opt
]()
{
obj
.
material
.
opt
=
nm
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
[
id
,
this
,
om
=
old
](){
obj
.
material
.
opt
=
nm
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
material
.
opt
=
om
;
[
id
,
this
,
om
=
old
]()
{
});
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
material
.
opt
=
om
;
});
}
}
void
Undo
::
update_object
(
Scene_ID
id
,
Scene_Object
::
Options
old
)
{
void
Undo
::
update_object
(
Scene_ID
id
,
Scene_Object
::
Options
old
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
&&
old
.
shape_type
==
PT
::
Shape_Type
::
none
)
{
if
(
obj
.
opt
.
shape_type
!=
PT
::
Shape_Type
::
none
&&
old
.
shape_type
==
PT
::
Shape_Type
::
none
)
{
Halfedge_Mesh
old_mesh
;
Halfedge_Mesh
old_mesh
;
obj
.
copy_mesh
(
old_mesh
);
obj
.
copy_mesh
(
old_mesh
);
action
([
id
,
this
,
no
=
obj
.
opt
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
id
,
this
,
no
=
obj
.
opt
]()
{
obj
.
opt
=
no
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_mesh_dirty
();
obj
.
opt
=
no
;
},
[
id
,
this
,
oo
=
old
,
om
=
std
::
move
(
old_mesh
)]()
mutable
{
obj
.
set_mesh_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
opt
=
oo
;
[
id
,
this
,
oo
=
old
,
om
=
std
::
move
(
old_mesh
)]()
mutable
{
obj
.
set_mesh
(
om
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
obj
.
opt
=
oo
;
obj
.
set_mesh
(
om
);
});
return
;
return
;
}
}
if
(
obj
.
opt
.
shape_type
==
PT
::
Shape_Type
::
none
&&
if
(
obj
.
opt
.
shape_type
==
PT
::
Shape_Type
::
none
&&
old
.
shape_type
!=
PT
::
Shape_Type
::
none
)
{
old
.
shape_type
!=
PT
::
Shape_Type
::
none
)
{
action
([
id
,
this
,
no
=
obj
.
opt
,
ot
=
old
.
shape_type
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
id
,
this
,
no
=
obj
.
opt
,
ot
=
old
.
shape_type
]()
{
obj
.
opt
=
no
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
try_make_editable
(
ot
);
obj
.
opt
=
no
;
},
[
id
,
this
,
oo
=
old
]()
{
obj
.
try_make_editable
(
ot
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
opt
=
oo
;
[
id
,
this
,
oo
=
old
]()
{
obj
.
set_mesh_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
obj
.
opt
=
oo
;
obj
.
set_mesh_dirty
();
});
return
;
return
;
}
}
action
([
id
,
this
,
no
=
obj
.
opt
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
id
,
this
,
no
=
obj
.
opt
]()
{
obj
.
opt
=
no
;
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_mesh_dirty
();
obj
.
opt
=
no
;
},
[
id
,
this
,
oo
=
old
](){
obj
.
set_mesh_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
obj
.
opt
=
oo
;
[
id
,
this
,
oo
=
old
]()
{
obj
.
set_mesh_dirty
();
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
});
obj
.
opt
=
oo
;
obj
.
set_mesh_dirty
();
});
}
}
void
Undo
::
update_pose
(
Scene_ID
id
,
Pose
old
)
{
void
Undo
::
update_pose
(
Scene_ID
id
,
Pose
old
)
{
Scene_Item
&
item
=
*
scene
.
get
(
id
);
Scene_Item
&
item
=
*
scene
.
get
(
id
);
action
([
id
,
this
,
np
=
item
.
pose
()](){
action
(
Scene_Item
&
item
=
*
scene
.
get
(
id
);
[
id
,
this
,
np
=
item
.
pose
()]()
{
item
.
pose
()
=
np
;
Scene_Item
&
item
=
*
scene
.
get
(
id
);
},
[
id
,
this
,
op
=
old
](){
item
.
pose
()
=
np
;
Scene_Item
&
item
=
*
scene
.
get
(
id
);
},
item
.
pose
()
=
op
;
[
id
,
this
,
op
=
old
]()
{
});
Scene_Item
&
item
=
*
scene
.
get
(
id
);
item
.
pose
()
=
op
;
});
}
}
void
Undo
::
update_camera
(
Gui
::
Widget_Camera
&
widget
,
Camera
old
)
{
void
Undo
::
update_camera
(
Gui
::
Widget_Camera
&
widget
,
Camera
old
)
{
Camera
newc
=
widget
.
get
();
Camera
newc
=
widget
.
get
();
action
([
&
widget
,
nc
=
newc
](){
action
(
widget
.
load
(
nc
.
center
(),
nc
.
pos
(),
nc
.
get_ar
(),
nc
.
get_fov
());
[
&
widget
,
nc
=
newc
]()
{
widget
.
load
(
nc
.
center
(),
nc
.
pos
(),
nc
.
get_ar
(),
nc
.
get_fov
());
},
},
[
&
widget
,
oc
=
old
](){
[
&
widget
,
oc
=
old
]()
{
widget
.
load
(
oc
.
center
(),
oc
.
pos
(),
oc
.
get_ar
(),
oc
.
get_fov
());
});
widget
.
load
(
oc
.
center
(),
oc
.
pos
(),
oc
.
get_ar
(),
oc
.
get_fov
());
});
}
}
void
Undo
::
anim_pose_bones
(
Scene_ID
id
,
float
t
)
{
void
Undo
::
anim_pose_bones
(
Scene_ID
id
,
float
t
)
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
bool
had
=
obj
.
anim
.
splines
.
has
(
t
)
||
obj
.
armature
.
has_keyframes
();
bool
had
=
obj
.
anim
.
splines
.
has
(
t
)
||
obj
.
armature
.
has_keyframes
();
Pose
old_pose
=
obj
.
anim
.
at
(
t
);
Pose
old_pose
=
obj
.
anim
.
at
(
t
);
Pose
new_pose
=
obj
.
pose
;
Pose
new_pose
=
obj
.
pose
;
auto
old_joints
=
obj
.
armature
.
at
(
t
);
auto
old_joints
=
obj
.
armature
.
at
(
t
);
...
@@ -278,45 +293,51 @@ void Undo::anim_pose_bones(Scene_ID id, float t) {
...
@@ -278,45 +293,51 @@ void Undo::anim_pose_bones(Scene_ID id, float t) {
obj
.
anim
.
set
(
t
,
new_pose
);
obj
.
anim
.
set
(
t
,
new_pose
);
obj
.
armature
.
set
(
t
);
obj
.
armature
.
set
(
t
);
action
([
=
](){
action
(
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
[
=
]()
{
obj
.
anim
.
set
(
t
,
new_pose
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
armature
.
set
(
t
,
new_joints
);
obj
.
anim
.
set
(
t
,
new_pose
);
gui
.
get_animate
().
refresh
(
scene
);
obj
.
armature
.
set
(
t
,
new_joints
);
},
[
=
](){
gui
.
get_animate
().
refresh
(
scene
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
},
if
(
had
)
{
[
=
]()
{
obj
.
anim
.
set
(
t
,
old_pose
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
armature
.
set
(
t
,
old_joints
);
if
(
had
)
{
}
else
{
obj
.
anim
.
set
(
t
,
old_pose
);
obj
.
anim
.
splines
.
erase
(
t
);
obj
.
armature
.
set
(
t
,
old_joints
);
obj
.
armature
.
erase
(
t
);
}
else
{
}
obj
.
anim
.
splines
.
erase
(
t
);
});
obj
.
armature
.
erase
(
t
);
}
});
}
}
void
Undo
::
anim_pose
(
Scene_ID
id
,
float
t
)
{
void
Undo
::
anim_pose
(
Scene_ID
id
,
float
t
)
{
Scene_Item
&
item
=
*
scene
.
get
(
id
);
Scene_Item
&
item
=
*
scene
.
get
(
id
);
bool
had
=
item
.
animation
().
splines
.
has
(
t
);
bool
had
=
item
.
animation
().
splines
.
has
(
t
);
Pose
old
=
item
.
animation
().
at
(
t
);
Pose
old
=
item
.
animation
().
at
(
t
);
Pose
p
=
item
.
pose
();
Pose
p
=
item
.
pose
();
item
.
animation
().
set
(
t
,
p
);
item
.
animation
().
set
(
t
,
p
);
action
([
=
](){
action
(
Scene_Item
&
item
=
*
scene
.
get
(
id
);
[
=
]()
{
item
.
animation
().
set
(
t
,
p
);
Scene_Item
&
item
=
*
scene
.
get
(
id
);
gui
.
get_animate
().
refresh
(
scene
);
item
.
animation
().
set
(
t
,
p
);
},
[
=
](){
gui
.
get_animate
().
refresh
(
scene
);
Scene_Item
&
item
=
*
scene
.
get
(
id
);
},
if
(
had
)
item
.
animation
().
set
(
t
,
old
);
[
=
]()
{
else
item
.
animation
().
splines
.
erase
(
t
);
Scene_Item
&
item
=
*
scene
.
get
(
id
);
});
if
(
had
)
item
.
animation
().
set
(
t
,
old
);
else
item
.
animation
().
splines
.
erase
(
t
);
});
}
}
void
Undo
::
anim_camera
(
Gui
::
Anim_Camera
&
anim
,
float
t
,
const
Camera
&
cam
)
{
void
Undo
::
anim_camera
(
Gui
::
Anim_Camera
&
anim
,
float
t
,
const
Camera
&
cam
)
{
bool
had
=
anim
.
splines
.
has
(
t
);
bool
had
=
anim
.
splines
.
has
(
t
);
Camera
oldc
=
anim
.
at
(
t
);
Camera
oldc
=
anim
.
at
(
t
);
...
@@ -324,22 +345,26 @@ void Undo::anim_camera(Gui::Anim_Camera& anim, float t, const Camera& cam) {
...
@@ -324,22 +345,26 @@ void Undo::anim_camera(Gui::Anim_Camera& anim, float t, const Camera& cam) {
anim
.
set
(
t
,
newc
);
anim
.
set
(
t
,
newc
);
action
([
=
,
&
anim
](){
action
(
anim
.
set
(
t
,
newc
);
[
=
,
&
anim
]()
{
gui
.
get_animate
().
refresh
(
scene
);
anim
.
set
(
t
,
newc
);
},
[
=
,
&
anim
](){
gui
.
get_animate
().
refresh
(
scene
);
if
(
had
)
anim
.
set
(
t
,
oldc
);
},
else
anim
.
splines
.
erase
(
t
);
[
=
,
&
anim
]()
{
});
if
(
had
)
anim
.
set
(
t
,
oldc
);
else
anim
.
splines
.
erase
(
t
);
});
}
}
void
Undo
::
anim_light
(
Scene_ID
id
,
float
t
)
{
void
Undo
::
anim_light
(
Scene_ID
id
,
float
t
)
{
Scene_Light
&
item
=
scene
.
get_light
(
id
);
Scene_Light
&
item
=
scene
.
get_light
(
id
);
bool
had_l
=
item
.
lanim
.
splines
.
has
(
t
);
bool
had_l
=
item
.
lanim
.
splines
.
has
(
t
);
bool
had_p
=
item
.
anim
.
splines
.
has
(
t
);
bool
had_p
=
item
.
anim
.
splines
.
has
(
t
);
Pose
old_pose
=
item
.
anim
.
at
(
t
);
Pose
old_pose
=
item
.
anim
.
at
(
t
);
Pose
new_pose
=
item
.
pose
;
Pose
new_pose
=
item
.
pose
;
...
@@ -350,35 +375,43 @@ void Undo::anim_light(Scene_ID id, float t) {
...
@@ -350,35 +375,43 @@ void Undo::anim_light(Scene_ID id, float t) {
item
.
anim
.
set
(
t
,
new_pose
);
item
.
anim
.
set
(
t
,
new_pose
);
item
.
lanim
.
set
(
t
,
new_l
);
item
.
lanim
.
set
(
t
,
new_l
);
action
([
=
](){
action
(
Scene_Light
&
item
=
scene
.
get_light
(
id
);
[
=
]()
{
item
.
lanim
.
set
(
t
,
new_l
);
Scene_Light
&
item
=
scene
.
get_light
(
id
);
item
.
anim
.
set
(
t
,
new_pose
);
item
.
lanim
.
set
(
t
,
new_l
);
gui
.
get_animate
().
refresh
(
scene
);
item
.
anim
.
set
(
t
,
new_pose
);
},
[
=
](){
gui
.
get_animate
().
refresh
(
scene
);
Scene_Light
&
item
=
scene
.
get_light
(
id
);
},
if
(
had_l
)
item
.
lanim
.
set
(
t
,
old_l
);
[
=
]()
{
else
item
.
lanim
.
splines
.
erase
(
t
);
Scene_Light
&
item
=
scene
.
get_light
(
id
);
if
(
had_p
)
item
.
anim
.
set
(
t
,
old_pose
);
if
(
had_l
)
else
item
.
anim
.
splines
.
erase
(
t
);
item
.
lanim
.
set
(
t
,
old_l
);
item
.
dirty
();
else
});
item
.
lanim
.
splines
.
erase
(
t
);
if
(
had_p
)
item
.
anim
.
set
(
t
,
old_pose
);
else
item
.
anim
.
splines
.
erase
(
t
);
item
.
dirty
();
});
}
}
void
Undo
::
action
(
std
::
unique_ptr
<
Action_Base
>&&
action
)
{
void
Undo
::
action
(
std
::
unique_ptr
<
Action_Base
>
&&
action
)
{
redos
=
{};
redos
=
{};
undos
.
push
(
std
::
move
(
action
));
undos
.
push
(
std
::
move
(
action
));
}
}
void
Undo
::
undo
()
{
void
Undo
::
undo
()
{
if
(
undos
.
empty
())
return
;
if
(
undos
.
empty
())
return
;
undos
.
top
()
->
undo
();
undos
.
top
()
->
undo
();
redos
.
push
(
std
::
move
(
undos
.
top
()));
redos
.
push
(
std
::
move
(
undos
.
top
()));
undos
.
pop
();
undos
.
pop
();
}
}
void
Undo
::
redo
()
{
void
Undo
::
redo
()
{
if
(
redos
.
empty
())
return
;
if
(
redos
.
empty
())
return
;
redos
.
top
()
->
redo
();
redos
.
top
()
->
redo
();
undos
.
push
(
std
::
move
(
redos
.
top
()));
undos
.
push
(
std
::
move
(
redos
.
top
()));
redos
.
pop
();
redos
.
pop
();
...
...
src/scene/undo.h
View file @
c2535f0f
...
@@ -4,76 +4,80 @@
...
@@ -4,76 +4,80 @@
#include <memory>
#include <memory>
#include <stack>
#include <stack>
#include "scene.h"
#include "../gui/widgets.h"
#include "../gui/widgets.h"
#include "scene.h"
namespace
Gui
{
class
Manager
;
class
Anim_Camera
;
class
Rig
;
}
namespace
Gui
{
class
Manager
;
class
Anim_Camera
;
class
Rig
;
}
// namespace Gui
class
Action_Base
{
class
Action_Base
{
virtual
void
undo
()
=
0
;
virtual
void
undo
()
=
0
;
virtual
void
redo
()
=
0
;
virtual
void
redo
()
=
0
;
friend
class
Undo
;
friend
class
Undo
;
public:
public:
virtual
~
Action_Base
()
=
default
;
virtual
~
Action_Base
()
=
default
;
};
};
template
<
typename
T
>
template
<
typename
T
>
class
MeshOp
:
public
Action_Base
{
class
MeshOp
:
public
Action_Base
{
void
undo
()
{
void
undo
()
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
obj
.
set_mesh
(
mesh
);
obj
.
set_mesh
(
mesh
);
}
}
void
redo
()
{
void
redo
()
{
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
Scene_Object
&
obj
=
scene
.
get_obj
(
id
);
auto
sel
=
obj
.
set_mesh
(
mesh
,
eid
);
auto
sel
=
obj
.
set_mesh
(
mesh
,
eid
);
op
(
obj
.
get_mesh
(),
sel
);
op
(
obj
.
get_mesh
(),
sel
);
}
}
Scene
&
scene
;
Scene
&
scene
;
Scene_ID
id
;
Scene_ID
id
;
unsigned
int
eid
;
unsigned
int
eid
;
T
op
;
T
op
;
Halfedge_Mesh
mesh
;
Halfedge_Mesh
mesh
;
public:
public:
MeshOp
(
Scene
&
s
,
Scene_ID
i
,
unsigned
int
e
,
Halfedge_Mesh
&&
m
,
T
&&
t
)
:
MeshOp
(
Scene
&
s
,
Scene_ID
i
,
unsigned
int
e
,
Halfedge_Mesh
&&
m
,
T
&&
t
)
scene
(
s
),
id
(
i
),
eid
(
e
),
op
(
t
),
mesh
(
std
::
move
(
m
))
{}
:
scene
(
s
),
id
(
i
),
eid
(
e
),
op
(
t
),
mesh
(
std
::
move
(
m
))
{}
~
MeshOp
()
=
default
;
~
MeshOp
()
=
default
;
};
};
class
Undo
{
class
Undo
{
public:
public:
Undo
(
Scene
&
scene
,
Gui
::
Manager
&
man
);
Undo
(
Scene
&
scene
,
Gui
::
Manager
&
man
);
// These could just take Scene_Object&& but this was easier
// These could just take Scene_Object&& but this was easier
Scene_Object
&
add_obj
(
GL
::
Mesh
&&
mesh
,
std
::
string
name
);
Scene_Object
&
add_obj
(
GL
::
Mesh
&&
mesh
,
std
::
string
name
);
Scene_Object
&
add_obj
(
Halfedge_Mesh
&&
mesh
,
std
::
string
name
);
Scene_Object
&
add_obj
(
Halfedge_Mesh
&&
mesh
,
std
::
string
name
);
void
add_light
(
Scene_Light
&&
mesh
);
void
add_light
(
Scene_Light
&&
mesh
);
void
del_obj
(
Scene_ID
id
);
void
del_obj
(
Scene_ID
id
);
void
update_pose
(
Scene_ID
id
,
Pose
old
);
void
update_pose
(
Scene_ID
id
,
Pose
old
);
void
del_bone
(
Scene_ID
id
,
Joint
*
j
);
void
del_bone
(
Scene_ID
id
,
Joint
*
j
);
void
add_bone
(
Scene_ID
id
,
Joint
*
j
);
void
add_bone
(
Scene_ID
id
,
Joint
*
j
);
void
move_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
);
void
move_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
);
void
pose_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
);
void
pose_bone
(
Scene_ID
id
,
Joint
*
j
,
Vec3
old
);
void
move_root
(
Scene_ID
id
,
Vec3
old
);
void
move_root
(
Scene_ID
id
,
Vec3
old
);
void
update_light
(
Scene_ID
id
,
Scene_Light
::
Options
old
);
void
update_light
(
Scene_ID
id
,
Scene_Light
::
Options
old
);
void
update_object
(
Scene_ID
id
,
Scene_Object
::
Options
old
);
void
update_object
(
Scene_ID
id
,
Scene_Object
::
Options
old
);
void
update_material
(
Scene_ID
id
,
Material
::
Options
old
);
void
update_material
(
Scene_ID
id
,
Material
::
Options
old
);
void
update_camera
(
Gui
::
Widget_Camera
&
widget
,
Camera
old
);
void
update_camera
(
Gui
::
Widget_Camera
&
widget
,
Camera
old
);
template
<
typename
T
>
template
<
typename
T
>
void
update_mesh
(
Scene_ID
id
,
Halfedge_Mesh
&&
old
,
unsigned
int
e_id
,
T
&&
op
)
{
void
update_mesh
(
Scene_ID
id
,
Halfedge_Mesh
&&
old
,
unsigned
int
e_id
,
T
&&
op
)
{
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
empty
;
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
empty
;
redos
.
swap
(
empty
);
redos
.
swap
(
empty
);
undos
.
push
(
std
::
make_unique
<
MeshOp
<
T
>>
(
scene
,
id
,
e_id
,
std
::
move
(
old
),
std
::
move
(
op
)));
undos
.
push
(
std
::
make_unique
<
MeshOp
<
T
>>
(
scene
,
id
,
e_id
,
std
::
move
(
old
),
std
::
move
(
op
)));
}
}
void
update_mesh_full
(
Scene_ID
id
,
Halfedge_Mesh
&&
old_mesh
);
void
update_mesh_full
(
Scene_ID
id
,
Halfedge_Mesh
&&
old_mesh
);
void
anim_pose
(
Scene_ID
id
,
float
t
);
void
anim_pose
(
Scene_ID
id
,
float
t
);
void
anim_pose_bones
(
Scene_ID
id
,
float
t
);
void
anim_pose_bones
(
Scene_ID
id
,
float
t
);
void
anim_camera
(
Gui
::
Anim_Camera
&
anim
,
float
t
,
const
Camera
&
cam
);
void
anim_camera
(
Gui
::
Anim_Camera
&
anim
,
float
t
,
const
Camera
&
cam
);
void
anim_light
(
Scene_ID
id
,
float
t
);
void
anim_light
(
Scene_ID
id
,
float
t
);
void
undo
();
void
undo
();
...
@@ -81,13 +85,12 @@ public:
...
@@ -81,13 +85,12 @@ public:
void
reset
();
void
reset
();
private:
private:
Scene
&
scene
;
Scene
&
scene
;
Gui
::
Manager
&
gui
;
Gui
::
Manager
&
gui
;
template
<
typename
R
,
typename
U
>
void
action
(
R
&&
redo
,
U
&&
undo
);
void
action
(
std
::
unique_ptr
<
Action_Base
>
&&
action
);
template
<
typename
R
,
typename
U
>
void
action
(
R
&&
redo
,
U
&&
undo
);
void
action
(
std
::
unique_ptr
<
Action_Base
>&&
action
);
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
undos
;
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
undos
;
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
redos
;
std
::
stack
<
std
::
unique_ptr
<
Action_Base
>>
redos
;
};
};
src/student/bbox.cpp
View file @
c2535f0f
#include "debug.h"
#include "../lib/mathlib.h"
#include "../lib/mathlib.h"
#include "debug.h"
bool
BBox
::
hit
(
const
Ray
&
ray
,
Vec2
&
times
)
const
{
bool
BBox
::
hit
(
const
Ray
&
ray
,
Vec2
&
times
)
const
{
// TODO (PathTracer):
// TODO (PathTracer):
// Implement ray - bounding box intersection test
// Implement ray - bounding box intersection test
// If the ray intersected the bounding box within the range given by
// If the ray intersected the bounding box within the range given by
...
...
src/student/bsdf.cpp
View file @
c2535f0f
#include "debug.h"
#include "../rays/bsdf.h"
#include "../rays/bsdf.h"
#include "../util/rand.h"
#include "../util/rand.h"
#include "debug.h"
namespace
PT
{
namespace
PT
{
...
@@ -12,14 +12,14 @@ Vec3 reflect(Vec3 dir) {
...
@@ -12,14 +12,14 @@ Vec3 reflect(Vec3 dir) {
return
Vec3
();
return
Vec3
();
}
}
Vec3
refract
(
Vec3
out_dir
,
float
index_of_refraction
,
bool
&
was_internal
)
{
Vec3
refract
(
Vec3
out_dir
,
float
index_of_refraction
,
bool
&
was_internal
)
{
// TODO (PathTracer): Task 6
// TODO (PathTracer): Task 6
// Use Snell's Law to refract out_dir through the surface
// Use Snell's Law to refract out_dir through the surface
// Return the refracted direction. Set was_internal to false if
// Return the refracted direction. Set was_internal to false if
// refraction does not occur due to total internal reflection,
// refraction does not occur due to total internal reflection,
// and true otherwise.
// and true otherwise.
// When dot(out_dir,normal=(0,1,0)) is positive, then out_dir corresponds to a
// When dot(out_dir,normal=(0,1,0)) is positive, then out_dir corresponds to a
// ray exiting the surface into vaccum (ior = 1). However, note that
// ray exiting the surface into vaccum (ior = 1). However, note that
// you should actually treat this case as _entering_ the surface, because
// you should actually treat this case as _entering_ the surface, because
...
@@ -30,14 +30,14 @@ Vec3 refract(Vec3 out_dir, float index_of_refraction, bool& was_internal) {
...
@@ -30,14 +30,14 @@ Vec3 refract(Vec3 out_dir, float index_of_refraction, bool& was_internal) {
}
}
BSDF_Sample
BSDF_Lambertian
::
sample
(
Vec3
out_dir
)
const
{
BSDF_Sample
BSDF_Lambertian
::
sample
(
Vec3
out_dir
)
const
{
// TODO (PathTracer): Task 5
// TODO (PathTracer): Task 5
// Implement lambertian BSDF. Use of BSDF_Lambertian::sampler may be useful
// Implement lambertian BSDF. Use of BSDF_Lambertian::sampler may be useful
BSDF_Sample
ret
;
BSDF_Sample
ret
;
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction?
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction?
return
ret
;
return
ret
;
}
}
...
@@ -46,13 +46,13 @@ Spectrum BSDF_Lambertian::evaluate(Vec3 out_dir, Vec3 in_dir) const {
...
@@ -46,13 +46,13 @@ Spectrum BSDF_Lambertian::evaluate(Vec3 out_dir, Vec3 in_dir) const {
}
}
BSDF_Sample
BSDF_Mirror
::
sample
(
Vec3
out_dir
)
const
{
BSDF_Sample
BSDF_Mirror
::
sample
(
Vec3
out_dir
)
const
{
// TODO (PathTracer): Task 6
// TODO (PathTracer): Task 6
// Implement mirror BSDF
// Implement mirror BSDF
BSDF_Sample
ret
;
BSDF_Sample
ret
;
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
return
ret
;
return
ret
;
}
}
...
@@ -60,16 +60,16 @@ BSDF_Sample BSDF_Mirror::sample(Vec3 out_dir) const {
...
@@ -60,16 +60,16 @@ BSDF_Sample BSDF_Mirror::sample(Vec3 out_dir) const {
Spectrum
BSDF_Mirror
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
Spectrum
BSDF_Mirror
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
// Technically, we would return the proper reflectance
// Technically, we would return the proper reflectance
// if in_dir was the perfectly reflected out_dir, but given
// if in_dir was the perfectly reflected out_dir, but given
// that we assume these are single exact directions in a
// that we assume these are single exact directions in a
// continuous space, just assume that we never hit them
// continuous space, just assume that we never hit them
// _exactly_ and always return 0.
// _exactly_ and always return 0.
return
{};
return
{};
}
}
BSDF_Sample
BSDF_Glass
::
sample
(
Vec3
out_dir
)
const
{
BSDF_Sample
BSDF_Glass
::
sample
(
Vec3
out_dir
)
const
{
// TODO (PathTracer): Task 6
// TODO (PathTracer): Task 6
// Implement glass BSDF.
// Implement glass BSDF.
// (1) Compute Fresnel coefficient. Tip: use Schlick's approximation.
// (1) Compute Fresnel coefficient. Tip: use Schlick's approximation.
// (2) Reflect or refract probabilistically based on Fresnel coefficient. Tip: RNG::coin_flip
// (2) Reflect or refract probabilistically based on Fresnel coefficient. Tip: RNG::coin_flip
...
@@ -79,14 +79,14 @@ BSDF_Sample BSDF_Glass::sample(Vec3 out_dir) const {
...
@@ -79,14 +79,14 @@ BSDF_Sample BSDF_Glass::sample(Vec3 out_dir) const {
BSDF_Sample
ret
;
BSDF_Sample
ret
;
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
return
ret
;
return
ret
;
}
}
Spectrum
BSDF_Glass
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
Spectrum
BSDF_Glass
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
// As with BSDF_Mirror, just assume that we never hit the correct
// As with BSDF_Mirror, just assume that we never hit the correct
// directions _exactly_ and always return 0.
// directions _exactly_ and always return 0.
return
{};
return
{};
}
}
...
@@ -104,23 +104,23 @@ Spectrum BSDF_Diffuse::evaluate(Vec3 out_dir, Vec3 in_dir) const {
...
@@ -104,23 +104,23 @@ Spectrum BSDF_Diffuse::evaluate(Vec3 out_dir, Vec3 in_dir) const {
}
}
BSDF_Sample
BSDF_Refract
::
sample
(
Vec3
out_dir
)
const
{
BSDF_Sample
BSDF_Refract
::
sample
(
Vec3
out_dir
)
const
{
// TODO (PathTracer): Task 6
// TODO (PathTracer): Task 6
// Implement pure refraction BSDF.
// Implement pure refraction BSDF.
// Be wary of your eta1/eta2 ratio - are you entering or leaving the surface?
// Be wary of your eta1/eta2 ratio - are you entering or leaving the surface?
BSDF_Sample
ret
;
BSDF_Sample
ret
;
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
attenuation
=
Spectrum
();
// What is the ratio of reflected/incoming light?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
direction
=
Vec3
();
// What direction should we sample incoming light from?
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
ret
.
pdf
=
0.0
f
;
// Was was the PDF of the sampled direction? (In this case, the PMF)
return
ret
;
return
ret
;
}
}
Spectrum
BSDF_Refract
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
Spectrum
BSDF_Refract
::
evaluate
(
Vec3
out_dir
,
Vec3
in_dir
)
const
{
// As with BSDF_Mirror, just assume that we never hit the correct
// As with BSDF_Mirror, just assume that we never hit the correct
// directions _exactly_ and always return 0.
// directions _exactly_ and always return 0.
return
{};
return
{};
}
}
}
}
// namespace PT
src/student/bvh.cpp
View file @
c2535f0f
#include "debug.h"
#include "../rays/bvh.h"
#include "../rays/bvh.h"
#include "debug.h"
#include <stack>
#include <stack>
namespace
PT
{
namespace
PT
{
template
<
typename
Primitive
>
template
<
typename
Primitive
>
void
BVH
<
Primitive
>::
build
(
std
::
vector
<
Primitive
>&&
prims
,
size_t
max_leaf_size
)
{
void
BVH
<
Primitive
>::
build
(
std
::
vector
<
Primitive
>
&&
prims
,
size_t
max_leaf_size
)
{
// NOTE (PathTracer):
// NOTE (PathTracer):
// This BVH is parameterized on the type of the primitive it contains. This allows
// This BVH is parameterized on the type of the primitive it contains. This allows
...
@@ -37,12 +37,12 @@ void BVH<Primitive>::build(std::vector<Primitive>&& prims, size_t max_leaf_size)
...
@@ -37,12 +37,12 @@ void BVH<Primitive>::build(std::vector<Primitive>&& prims, size_t max_leaf_size)
// primitives.
// primitives.
BBox
box
;
BBox
box
;
for
(
const
Primitive
&
prim
:
primitives
)
box
.
enclose
(
prim
.
bbox
());
for
(
const
Primitive
&
prim
:
primitives
)
box
.
enclose
(
prim
.
bbox
());
new_node
(
box
,
0
,
primitives
.
size
(),
0
,
0
);
new_node
(
box
,
0
,
primitives
.
size
(),
0
,
0
);
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
Trace
BVH
<
Primitive
>::
hit
(
const
Ray
&
ray
)
const
{
Trace
BVH
<
Primitive
>::
hit
(
const
Ray
&
ray
)
const
{
// TODO (PathTracer): Task 3
// TODO (PathTracer): Task 3
// Implement ray - BVH intersection test. A ray intersects
// Implement ray - BVH intersection test. A ray intersects
...
@@ -53,24 +53,23 @@ Trace BVH<Primitive>::hit(const Ray& ray) const {
...
@@ -53,24 +53,23 @@ Trace BVH<Primitive>::hit(const Ray& ray) const {
// Again, remember you can use hit() on any Primitive value.
// Again, remember you can use hit() on any Primitive value.
Trace
ret
;
Trace
ret
;
for
(
const
Primitive
&
prim
:
primitives
)
{
for
(
const
Primitive
&
prim
:
primitives
)
{
Trace
hit
=
prim
.
hit
(
ray
);
Trace
hit
=
prim
.
hit
(
ray
);
ret
=
Trace
::
min
(
ret
,
hit
);
ret
=
Trace
::
min
(
ret
,
hit
);
}
}
return
ret
;
return
ret
;
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
BVH
<
Primitive
>::
BVH
(
std
::
vector
<
Primitive
>&&
prims
,
size_t
max_leaf_size
)
{
BVH
<
Primitive
>::
BVH
(
std
::
vector
<
Primitive
>
&&
prims
,
size_t
max_leaf_size
)
{
build
(
std
::
move
(
prims
),
max_leaf_size
);
build
(
std
::
move
(
prims
),
max_leaf_size
);
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
bool
BVH
<
Primitive
>::
Node
::
is_leaf
()
const
{
bool
BVH
<
Primitive
>::
Node
::
is_leaf
()
const
{
return
l
==
0
&&
r
==
0
;
return
l
==
0
&&
r
==
0
;
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
size_t
BVH
<
Primitive
>::
new_node
(
BBox
box
,
size_t
start
,
size_t
size
,
size_t
l
,
size_t
r
)
{
size_t
BVH
<
Primitive
>::
new_node
(
BBox
box
,
size_t
start
,
size_t
size
,
size_t
l
,
size_t
r
)
{
Node
n
;
Node
n
;
n
.
bbox
=
box
;
n
.
bbox
=
box
;
...
@@ -82,49 +81,44 @@ size_t BVH<Primitive>::new_node(BBox box, size_t start, size_t size, size_t l, s
...
@@ -82,49 +81,44 @@ size_t BVH<Primitive>::new_node(BBox box, size_t start, size_t size, size_t l, s
return
nodes
.
size
()
-
1
;
return
nodes
.
size
()
-
1
;
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
BBox
BVH
<
Primitive
>::
bbox
()
const
{
return
nodes
[
0
].
bbox
;
}
BBox
BVH
<
Primitive
>::
bbox
()
const
{
return
nodes
[
0
].
bbox
;
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
std
::
vector
<
Primitive
>
BVH
<
Primitive
>::
destructure
()
{
std
::
vector
<
Primitive
>
BVH
<
Primitive
>::
destructure
()
{
nodes
.
clear
();
nodes
.
clear
();
return
std
::
move
(
primitives
);
return
std
::
move
(
primitives
);
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
void
BVH
<
Primitive
>::
clear
()
{
void
BVH
<
Primitive
>::
clear
()
{
nodes
.
clear
();
nodes
.
clear
();
primitives
.
clear
();
primitives
.
clear
();
}
}
template
<
typename
Primitive
>
template
<
typename
Primitive
>
size_t
BVH
<
Primitive
>::
visualize
(
GL
::
Lines
&
lines
,
GL
::
Lines
&
active
,
size_t
level
,
const
Mat4
&
trans
)
const
{
size_t
BVH
<
Primitive
>::
visualize
(
GL
::
Lines
&
lines
,
GL
::
Lines
&
active
,
size_t
level
,
const
Mat4
&
trans
)
const
{
std
::
stack
<
std
::
pair
<
size_t
,
size_t
>>
tstack
;
std
::
stack
<
std
::
pair
<
size_t
,
size_t
>>
tstack
;
tstack
.
push
({
0
,
0
});
tstack
.
push
({
0
,
0
});
size_t
max_level
=
0
;
size_t
max_level
=
0
;
if
(
nodes
.
empty
())
return
max_level
;
if
(
nodes
.
empty
())
return
max_level
;
while
(
!
tstack
.
empty
())
{
while
(
!
tstack
.
empty
())
{
auto
[
idx
,
lvl
]
=
tstack
.
top
();
auto
[
idx
,
lvl
]
=
tstack
.
top
();
max_level
=
std
::
max
(
max_level
,
lvl
);
max_level
=
std
::
max
(
max_level
,
lvl
);
const
Node
&
node
=
nodes
[
idx
];
const
Node
&
node
=
nodes
[
idx
];
tstack
.
pop
();
tstack
.
pop
();
Vec3
color
=
lvl
==
level
?
Vec3
(
1.0
f
,
0.0
f
,
0.0
f
)
:
Vec3
(
1.0
f
);
Vec3
color
=
lvl
==
level
?
Vec3
(
1.0
f
,
0.0
f
,
0.0
f
)
:
Vec3
(
1.0
f
);
GL
::
Lines
&
add
=
lvl
==
level
?
active
:
lines
;
GL
::
Lines
&
add
=
lvl
==
level
?
active
:
lines
;
BBox
box
=
node
.
bbox
;
BBox
box
=
node
.
bbox
;
box
.
transform
(
trans
);
box
.
transform
(
trans
);
Vec3
min
=
box
.
min
,
max
=
box
.
max
;
Vec3
min
=
box
.
min
,
max
=
box
.
max
;
auto
edge
=
[
&
](
Vec3
a
,
Vec3
b
)
{
auto
edge
=
[
&
](
Vec3
a
,
Vec3
b
)
{
add
.
add
(
a
,
b
,
color
);
};
add
.
add
(
a
,
b
,
color
);
};
edge
(
min
,
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
});
edge
(
min
,
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
});
edge
(
min
,
Vec3
{
min
.
x
,
max
.
y
,
min
.
z
});
edge
(
min
,
Vec3
{
min
.
x
,
max
.
y
,
min
.
z
});
...
@@ -139,11 +133,13 @@ size_t BVH<Primitive>::visualize(GL::Lines& lines, GL::Lines& active, size_t lev
...
@@ -139,11 +133,13 @@ size_t BVH<Primitive>::visualize(GL::Lines& lines, GL::Lines& active, size_t lev
edge
(
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
},
Vec3
{
max
.
x
,
max
.
y
,
min
.
z
});
edge
(
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
},
Vec3
{
max
.
x
,
max
.
y
,
min
.
z
});
edge
(
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
},
Vec3
{
max
.
x
,
min
.
y
,
max
.
z
});
edge
(
Vec3
{
max
.
x
,
min
.
y
,
min
.
z
},
Vec3
{
max
.
x
,
min
.
y
,
max
.
z
});
if
(
node
.
l
)
tstack
.
push
({
node
.
l
,
lvl
+
1
});
if
(
node
.
l
)
if
(
node
.
r
)
tstack
.
push
({
node
.
r
,
lvl
+
1
});
tstack
.
push
({
node
.
l
,
lvl
+
1
});
if
(
node
.
r
)
tstack
.
push
({
node
.
r
,
lvl
+
1
});
if
(
!
node
.
l
&&
!
node
.
r
)
{
if
(
!
node
.
l
&&
!
node
.
r
)
{
for
(
size_t
i
=
node
.
start
;
i
<
node
.
start
+
node
.
size
;
i
++
)
{
for
(
size_t
i
=
node
.
start
;
i
<
node
.
start
+
node
.
size
;
i
++
)
{
size_t
c
=
primitives
[
i
].
visualize
(
lines
,
active
,
level
-
lvl
,
trans
);
size_t
c
=
primitives
[
i
].
visualize
(
lines
,
active
,
level
-
lvl
,
trans
);
max_level
=
std
::
max
(
c
,
max_level
);
max_level
=
std
::
max
(
c
,
max_level
);
}
}
...
@@ -152,4 +148,4 @@ size_t BVH<Primitive>::visualize(GL::Lines& lines, GL::Lines& active, size_t lev
...
@@ -152,4 +148,4 @@ size_t BVH<Primitive>::visualize(GL::Lines& lines, GL::Lines& active, size_t lev
return
max_level
;
return
max_level
;
}
}
}
}
// namespace PT
src/student/camera.cpp
View file @
c2535f0f
#include "debug.h"
#include "../util/camera.h"
#include "../util/camera.h"
#include "debug.h"
Ray
Camera
::
generate_ray
(
Vec2
screen_coord
)
const
{
Ray
Camera
::
generate_ray
(
Vec2
screen_coord
)
const
{
...
...
src/student/debug.cpp
View file @
c2535f0f
...
@@ -23,17 +23,17 @@ Debug_Data debug_data;
...
@@ -23,17 +23,17 @@ Debug_Data debug_data;
// This runs when the button is clicked
// This runs when the button is clicked
}
}
Similarly, you can directly connect UI elements to data values by
Similarly, you can directly connect UI elements to data values by
passing in the address of your storage variable:
passing in the address of your storage variable:
Checkbox("My Checkbox", &bool_variable);
Checkbox("My Checkbox", &bool_variable);
Then, bool_variable will always reflect the state of the checkbox.
Then, bool_variable will always reflect the state of the checkbox.
These constructs are composable to make pretty advanced UI elements!
These constructs are composable to make pretty advanced UI elements!
The whole Scotty3D UI is implemented in this way.
The whole Scotty3D UI is implemented in this way.
Some useful functions are documented below, and you can refer to
Some useful functions are documented below, and you can refer to
deps/imgui/imgui.h for many more.
deps/imgui/imgui.h for many more.
*/
*/
void
student_debug_ui
()
{
void
student_debug_ui
()
{
...
@@ -43,13 +43,13 @@ void student_debug_ui() {
...
@@ -43,13 +43,13 @@ void student_debug_ui() {
Checkbox
(
"Pathtracer: use normal colors"
,
&
debug_data
.
normal_colors
);
Checkbox
(
"Pathtracer: use normal colors"
,
&
debug_data
.
normal_colors
);
// ImGui examples
// ImGui examples
if
(
Button
(
"Press Me"
))
{
if
(
Button
(
"Press Me"
))
{
info
(
"Debug button pressed!"
);
info
(
"Debug button pressed!"
);
}
}
// We need to store values somewhere, or else they will get reset every time
// We need to store values somewhere, or else they will get reset every time
// we run this function (which is every frame). For convenience, we make them
// we run this function (which is every frame). For convenience, we make them
// static, which gives them the same storage class as global variables.
// static, which gives them the same storage class as global variables.
static
int
int_value
=
0
;
static
int
int_value
=
0
;
InputInt
(
"Int Input"
,
&
int_value
);
InputInt
(
"Int Input"
,
&
int_value
);
...
...
src/student/debug.h
View file @
c2535f0f
...
@@ -4,17 +4,17 @@
...
@@ -4,17 +4,17 @@
/* Debugging Tips:
/* Debugging Tips:
You may use this file, as well as debug.cpp, to add any debugging features and
You may use this file, as well as debug.cpp, to add any debugging features and
UI options that you find useful. To do so, you can add fields to the global
UI options that you find useful. To do so, you can add fields to the global
Debug_Data type here and access them in any other student/ files via debug_data.field
Debug_Data type here and access them in any other student/ files via debug_data.field
You can use your fields to enable/disable features or otherwise change how your
You can use your fields to enable/disable features or otherwise change how your
implementation behaves in the other files.
implementation behaves in the other files.
You can also connect your debug fields to specific UI options by adding
You can also connect your debug fields to specific UI options by adding
ImGui calls in debug.cpp. This creates a special UI panel that can be enabled
ImGui calls in debug.cpp. This creates a special UI panel that can be enabled
by the Edit -> Edit Debug Data menu item or by pressing Ctrl+D.
by the Edit -> Edit Debug Data menu item or by pressing Ctrl+D.
This panel will contain your specific debug controls.
This panel will contain your specific debug controls.
For example, we have already implemented an option to color pathtracer objects
For example, we have already implemented an option to color pathtracer objects
based on their surface normal. This involved adding the following field to
based on their surface normal. This involved adding the following field to
Debug_Data:
Debug_Data:
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
This ImGui option to student_debug_ui in debug.cpp:
This ImGui option to student_debug_ui in debug.cpp:
void student_debug_ui() {
void student_debug_ui() {
// ...
// ...
Checkbox("Use Normal Colors", &debugger.normal_colors);
Checkbox("Use Normal Colors", &debugger.normal_colors);
// ...
// ...
...
@@ -34,9 +34,10 @@
...
@@ -34,9 +34,10 @@
And we finally used the option in pathtracer.cpp:
And we finally used the option in pathtracer.cpp:
Spectrum Pathtracer::trace_ray(const Ray& ray) {
Spectrum Pathtracer::trace_ray(const Ray& ray) {
// ...
// ...
Spectrum radiance_out = debug_data.normal_colors ? Spectrum(0.5f) : Spectrum::direction(hit.normal);
Spectrum radiance_out = debug_data.normal_colors ? Spectrum(0.5f) :
Spectrum::direction(hit.normal);
// ...
// ...
}
}
*/
*/
...
...
src/student/env_light.cpp
View file @
c2535f0f
#include "debug.h"
#include "../rays/env_light.h"
#include "../rays/env_light.h"
#include "debug.h"
#include <limits>
#include <limits>
...
@@ -16,7 +16,7 @@ Light_Sample Env_Map::sample() const {
...
@@ -16,7 +16,7 @@ Light_Sample Env_Map::sample() const {
Samplers
::
Sphere
::
Uniform
uniform
;
Samplers
::
Sphere
::
Uniform
uniform
;
ret
.
direction
=
uniform
.
sample
(
ret
.
pdf
);
ret
.
direction
=
uniform
.
sample
(
ret
.
pdf
);
// Once you've implemented Samplers::Sphere::Image, remove the above and
// Once you've implemented Samplers::Sphere::Image, remove the above and
// uncomment this line to use importance sampling instead.
// uncomment this line to use importance sampling instead.
// ret.direction = sampler.sample(ret.pdf);
// ret.direction = sampler.sample(ret.pdf);
...
@@ -42,7 +42,8 @@ Light_Sample Env_Hemisphere::sample() const {
...
@@ -42,7 +42,8 @@ Light_Sample Env_Hemisphere::sample() const {
}
}
Spectrum
Env_Hemisphere
::
sample_direction
(
Vec3
dir
)
const
{
Spectrum
Env_Hemisphere
::
sample_direction
(
Vec3
dir
)
const
{
if
(
dir
.
y
>
0.0
f
)
return
radiance
;
if
(
dir
.
y
>
0.0
f
)
return
radiance
;
return
{};
return
{};
}
}
...
@@ -54,8 +55,6 @@ Light_Sample Env_Sphere::sample() const {
...
@@ -54,8 +55,6 @@ Light_Sample Env_Sphere::sample() const {
return
ret
;
return
ret
;
}
}
Spectrum
Env_Sphere
::
sample_direction
(
Vec3
)
const
{
Spectrum
Env_Sphere
::
sample_direction
(
Vec3
)
const
{
return
radiance
;
}
return
radiance
;
}
}
}
// namespace PT
src/student/meshedit.cpp
View file @
c2535f0f
#include <set>
#include <queue>
#include <queue>
#include <set>
#include <unordered_map>
#include <unordered_map>
#include "debug.h"
#include "../geometry/halfedge.h"
#include "../geometry/halfedge.h"
#include "debug.h"
/* Note on local operation return types:
/* Note on local operation return types:
The local operations all return a std::optional<T> type. This is used so that your
The local operations all return a std::optional<T> type. This is used so that your
implementation can signify that it does not want to perform the operation for
implementation can signify that it does not want to perform the operation for
whatever reason (e.g. you don't want to allow the user to erase the last vertex).
whatever reason (e.g. you don't want to allow the user to erase the last vertex).
An optional can have two values: std::nullopt, or a value of the type it is
An optional can have two values: std::nullopt, or a value of the type it is
parameterized on. In this way, it's similar to a pointer, but has two advantages:
parameterized on. In this way, it's similar to a pointer, but has two advantages:
the value it holds need not be allocated elsewhere, and it provides an API that
the value it holds need not be allocated elsewhere, and it provides an API that
forces the user to check if it is null before using the value.
forces the user to check if it is null before using the value.
In your implementaiton, if you have successfully performed the operation, you can
In your implementaiton, if you have successfully performed the operation, you can
simply return the required reference:
simply return the required reference:
... collapse the edge ...
... collapse the edge ...
return collapsed_vertex_ref;
return collapsed_vertex_ref;
And if you wish to deny the operation, you can return the null optional:
And if you wish to deny the operation, you can return the null optional:
return std::nullopt;
return std::nullopt;
Note that the stubs below all reject their duties by returning the null optional.
Note that the stubs below all reject their duties by returning the null optional.
*/
*/
/*
/*
This method should replace the given vertex and all its neighboring
This method should replace the given vertex and all its neighboring
edges and faces with a single face, returning the new face.
edges and faces with a single face, returning the new face.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
erase_vertex
(
Halfedge_Mesh
::
VertexRef
v
)
{
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
erase_vertex
(
Halfedge_Mesh
::
VertexRef
v
)
{
(
void
)
v
;
(
void
)
v
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should erase the given edge and return an iterator to the
This method should erase the given edge and return an iterator to the
merged face.
merged face.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
erase_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
erase_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
(
void
)
e
;
(
void
)
e
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should collapse the given edge and return an iterator to
This method should collapse the given edge and return an iterator to
the new vertex created by the collapse.
the new vertex created by the collapse.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
collapse_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
collapse_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
(
void
)
e
;
(
void
)
e
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should collapse the given face and return an iterator to
This method should collapse the given face and return an iterator to
the new vertex created by the collapse.
the new vertex created by the collapse.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
collapse_face
(
Halfedge_Mesh
::
FaceRef
f
)
{
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
collapse_face
(
Halfedge_Mesh
::
FaceRef
f
)
{
(
void
)
f
;
(
void
)
f
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should flip the given edge and return an iterator to the
This method should flip the given edge and return an iterator to the
flipped edge.
flipped edge.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
EdgeRef
>
Halfedge_Mesh
::
flip_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
std
::
optional
<
Halfedge_Mesh
::
EdgeRef
>
Halfedge_Mesh
::
flip_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
(
void
)
e
;
(
void
)
e
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should split the given edge and return an iterator to the
This method should split the given edge and return an iterator to the
newly inserted vertex. The halfedge of this vertex should point along
newly inserted vertex. The halfedge of this vertex should point along
the edge that was split, rather than the new edges.
the edge that was split, rather than the new edges.
*/
*/
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
split_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
std
::
optional
<
Halfedge_Mesh
::
VertexRef
>
Halfedge_Mesh
::
split_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
(
void
)
e
;
(
void
)
e
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/* Note on the beveling process:
/* Note on the beveling process:
Each of the bevel_vertex, bevel_edge, and bevel_face functions do not represent
Each of the bevel_vertex, bevel_edge, and bevel_face functions do not represent
a full bevel operation. Instead, they should only update the _connectivity_ of
a full bevel operation. Instead, they should only update the _connectivity_ of
the mesh, _not_ the positions of newly created vertices. In fact, you should set
the mesh, _not_ the positions of newly created vertices. In fact, you should set
the positions of new vertices to be exactly the same as wherever they "started from."
the positions of new vertices to be exactly the same as wherever they "started from."
When you click on a mesh element while in bevel mode, one of those three functions
When you click on a mesh element while in bevel mode, one of those three functions
is called. But, because you may then adjust the distance/offset of the newly
is called. But, because you may then adjust the distance/offset of the newly
beveled face, we need another method of updating the positions of the new vertices.
beveled face, we need another method of updating the positions of the new vertices.
This is where bevel_vertex_positions, bevel_edge_positions, and
This is where bevel_vertex_positions, bevel_edge_positions, and
bevel_face_positions come in: these functions are called repeatedly as you
bevel_face_positions come in: these functions are called repeatedly as you
move your mouse, the position of which determins the normal and tangent offset
move your mouse, the position of which determins the normal and tangent offset
parameters. These functions are also passed an array of the original vertex
parameters. These functions are also passed an array of the original vertex
positions: for bevel_vertex, it has one element, the original vertex position,
positions: for bevel_vertex, it has one element, the original vertex position,
for bevel_edge, two for the two vertices, and for bevel_face, it has the original
for bevel_edge, two for the two vertices, and for bevel_face, it has the original
position of each vertex in halfedge order. You should use these positions, as well
position of each vertex in halfedge order. You should use these positions, as well
as the normal and tangent offset fields to assign positions to the new vertices.
as the normal and tangent offset fields to assign positions to the new vertices.
Finally, note that the normal and tangent offsets are not relative values - you
Finally, note that the normal and tangent offsets are not relative values - you
should compute a particular new position from them, not a delta to apply.
should compute a particular new position from them, not a delta to apply.
*/
*/
/*
/*
This method should replace the vertex v with a face, corresponding to
This method should replace the vertex v with a face, corresponding to
a bevel operation. It should return the new face. NOTE: This method is
a bevel operation. It should return the new face. NOTE: This method is
responsible for updating the *connectivity* of the mesh only---it does not
responsible for updating the *connectivity* of the mesh only---it does not
need to update the vertex positions. These positions will be updated in
need to update the vertex positions. These positions will be updated in
Halfedge_Mesh::bevel_vertex_positions (which you also have to
Halfedge_Mesh::bevel_vertex_positions (which you also have to
implement!)
implement!)
*/
*/
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_vertex
(
Halfedge_Mesh
::
VertexRef
v
)
{
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_vertex
(
Halfedge_Mesh
::
VertexRef
v
)
{
(
void
)
v
;
(
void
)
v
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should replace the edge e with a face, corresponding to a
This method should replace the edge e with a face, corresponding to a
bevel operation. It should return the new face. NOTE: This method is
bevel operation. It should return the new face. NOTE: This method is
responsible for updating the *connectivity* of the mesh only---it does not
responsible for updating the *connectivity* of the mesh only---it does not
need to update the vertex positions. These positions will be updated in
need to update the vertex positions. These positions will be updated in
Halfedge_Mesh::bevel_edge_positions (which you also have to
Halfedge_Mesh::bevel_edge_positions (which you also have to
implement!)
implement!)
*/
*/
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_edge
(
Halfedge_Mesh
::
EdgeRef
e
)
{
(
void
)
e
;
(
void
)
e
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
This method should replace the face f with an additional, inset face
This method should replace the face f with an additional, inset face
(and ring of faces around it), corresponding to a bevel operation. It
(and ring of faces around it), corresponding to a bevel operation. It
should return the new face. NOTE: This method is responsible for updating
should return the new face. NOTE: This method is responsible for updating
the *connectivity* of the mesh only---it does not need to update the vertex
the *connectivity* of the mesh only---it does not need to update the vertex
positions. These positions will be updated in
positions. These positions will be updated in
Halfedge_Mesh::bevel_face_positions (which you also have to
Halfedge_Mesh::bevel_face_positions (which you also have to
implement!)
implement!)
*/
*/
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_face
(
Halfedge_Mesh
::
FaceRef
f
)
{
std
::
optional
<
Halfedge_Mesh
::
FaceRef
>
Halfedge_Mesh
::
bevel_face
(
Halfedge_Mesh
::
FaceRef
f
)
{
(
void
)
f
;
(
void
)
f
;
return
std
::
nullopt
;
return
std
::
nullopt
;
}
}
/*
/*
Compute new vertex positions for the vertices of the beveled vertex.
Compute new vertex positions for the vertices of the beveled vertex.
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
i = 1, ..., new_halfedges.size()-1.
i = 1, ..., new_halfedges.size()-1.
The basic strategy here is to loop over the list of outgoing halfedges,
The basic strategy here is to loop over the list of outgoing halfedges,
and use the original vertex position and its associated outgoing edge
and use the original vertex position and its associated outgoing edge
to compute a new vertex position along the outgoing edge.
to compute a new vertex position along the outgoing edge.
*/
*/
void
Halfedge_Mesh
::
bevel_vertex_positions
(
const
std
::
vector
<
Vec3
>
&
start_positions
,
Halfedge_Mesh
::
FaceRef
face
,
void
Halfedge_Mesh
::
bevel_vertex_positions
(
const
std
::
vector
<
Vec3
>
&
start_positions
,
float
tangent_offset
)
{
Halfedge_Mesh
::
FaceRef
face
,
float
tangent_offset
)
{
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
auto
h
=
face
->
halfedge
();
auto
h
=
face
->
halfedge
();
do
{
do
{
new_halfedges
.
push_back
(
h
);
new_halfedges
.
push_back
(
h
);
h
=
h
->
next
();
h
=
h
->
next
();
}
while
(
h
!=
face
->
halfedge
());
}
while
(
h
!=
face
->
halfedge
());
(
void
)
new_halfedges
;
(
void
)
new_halfedges
;
(
void
)
start_positions
;
(
void
)
start_positions
;
(
void
)
face
;
(
void
)
face
;
(
void
)
tangent_offset
;
(
void
)
tangent_offset
;
}
}
/*
/*
Compute new vertex positions for the vertices of the beveled edge.
Compute new vertex positions for the vertices of the beveled edge.
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
i = 1, ..., new_halfedges.size()-1.
i = 1, ..., new_halfedges.size()-1.
The basic strategy here is to loop over the list of outgoing halfedges,
The basic strategy here is to loop over the list of outgoing halfedges,
and use the preceding and next vertex position from the original mesh
and use the preceding and next vertex position from the original mesh
(in the orig array) to compute an offset vertex position.
(in the orig array) to compute an offset vertex position.
Note that there is a 1-to-1 correspondence between halfedges in
Note that there is a 1-to-1 correspondence between halfedges in
newHalfedges and vertex positions
newHalfedges and vertex positions
in orig. So, you can write loops of the form
in orig. So, you can write loops of the form
for(size_t i = 0; i < new_halfedges.size(); i++)
for(size_t i = 0; i < new_halfedges.size(); i++)
{
{
Vector3D pi = start_positions[i]; // get the original vertex
Vector3D pi = start_positions[i]; // get the original vertex
position corresponding to vertex i
position corresponding to vertex i
}
}
*/
*/
void
Halfedge_Mesh
::
bevel_edge_positions
(
const
std
::
vector
<
Vec3
>
&
start_positions
,
Halfedge_Mesh
::
FaceRef
face
,
void
Halfedge_Mesh
::
bevel_edge_positions
(
const
std
::
vector
<
Vec3
>
&
start_positions
,
float
tangent_offset
)
{
Halfedge_Mesh
::
FaceRef
face
,
float
tangent_offset
)
{
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
auto
h
=
face
->
halfedge
();
auto
h
=
face
->
halfedge
();
do
{
do
{
new_halfedges
.
push_back
(
h
);
new_halfedges
.
push_back
(
h
);
h
=
h
->
next
();
h
=
h
->
next
();
}
while
(
h
!=
face
->
halfedge
());
}
while
(
h
!=
face
->
halfedge
());
(
void
)
new_halfedges
;
(
void
)
new_halfedges
;
(
void
)
start_positions
;
(
void
)
start_positions
;
(
void
)
face
;
(
void
)
face
;
(
void
)
tangent_offset
;
(
void
)
tangent_offset
;
}
}
/*
/*
Compute new vertex positions for the vertices of the beveled face.
Compute new vertex positions for the vertices of the beveled face.
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
These vertices can be accessed via new_halfedges[i]->vertex()->pos for
i = 1, ..., new_halfedges.size()-1.
i = 1, ..., new_halfedges.size()-1.
The basic strategy here is to loop over the list of outgoing halfedges,
The basic strategy here is to loop over the list of outgoing halfedges,
and use the preceding and next vertex position from the original mesh
and use the preceding and next vertex position from the original mesh
(in the start_positions array) to compute an offset vertex
(in the start_positions array) to compute an offset vertex
position.
position.
Note that there is a 1-to-1 correspondence between halfedges in
Note that there is a 1-to-1 correspondence between halfedges in
new_halfedges and vertex positions
new_halfedges and vertex positions
in orig. So, you can write loops of the form
in orig. So, you can write loops of the form
for(size_t i = 0; i < new_halfedges.size(); hs++)
for(size_t i = 0; i < new_halfedges.size(); hs++)
{
{
Vec3 pi = start_positions[i]; // get the original vertex
Vec3 pi = start_positions[i]; // get the original vertex
position corresponding to vertex i
position corresponding to vertex i
}
}
*/
*/
void
Halfedge_Mesh
::
bevel_face_positions
(
const
std
::
vector
<
Vec3
>&
start_positions
,
Halfedge_Mesh
::
FaceRef
face
,
void
Halfedge_Mesh
::
bevel_face_positions
(
const
std
::
vector
<
Vec3
>
&
start_positions
,
float
tangent_offset
,
float
normal_offset
)
{
Halfedge_Mesh
::
FaceRef
face
,
float
tangent_offset
,
float
normal_offset
)
{
if
(
flip_orientation
)
normal_offset
=
-
normal_offset
;
if
(
flip_orientation
)
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
normal_offset
=
-
normal_offset
;
std
::
vector
<
HalfedgeRef
>
new_halfedges
;
auto
h
=
face
->
halfedge
();
auto
h
=
face
->
halfedge
();
do
{
do
{
new_halfedges
.
push_back
(
h
);
new_halfedges
.
push_back
(
h
);
h
=
h
->
next
();
h
=
h
->
next
();
}
while
(
h
!=
face
->
halfedge
());
}
while
(
h
!=
face
->
halfedge
());
(
void
)
new_halfedges
;
(
void
)
new_halfedges
;
(
void
)
start_positions
;
(
void
)
start_positions
;
(
void
)
face
;
(
void
)
face
;
(
void
)
tangent_offset
;
(
void
)
tangent_offset
;
(
void
)
normal_offset
;
(
void
)
normal_offset
;
}
}
/*
/*
Splits all non-triangular faces into triangles.
Splits all non-triangular faces into triangles.
*/
*/
void
Halfedge_Mesh
::
triangulate
()
{
void
Halfedge_Mesh
::
triangulate
()
{
// For each face...
// For each face...
}
}
/* Note on the quad subdivision process:
/* Note on the quad subdivision process:
Unlike the local mesh operations (like bevel or edge flip), we will perform
Unlike the local mesh operations (like bevel or edge flip), we will perform
subdivision by splitting *all* faces into quads "simultaneously." Rather
subdivision by splitting *all* faces into quads "simultaneously." Rather
than operating directly on the halfedge data structure (which as you've
than operating directly on the halfedge data structure (which as you've
seen is quite difficult to maintain!) we are going to do something a bit nicer:
seen is quite difficult to maintain!) we are going to do something a bit nicer:
1. Create a raw list of vertex positions and faces (rather than a full-
1. Create a raw list of vertex positions and faces (rather than a full-
blown halfedge mesh).
blown halfedge mesh).
2. Build a new halfedge mesh from these lists, replacing the old one.
2. Build a new halfedge mesh from these lists, replacing the old one.
Sometimes rebuilding a data structure from scratch is simpler (and even
Sometimes rebuilding a data structure from scratch is simpler (and even
more efficient) than incrementally modifying the existing one. These steps are
more efficient) than incrementally modifying the existing one. These steps are
detailed below.
detailed below.
Step I: Compute the vertex positions for the subdivided mesh.
Step I: Compute the vertex positions for the subdivided mesh.
Here we're going to do something a little bit strange: since we will
Here we're going to do something a little bit strange: since we will
have one vertex in the subdivided mesh for each vertex, edge, and face in
have one vertex in the subdivided mesh for each vertex, edge, and face in
the original mesh, we can nicely store the new vertex *positions* as
the original mesh, we can nicely store the new vertex *positions* as
attributes on vertices, edges, and faces of the original mesh. These positions
attributes on vertices, edges, and faces of the original mesh. These positions
can then be conveniently copied into the new, subdivided mesh.
can then be conveniently copied into the new, subdivided mesh.
This is what you will implement in linear_subdivide_positions() and
This is what you will implement in linear_subdivide_positions() and
catmullclark_subdivide_positions().
catmullclark_subdivide_positions().
Steps II-IV are provided (see Halfedge_Mesh::subdivide()), but are still detailed
Steps II-IV are provided (see Halfedge_Mesh::subdivide()), but are still detailed
here:
here:
Step II: Assign a unique index (starting at 0) to each vertex, edge, and
Step II: Assign a unique index (starting at 0) to each vertex, edge, and
face in the original mesh. These indices will be the indices of the
face in the original mesh. These indices will be the indices of the
vertices in the new (subdivided mesh). They do not have to be assigned
vertices in the new (subdivided mesh). They do not have to be assigned
in any particular order, so long as no index is shared by more than one
in any particular order, so long as no index is shared by more than one
mesh element, and the total number of indices is equal to V+E+F, i.e.,
mesh element, and the total number of indices is equal to V+E+F, i.e.,
the total number of vertices plus edges plus faces in the original mesh.
the total number of vertices plus edges plus faces in the original mesh.
Basically we just need a one-to-one mapping between original mesh elements
Basically we just need a one-to-one mapping between original mesh elements
and subdivided mesh vertices.
and subdivided mesh vertices.
Step III: Build a list of quads in the new (subdivided) mesh, as tuples of
Step III: Build a list of quads in the new (subdivided) mesh, as tuples of
the element indices defined above. In other words, each new quad should be
the element indices defined above. In other words, each new quad should be
of the form (i,j,k,l), where i,j,k and l are four of the indices stored on
of the form (i,j,k,l), where i,j,k and l are four of the indices stored on
our original mesh elements. Note that it is essential to get the orientation
our original mesh elements. Note that it is essential to get the orientation
right here: (i,j,k,l) is not the same as (l,k,j,i). Indices of new faces
right here: (i,j,k,l) is not the same as (l,k,j,i). Indices of new faces
should circulate in the same direction as old faces (think about the right-hand
should circulate in the same direction as old faces (think about the right-hand
rule).
rule).
Step IV: Pass the list of vertices and quads to a routine that clears
Step IV: Pass the list of vertices and quads to a routine that clears
the internal data for this halfedge mesh, and builds new halfedge data from
the internal data for this halfedge mesh, and builds new halfedge data from
scratch, using the two lists.
scratch, using the two lists.
*/
*/
/*
/*
Compute new vertex positions for a mesh that splits each polygon
Compute new vertex positions for a mesh that splits each polygon
into quads (by inserting a vertex at the face midpoint and each
into quads (by inserting a vertex at the face midpoint and each
of the edge midpoints). The new vertex positions will be stored
of the edge midpoints). The new vertex positions will be stored
in the members Vertex::new_pos, Edge::new_pos, and
in the members Vertex::new_pos, Edge::new_pos, and
Face::new_pos. The values of the positions are based on
Face::new_pos. The values of the positions are based on
simple linear interpolation, e.g., the edge midpoints and face
simple linear interpolation, e.g., the edge midpoints and face
centroids.
centroids.
*/
*/
void
Halfedge_Mesh
::
linear_subdivide_positions
()
{
void
Halfedge_Mesh
::
linear_subdivide_positions
()
{
// For each vertex, assign Vertex::new_pos to
// For each vertex, assign Vertex::new_pos to
// its original position, Vertex::pos.
// its original position, Vertex::pos.
// For each edge, assign the midpoint of the two original
// For each edge, assign the midpoint of the two original
// positions to Edge::new_pos.
// positions to Edge::new_pos.
// For each face, assign the centroid (i.e., arithmetic mean)
// For each face, assign the centroid (i.e., arithmetic mean)
// of the original vertex positions to Face::new_pos. Note
// of the original vertex positions to Face::new_pos. Note
// that in general, NOT all faces will be triangles!
// that in general, NOT all faces will be triangles!
}
}
/*
/*
Compute new vertex positions for a mesh that splits each polygon
Compute new vertex positions for a mesh that splits each polygon
into quads (by inserting a vertex at the face midpoint and each
into quads (by inserting a vertex at the face midpoint and each
of the edge midpoints). The new vertex positions will be stored
of the edge midpoints). The new vertex positions will be stored
in the members Vertex::new_pos, Edge::new_pos, and
in the members Vertex::new_pos, Edge::new_pos, and
Face::new_pos. The values of the positions are based on
Face::new_pos. The values of the positions are based on
the Catmull-Clark rules for subdivision.
the Catmull-Clark rules for subdivision.
Note: this will only be called on meshes without boundary
Note: this will only be called on meshes without boundary
*/
*/
void
Halfedge_Mesh
::
catmullclark_subdivide_positions
()
{
void
Halfedge_Mesh
::
catmullclark_subdivide_positions
()
{
// The implementation for this routine should be
// The implementation for this routine should be
// a lot like Halfedge_Mesh:linear_subdivide_positions:(),
// a lot like Halfedge_Mesh:linear_subdivide_positions:(),
// except that the calculation of the positions themsevles is
// except that the calculation of the positions themsevles is
// slightly more involved, using the Catmull-Clark subdivision
// slightly more involved, using the Catmull-Clark subdivision
// rules. (These rules are outlined in the Developer Manual.)
// rules. (These rules are outlined in the Developer Manual.)
// Faces
// Faces
// Edges
// Edges
// Vertices
// Vertices
}
}
/*
/*
This routine should increase the number of triangles in the mesh
This routine should increase the number of triangles in the mesh
using Loop subdivision. Note: this is will only be called on triangle meshes.
using Loop subdivision. Note: this is will only be called on triangle meshes.
*/
*/
void
Halfedge_Mesh
::
loop_subdivide
()
{
void
Halfedge_Mesh
::
loop_subdivide
()
{
// Compute new positions for all the vertices in the input mesh, using
// Compute new positions for all the vertices in the input mesh, using
// the Loop subdivision rule, and store them in Vertex::new_pos.
// the Loop subdivision rule, and store them in Vertex::new_pos.
// -> At this point, we also want to mark each vertex as being a vertex of the
// -> At this point, we also want to mark each vertex as being a vertex of the
// original mesh. Use Vertex::is_new for this.
// original mesh. Use Vertex::is_new for this.
// -> Next, compute the updated vertex positions associated with edges, and
// -> Next, compute the updated vertex positions associated with edges, and
// store it in Edge::new_pos.
// store it in Edge::new_pos.
// -> Next, we're going to split every edge in the mesh, in any order. For
// -> Next, we're going to split every edge in the mesh, in any order. For
// future reference, we're also going to store some information about which
// future reference, we're also going to store some information about which
// subdivided edges come from splitting an edge in the original mesh, and
// subdivided edges come from splitting an edge in the original mesh, and
// which edges are new, by setting the flat Edge::is_new. Note that in this
// which edges are new, by setting the flat Edge::is_new. Note that in this
// loop, we only want to iterate over edges of the original mesh.
// loop, we only want to iterate over edges of the original mesh.
// Otherwise, we'll end up splitting edges that we just split (and the
// Otherwise, we'll end up splitting edges that we just split (and the
// loop will never end!)
// loop will never end!)
// -> Now flip any new edge that connects an old and new vertex.
// -> Now flip any new edge that connects an old and new vertex.
// -> Finally, copy the new vertex positions into final Vertex::pos.
// -> Finally, copy the new vertex positions into final Vertex::pos.
// Each vertex and edge of the original surface can be associated with a
// Each vertex and edge of the original surface can be associated with a
// vertex in the new (subdivided) surface.
// vertex in the new (subdivided) surface.
// Therefore, our strategy for computing the subdivided vertex locations is to
// Therefore, our strategy for computing the subdivided vertex locations is to
// *first* compute the new positions
// *first* compute the new positions
// using the connectivity of the original (coarse) mesh; navigating this mesh
// using the connectivity of the original (coarse) mesh; navigating this mesh
// will be much easier than navigating
// will be much easier than navigating
// the new subdivided (fine) mesh, which has more elements to traverse. We
// the new subdivided (fine) mesh, which has more elements to traverse. We
// will then assign vertex positions in
// will then assign vertex positions in
// the new mesh based on the values we computed for the original mesh.
// the new mesh based on the values we computed for the original mesh.
// Compute updated positions for all the vertices in the original mesh, using
// Compute updated positions for all the vertices in the original mesh, using
// the Loop subdivision rule.
// the Loop subdivision rule.
// Next, compute the updated vertex positions associated with edges.
// Next, compute the updated vertex positions associated with edges.
// Next, we're going to split every edge in the mesh, in any order. For
// Next, we're going to split every edge in the mesh, in any order. For
// future reference, we're also going to store some information about which
// future reference, we're also going to store some information about which
// subdivided edges come from splitting an edge in the original mesh, and
// subdivided edges come from splitting an edge in the original mesh, and
// which edges are new.
// which edges are new.
// In this loop, we only want to iterate over edges of the original
// In this loop, we only want to iterate over edges of the original
// mesh---otherwise, we'll end up splitting edges that we just split (and
// mesh---otherwise, we'll end up splitting edges that we just split (and
// the loop will never end!)
// the loop will never end!)
// Finally, flip any new edge that connects an old and new vertex.
// Finally, flip any new edge that connects an old and new vertex.
// Copy the updated vertex positions to the subdivided mesh.
// Copy the updated vertex positions to the subdivided mesh.
}
}
/*
/*
Isotropic remeshing. Note that this function returns success in a similar
Isotropic remeshing. Note that this function returns success in a similar
manner to the local operations, except with only a boolean value.
manner to the local operations, except with only a boolean value.
(e.g. you may want to return false if this is not a triangle mesh)
(e.g. you may want to return false if this is not a triangle mesh)
*/
*/
bool
Halfedge_Mesh
::
isotropic_remesh
()
{
bool
Halfedge_Mesh
::
isotropic_remesh
()
{
// Compute the mean edge length.
// Compute the mean edge length.
// Repeat the four main steps for 5 or 6 iterations
// Repeat the four main steps for 5 or 6 iterations
// -> Split edges much longer than the target length (being careful about
// -> Split edges much longer than the target length (being careful about
// how the loop is written!)
// how the loop is written!)
// -> Collapse edges much shorter than the target length. Here we need to
// -> Collapse edges much shorter than the target length. Here we need to
// be EXTRA careful about advancing the loop, because many edges may have
// be EXTRA careful about advancing the loop, because many edges may have
// been destroyed by a collapse (which ones?)
// been destroyed by a collapse (which ones?)
// -> Now flip each edge if it improves vertex degree
// -> Now flip each edge if it improves vertex degree
// -> Finally, apply some tangential smoothing to the vertex positions
// -> Finally, apply some tangential smoothing to the vertex positions
return
false
;
return
false
;
}
}
/* Helper type for quadric simplification */
/* Helper type for quadric simplification */
struct
Edge_Record
{
struct
Edge_Record
{
Edge_Record
()
{}
Edge_Record
()
{}
Edge_Record
(
std
::
unordered_map
<
Halfedge_Mesh
::
VertexRef
,
Mat4
>&
vertex_quadrics
,
Edge_Record
(
std
::
unordered_map
<
Halfedge_Mesh
::
VertexRef
,
Mat4
>
&
vertex_quadrics
,
Halfedge_Mesh
::
EdgeRef
e
)
:
edge
(
e
)
{
Halfedge_Mesh
::
EdgeRef
e
)
:
edge
(
e
)
{
// Compute the combined quadric from the edge endpoints.
// -> Build the 3x3 linear system whose solution minimizes the quadric error
// Compute the combined quadric from the edge endpoints.
// associated with these two endpoints.
// -> Build the 3x3 linear system whose solution minimizes the quadric error
// -> Use this system to solve for the optimal position, and store it in
// associated with these two endpoints.
// Edge_Record::optimal.
// -> Use this system to solve for the optimal position, and store it in
// -> Also store the cost associated with collapsing this edge in
// Edge_Record::optimal.
// Edge_Record::cost.
// -> Also store the cost associated with collapsing this edge in
// Edge_Record::cost.
}
}
Halfedge_Mesh
::
EdgeRef
edge
;
Halfedge_Mesh
::
EdgeRef
edge
;
Vec3
optimal
;
Vec3
optimal
;
...
@@ -451,7 +454,7 @@ struct Edge_Record {
...
@@ -451,7 +454,7 @@ struct Edge_Record {
};
};
/** Helper type for quadric simplification
/** Helper type for quadric simplification
*
*
* A PQueue is a minimum-priority queue that
* A PQueue is a minimum-priority queue that
* allows elements to be both inserted and removed from the
* allows elements to be both inserted and removed from the
* queue. Together, one can easily change the priority of
* queue. Together, one can easily change the priority of
...
@@ -504,48 +507,47 @@ struct Edge_Record {
...
@@ -504,48 +507,47 @@ struct Edge_Record {
* queue.remove( item2 );
* queue.remove( item2 );
*
*
*/
*/
template
<
class
T
>
template
<
class
T
>
struct
PQueue
{
struct
PQueue
{
void
insert
(
const
T
&
item
)
{
queue
.
insert
(
item
);
}
void
insert
(
const
T
&
item
)
{
queue
.
insert
(
item
);
}
void
remove
(
const
T
&
item
)
{
void
remove
(
const
T
&
item
)
{
if
(
queue
.
find
(
item
)
!=
queue
.
end
())
{
if
(
queue
.
find
(
item
)
!=
queue
.
end
())
{
queue
.
erase
(
item
);
queue
.
erase
(
item
);
}
}
}
}
const
T
&
top
(
void
)
const
{
return
*
(
queue
.
begin
());
}
const
T
&
top
(
void
)
const
{
return
*
(
queue
.
begin
());
}
void
pop
(
void
)
{
queue
.
erase
(
queue
.
begin
());
}
void
pop
(
void
)
{
queue
.
erase
(
queue
.
begin
());
}
size_t
size
()
{
return
queue
.
size
();}
size_t
size
()
{
return
queue
.
size
();
}
std
::
set
<
T
>
queue
;
std
::
set
<
T
>
queue
;
};
};
/*
/*
Mesh simplification. Note that this function returns success in a similar
Mesh simplification. Note that this function returns success in a similar
manner to the local operations, except with only a boolean value.
manner to the local operations, except with only a boolean value.
(e.g. you may want to return false if you can't simplify the mesh any
(e.g. you may want to return false if you can't simplify the mesh any
further without destroying it.)
further without destroying it.)
*/
*/
bool
Halfedge_Mesh
::
simplify
()
{
bool
Halfedge_Mesh
::
simplify
()
{
std
::
unordered_map
<
VertexRef
,
Mat4
>
vertex_quadrics
;
std
::
unordered_map
<
VertexRef
,
Mat4
>
vertex_quadrics
;
std
::
unordered_map
<
FaceRef
,
Mat4
>
face_quadrics
;
std
::
unordered_map
<
FaceRef
,
Mat4
>
face_quadrics
;
std
::
unordered_map
<
EdgeRef
,
Edge_Record
>
edge_records
;
std
::
unordered_map
<
EdgeRef
,
Edge_Record
>
edge_records
;
PQueue
<
Edge_Record
>
edge_queue
;
PQueue
<
Edge_Record
>
edge_queue
;
// Compute initial quadrics for each face by simply writing the plane equation
// Compute initial quadrics for each face by simply writing the plane equation
// for the face in homogeneous coordinates. These quadrics should be stored
// for the face in homogeneous coordinates. These quadrics should be stored
// in face_quadrics
// in face_quadrics
// -> Compute an initial quadric for each vertex as the sum of the quadrics
// -> Compute an initial quadric for each vertex as the sum of the quadrics
// associated with the incident faces, storing it in vertex_quadrics
// associated with the incident faces, storing it in vertex_quadrics
// -> Build a priority queue of edges according to their quadric error cost,
// -> Build a priority queue of edges according to their quadric error cost,
// i.e., by building an Edge_Record for each edge and sticking it in the
// i.e., by building an Edge_Record for each edge and sticking it in the
// queue. You may want to use the above PQueue<Edge_Record> for this.
// queue. You may want to use the above PQueue<Edge_Record> for this.
// -> Until we reach the target edge budget, collapse the best edge. Remember
// -> Until we reach the target edge budget, collapse the best edge. Remember
// to remove from the queue any edge that touches the collapsing edge
// to remove from the queue any edge that touches the collapsing edge
// BEFORE it gets collapsed, and add back into the queue any edge touching
// BEFORE it gets collapsed, and add back into the queue any edge touching
// the collapsed vertex AFTER it's been collapsed. Also remember to assign
// the collapsed vertex AFTER it's been collapsed. Also remember to assign
// a quadric to the collapsed vertex, and to pop the collapsed edge off the
// a quadric to the collapsed vertex, and to pop the collapsed edge off the
// top of the queue.
// top of the queue.
return
false
;
return
false
;
}
}
src/student/pathtracer.cpp
View file @
c2535f0f
#include "debug.h"
#include "../rays/pathtracer.h"
#include "../rays/pathtracer.h"
#include "../rays/samplers.h"
#include "../rays/samplers.h"
#include "../util/rand.h"
#include "../util/rand.h"
#include "debug.h"
namespace
PT
{
namespace
PT
{
...
@@ -12,13 +12,13 @@ Spectrum Pathtracer::trace_pixel(size_t x, size_t y) {
...
@@ -12,13 +12,13 @@ Spectrum Pathtracer::trace_pixel(size_t x, size_t y) {
Vec2
wh
((
float
)
out_w
,
(
float
)
out_h
);
Vec2
wh
((
float
)
out_w
,
(
float
)
out_h
);
// TODO (PathTracer): Task 1
// TODO (PathTracer): Task 1
// Generate a sample within the pixel with coordinates xy and return the
// Generate a sample within the pixel with coordinates xy and return the
// incoming light using trace_ray.
// incoming light using trace_ray.
// Tip: Samplers::Rect::Uniform
// Tip: Samplers::Rect::Uniform
// Tip: you may want to use log_ray for debugging
// Tip: you may want to use log_ray for debugging
// This currently generates a ray at the bottom left of the pixel every time.
// This currently generates a ray at the bottom left of the pixel every time.
Ray
out
=
camera
.
generate_ray
(
xy
/
wh
);
Ray
out
=
camera
.
generate_ray
(
xy
/
wh
);
...
@@ -26,12 +26,12 @@ Spectrum Pathtracer::trace_pixel(size_t x, size_t y) {
...
@@ -26,12 +26,12 @@ Spectrum Pathtracer::trace_pixel(size_t x, size_t y) {
return
trace_ray
(
out
);
return
trace_ray
(
out
);
}
}
Spectrum
Pathtracer
::
trace_ray
(
const
Ray
&
ray
)
{
Spectrum
Pathtracer
::
trace_ray
(
const
Ray
&
ray
)
{
// Trace ray into scene. If nothing is hit, sample the environment
// Trace ray into scene. If nothing is hit, sample the environment
Trace
hit
=
scene
.
hit
(
ray
);
Trace
hit
=
scene
.
hit
(
ray
);
if
(
!
hit
.
hit
)
{
if
(
!
hit
.
hit
)
{
if
(
env_light
.
has_value
())
{
if
(
env_light
.
has_value
())
{
return
env_light
.
value
().
sample_direction
(
ray
.
dir
);
return
env_light
.
value
().
sample_direction
(
ray
.
dir
);
}
}
return
{};
return
{};
...
@@ -43,7 +43,7 @@ Spectrum Pathtracer::trace_ray(const Ray& ray) {
...
@@ -43,7 +43,7 @@ Spectrum Pathtracer::trace_ray(const Ray& ray) {
Mat4
object_to_world
=
Mat4
::
rotate_to
(
hit
.
normal
);
Mat4
object_to_world
=
Mat4
::
rotate_to
(
hit
.
normal
);
Mat4
world_to_object
=
object_to_world
.
T
();
Mat4
world_to_object
=
object_to_world
.
T
();
Vec3
out_dir
=
world_to_object
.
rotate
(
ray
.
point
-
hit
.
position
).
unit
();
Vec3
out_dir
=
world_to_object
.
rotate
(
ray
.
point
-
hit
.
position
).
unit
();
const
BSDF
&
bsdf
=
materials
[
hit
.
material
];
const
BSDF
&
bsdf
=
materials
[
hit
.
material
];
// Now we can compute the rendering equation at this point.
// Now we can compute the rendering equation at this point.
// We split it into two stages: sampling lighting (i.e. directly connecting
// We split it into two stages: sampling lighting (i.e. directly connecting
...
@@ -55,68 +55,71 @@ Spectrum Pathtracer::trace_ray(const Ray& ray) {
...
@@ -55,68 +55,71 @@ Spectrum Pathtracer::trace_ray(const Ray& ray) {
// indirect lighting components calculated in the code below. The starter
// indirect lighting components calculated in the code below. The starter
// code sets radiance_out to (0.5,0.5,0.5) so that you can test your geometry
// code sets radiance_out to (0.5,0.5,0.5) so that you can test your geometry
// queries before you implement path tracing.
// queries before you implement path tracing.
Spectrum
radiance_out
=
debug_data
.
normal_colors
?
Spectrum
(
0.5
f
)
:
Spectrum
::
direction
(
hit
.
normal
);
Spectrum
radiance_out
=
debug_data
.
normal_colors
?
Spectrum
(
0.5
f
)
:
Spectrum
::
direction
(
hit
.
normal
);
{
{
auto
sample_light
=
[
&
](
const
auto
&
light
)
{
auto
sample_light
=
[
&
](
const
auto
&
light
)
{
// If the light is discrete (e.g. a point light), then we only need
// If the light is discrete (e.g. a point light), then we only need
// one sample, as all samples will be equivalent
// one sample, as all samples will be equivalent
int
samples
=
light
.
is_discrete
()
?
1
:
(
int
)
n_area_samples
;
int
samples
=
light
.
is_discrete
()
?
1
:
(
int
)
n_area_samples
;
for
(
int
i
=
0
;
i
<
samples
;
i
++
)
{
for
(
int
i
=
0
;
i
<
samples
;
i
++
)
{
Light_Sample
sample
=
light
.
sample
(
hit
.
position
);
Light_Sample
sample
=
light
.
sample
(
hit
.
position
);
Vec3
in_dir
=
world_to_object
.
rotate
(
sample
.
direction
);
Vec3
in_dir
=
world_to_object
.
rotate
(
sample
.
direction
);
// If the light is below the horizon, ignore it
// If the light is below the horizon, ignore it
float
cos_theta
=
in_dir
.
y
;
float
cos_theta
=
in_dir
.
y
;
if
(
cos_theta
<=
0.0
f
)
continue
;
if
(
cos_theta
<=
0.0
f
)
continue
;
// If the BSDF has 0 throughput in this direction, ignore it
// If the BSDF has 0 throughput in this direction, ignore it
// This is another oppritunity to do Russian roulette on low-throughput rays,
// This is another oppritunity to do Russian roulette on low-throughput rays,
// which would allow us to skip the shadow ray cast, increasing efficiency.
// which would allow us to skip the shadow ray cast, increasing efficiency.
Spectrum
absorbsion
=
bsdf
.
evaluate
(
out_dir
,
in_dir
);
Spectrum
absorbsion
=
bsdf
.
evaluate
(
out_dir
,
in_dir
);
if
(
absorbsion
.
luma
()
==
0.0
f
)
continue
;
if
(
absorbsion
.
luma
()
==
0.0
f
)
continue
;
// TODO (PathTracer): Task 4
// TODO (PathTracer): Task 4
// Construct a shadow ray and compute whether the intersected surface is
// Construct a shadow ray and compute whether the intersected surface is
// in shadow. Only accumulate light if not in shadow.
// in shadow. Only accumulate light if not in shadow.
// Tip: when making your ray, you will want to slightly offset it from the
// Tip: when making your ray, you will want to slightly offset it from the
// surface it starts on, lest it intersect at time=0. Similarly, you may want
// surface it starts on, lest it intersect at time=0. Similarly, you may want
// to limit the ray slightly before it would hit the light itself.
// to limit the ray slightly before it would hit the light itself.
// Note: that along with the typical cos_theta, pdf factors, we divide by samples.
// Note: that along with the typical cos_theta, pdf factors, we divide by samples.
// This is because we're doing another monte-carlo estimate of the lighting from area lights.
// This is because we're doing another monte-carlo estimate of the lighting from
// area lights.
radiance_out
+=
(
cos_theta
/
(
samples
*
sample
.
pdf
))
*
sample
.
radiance
*
absorbsion
;
radiance_out
+=
(
cos_theta
/
(
samples
*
sample
.
pdf
))
*
sample
.
radiance
*
absorbsion
;
}
}
};
};
// If the BSDF is discrete (i.e. uses dirac deltas/if statements), then we are never
// If the BSDF is discrete (i.e. uses dirac deltas/if statements), then we are never
// going to hit the exact right direction by sampling lights, so ignore them.
// going to hit the exact right direction by sampling lights, so ignore them.
if
(
!
bsdf
.
is_discrete
())
{
if
(
!
bsdf
.
is_discrete
())
{
for
(
const
auto
&
light
:
lights
)
for
(
const
auto
&
light
:
lights
)
sample_light
(
light
);
sample_light
(
light
);
if
(
env_light
.
has_value
())
if
(
env_light
.
has_value
())
sample_light
(
env_light
.
value
());
sample_light
(
env_light
.
value
());
}
}
}
}
// TODO (PathTracer): Task 5
// TODO (PathTracer): Task 5
// Compute an indirect lighting estimate using pathtracing with Monte Carlo.
// Compute an indirect lighting estimate using pathtracing with Monte Carlo.
// (1) Ray objects have a depth field; you should use this to avoid
// (1) Ray objects have a depth field; you should use this to avoid
// traveling down one path forever.
// traveling down one path forever.
// (2) randomly select a new ray direction (it may be reflection or transmittence
// (2) randomly select a new ray direction (it may be reflection or transmittence
// ray depending on surface type) using bsdf.sample()
// ray depending on surface type) using bsdf.sample()
// (3) potentially terminate path (using Russian roulette). You can make this
// (3) potentially terminate path (using Russian roulette). You can make this
// a function of the bsdf attenuation or track overall ray throughput
// a function of the bsdf attenuation or track overall ray throughput
// (4) create new scene-space ray and cast it to get incoming light
// (4) create new scene-space ray and cast it to get incoming light
// (5) add contribution due to incoming light with proper weighting
// (5) add contribution due to incoming light with proper weighting
return
radiance_out
;
return
radiance_out
;
}
}
}
}
// namespace PT
Prev
1
2
3
4
5
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment