MipMap的LOD实现原理



当使用MipMap时我们可能会遇到tex2D,tex2Dbias,tex2Dgrad,tex2Dlod几种纹理采样函数。

在PS中tex2D自动计算应该使用的纹理层。

tex2Dbias需要在t.w中指定一个偏移量来把自动计算出的纹理层全部偏移指定的值。

tex2Dgrad需要提供屏幕坐标x和y方向上的梯度来确定应该使用的纹理层。

tex2Dlod需要在t.w中明确指定要使用的纹理层。

下面这段话摘自某论坛,具体的出处记不住了:

In the PS the LOD is determined from the derivatives of the texCoords automatically(tex2D). You can also specify the derivatives explicitly as two extra arguments

tex2D(textureMap, texCoord, ddx(texCoord), ddy(texCoord))
is equivalent to your tex2D, though of course you could use something else as the derivative.
Alternately, you can use tex2Dlod to explicitly select the LOD speicifed by the 'w' component of texCoord; eg, something like:

tex2Dlod(textureMap, float4(texCoord.xy, 0, lod))

关于tex2D自动确定使用的纹理层的原理:

首先明确几个概念:

1屏幕上的颜色点叫像素,纹理上的颜色点叫纹素。

2屏幕坐标系我们用XY坐标系,纹理坐标系用UV坐标系。

3GPU在PS阶段是在屏幕空间XY坐标系中对每一个像素去对应的纹理中查找对应的纹素来确定像素的颜色。

下面介绍基本原理:

我们通过上面的原理3可以知道该查找过程是一个从XY空间到UV空间的一个映射。我们可以通过分别求x和y偏导数来求屏幕单个像素宽度纹理坐标的变化率。举个例子,屏幕上某像素区域,对应到实际的纹理中可能是一个长方形的区域。x轴方向实际texel覆盖率为1,y轴的实际texel覆盖率为4。我们可以用ddx和ddy分别来求这个两个方向上的覆盖率,然后取较大的覆盖率,查找应该使用的纹理层使覆盖率尽量接近1但是小余2。如果没有纹理层使覆盖率正好等于1那就取大于1的那层(参见Texture filtering mipmaps)然后用固定的过滤模式对纹理进行缩小操作。

 在Shader中使用tex2D(tex, uv)的时候相当于在GPU内部展开成下面:
tex2D(sampler2D tex, float4 uv)
{
    float lod = CalcLod(ddx(uv), ddy(uv));
    uv.w= lod;
    return tex2Dlod(tex, uv);
}

计算MipMap层函数:

float mipmapLevel(float2 uv, float2 textureSize)
{
    float dx = ddx(uv * textureSize.x);
    float dy = ddy(uv * textureSize.y);
    float d = max(dot(dx, dx), dot(dy, dy));  
    return 0.5 * log2(d);//0.5是技巧,本来是d的平方。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安卓开发中,我们可以通过代码实现将图片下载到mipmap中。 首先,我们需要创建一个AsyncTask类用于在后台下载图片,该类需要三个泛型参数,分别是参数类型,进度类型和结果类型。 接着,在AsyncTask类的doInBackground方法中,我们可以使用HttpURLConnection或OkHttpClient等网络库发送网络请求,将图片下载到本地。 最后,我们可以在AsyncTask类的onPostExecute方法中获取下载的结果,并将图片保存到mipmap中。 具体步骤如下: 1. 创建一个AsyncTask类,用于在后台下载图片。 ``` class DownloadTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... urls) { String imageUrl = urls[0]; Bitmap bitmap = null; try { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); conn.connect(); InputStream inputStream = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(inputStream); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } @Override protected void onPostExecute(Bitmap result) { if(result != null){ addToMipmap(result); } } } ``` 2. 在AsyncTask类的doInBackground方法中,使用HttpURLConnection或OkHttpClient等网络库发送网络请求,将图片下载到本地。 ``` URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoInput(true); conn.connect(); InputStream inputStream = conn.getInputStream(); bitmap = BitmapFactory.decodeStream(inputStream); inputStream.close(); ``` 3. 在AsyncTask类的onPostExecute方法中,获取下载的结果,并将图片保存到mipmap中。 ``` private void addToMipmap(Bitmap bitmap) { try { Resources res = getResources(); String imageName = "downloaded_image"; int drawableId = res.getIdentifier(imageName, "mipmap", getPackageName()); Drawable drawable = new BitmapDrawable(res, bitmap); ((BitmapDrawable) drawable).setGravity(Gravity.CENTER); if (drawableId != 0) { res.getDrawable(drawableId); } } catch (Exception e) { e.printStackTrace(); } } ``` 在addToMipmap方法中,我们通过调用getResources方法获取资源对象,使用getIdentifier方法获取mipmap中的资源ID,然后将下载的图片转化成Drawable对象,并将其保存到mipmap中。 最后,在Activity中,我们可以调用DownloadTask类的execute方法,启动图片下载任务。 ``` new DownloadTask().execute(imageUrl); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值