Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
formation
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jean-Claude Iehl
formation
Commits
28021116
Commit
28021116
authored
Mar 20, 2024
by
jean-claude iehl
Browse files
Options
Downloads
Patches
Plain Diff
et le code...
parent
ae71b5b9
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
code/projects/path_sobol.cpp
+380
-0
380 additions, 0 deletions
code/projects/path_sobol.cpp
with
380 additions
and
0 deletions
code/projects/path_sobol.cpp
0 → 100644
+
380
−
0
View file @
28021116
#include
<omp.h>
#include
<chrono>
#include
<random>
#include
<stdint.h>
#include
"options.h"
#include
"vec.h"
#include
"mat.h"
#include
"color.h"
#include
"framebuffer.h"
#include
"image.h"
#include
"image_io.h"
#include
"gltf/gltf.h"
#include
"gltf/scene.h"
#include
"orbiter.h"
#include
"sampler.h"
#include
"sampler_sobol.h"
// utilise sobol' global
typedef
Sobol
Sampler
;
Options
options
;
Color
direct
(
const
Point
&
o
,
const
Point
&
p
,
const
Brdf
&
pbrdf
,
const
Scene
&
scene
,
Sampler
&
rng
)
{
Color
color
;
/* strategie 1 : genere un point sur une source
*/
const
Source
&
source
=
scene
.
sources
.
sample
(
rng
.
sample
()
);
Point
s
=
source
.
sample
(
rng
.
sample
(),
rng
.
sample
()
);
Vector
sn
=
source
.
n
;
Vector
l
=
normalize
(
Vector
(
p
,
s
)
);
float
cos_theta
=
std
::
max
(
float
(
0
),
dot
(
pbrdf
.
world
.
n
,
l
));
float
cos_theta_s
=
std
::
max
(
float
(
0
),
dot
(
sn
,
-
l
));
float
G
=
cos_theta_s
/
distance2
(
p
,
s
);
float
pdf
=
source
.
pdf
(
s
)
*
scene
.
sources
.
pdf
(
source
);
if
(
pdf
*
cos_theta
*
cos_theta_s
>
0
&&
scene
.
visible
(
offset_point
(
p
,
pbrdf
.
world
.
n
),
offset_point
(
s
,
sn
)
))
{
Color
fr
=
pbrdf
.
f
(
l
,
normalize
(
o
-
p
));
color
=
color
+
source
.
emission
*
G
*
fr
*
cos_theta
/
pdf
;
}
/* strategie 2 : genere une direction en fonction de la matiere
Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p));
float pdf= pbrdf.pdf( l, normalize(o - p) );
float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
if(pdf * cos_theta > 0
&& scene.visible(offset_point(p, pbrdf.world.n), l))
{
Color fr= pbrdf.f(l, normalize(o - p));
color= color + Color(0.02) * fr * cos_theta / pdf;
}
*/
return
color
;
}
// mis multi-sample, evalue les 2 integrales + ponderation de chaque echantillon
Color
direct_mis
(
const
Point
&
o
,
const
Point
&
p
,
const
Brdf
&
pbrdf
,
Hit
&
qhit
,
const
Scene
&
scene
,
Sampler
&
rng
)
{
Color
color
;
// strategie 1 : selectionne une source + un point sur la source
{
const
Source
&
source
=
scene
.
sources
.
sample
(
rng
.
sample
()
);
Point
s
=
source
.
sample
(
rng
.
sample
(),
rng
.
sample
()
);
Vector
sn
=
source
.
n
;
Vector
l
=
normalize
(
Vector
(
p
,
s
)
);
float
cos_theta
=
std
::
max
(
float
(
0
),
dot
(
pbrdf
.
world
.
n
,
l
));
float
cos_theta_s
=
std
::
max
(
float
(
0
),
dot
(
sn
,
-
l
));
float
G
=
cos_theta_s
/
distance2
(
p
,
s
);
if
(
G
*
cos_theta
>
0
)
{
float
pdf1
=
source
.
pdf
(
s
)
*
scene
.
sources
.
pdf
(
source
);
if
(
pdf1
>
0
)
{
if
(
scene
.
visible
(
offset_point
(
p
,
pbrdf
.
world
.
n
),
offset_point
(
s
,
sn
)
)
)
{
float
pdf2
=
pbrdf
.
pdf
(
l
,
normalize
(
Vector
(
p
,
o
)
))
*
G
;
float
w
=
(
pdf1
*
pdf1
)
/
(
pdf1
*
pdf1
+
pdf2
*
pdf2
);
// pdf1 et pdf2 sur les aires, power heuristic
Color
fr
=
pbrdf
.
f
(
l
,
normalize
(
o
-
p
));
color
=
color
+
w
*
source
.
emission
*
fr
*
G
*
cos_theta
/
pdf1
;
}
}
}
}
// strategie 2 : selectionne un terme de la brdf et genere une direcion
{
Vector
l
=
pbrdf
.
sample
(
rng
.
sample
(),
rng
.
sample
(),
rng
.
sample
(),
normalize
(
o
-
p
)
);
float
pdf2
=
pbrdf
.
pdf
(
l
,
normalize
(
o
-
p
)
);
if
(
pdf2
>
0
)
{
Ray
ray
(
offset_point
(
p
,
pbrdf
.
world
.
n
),
l
);
if
(
Hit
hit
=
scene
.
intersect
(
ray
))
{
Color
emission
=
scene
.
material
(
hit
).
emission
;
if
(
emission
.
max
()
>
0
)
{
Point
s
=
ray
.
o
+
ray
.
d
*
hit
.
t
;
Vector
sn
=
scene
.
normal
(
hit
);
float
cos_theta
=
std
::
max
(
float
(
0
),
dot
(
pbrdf
.
world
.
n
,
l
));
float
cos_theta_s
=
std
::
max
(
float
(
0
),
dot
(
sn
,
-
l
));
float
G
=
cos_theta_s
/
distance2
(
p
,
s
);
if
(
G
*
cos_theta
>
0
)
{
pdf2
=
pdf2
*
G
;
float
pdf1
=
1
/
scene
.
sources
.
area
;
float
w
=
(
pdf2
*
pdf2
)
/
(
pdf1
*
pdf1
+
pdf2
*
pdf2
);
// pdf1 et pdf2 sur les aires, power heuristic
Color
fr
=
pbrdf
.
f
(
l
,
normalize
(
o
-
p
));
color
=
color
+
w
*
emission
*
fr
*
G
*
cos_theta
/
pdf2
;
}
}
else
// conserve le point pour prolonger le chemin...
qhit
=
hit
;
}
}
}
return
color
;
}
Color
path
(
const
int
depth
,
const
Point
&
o
,
const
Point
&
p
,
const
Brdf
&
pbrdf
,
const
Scene
&
scene
,
Sampler
&
rng
)
{
Hit
qhit
;
//~ Color color= direct(o, p, pbrdf, scene, rng );
Color
color
=
direct_mis
(
o
,
p
,
pbrdf
,
qhit
,
scene
,
rng
);
if
(
depth
==
0
)
return
color
;
// recuperer l'intersection mis du direct... cf direct_mis, elimine un rayon par rebond
if
(
qhit
)
{
Point
q
=
scene
.
position
(
qhit
);
Vector
l
=
normalize
(
q
-
p
);
float
pdf
=
pbrdf
.
pdf
(
l
,
normalize
(
o
-
p
));
if
(
pdf
>
0
)
// ne devrait pas arriver...
{
Vector
qn
=
scene
.
normal
(
qhit
);
Brdf
qbrdf
=
scene
.
brdf
(
qhit
,
qn
);
float
cos_theta
=
std
::
max
(
float
(
0
),
dot
(
pbrdf
.
world
.
n
,
l
));
Color
fr
=
pbrdf
.
f
(
l
,
normalize
(
o
-
p
));
return
color
+
path
(
depth
-
1
,
p
,
q
,
qbrdf
,
scene
,
rng
)
*
fr
*
cos_theta
/
pdf
;
}
}
/* sinon genere une direction pour prolonger le chemin...
Vector l= pbrdf.sample( rng.sample(), rng.sample(), rng.sample(), normalize(o - p) );
float pdf= pbrdf.pdf(l, normalize(Vector(p, o)));
if(pdf > 0)
{
Ray ray( offset_point(p, pbrdf.world.n), l );
if(Hit hit= scene.intersect(ray))
{
Point q= scene.position(hit, ray);
Vector qn= scene.normal(hit);
Brdf qbrdf= scene.brdf(hit, qn);
float cos_theta= std::max(float(0), dot(pbrdf.world.n, l));
Color fr= pbrdf.f(l, normalize(o - p));
return color + path(depth -1, p, q, qbrdf, scene, rng) * fr * cos_theta / pdf;
}
}
*/
return
color
;
}
struct
alpha_filter
{
const
Scene
&
scene
;
FCRNG
&
rng
;
alpha_filter
(
const
Scene
&
_scene
,
FCRNG
&
_rng
)
:
scene
(
_scene
),
rng
(
_rng
)
{}
bool
operator
()
(
const
Hit
&
hit
)
const
{
const
GLTFMaterial
&
material
=
scene
.
material
(
hit
);
if
(
material
.
color_texture
==
-
1
)
return
true
;
if
(
scene
.
textures
[
material
.
color_texture
].
opaque
)
return
true
;
vec3
uv_lod
=
scene
.
texcoords_lod
(
hit
);
Color
diffuse
=
scene
.
textures
[
material
.
color_texture
].
sample
(
uv_lod
.
x
,
uv_lod
.
y
,
uv_lod
.
z
);
return
(
rng
.
sample
()
<=
diffuse
.
a
);
}
};
int
main
(
const
int
argc
,
const
char
**
argv
)
{
options
=
Options
(
argv
,
argv
+
argc
);
Scene
scene
=
read_scene
(
options
.
filename
);
if
(
scene
.
gltf
.
nodes
.
empty
())
return
1
;
// pas de geometrie, pas d'image
// transformations
Transform
view
;
Transform
projection
;
float
aspect
=
1
;
if
(
options
.
orbiter_filename
)
{
Orbiter
camera
;
if
(
camera
.
read_orbiter
(
options
.
orbiter_filename
)
==
false
)
return
1
;
// pas de camera, pas d'image
view
=
camera
.
view
();
projection
=
camera
.
projection
();
aspect
=
camera
.
aspect
();
}
else
if
(
scene
.
gltf
.
cameras
.
size
())
{
view
=
scene
.
camera
.
view
;
projection
=
scene
.
camera
.
projection
;
aspect
=
scene
.
camera
.
aspect
;
}
else
{
printf
(
"[error] no glTF camera...
\n
"
);
return
1
;
// pas de camera, pas d'image
}
if
(
scene
.
sources
.
size
()
==
0
)
{
printf
(
"[error] no emissive triangles / light sources...
\n
"
);
return
1
;
}
// proportions largeur/hauteur de la camera gltf
int
samples
=
options
.
samples
;
int
width
=
1024
;
int
height
=
width
/
aspect
;
Framebuffer
image
(
width
,
height
);
Image
aov_normal
(
width
,
height
);
Image
aov_albedo
(
width
,
height
);
// charge les textures + parametres de filtrage en fonction de l'image
read_textures
(
options
.
filename
,
scene
,
width
,
height
);
//~ read_textures(options.filename, scene, 256, 256);
//
Transform
viewport
=
Viewport
(
image
.
width
(),
image
.
height
());
Transform
inv
=
Inverse
(
viewport
*
projection
*
view
);
unsigned
maxdims
=
0
;
unsigned
lines
=
0
;
auto
cpu_start
=
std
::
chrono
::
high_resolution_clock
::
now
();
// determine les dimensions d'une image carre / puissance de 2
int
pow2
=
1
;
while
(
pow2
<
width
&&
pow2
<
height
)
pow2
*=
2
;
printf
(
"image %dx%d
\n
"
,
width
,
height
);
printf
(
"square image %dx%d
\n
"
,
pow2
,
pow2
);
// c'est parti ! parcours tous samples de la sequence de sobol
const
size_t
n
=
width
*
height
*
samples
;
#pragma omp parallel for schedule(dynamic, 4096)
for
(
size_t
i
=
0
;
i
<
n
;
i
++
)
{
Sobol
rng
;
rng
.
index
(
i
);
// les dimensions 0, 1 de la sequence de Sobol' choisissent le pixel
float
x
=
rng
.
sample
();
float
y
=
rng
.
sample
();
// rejette les echantillons en dehors de l'image
int
py
=
y
*
pow2
;
int
px
=
x
*
pow2
;
if
(
py
>=
height
)
continue
;
if
(
px
>=
width
)
continue
;
// generer le rayon
x
=
x
*
pow2
;
y
=
y
*
pow2
;
Point
origine
=
inv
(
Point
(
x
,
y
,
0
));
Point
extremite
=
inv
(
Point
(
x
,
y
,
1
));
Ray
ray
(
origine
,
extremite
);
Color
color
;
Vector
normal
;
Color
albedo
;
// todo : pour initialiser le rng d'alpha_filter, il faut recalculer le seed du pixel (px, py), cf path.cpp
// calculer les intersections avec tous les triangles
if
(
Hit
hit
=
scene
.
bvh
.
intersect
(
ray
))
//~ if(Hit hit= scene.bvh.intersect(ray, alpha_filter(scene, alpha_rng)))
{
Point
p
=
scene
.
position
(
hit
,
ray
);
Vector
pn
=
scene
.
normal
(
hit
);
// matiere emissive, si la source est orientee vers la camera
if
(
dot
(
pn
,
ray
.
d
)
<
0
)
{
const
GLTFMaterial
&
material
=
scene
.
material
(
hit
);
color
=
color
+
material
.
emission
;
// suppose que les normales des sources sont correctes...
}
if
(
dot
(
pn
,
ray
.
d
)
>
0
)
// mais ce n'est pas toujours le cas pour le reste de la geometrie...
pn
=
-
pn
;
Brdf
brdf
=
scene
.
brdf
(
hit
,
pn
);
//~ color= color + direct(origine, p, brdf, scene, rng);
color
=
color
+
path
(
options
.
depth
,
origine
,
p
,
brdf
,
scene
,
rng
);
normal
=
normal
+
pn
;
albedo
=
albedo
+
brdf
.
f
(
pn
,
normalize
(
ray
.
o
-
p
));
}
image
.
splat
(
px
,
py
,
color
);
// accumule l'echantillon
aov_normal
(
px
,
py
)
=
Color
(
normal
/
float
(
samples
),
1
);
// force une couleur opaque...
aov_albedo
(
px
,
py
)
=
Color
(
albedo
/
float
(
samples
),
1
);
// force une couleur opaque...
// #pragma omp compare // ne marche pas sur visual...
maxdims
=
std
::
max
(
rng
.
d
,
maxdims
);
}
printf
(
"sampler dimensions %u
\n
"
,
maxdims
);
auto
cpu_stop
=
std
::
chrono
::
high_resolution_clock
::
now
();
auto
cpu_time
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
cpu_stop
-
cpu_start
).
count
();
printf
(
"cpu %ds %03dms
\n
"
,
int
(
cpu_time
/
1000
),
int
(
cpu_time
%
1000
));
char
tmp
[
1024
];
//~ sprintf(tmp, "%s-%05u-%04u.png", options.prefix, unsigned(cpu_time), samples);
sprintf
(
tmp
,
"%s-%04u.png"
,
options
.
prefix
,
samples
);
printf
(
"writing '%s'...
\n
"
,
tmp
);
write_image_preview
(
image
.
flatten
(),
tmp
);
//~ sprintf(tmp, "%s-%05u-%04u.pfm", options.prefix, unsigned(cpu_time), samples);
sprintf
(
tmp
,
"%s-%04u.pfm"
,
options
.
prefix
,
samples
);
printf
(
"writing '%s'...
\n
"
,
tmp
);
write_image_pfm
(
image
.
flatten
(),
tmp
);
sprintf
(
tmp
,
"%s-normals-%04u.pfm"
,
options
.
prefix
,
samples
);
write_image_pfm
(
aov_normal
,
tmp
);
sprintf
(
tmp
,
"%s-albedo-%04u.pfm"
,
options
.
prefix
,
samples
);
write_image_pfm
(
aov_albedo
,
tmp
);
printf
(
"
\n
"
);
return
0
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
sign in
to comment