You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.9 KiB
145 lines
4.9 KiB
1 year ago
|
#include <igl/opengl/glfw/Viewer.h>
|
||
|
#include <igl/read_triangle_mesh.h>
|
||
|
#include <igl/triangulated_grid.h>
|
||
|
#include <igl/stb/read_image.h>
|
||
|
#include <igl/get_seconds.h>
|
||
|
#include <igl/PI.h>
|
||
|
#include <Eigen/Core>
|
||
|
|
||
|
#include <algorithm>
|
||
|
|
||
|
void floor(const Eigen::MatrixXd & V,
|
||
|
Eigen::MatrixXd & fV,
|
||
|
Eigen::MatrixXd & fU,
|
||
|
Eigen::MatrixXi & fF)
|
||
|
{
|
||
|
igl::triangulated_grid(2,2,fU,fF);
|
||
|
fV = fU;
|
||
|
fV.array() -= 0.5;
|
||
|
fV.array() *= 2 * 2 *
|
||
|
(V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
|
||
|
fV = (fV * (Eigen::Matrix<double,2,3>()<<1,0,0,0,0,-1).finished() ).eval();
|
||
|
fV.col(0).array() += 0.5*(V.col(0).minCoeff()+ V.col(0).maxCoeff());
|
||
|
fV.col(1).array() += V.col(1).minCoeff();
|
||
|
fV.col(2).array() += 0.5*(V.col(2).minCoeff()+ V.col(2).maxCoeff());
|
||
|
}
|
||
|
|
||
|
void checker_texture(const int s, const int f,
|
||
|
Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & X,
|
||
|
Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> & A)
|
||
|
{
|
||
|
X.resize(s*f,s*f);
|
||
|
A.resize(s*f,s*f);
|
||
|
for(int i = 0;i<s*f;i++)
|
||
|
{
|
||
|
const double x = double(i)/double(s*f-1)*2-1;
|
||
|
for(int j = 0;j<s*f;j++)
|
||
|
{
|
||
|
const int u = i/f;
|
||
|
const int v = j/f;
|
||
|
const double y = double(j)/double(s*f-1)*2-1;
|
||
|
const double r1 = std::min(std::max( (1.0 - sqrt(x*x+y*y))*1.0 ,0.0),1.0);
|
||
|
const double r3 = std::min(std::max( (1.0 - sqrt(x*x+y*y))*3.0 ,0.0),1.0);
|
||
|
//const double a = 3*r*r - 2*r*r*r;
|
||
|
const auto smooth_step = [](const double w)
|
||
|
{
|
||
|
return ((w * (w * 6.0 - 15.0) + 10.0) * w * w * w) ;
|
||
|
};
|
||
|
double a3 = smooth_step(r1);
|
||
|
double a1 = smooth_step(r1);
|
||
|
X(i,j) = (0.75+0.25*a1) * (u%2 == v%2 ? 245 : 235);
|
||
|
A(i,j) = a3 * 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
igl::opengl::glfw::Viewer vr;
|
||
|
Eigen::MatrixXd V;
|
||
|
Eigen::MatrixXi F;
|
||
|
igl::read_triangle_mesh(
|
||
|
argc>1?argv[1]: TUTORIAL_SHARED_PATH "/armadillo.obj",V,F);
|
||
|
|
||
|
// Create a floor
|
||
|
Eigen::MatrixXd fV, fU;
|
||
|
Eigen::MatrixXi fF;
|
||
|
floor(V,fV,fU,fF);
|
||
|
const int s = 16;
|
||
|
const int f = 100;
|
||
|
Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> X;
|
||
|
Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> A;
|
||
|
checker_texture(s,f,X,A);
|
||
|
vr.data().set_mesh(fV,fF);
|
||
|
vr.data().set_uv(fU);
|
||
|
vr.data().uniform_colors(Eigen::Vector3d(0.3,0.3,0.3),Eigen::Vector3d(0.8,0.8,0.8),Eigen::Vector3d(0,0,0));
|
||
|
vr.data().set_texture(X,X,X,A);
|
||
|
vr.data().show_texture = true;
|
||
|
vr.data().show_lines = false;
|
||
|
|
||
|
// Move the light a bit off center to cast a more visible shadow.
|
||
|
vr.core().light_position << 1.0f, 2.0f, 0.0f;
|
||
|
// For now, the default is a positional light with no shadows. Meanwhile,
|
||
|
// shadows only support a directional light. To best match the appearance of
|
||
|
// current lighting use this conversion when turning on shadows. In the
|
||
|
// future, hopefully this will reduce to just
|
||
|
// core().is_shadow_mapping = true
|
||
|
vr.core().is_directional_light = true;
|
||
|
vr.core().light_position = vr.core().light_position + vr.core().camera_eye;
|
||
|
vr.core().is_shadow_mapping = true;
|
||
|
|
||
|
// Send the main object to the viewer
|
||
|
vr.append_mesh();
|
||
|
vr.data().set_mesh(V,F);
|
||
|
vr.data().show_lines = false;
|
||
|
vr.data().set_face_based(true);
|
||
|
|
||
|
// If a second argument is present read it as a matcap
|
||
|
if(argc>2)
|
||
|
{
|
||
|
Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> R,G,B,A;
|
||
|
igl::stb::read_image(argv[2],R,G,B,A);
|
||
|
// If more args, read them as light direction
|
||
|
if(argc>2+3)
|
||
|
{
|
||
|
Eigen::Vector3f D;
|
||
|
D << std::atof(argv[3]), std::atof(argv[4]), std::atof(argv[5]);
|
||
|
D.normalize();
|
||
|
vr.core().light_position = D;
|
||
|
Eigen::Vector3d Ka(0.14,0.14,0.14);
|
||
|
if(argc>2+3+1 && std::atoi(argv[6]))
|
||
|
{
|
||
|
// Assume that color opposite D along umbra boundary is ambient color
|
||
|
const double s = -D(2)*1.0/sqrt((D(0)*D(0)+D(1)*D(1))*(D(0)*D(0)+D(1)*D(1)+D(2)*D(2)));
|
||
|
const int i = ((D(0)*s)*0.5+0.5)*R.cols();
|
||
|
const int j = ((D(1)*s)*0.5+0.5)*R.rows();
|
||
|
Ka << double(R(i,j))/255.0, double(G(i,j))/255.0, double(B(i,j))/255.0;
|
||
|
}
|
||
|
std::cout<<"Ka : "<<Ka<<std::endl;
|
||
|
// viewer only exposes ambient color through per-face and per-vertex
|
||
|
// materials
|
||
|
vr.data().V_material_ambient.col(0).setConstant( Ka(0) );
|
||
|
vr.data().V_material_ambient.col(1).setConstant( Ka(1) );
|
||
|
vr.data().V_material_ambient.col(2).setConstant( Ka(2) );
|
||
|
vr.data().F_material_ambient.col(0).setConstant( Ka(0) );
|
||
|
vr.data().F_material_ambient.col(1).setConstant( Ka(1) );
|
||
|
vr.data().F_material_ambient.col(2).setConstant( Ka(2) );
|
||
|
}
|
||
|
vr.data().set_texture(R,G,B,A);
|
||
|
vr.data().use_matcap = true;
|
||
|
}
|
||
|
vr.core().is_animating = true;
|
||
|
vr.core().camera_zoom *= 1.5;
|
||
|
vr.callback_pre_draw = [&](decltype(vr)&)
|
||
|
{
|
||
|
if(vr.core().is_animating)
|
||
|
{
|
||
|
vr.core().trackball_angle = Eigen::AngleAxisf(
|
||
|
sin(igl::get_seconds())*igl::PI*0.5,
|
||
|
Eigen::Vector3f(0,1,0));
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
vr.launch();
|
||
|
}
|