纹理采样和过滤

论坛 期权论坛 脚本     
匿名网站用户   2020-12-20 02:46   17   0

纹理采样


在opengl和directx里有纹理采样函数vector4 Sampler.texture2d(float s,float t),用它可以取得对应纹理坐标的纹理值;然而,并不知道这个函数的具体实现是怎么样的.事实上从图像读取的纹理就是一个数组,类似这样:

  1. imgData=newunsignedchar[width*height*3];

纹理坐标可以转换为数组的下标,类似这样:

  1. floatu=(float)(width-1)*s;
  2. floatv=(float)(height-1)*(1.0-t);
  3. intiu=(int)u;
  4. intiv=(int)v;

纹理坐标s和t的范围是0到1,这边采用的是opengl的坐标系,y轴从下到上递增,但是图片保存的坐标系y轴是从上到下递增,所以1.0-t做y轴取反以获得opengl坐标系的对应的纹理坐标,这边运算出的u和v的范围是0到纹理宽和0到纹理高,然后将v乘以纹理宽加上u然后乘以3(一个纹理包含rgb分量)即可获得数组下标:

  1. intimgIndex=3*(iv*width+iu);
最后通过数组下标取得对应的纹理值:
  1. color.x=(float)imgData[imgIndex]*INV_SCALE;
  2. color.y=(float)imgData[imgIndex+1]*INV_SCALE;
  3. color.z=(float)imgData[imgIndex+2]*INV_SCALE;
这边直接把1/255作为一个宏可以加快运算速度:
  1. #defineINV_SCALE0.003921568627451

然后return color;即可获得纹理颜色值,以上就是POINT/NEAREST采样的实现.事实上这是最基本的纹理采样函数实现,这里边还有问题,效果不是很好.


线性纹理过滤


POINT/NEAREST采样固然能够取得纹理的颜色值,但是效果看上去很差,有大块的走样,上面有这样的代码:
  1. intiu=(int)u;
  2. intiv=(int)v;
问题就出在这里,(int)这样直接抛弃小数点以后的值导致采样出的相邻纹理并不连续,那么用float采样行吗? 答案是:不行! 这边实现的采样函数是从数组取值,纹理坐标转为数组下标,数组下标不能用float只能用int,那么就没办法了吗? 并不是,可以对周围纹理进行采样然后按照各自比例进行混合,这样能够提高显示效果.原理如下:
例如计算出的u和v类似这样:3.45,4.55 那么u就在3到4之间,v在4到5之间,比例是(1-0.45):0.45和(1-0.55):0.55,那么对(3,4),(4,4),(3,5),(4,5)进行采样,然后乘以各自比例进行颜色混合计算即可得出经过过滤的颜色值.
具体实现如下:
  1. VECTOR4DSampler::texture2D(floats,floatt){
  2. VECTOR4Dcolor(1,1,1,1);
  3. floatu=(float)(width-1)*s;
  4. floatv=(float)(height-1)*(1.0-t);
  5. intiu=(int)u;
  6. intiv=(int)v;
  7. intuNext=iu+1<=(width-1)?iu+1:iu;
  8. intvNext=iv+1<=(height-1)?iv+1:iv;
  9. floatuNextPer=u-iu;
  10. floatvNextPer=v-iv;
  11. floatuPer=1.0-uNextPer;
  12. floatvPer=1.0-vNextPer;
  13. intimgIndex=3*(iv*width+iu);
  14. color.x=(float)imgData[imgIndex]*INV_SCALE;
  15. color.y=(float)imgData[imgIndex+1]*INV_SCALE;
  16. color.z=(float)imgData[imgIndex+2]*INV_SCALE;
  17. intimgIndexNextU=3*(iv*width+uNext);
  18. intimgIndexNextV=3*(vNext*width+iu);
  19. intimgIndexNextUV=3*(vNext*width+uNext);
  20. VECTOR4DcolorNextU(1,1,1,1),colorNextV(1,1,1,1),colorNextUV(1,1,1,1);
  21. colorNextU.x=(float)imgData[imgIndexNextU]*INV_SCALE;
  22. colorNextU.y=(float)imgData[imgIndexNextU+1]*INV_SCALE;
  23. colorNextU.z=(float)imgData[imgIndexNextU+2]*INV_SCALE;
  24. colorNextV.x=(float)imgData[imgIndexNextV]*INV_SCALE;
  25. colorNextV.y=(float)imgData[imgIndexNextV+1]*INV_SCALE;
  26. colorNextV.z=(float)imgData[imgIndexNextV+2]*INV_SCALE;
  27. colorNextUV.x=(float)imgData[imgIndexNextUV]*INV_SCALE;
  28. colorNextUV.y=(float)imgData[imgIndexNextUV+1]*INV_SCALE;
  29. colorNextUV.z=(float)imgData[imgIndexNextUV+2]*INV_SCALE;
  30. color.x=color.x*uPer*vPer+colorNextU.x*uNextPer*vPer+colorNextV.x*uPer*vNextPer+colorNextUV.x*uNextPer*vNextPer;
  31. color.y=color.y*uPer*vPer+colorNextU.y*uNextPer*vPer+colorNextV.y*uPer*vNextPer+colorNextUV.y*uNextPer*vNextPer;
  32. color.z=color.z*uPer*vPer+colorNextU.z*uNextPer*vPer+colorNextV.z*uPer*vNextPer+colorNextUV.z*uNextPer*vNextPer;
  33. returncolor;
  34. }
这样得出的纹理颜色比之前点采样的看上去好多了.

渲染到纹理


现代opengl和directx都有FrameBuffer/RenderTarget功能,有了这项功能可以进行Render To Texture(渲染到纹理)操作.RTT操作的具体应用有很多,最普遍的应用莫过于Shadow Map技术.事实上RTT的具体实现方法就是把渲染缓冲区的值复制给纹理数组,也并没有多少复杂的,具体实现如下:
  1. voidwriteFrameBuffer2Sampler(FrameBuffer*fb,Sampler*sampler){
  2. for(inti=0;i<fb->height;i++){
  3. for(intj=0;j<fb->width;j++){
  4. intindex=(i*fb->width+j)*3;
  5. sampler->imgData[((i)*fb->width+j)*3]=fb->colorBuffer[index];
  6. sampler->imgData[((i)*fb->width+j)*3+1]=fb->colorBuffer[index+1];
  7. sampler->imgData[((i)*fb->width+j)*3+2]=fb->colorBuffer[index+2];
  8. }
  9. }
  10. }
那样,渲染得到的结果就可以作为纹理使用了.

调用方法


类似opengl和directx在shader里调用纹理采样函数,这边模拟了opengl的shader:
  1. voidfragmentShader(Fragmentinput,FragmentOut&output){
  2. VECTOR4DtexColor(1,1,1,1);
  3. if(currTexture!=NULL)
  4. texColor=currTexture->texture2D(input.s,input.t);
  5. output.r=texColor.x;
  6. output.g=texColor.y;
  7. output.b=texColor.z;
  8. output.a=texColor.w;
  9. }
FragmentShader在光栅化函数rasterize中调用,每生成一个fragment则调用一次FragmentShader.

图片数据加载参见:http://blog.csdn.net/zxx43/article/details/41594871
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP