我有点好奇,所以我编码了一个照明面编码的小例子
for each pixel of input image
height = (color_intensity)*scale
这是我测试的输入图像
(谷歌搜索中的第一幅漂亮的油画)
:
This is the result (point cloud 3D preview)
左边是GIF动画,如果动画已经停止,请重新加载/刷新页面以查看动画,或者下载GIF并在更高级的东西中打开,然后用brownser进行GIF预览...。右边是彩色点云预览(静态图像)。
This is the C++ code for computing this:
OpenGLtexture zed,nx,ny,nz; // height map,normal maps (just 2D images)
picture pic; // source image
int x,y,a;
// resize textures to source image size
zed.resize(pic.xs,pic.ys);
nx.resize(pic.xs,pic.ys); float *pnx=(float*) nx.txr;
ny.resize(pic.xs,pic.ys); float *pny=(float*) ny.txr;
nz.resize(pic.xs,pic.ys); float *pnz=(float*) nz.txr;
// prepare tmp image for height map extraction
picture pic0;
pic0=pic; // copy
pic0.rgb2i(); // grayscale
// this computes the point cloud (this is the only important stuff from this code)
// as you can see there are just 3 lines of code important from all of this
for (a=0,y=0;y<pic.ys;y++)
for (x=0;x<pic.xs;x++,a++)
zed.txr[a]=pic0.p[y][x].dd>>3; // height = intensity/(2^3)
// compute normals (for OpenGL rendering only)
double n[3],p0[3],px[3],py[3];
int zedx,zedy,picx,picy;
for (a=zed.xs,zedy=-(pic.ys>>1),picy=1;picy<pic.ys;picy++,zedy++)
for (a++, zedx=-(pic.xs>>1),picx=1;picx<pic.xs;picx++,zedx++,a++)
vector_ld(p0,zedx-1,zedy ,-zed.txr[a -1]); // 3 neighboring points
vector_ld(py,zedx ,zedy-1,-zed.txr[a+zed.xs ]);
vector_ld(px,zedx ,zedy ,-zed.txr[a ]);
vector_sub(px,p0,px); // 2 vectors (latices of quad/triangle)
vector_sub(py,p0,py);
vector_mul(n,px,py); // cross product
vector_one(n,n); // unit vector normalization
pnx[a]=n[0]; // store vector components to textures
pny[a]=n[1];
pnz[a]=n[2];
Here OpenGL preview code (C++):
scr.cls(); // clear buffers
scr.set_perspective(); // set camera matrix
glMatrixMode(GL_MODELVIEW); // set object matrix
rep.use_rep();
glLoadMatrixd(rep.rep);
// directional (normal shading)
float lightAmbient [4]={0.20,0.20,0.20,1.00};
float lightDiffuse [4]={1.00,1.00,1.00,1.00};
float lightDirection[4]={0.00,0.00,+1.0,0.00};
glLightfv(GL_LIGHT1,GL_AMBIENT ,lightAmbient );
glLightfv(GL_LIGHT1,GL_DIFFUSE ,lightDiffuse );
glLightfv(GL_LIGHT1,GL_POSITION,lightDirection);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL);
// render point cloud
int zedx,zedy,picx,picy,a;
glColor3f(0.7,0.7,0.7);
float *pnx=(float*)nx.txr;
float *pny=(float*)ny.txr;
float *pnz=(float*)nz.txr;
glBegin(GL_POINTS);
for (a=zed.xs,zedy=-(pic.ys>>1),picy=1;picy<pic.ys;picy++,zedy++)
for (a++, zedx=-(pic.xs>>1),picx=1;picx<pic.xs;picx++,zedx++,a++)
//glColor4ubv((BYTE*)&pic.p[picy][picx].dd); // this is coloring with original image colors but it hides the 3D effect
glNormal3f(pnx[a],pny[a],pnz[a]); // normal for lighting
glVertex3i(zedx ,zedy ,-zed.txr[a]); // this is the point cloud surface point coordinate
glEnd();
scr.exe(); // finalize OpenGL calls and swap buffers ...
scr.rfs();
矩阵是这样设置的。
// gluProjection parameters
double f=100; //[pixels] focus
scr.views[0].znear= f; //[pixels]
scr.views[0].zfar =1000.0+f; //[pixels]
scr.views[0].zang = 60.0; //[deg] view projection angle
scr.init(this); // this compute the Projection matrix and init OpenGL
// place the painting surface in the middle of frustrum
rep.reset();
rep.gpos_set(vector_ld(0.0,0.0,-0.5*(scr.views[0].zfar+scr.views[0].znear)));
rep.lrotx(180.0*deg); // rotate it to match original image
[notes]
我正在使用自己的图片类,所以这里有一些成员。
xs,ys
size of image in pixels
p[y][x].dd
is pixel at (x,y) position as 32 bit integer type
p[y][x].db[4]
is pixel access by color bands (r,g,b,a)
我还使用了自定义的OpenGlscr
和Texture Clases。
xs,ys
size of buffer in pixels
Texture::txr
is 32bit pixel pointer (image is allocated as linear 1D array)
height map is used to store int values
normal maps is used to store float normal vector components
The only thing left to do is:
filter the pointcloud to your liking
triangulate/export to mesh supported by your printer
还有其他方法可以将光照编码到表面。
你可以做这样的事情菲涅尔透镜表面
so divide mesh to segments
and offset each so it starts from the same reference plane (z offset)
这需要更少的体积/材料
动画的前半部分是正常的高度编码,然后切换到菲涅尔表面编码/包装,以进行比较
编码照度不是作为高度图,而是作为粗糙度图而不是
each pixel will be mapped into small sub height map
flat surface is high illumination/intensity of color
rough surface is black
and in between are the shades of gray