优化ClipSpace to Screen TexCoord 变换.

在deferred shading 和post process 阶段, 通常要做的一件事情就是讲裁减空间坐标转换到屏幕空间的纹理坐标.

这里面通常的做法就是Vertex Shader 输出clip space position 到pixel shader.

pixel shader 做除法,然后再 + 1  * 0.5 变换到纹理坐标, 然后在D3D9 中还要根据采样纹理的大小进行texel 偏移.

我有太多的像素要处理, 所以, 这些没必要的计算能少则少! 或者交给vertex shader 来分担.

下面的目的就是让Vertexshader 来计算屏幕空间TexCoord , 在 pixel shader 中只做最少的事情.

/////////////////////////////////////////////////////////////////////////////

// 推导:

/////////////////////////////////////////////////////////////////////////////

Clip Space Vertex:
Vc = mul(matViewProj, Vworld)
Vc.xy = Vc.xy/Vc.w [-1 1]
接着设备会在光栅化阶段, Clip->NDC->Viewport 将其从裁减空间变换到屏幕空间(Vs). [0, ViewportSize]

Vs.x = (Vc.x +1)*ViewportWidth*0.5;
Vs.y = ({-}Vc.y + 1)*ViewportHeight*0.5; //NOTE: D3D窗口坐标. Y轴指向下方向和 CLIP 空间相反. OPENGL 则刚好反过来. 下面的推导基于D3D9

这里我们已经获得在屏幕空间坐标, 但是实际上, 需要的纹理坐标. [0 1]

TexCoord = Vs / ViewportSize ;
TexCoord.u = (Vc.x +1)*0.5;
TexCoord.v = (-Vc.y + 1)*0.5;
// map texel to pixel.
float2 texel_offset = float2(0.5,0.5);
TexCoord = TexCoord + texel_offset * InvViewportSize;  // 1/ViewportSize

TexCoord.u = (Vc.x +1)*0.5 + 0.5*InvViewportSize.x;
TexCoord.v = (-Vc.y + 1)*0.5 + 0.5*InvViewportSize.y;

再次展开:

HPos = mul(matViewProj, Vworld)
TexCoord.u = (HPos.x/HPos.w +1)*0.5 + 0.5*InvViewportSize.x;
TexCoord.v = (-HPos.y/HPos.w + 1)*0.5 + 0.5*InvViewportSize.y;

这部分的计算是在Vertex Shader中完成, 我们将结果TexCoord 以TEXCORRDn的语义传给Pixel Shader, 在光栅化阶段对每个pixel, 输入的数据会被插值.
假设针对顶点输入数据的插值是: [interp(X), interp(Y), interp(Z), interp(W)] ;
1/ interp(W) 不一定会等于 interp(1/W)

然后我们在回头来看上面的变换.
TexCoord 中正好就包含了一个 1/ HPos.w 的因子. 在这里跌了个跟头....:(

于是修改上面的结果, 将/ W 放到PIXEL SHADER 中进行.

TexCoord.u = (HPos.x/HPos.w +1)*0.5 + 0.5*InvViewportSize.x) *HPos.w;
TexCoord.v = ((-HPos.y/HPos.w + 1)*0.5 + 0.5*InvViewportSize.y) *HPos.w;

// 最终结果:

Vertex Shader:

float4x4 ViewProjMat;// view projection matrix.
float4 ViewportSize;     //[width, height, 0.5f/width, 0.5f/height]
struct VERTEX_INPUT
{
  float4 Position : POSITION;
};
struct VERTEX_OUTPUT
{
  float4 HPos: POSITION;
  float4 ScreenTexCoord: TEXCOORD0;
};
float4 HPosToScreenTexCoord( float4 p )
{
  float4 ScrTC = HPos;     // clip space
  // [-1 1] --> [0 1]
  ScrTC.xy = (HPos.xy * float2(1,-1) + HPos.ww ) * 0.5;
  ScrTC.xy += ViewportSize.zw*HPos.w;// texel offset
  return ScrTC;
}

VERTEX_OUTPUT VMain(VERTEX_INPUT IN )
{   VERTEX_OUTPUT OUT;
  OUT.HPos= mul(ViewProjMat, IN.Position);
  OUT.ScreenTexCoord =HPosToScreenTexCoord(OUT.HPos);
  return OUT;}

Pixel Shader:

float4 PMain(VERTEX_OUTPUT IN) : COLOR0
{
  IN.ScreenTexCoord.xy /= Input.ScreenTexCoord.w;
  return float4(IN.ScreenTexCoord.xy,0,1);
}

screen u texcoord :

// screen v coord:

时间: 2024-10-31 18:52:28

优化ClipSpace to Screen TexCoord 变换.的相关文章

MySql学习(五) —— 数据库优化理论篇(一)

一.数据库管理系统 数据库管理系统(Database Management System, DBMS) 衡量是否是数据库的标准: ACID:是指在数据库管理系统(DBMS)中事务所具有的四个特性: 1) 原子性(Atomicity) 2) 一致性(Consistency) 3)隔离性(Isolation) 4)持久性(Durability) 1.关系型数据库:是建立在关系数据库模型基础上的数据库,借助于关系代数等概念和方法来处理数据库中的数据,同时也是一个被组织成一组拥有正式描述性的表格,该形式

深入理解PHP opcode优化

1.概述 PHP(本文所述案例PHP版本均为7.1.3)作为一门动态脚本语言,其在zend虚拟机执行过程为:读入脚本程序字符串,经由词法分析器将其转换为单词符号,接着语法分析器从中发现语法结构后生成抽象语法树,再经静态编译器生成opcode,最后经解释器模拟机器指令来执行每一条opcode. 在上述整个环节中,生成的opcode可以应用编译优化技术如死代码删除.条件常量传播.函数内联等各种优化来精简opcode,达到提高代码的执行性能的目的. PHP扩展opcache,针对生成的opcode基于

【一步步学OpenGL 26】-《法线贴图》

教程 26 法线贴图 原文: http://ogldev.atspace.co.uk/www/tutorial26/tutorial26.html CSDN完整版专栏: http://blog.csdn.net/column/details/13062.html 背景 之前的我们的光线着色器类已经可以达到很不错的效果了,光线效果通过插值计算遍布到整个模型表面,使整个场景看上去比较真实,但这个效果还可以进行更好的优化.事实上,有时插值计算反而会影响场景的真实性,尤其是用材质来表现一些凹凸不平的纹理

JavaScript初探三

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <ul id

JavaScript初探 三

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <input

静态库和动态库系列(1)

最近一个哥们问了我一些他们公司的代码的问题,他是得到了别的公司给医院提供的dll,然后调用dll的接口为医院继续写代码..问题是.我也不会啊! 所以趁此机会,好好搞一搞lib和dll.争取能弄明白windows下的lib和dll的一些问题.  一点一点来吧.. 什么是lib,什么是dll.为什么要生成lib和dll 不管是静态库还是动态库,两者都是为了共享程序代码,类比的例子就是你封装了一段代码成为一个函数,别的函数能调用你封装的函数,而不必拷贝粘贴一份.这就叫共享程序代码 库通俗的说就是把一些

x264源代码简单分析:宏块编码(Encode)部分

本文记录x264的 x264_slice_write()函数中调用的x264_macroblock_encode()的源代码.x264_macroblock_encode()对应着x264中的宏块编码模块.宏块编码模块主要完成了DCT变换和量化两个步骤. 函数调用关系图 宏块编码(Encode)部分的源代码在整个x264中的位置如下图所示. 单击查看更清晰的图片 宏块编码(Encode)部分的函数调用关系如下图所示. 单击查看更清晰的图片 从源代码可以看出,宏块编码模块的x264_macrobl

转:x264源代码简单分析:编码器主干部分-1

本文来自:http://blog.csdn.net/leixiaohua1020/article/details/45644367 本文分析x264编码器主干部分的源代码."主干部分"指的就是 libx264中最核心的接口函数--x264_encoder_encode(),以及相关的几个接口函数 x264_encoder_open(),x264_encoder_headers(),和x264_encoder_close().这一部分源代码 比较复杂,现在看了半天依然感觉很多地方不太清晰

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

本文分析FFmpeg的H.264解码器的宏块解码(Decode)部分的源代码.FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作.这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波.本文分析这3个步骤中的第2个步骤.由于宏块解码部分的内容比较多,因此将本部分内容拆分成两篇文章:一篇文章记录帧内预测宏块(Intra)的宏块解码,另一篇文章记录帧间预测宏块(Inter)的宏块解码. 函数调用关系图 宏块解码(Decode)部分的源代码在整个H.264解码器