纹理采样和过滤
2017-04-15 09:09
169 查看
纹理采样
在opengl和directx里有纹理采样函数vector4 Sampler.texture2d(float s,float t),用它可以取得对应纹理坐标的纹理值;然而,并不知道这个函数的具体实现是怎么样的.事实上从图像读取的纹理就是一个数组,类似这样:[cpp]
view plain
copy
imgData=new unsigned char[width*height*3];
纹理坐标可以转换为数组的下标,类似这样:
[cpp]
view plain
copy
float u=(float)(width-1)*s;
float v=(float)(height-1)*(1.0-t);
int iu=(int)u;
int iv=(int)v;
纹理坐标s和t的范围是0到1,这边采用的是opengl的坐标系,y轴从下到上递增,但是图片保存的坐标系y轴是从上到下递增,所以1.0-t做y轴取反以获得opengl坐标系的对应的纹理坐标,这边运算出的u和v的范围是0到纹理宽和0到纹理高,然后将v乘以纹理宽加上u然后乘以3(一个纹理包含rgb分量)即可获得数组下标:
[cpp]
view plain
copy
int imgIndex=3*(iv*width+iu);
最后通过数组下标取得对应的纹理值:
[cpp]
view plain
copy
color.x=(float)imgData[imgIndex]*INV_SCALE;
color.y=(float)imgData[imgIndex+1]*INV_SCALE;
color.z=(float)imgData[imgIndex+2]*INV_SCALE;
这边直接把1/255作为一个宏可以加快运算速度:
[cpp]
view plain
copy
#define INV_SCALE 0.003921568627451
然后return color;即可获得纹理颜色值,以上就是POINT/NEAREST采样的实现.事实上这是最基本的纹理采样函数实现,这里边还有问题,效果不是很好.
线性纹理过滤
POINT/NEAREST采样固然能够取得纹理的颜色值,但是效果看上去很差,有大块的走样,上面有这样的代码:[cpp]
view plain
copy
int iu=(int)u;
int iv=(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)进行采样,然后乘以各自比例进行颜色混合计算即可得出经过过滤的颜色值.
具体实现如下:
[cpp]
view plain
copy
VECTOR4D Sampler::texture2D(float s,float t) {
VECTOR4D color(1,1,1,1);
float u=(float)(width-1)*s;
float v=(float)(height-1)*(1.0-t);
int iu=(int)u;
int iv=(int)v;
int uNext=iu+1<=(width-1)?iu+1:iu;
int vNext=iv+1<=(height-1)?iv+1:iv;
float uNextPer=u-iu;
float vNextPer=v-iv;
float uPer=1.0-uNextPer;
float vPer=1.0-vNextPer;
int imgIndex=3*(iv*width+iu);
color.x=(float)imgData[imgIndex]*INV_SCALE;
color.y=(float)imgData[imgIndex+1]*INV_SCALE;
color.z=(float)imgData[imgIndex+2]*INV_SCALE;
int imgIndexNextU=3*(iv*width+uNext);
int imgIndexNextV=3*(vNext*width+iu);
int imgIndexNextUV=3*(vNext*width+uNext);
VECTOR4D colorNextU(1,1,1,1),colorNextV(1,1,1,1),colorNextUV(1,1,1,1);
colorNextU.x=(float)imgData[imgIndexNextU]*INV_SCALE;
colorNextU.y=(float)imgData[imgIndexNextU+1]*INV_SCALE;
colorNextU.z=(float)imgData[imgIndexNextU+2]*INV_SCALE;
colorNextV.x=(float)imgData[imgIndexNextV]*INV_SCALE;
colorNextV.y=(float)imgData[imgIndexNextV+1]*INV_SCALE;
colorNextV.z=(float)imgData[imgIndexNextV+2]*INV_SCALE;
colorNextUV.x=(float)imgData[imgIndexNextUV]*INV_SCALE;
colorNextUV.y=(float)imgData[imgIndexNextUV+1]*INV_SCALE;
colorNextUV.z=(float)imgData[imgIndexNextUV+2]*INV_SCALE;
color.x=color.x*uPer*vPer+colorNextU.x*uNextPer*vPer+colorNextV.x*uPer*vNextPer+colorNextUV.x*uNextPer*vNextPer;
color.y=color.y*uPer*vPer+colorNextU.y*uNextPer*vPer+colorNextV.y*uPer*vNextPer+colorNextUV.y*uNextPer*vNextPer;
color.z=color.z*uPer*vPer+colorNextU.z*uNextPer*vPer+colorNextV.z*uPer*vNextPer+colorNextUV.z*uNextPer*vNextPer;
return color;
}
这样得出的纹理颜色比之前点采样的看上去好多了.
渲染到纹理
现代opengl和directx都有FrameBuffer/RenderTarget功能,有了这项功能可以进行Render To Texture(渲染到纹理)操作.RTT操作的具体应用有很多,最普遍的应用莫过于Shadow Map技术.事实上RTT的具体实现方法就是把渲染缓冲区的值复制给纹理数组,也并没有多少复杂的,具体实现如下:[cpp]
view plain
copy
void writeFrameBuffer2Sampler(FrameBuffer* fb,Sampler* sampler) {
for(int i=0;i<fb->height;i++) {
for(int j=0;j<fb->width;j++) {
int index=(i*fb->width+j)*3;
sampler->imgData[((i)*fb->width+j)*3]=fb->colorBuffer[index];
sampler->imgData[((i)*fb->width+j)*3+1]=fb->colorBuffer[index+1];
sampler->imgData[((i)*fb->width+j)*3+2]=fb->colorBuffer[index+2];
}
}
}
那样,渲染得到的结果就可以作为纹理使用了.
调用方法
类似opengl和directx在shader里调用纹理采样函数,这边模拟了opengl的shader:[cpp]
view plain
copy
void fragmentShader(Fragment input,FragmentOut& output) {
VECTOR4D texColor(1,1,1,1);
if(currTexture!=NULL)
texColor=currTexture->texture2D(input.s,input.t);
output.r=texColor.x;
output.g=texColor.y;
output.b=texColor.z;
output.a=texColor.w;
}
FragmentShader在光栅化函数rasterize中调用,每生成一个fragment则调用一次FragmentShader.
图片数据加载参见: http://blog.csdn.net/zxx43/article/details/41594871
相关文章推荐
- Unity Shader 设置纹理采样tex2D过滤方式
- 纹理采样和过滤
- 纹理采样过滤方式
- 纹理过滤相关内容
- 纹理 放大缩小过滤
- Shader学习 基于vert/frag顶点片段级的纹理采样 光照贴图实现
- 纹理采样的理论与实现
- vtk体绘制时采样的起点使用噪声纹理来进行扰动
- Direct3D9纹理坐标采样的计算方法
- DirectX11 纹理采样
- (转)纹理映射过滤
- OGL纹理坐标计算和纹理边框颜色环绕模式过滤方法
- Unity中写GLSL(二)—— Unlit着色器,无光照,只从纹理采样
- Direct3D中的MipMap(多级惭近纹理过滤)
- 纹理 放大缩小过滤
- 纹理过滤模式中的Bilinear、Trilinear以及Anistropic Filtering (转)
- OpenGL之纹理过滤的四种方式
- NeHe OpenGL教程 07 纹理过滤、应用光照
- OpenGL学习十九:纹理过滤
- 【pandas】[4] 数据清洗(数据合并,重塑,转换,离散化,过滤,采样)