精华内容
下载资源
问答
  • 在论述X光掠入射平面反射镜工作原理的基础上,重点讨论了超高精度X光镍平面反射镜的制备过程,研制出表面粗糙度小于1.5 nm的平面反射镜。测试和使用表明:在掠入射角为5°时,该反射镜的反射率在54%以上。
  • 为了解决光学相关器无法与发生旋转的目标进行光学相关识别的问题,提出了使用平面反射镜组获取目标图像,与模板图像进行相关识别。在获取目标的光学系统中,加入一个由多个平面反射镜围成的正多棱柱体,它可以使目标...
  • 推导了斜入射法检测平面反射镜面形的公式,并考虑了此方法可能引入的误差。对尺寸为124 mm×42 mm的平面反射镜分别在垂直和不同斜入射角条件下进行了测量,垂直入射时测得镜子工作表面面形起伏高度均方根(RMS)和...
  • 根据初级波面像差理论,推导了自准检测法中平面反射镜的误差允许值.所得结果既适用于轴上,也适用于轴外.同时指出了Burch的结果的局限性.
  • 首先采用快慢轴准直透镜压缩LDA的发散角, 然后采用双平行平面反射镜光束整形装置, 将压缩后的LDA慢轴方向的光束分为4束(也可以根据需要分为任意多束), 并将4束子光束在快轴方向重新排列, 最后通过聚焦系统, 将整形后...
  • 在这项研究中,对通过放置在前一行顶部和后一行底部之间的前面的固定反射镜增强的太阳场进行了理论分析。 已经开发出一种分析模型,并将其用于估算太阳辐射。 该分析模型基于各向异性天空模型,假设收集器和反射器行...
  • 对于光学拼接,拼接反射镜几何参数设计不合理会导致定焦平面出现漏缝、杂光、遮挡光路等成像缺陷。反射镜参数计算是光学拼接焦平面设计的核心内容之一。详细介绍了光学拼接焦平面拼接反射镜的参数计算。根据几何光学...
  • 超表面介导的高效宽带平面聚焦反射镜
  • 本文在简介软X光掠入射平面反射镜基本工作原理及其制备的基础上,着重阐述了镍平面镜的反射率标定过程,给出了标定结果且用于激光-等离子体亚仟X光辐射谱测量,提高了能谱测量精度.
  • 报道了掠入射软X光平面镜反射率标定实验.实验利用北京同步辐射装置(BSRF)-3W1B束线及反射率计靶室,在束流35 mA~110mA、贮存环电子能量2 GeV专用光运行模式下,在50 eV~850eV能区分四个能段,进行了5°掠入射Ni平面镜...
  • 该方法将一个小平面反射镜贴于被测物体的表面,用三束呈空间分布的发散光波,在干版的三个不同区域或同一部位,记录被测物体的三个独立的双曝光干涉图。这些干涉图被由小平面反射镜运动造成的参考光虚点光源的位移所...
  • 为实现空间碳化硅反射镜表面硅改性...采用组合式加工方法对表面改性空间相机碳化硅平面反射镜进行了抛光。抛光后,空间碳化硅反射镜的面形精度均方根值达到0.014λ(λ=0.6328 μm),表面粗糙度的均方根值达到0.71 nm。
  • 基于欺骗表面等离激元极化子色散工程的宽带平面消色差异常反射镜
  • 空间激光通信全光链路组网具有较高的通信速率,决定了其...提出了一种低轨双链路列队卫星组网方案,将激光通信终端光学天线四跟踪平面反射镜的工作面置于卫星轨道平面链路节点处,可实现低轨全光链路空间激光通信组网。
  • 针对热键合直角棱镜和角锥棱镜构成的946 nm激光器,详细讨论了输出端946 nm介质膜反射镜对单频运转的影响及热稳定性问题。指出通过改变p分量的透射比不能有效增加腔内激光的线偏振度;增强施加在角锥棱镜上的磁场强度,...
  • 结合理想坐标系下立方镜面微小倾斜后其三个平面法线坐标,利用刚体微量转动的反射法线向量公式,获得非理想立方镜反射矩阵;为了研究在光斜入射时镜面倾斜对出射光方向的影响,利用立方绕顶点旋转等效于光斜入射的...
  • UE4-(反射)平面反射

    千次阅读 2020-05-09 14:44:33
    平面反射会捕获反射信息,只能用于平面反射效果,所以只适用于平整的对象,例如镜子,水池水面、窗户玻璃。任何尺寸较小表面平整的对象,都可以用平面反射覆盖。 二、属性 1.平面反射既可以实时渲染,也可以一次性...

    一、创建

    注意:平面反射拖拽到场景后,会创建一大块平面,这个平面是临时创建的,当程序运行后,我们不会看到这个平面。

    平面反射会捕获反射信息,只能用于平面反射效果,所以只适用于平整的对象,例如镜子,水池水面、窗户玻璃。任何尺寸较小表面平整的对象,都可以用平面反射覆盖。

    二、开启平面反射

    项目创建时如果想要使用平面反射,需要开启支持平面反射的全局剪切平面

    勾选支持平面反射的全局裁剪平面选项后需要重启UE4。

    注意:如果启用平面反射后没有重启UE4,可能导致平面反射无法使用。

    三、属性

    1.平面反射既可以实时渲染,也可以一次性捕获(属性面板中设置)

    平面反射使用实时渲染,性能开销非常大,因为平面反射实际上将从反射方向再次对关卡进行渲染。所以要比屏幕空间反射更加精确。

    对比:

    左侧屏幕空间反射:摄像机视角的池塘部分上的反射开始淡出,原因是因为SSR无法反射画面外的物体

    右侧屏幕平面反射:池塘的两侧和边缘均未出现问题,反射保持了连贯和精准,原因是平面反射能够无视摄像机视角,反射画面外的物体。

    2.参数:

    平面反射Actor属性

    法线失真强度(Normal Distortion Strength): 扭曲平面反射时控制法线强度。

    预过滤粗糙度(Prefilter Roughness):预过滤平面反射纹理所使用的粗糙度值。此属性适用于隐藏低分辨率。值越大,GPU开销越高。

    平面淡出起点的距离(Distance from Plane Fadeout Start):从反射平面 接收处于此距离的像素时 将 开始 淡化平面反射。

    平面淡出终点的距离(Distance from Plane Fadeout End):从反射平面 接收处于此距离的像素时 将 完全 淡化平面反射。

    平面淡化起点的角度(Angle from Plane Fade Start):从反射平面 接收法线处于此角度的像素时 将 开始 淡化平面反射。

    平面淡化终点的角度(Angle from Plane Fade End):从反射平面 接收法线处于此角度的像素时 将 完全 淡化平面反射。

    (常用)显示预览平面(Show Preview Plane):在编辑器中工作时切换反射平面的可见性。此属性不会影响平面反射。(设置平面反射完成后,可以关闭此属性,区别在于是否显示平面反射临时生成的那个可视性的平面)

     

    预过滤粗糙度距离(Prefilter Roughness Distance):将达到预过滤粗糙度值的距离

    屏幕百分比(Screen Percentage):下采样百分比,可用于减少GPU渲染平面反射的时间。此属性直接影响平面反射所产生的反射的质量。

    平面反射Actor的场景采集属性

    基元渲染模式:渲染场景基元(旧有):渲染场景中所有的基元

    渲染场景基元:渲染场景中所有的基元,但是添加到 隐藏Actor列表中的基元除外

    使用仅显示列表:仅渲染仅显示actor列表中的actor。

    隐藏Actor:关卡中要在场景采集中隐藏的选定actor列表

    仅显示actor:当使用 showOnly 列表(仅显示actor列表)的基元渲染模式时,将被此场景采集渲染的可用actor列表。

    (常用)采集每帧(Capture Every Frame):是否每帧更行采集的内容,如果禁用,组件只在加载时渲染一次,然后只在移动时再次渲染。 设置反射平面是否实时渲染,常设置为渲染一次。

    移动时采集:是否更新运动中的采集内容,如果要从蓝图手动采集,则禁用此功能。

    固定坚持渲染状态:是否保留渲染状态,即便禁用 采集每帧 也是如此。

    最大视图距离覆盖:设置当值大于0时,场景采集中渲染的基元的最大渲染距离。如:反射平面出一个封闭区域(走廊或者房间中),则可以使用此选项来剔除反射的远景物体。

    采集排序优先级:设置帧中的采集优先级,对GPU上的场景采集进行排序,解决多个采集组件之间的相互依赖性,优先级最高则最先进行。

    分析事件名:设置分析GPU时分析事件的名称,当在关卡中使用了多个平面反射时,了解正在使用哪个平面反射。

     

    三、使用平面反射限制

    1.平面反射会导致整个场景被渲染两次,所以要把一半的帧时间花在渲染线程和GPU上

    2.限制世界场景中放置的平面反射的数量

    3.适当的调整平面反射的大小,使其能够在不可见的情况下被剔除

    注意:平面反射可以实现很精确的反射,但是该功能会对项目性能产生直接影响。

    效果:

     

    展开全文
  • 在电荷耦合器件(CCD)摄像机前放置一平面反射镜,通过对目标物体和其虚像进行拍摄,得到一幅具有视差的图像,该图像相当于摄像机和其在平面镜中的虚拟摄像机从不同角度对目标物体进行拍摄,具有双目立体视觉的功能。...
  • 基于结构化光反射平面镜倾斜和活塞测量
  • 如果激活物质和反射镜不是一个整体,则调节过程是必不可少的。最好能将腔内的反射镜与激活物质调节至适当位置,这样就可以修正激活物质任何不完善的影响。调节反射镜通常的方法是利用自动准直仪。但当激活物质直径...
  • 在此基础上,利用ABCD矩阵结合Rytov近似,计算了湍流中有限尺寸圆形平面镜回波的平均强度及后向增强系数,揭示了反射波二阶矩振荡区间的存在。通过计算相干度函数及相干长度,证明了振荡区间湍流会对波前产生更大的...
  • 本文报道了一种超薄的平面抛物面反射镜,用于基于梯度超表面聚焦1.47μm波长的激光束。 超颖表面由一系列亚波长交叉谐振器组成,这些谐振器制造在由一层SiO2隔开的连续金膜上。 交叉谐振器按照双曲面相位分布以径向...
  • 研究了无遮拦三反射镜变形光学系统的设计方法,利用Zernike像差分析方法分析变形系统的像差特点,使用具有双曲率的Biconic Zernike曲面作为反射面校正系统像差。设计了一个X方向焦距fx为100 mm,Y方向焦距fy为150 mm...
  • 利用Zemax光学软件设计出一种大孔径长焦距的6次反射环形孔径超薄透镜,该透镜前表面为平面反射镜,后表面为4个同轴环形非球面反射镜,外直径为28 mm,有效焦距为38 mm,镜头厚度为5 mm。在保证与4次反射透镜通光孔径...
  • 在傅里叶变换红外光谱仪中,用立方反射镜作为动镜的光路系统比平面镜时的情形复杂。通过建立系统的数学模型分析光路,确定了干涉信号的数学表达式;从干涉图调制度的角度对系统在非理想状态下的运动误差容限以及安装...
  • 方法:镜面反射法 实施步骤: 1、相机位置 ,通过设置镜面位置 , 得到对应位置成像view0,view1; 2、计算 与 的变换矩阵 ; 3、同理计算 与 的变换矩阵 ,将 用 , , 表示:其中 为旋转轴(3*1向量)...

    本文是基于Rodrigues et al. Camera Pose Estimation Using Images of Planar Mirror Reflections 的实现。论文链接https://www.ixueshu.com/document/31d59a8ac6ae0ce6318947a18e7f9386.html

    已知条件:单目相机内参K,参考物体Q(被观测物体)上点的世界坐标。

    求:相机坐标。

    该方法适用于相机和被观测目标固定,相机无法直接拍摄到被观测目标,被观测目标具有足够多的清晰的特征点且各点坐标已知。


    方法:镜面反射法

    实施步骤:

    1、相机位置C_{r},通过设置镜面位置\pi _{0}\pi _{1}得到对应位置成像view0,view1;

    2、计算\hat{C_{1}}\hat{C_{0}}的变换矩阵T_{1}

    3、同理计算\hat{C_{2}}\hat{C_{0}}的变换矩阵T_{2},将T_{i}\vec{w}\theta\vec{t}表示:其中\vec{w}为旋转轴(3*1向量),\theta为旋转角度,\vec{t}为平移量(3*1向量)。

    4、通过论文中方法一或方法二方程组,得到镜面位置和摄像机C_{r}位置,其中镜面位置\vec{}(\vec{n},d),\vec{n}为镜面法向量,d为相对Q的距离,相机位置C_{r}

    原理图如下: 

     

    q与Q的关系为:

    其中K为相机内参,I为3*3单位矩阵,T为世界坐标系到相机坐标系变幻矩阵,

    \hat{Q}与Q的关系可用平面表示:

     

     

    方法一:根据虚拟相机与成像物体之间的关系,可以得到线性方程组:

    其中, 

     ,

    A为3*4矩阵,其中\vec{w}为旋转轴,\theta为旋转角度,t为平移量。

    方法二:根据方程组

    其中B为4*4方程组 ,b为四维向量

     

    展开全文
  • 离轴三反系统的装调主要采用初始定位与计算机辅助装调相结合的方法,实际加工过程中由于检测手段的限制,使得离轴量以及离轴角的控制精度较低,根据加工提供的离轴量参数并以其背部平面为基准进行反射镜初始定位会...
  • DirectX11 With Windows SDK--12 深度/模板状态、平面镜反射绘制 原文:DirectX11 With Windows SDK--12 深度/模板状态、平面镜反射绘制前言 深度/模板测试使用的是与后备缓冲区同等分辨率大小的缓冲...
    原文:DirectX11 With Windows SDK--12 深度/模板状态、平面镜反射绘制

    前言

    深度/模板测试使用的是与后备缓冲区同等分辨率大小的缓冲区,每个元素的一部分连续位用于深度测试,其余的则用作模板测试。两个测试的目的都是为了能够根据深度/模板状态需求的设置来选择需要绘制的像素。

    DirectX11 With Windows SDK完整目录

    Github项目源码

    欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

    深度/模板测试

    深度测试、模板测试的执行是在混合操作之前执行的,具体的执行顺序为:模板测试→深度测试→混合操作。

    深度测试

    深度测试需要用到深度/模板缓冲区,对每个像素使用24位或32位来映射物体从世界到NDC坐标系下z的值(即深度,范围[0.0, 1.0])。0.0时达到摄像机的最近可视距离,而1.0时达到摄像机的最远可视距离。若某一像素位置接收到多个像素片元,只有z值最小的像素才会通过最终的深度测试。具体细化的话,就是现在有一个像素片元,已知它的深度值,然后需要跟深度缓冲区中的深度值进行比较,若小于深度缓冲区的深度值,则该像素片元将会覆盖后备缓冲区原来的像素片元,并更新深度缓冲区中对应位置的深度值。

    模板测试

    除了深度测试以为,我们还可以设定模板测试来阻挡某些特定的区域的像素通过后备缓冲区。而且模板测试在操作上自由度会比深度测试大。对于需要进行模板测试的像素,比较式如下:
    (StencilRef & StencilReadMask) ⊴ (Value & StencilReadMask)

    该表达式首先括号部分是两个操作数进行与运算,然后通过⊴(用户指定的运算符)对两个结果进行比较。若该表达式的值为真,则最终通过模板测试,并保留该像素进行后续的混合操作。

    其中StencilReadMask则是应用程序所提供的掩码值。

    深度/模板格式

    深度/模板缓冲区是一个2D数组(纹理),它必须经由确定的数据格式创建:

    1. DXGI_FORMAT_D32_FLOAT_S8X24_UINT:每个元素占64位,其中32位浮点数用于深度测试,8位无符号整数用于模板测试,剩余24位仅用于填充。
    2. DXGI_FORMAT_D24_UNORM_S8_UINT:每个元素占32位,其中24位无符号整数映射到深度值[0.0, 1.0]的区间,8位无符号整数用于模板测试。

    ID3D11DeviceContext::ClearDepthStencilView方法–深度/模板缓冲区内容清空

    方法原型如下:

    void ID3D11DeviceContext::ClearDepthStencilView(
        ID3D11DepthStencilView *pDepthStencilView,  // [In]深度模板视图
        UINT ClearFlags,     // [In]使用D3D11_CLEAR_FLAG枚举类型决定需要清空的部分
        FLOAT Depth,         // [In]使用Depth值填充所有元素的深度部分
        UINT8 Stencil);      // [In]使用Stencil值填充所有元素的模板部分

    其中D3D11_CLEAR_FLAG有如下枚举值:

    枚举值 含义
    D3D11_CLEAR_DEPTH 清空深度部分
    D3D11_CLEAR_STENCIL 清空模板部分

    可以使用位运算或来同时清理。

    通常深度值会默认设为1.0以确保任何在摄像机视野范围内的物体都能被显示出来

    模板值则默认会设置为0

    ID3D11Device::CreateDepthStencilState方法–创建深度/模板状态

    要创建深度/模板状态ID3D11DepthStencilState之前,首先需要填充D3D11_DEPTH_STENCIL_DESC结构体:

    typedef struct D3D11_DEPTH_STENCIL_DESC {
        BOOL                       DepthEnable;        // 是否开启深度测试
        D3D11_DEPTH_WRITE_MASK     DepthWriteMask;     // 深度值写入掩码
        D3D11_COMPARISON_FUNC      DepthFunc;          // 深度比较函数
        BOOL                       StencilEnable;      // 是否开启模板测试
        UINT8                      StencilReadMask;    // 模板值读取掩码
        UINT8                      StencilWriteMask;   // 模板值写入掩码
        D3D11_DEPTH_STENCILOP_DESC FrontFace;          // 对正面朝向的三角形进行深度/模板操作描述
        D3D11_DEPTH_STENCILOP_DESC BackFace;           // 对背面朝向的三角形进行深度/模板操作的描述
    } D3D11_DEPTH_STENCIL_DESC;

    深度状态设定

    1. DepthEnable:如果关闭了深度测试,则绘制的先后顺序就十分重要了。对于不透明的物体,必须按照从后到前的顺序进行绘制,否则最后绘制的内容会覆盖之前的内容,看起来就像在最前面那样。并且关闭深度测试会导致深度缓冲区的值会保持原样,不再进行更新,此时DepthWriteMask也不会使用。
    2. D3D11_DEPTH_WRITE_MASK枚举类型只有两种枚举值:
    枚举值 含义
    D3D11_DEPTH_WRITE_MASK_ZERO 不写入深度/模板缓冲区
    D3D11_DEPTH_WRITE_MASK_ALL 允许写入深度/模板缓冲区

    但即便设置了D3D11_DEPTH_WRITE_MASK_ZERO,如果DepthEnable开着的话仍会取原来的深度值进行深度比较,只是不会更新深度缓冲区。

    1. DepthFunc:指定D3D11_COMPARISON_FUNC枚举值来描述深度测试的比较操作,标准情况下是使用D3D11_COMPARISON_LESS来进行深度测试,当然你也可以自定义测试的比较方式。

    枚举类型D3D11_COMPARISON_FUNC的枚举值如下:

    枚举值 含义
    D3D11_COMPARISON_NEVER = 1 该比较函数一定返回false
    D3D11_COMPARISON_LESS = 2 使用<来替换⊴
    D3D11_COMPARISON_EQUAL = 3 使用==来替换⊴
    D3D11_COMPARISON_LESS_EQUAL = 4 使用<=来替换⊴
    D3D11_COMPARISON_GREATER = 5 使用>来替换⊴
    D3D11_COMPARISON_NOT_EQUAL = 6 使用!=来替换⊴
    D3D11_COMPARISON_GREATER_EQUAL = 7 使用>=来替换⊴
    D3D11_COMPARISON_ALWAYS = 8 该比较函数一定返回true

    默认情况下,深度状态的值如下:

    DepthEnable = TRUE;
    DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL
    DepthFunc = D3D11_COMPARISION_LESS

    模板状态设定

    1. StencilEnable:若要使用模板测试,则指定为true
    2. StencilReadMask:该掩码用于指定StencilRef和深度/模板缓冲区的模板值Value中的某些特定位,默认使用的是下面宏常量:
      #define D3D11_DEFAULT_STENCIL_READ_MASK (0xff)
    3. StencilWriteMask:该掩码指定待写入的模板值的哪些位要写入深度/模板缓冲区中,默认使用的是下面宏常量:
      #define D3D11_DEFAULT_STENCIL_WRITE_MASK (0xff)
    4. FrontFace:该结构体指定了不同测试结果下对模板值应做什么样的更新(对于正面朝向的三角形)
    5. BackFace:该结构体指定了不同测试结果下对模板值应做什么样的更新(对于背面朝向的三角形)

    深度/模板操作描述结构体如下:

    typedefstruct D3D11_DEPTH_STENCILOP_DESC {
        D3D11_STENCIL_OP StencilFailOp;      
        D3D11_STENCIL_OP StencilDepthFailOp; 
        D3D11_STENCIL_OP StencilPassOp;      
        D3D11_COMPARISON_FUNC StencilFunc;   
    } D3D11_DEPTH_STENCILOP_DESC;
    1. StencilFailOp:若模板测试不通过对深度/模板缓冲区的模板值部分的操作
    2. StencilDepthFailOp:若模板测试通过,但深度测试不通过对深度/模板缓冲区的模板值部分的操作
    3. StencilPassOp:若模板/深度测试通过对深度/模板缓冲区的模板值部分的操作
    4. StencilFunc:模板测试所用的比较函数

    枚举类型D3D11_STENCIL_OP的枚举值如下:

    枚举值 含义
    D3D11_STENCIL_OP_KEEP 保持目标模板值不变
    D3D11_STENCIL_OP_ZERO 保持目标模板值为0
    D3D11_STENCIL_OP_REPLACE 使用StencilRef的值替换模板模板值
    D3D11_STENCIL_OP_INCR_SAT 对目标模板值加1,超过255的话将值保持在255
    D3D11_STENCIL_OP_DECR_SAT 对目标模板值减1,低于0的话将保持在0
    D3D11_STENCIL_OP_INVERT 对目标模板值的每个位进行翻转
    D3D11_STENCIL_OP_INCR 对目标模板值加1,超过255的话值将上溢变成0
    D3D11_STENCIL_OP_DECR 对目标模板值减1,低于0的话将下溢变成255

    默认情况下,模板状态的值如下:

    StencilEnable = FALSE;
    StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
    StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    
    FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
    FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
    FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
    
    BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
    BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
    BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
    BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;

    填充完上面一堆结构体信息后,就终于可以创建深度模板状态了:

    HRESULT ID3D11Device::CreateDepthStencilState(
      const D3D11_DEPTH_STENCIL_DESC *pDepthStencilDesc,      // [In]深度/模板状态描述
      ID3D11DepthStencilState        **ppDepthStencilState    // [Out]输出深度/模板状态
    );

    ID3D11DeviceContext::OMSetDepthStencilState方法–输出合并阶段设置深度/模板状态

    创建好深度/模板状态后,我们就可以将它绑定到渲染管线上:

    void ID3D11DeviceContext::OMSetDepthStencilState(
        ID3D11DepthStencilState *pDepthStencilState,      // [In]深度/模板状态,使用nullptr的话则是默认深度/模板状态
        UINT StencilRef);                                 // [In]提供的模板值

    如果要恢复到默认状况,可以这样调用:

    md3dImmediateContext->OMSetDepthStencilState(nullptr, 0);

    利用模板测试绘制平面镜

    要实现镜面反射的效果,我们需要解决两个问题:

    1. 如何计算出一个物体的所有顶点在任意平面的镜面的反射位置
    2. 在镜面位置只显示镜面本身和反射的物体的混合

    若一个有平面镜的场景中包含透明和非透明物体,则实际的绘制顺序为:

    1. 只向镜面区域的模板缓冲区写入值1,而深度缓冲区和后备缓冲区的值都不应该写入
    2. 将需要绘制的镜面反射物体进行反射变换,然后仅在模板值为1的区域先绘制不透明的反射物体到后备缓冲区
    3. 在模板值为1的区域绘制透明的反射物体后,再绘制透明镜面到后备缓冲区
    4. 绘制正常的非透明物体到后备缓冲区
    5. 绘制透明物体到后备缓冲区

    在3D场景中,要绘制镜面反射的物体,我们只需要将原本的物体(所有顶点位置)进行镜面反射矩阵的变换即可得到。但是反射的物体仅可以在物体一侧透过镜面看到,在镜面的另一边是无法看到反射的物体的。通过模板测试,我们可以在摄像机仅与镜面同侧的时候标定镜面区域,并绘制镜面反射的物体。

    image

    我们可以使用XMMatrixReflection函数来创建反射矩阵,提供的参数为平面向量\((\mathbf{n} ,d)\)

    这里简单了解一下,平面可以表示为点法式:
    \[\mathbf{n} \cdot \mathbf{p} + d = 0\]
    n为平面法向量,p为平面一点,进行叉乘运算。

    d是一个有向距离值

    上面的式子展开后就是我们高数见到的平面方程:
    \[Ax + By + Cz + D = 0\]

    这相当于我

    1172605-20180729174023481-612473499.png

    例如(0.0f, 0.0f, -1.0f, 10.0f)可以表示z = 10的平面

    HLSL代码的变化

    Basic.hlsli中,添加了一个常量缓冲区用来控制反射开关,它的更新频率仅次于每次绘制更新的缓冲区。并且由于镜面是固定的,这里将镜面反射矩阵放在不会变化的常量缓冲区上:

    cbuffer CBChangesEveryDrawing : register(b0)
    {
        matrix g_World;
        matrix g_WorldInvTranspose;
        Material g_Material;
    }
    
    cbuffer CBDrawingStates : register(b1)
    {
        int g_IsReflection;
        float3 g_Pad1;
    }
    
    cbuffer CBChangesEveryFrame : register(b2)
    {
        matrix g_View;
        float3 g_EyePosW;
    }
    
    cbuffer CBChangesOnResize : register(b3)
    {
        matrix g_Proj;
    }
    
    cbuffer CBChangesRarely : register(b4)
    {
        matrix g_Reflection;
        DirectionalLight g_DirLight[10];
        PointLight g_PointLight[10];
        SpotLight g_SpotLight[10];
        int g_NumDirLight;
        int g_NumPointLight;
        int g_NumSpotLight;
        float g_Pad2;
    }
    
    

    所以现在目前已经使用了5个常量缓冲区,可以说在管理上会非常复杂,其中顶点着色器需要用到所有的常量缓冲区,而像素着色器需要用到除了CBChangesOnResize外的所有常量缓冲区。

    然后3D顶点着色器添加了是否需要乘上反射矩阵的判定:

    // Basic_VS_3D.hlsl
    #include "Basic.hlsli"
    
    // 顶点着色器(3D)
    VertexPosHWNormalTex VS_3D(VertexPosNormalTex vIn)
    {
        VertexPosHWNormalTex vOut;
        
        matrix viewProj = mul(g_View, g_Proj);
        float4 posW = mul(float4(vIn.PosL, 1.0f), g_World);
        float3 normalW = mul(vIn.NormalL, (float3x3) g_WorldInvTranspose);
        // 若当前在绘制反射物体,先进行反射操作
        [flatten]
        if (g_IsReflection)
        {
            posW = mul(posW, g_Reflection);
            normalW = mul(normalW, (float3x3) g_Reflection);
        }
        vOut.PosH = mul(posW, viewProj);
        vOut.PosW = posW.xyz;
        vOut.NormalW = normalW;
        vOut.Tex = vIn.Tex;
        return vOut;
    }
    
    

    对于像素着色器来说,由于点光灯和聚光灯都可以看做是物体,所以也应该进行镜面反射矩阵变换(主要反射光的方向和位置):

    // Basic_PS_3D.hlsl
    #include "Basic.hlsli"
    
    // 像素着色器(3D)
    float4 PS_3D(VertexPosHWNormalTex pIn) : SV_Target
    {
        // 提前进行裁剪,对不符合要求的像素可以避免后续运算
        float4 texColor = g_Tex.Sample(g_SamLinear, pIn.Tex);
        clip(texColor.a - 0.1f);
    
        // 标准化法向量
        pIn.NormalW = normalize(pIn.NormalW);
    
        // 顶点指向眼睛的向量
        float3 toEyeW = normalize(g_EyePosW - pIn.PosW);
    
        // 初始化为0 
        float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
        float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
        float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
        float4 A = float4(0.0f, 0.0f, 0.0f, 0.0f);
        float4 D = float4(0.0f, 0.0f, 0.0f, 0.0f);
        float4 S = float4(0.0f, 0.0f, 0.0f, 0.0f);
        int i;
    
    
        [unroll]
        for (i = 0; i < 5; ++i)
        {
            DirectionalLight dirLight = g_DirLight[i];
            [flatten]
            if (g_IsReflection)
            {
                dirLight.Direction = mul(dirLight.Direction, (float3x3) (g_Reflection));
            }
            ComputeDirectionalLight(g_Material, g_DirLight[i], pIn.NormalW, toEyeW, A, D, S);
            ambient += A;
            diffuse += D;
            spec += S;
        }
            
        
    
        
        // 若当前在绘制反射物体,需要对光照进行反射矩阵变换
        PointLight pointLight;
        [unroll]
        for (i = 0; i < 5; ++i)
        {
            pointLight = g_PointLight[i];
            [flatten]
            if (g_IsReflection)
            {
                pointLight.Position = (float3) mul(float4(pointLight.Position, 1.0f), g_Reflection);
            }
            ComputePointLight(g_Material, pointLight, pIn.PosW, pIn.NormalW, toEyeW, A, D, S);
            ambient += A;
            diffuse += D;
            spec += S;
        }
            
        
        
        SpotLight spotLight;
        // 若当前在绘制反射物体,需要对光照进行反射矩阵变换
        [unroll]
        for (i = 0; i < 5; ++i)
        {
            spotLight = g_SpotLight[i];
            [flatten]
            if (g_IsReflection)
            {
                spotLight.Position = (float3) mul(float4(spotLight.Position, 1.0f), g_Reflection);
                spotLight.Direction = mul(spotLight.Direction, (float3x3) g_Reflection);
            }
            ComputeSpotLight(g_Material, spotLight, pIn.PosW, pIn.NormalW, toEyeW, A, D, S);
            ambient += A;
            diffuse += D;
            spec += S;
        }
            
        
    
        
        float4 litColor = texColor * (ambient + diffuse) + spec;
        litColor.a = texColor.a * g_Material.Diffuse.a;
        return litColor;
    }
    

    RenderStates类的变化

    RenderStates类变化如下:

    class RenderStates
    {
    public:
        template <class T>
        using ComPtr = Microsoft::WRL::ComPtr<T>;
    
        static void InitAll(ID3D11Device * device);
        // 使用ComPtr无需手工释放
    
    public:
        static ComPtr<ID3D11RasterizerState> RSWireframe;       // 光栅化器状态:线框模式
        static ComPtr<ID3D11RasterizerState> RSNoCull;          // 光栅化器状态:无背面裁剪模式
        static ComPtr<ID3D11RasterizerState> RSCullClockWise;   // 光栅化器状态:顺时针裁剪模式
    
        static ComPtr<ID3D11SamplerState> SSLinear;         // 采样器状态:线性过滤
        static ComPtr<ID3D11SamplerState> SSAnistropic;     // 采样器状态:各项异性过滤
    
        static ComPtr<ID3D11BlendState> BSNoColorWrite;     // 混合状态:不写入颜色
        static ComPtr<ID3D11BlendState> BSTransparent;      // 混合状态:透明混合
        static ComPtr<ID3D11BlendState> BSAlphaToCoverage;  // 混合状态:Alpha-To-Coverage
    
        static ComPtr<ID3D11DepthStencilState> DSSMarkMirror;       // 深度/模板状态:标记镜面区域
        static ComPtr<ID3D11DepthStencilState> DSSDrawReflection;   // 深度/模板状态:绘制反射区域
        static ComPtr<ID3D11DepthStencilState> DSSNoDoubleBlend;    // 深度/模板状态:无二次混合区域
        static ComPtr<ID3D11DepthStencilState> DSSNoDepthTest;      // 深度/模板状态:关闭深度测试
        static ComPtr<ID3D11DepthStencilState> DSSNoDepthWrite;     // 深度/模板状态:仅深度测试,不写入深度值
    };
    
    

    新增的渲染状态的定义如下:

    void RenderStates::InitAll(ID3D11Device * device)
    {
        // 先前初始化过的话就没必要重来了
        if (IsInit())
            return;
    
        // ***********初始化光栅化器状态***********
        D3D11_RASTERIZER_DESC rasterizerDesc;
        ZeroMemory(&rasterizerDesc, sizeof(rasterizerDesc));
    
        // ...
    
        // 顺时针剔除模式
        rasterizerDesc.FillMode = D3D11_FILL_SOLID;
        rasterizerDesc.CullMode = D3D11_CULL_BACK;
        rasterizerDesc.FrontCounterClockwise = true;
        rasterizerDesc.DepthClipEnable = true;
        HR(device->CreateRasterizerState(&rasterizerDesc, &RSCullClockWise));
    
        
        // ***********初始化采样器状态***********
        // ...
        
        // ***********初始化混合状态***********
        // ...
        
        // ***********初始化深度/模板状态***********
        D3D11_DEPTH_STENCIL_DESC dsDesc;
    
        // 镜面标记深度/模板状态
        // 这里不写入深度信息
        // 无论是正面还是背面,原来指定的区域的模板值都会被写入StencilRef
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
        dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
    
        dsDesc.StencilEnable = true;
        dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
        dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    
        dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
        dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
        // 对于背面的几何体我们是不进行渲染的,所以这里的设置无关紧要
        dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
        dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
    
        HR(device->CreateDepthStencilState(&dsDesc, DSSMarkMirror.GetAddressOf()));
    
        // 反射绘制深度/模板状态
        // 由于要绘制反射镜面,需要更新深度
        // 仅当镜面标记模板值和当前设置模板值相等时才会进行绘制
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
        dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
    
        dsDesc.StencilEnable = true;
        dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
        dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    
        dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;
        // 对于背面的几何体我们是不进行渲染的,所以这里的设置无关紧要
        dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL;
    
        HR(device->CreateDepthStencilState(&dsDesc, DSSDrawReflection.GetAddressOf()));
    
        // 无二次混合深度/模板状态
        // 允许默认深度测试
        // 通过自递增使得原来StencilRef的值只能使用一次,实现仅一次混合
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
        dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
    
        dsDesc.StencilEnable = true;
        dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
        dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
    
        dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_INCR;
        dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL;
        // 对于背面的几何体我们是不进行渲染的,所以这里的设置无关紧要
        dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
        dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_INCR;
        dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL;
    
        HR(device->CreateDepthStencilState(&dsDesc, DSSNoDoubleBlend.GetAddressOf()));
    
        // 关闭深度测试的深度/模板状态
        // 若绘制非透明物体,务必严格按照绘制顺序
        // 绘制透明物体则不需要担心绘制顺序
        // 而默认情况下模板测试就是关闭的
        dsDesc.DepthEnable = false;
        dsDesc.StencilEnable = false;
    
        HR(device->CreateDepthStencilState(&dsDesc, DSSNoDepthTest.GetAddressOf()));
    
    
        // 进行深度测试,但不写入深度值的状态
        // 若绘制非透明物体时,应使用默认状态
        // 绘制透明物体时,使用该状态可以有效确保混合状态的进行
        // 并且确保较前的非透明物体可以阻挡较后的一切物体
        dsDesc.DepthEnable = true;
        dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
        dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
        dsDesc.StencilEnable = false;
    
        HR(device->CreateDepthStencilState(&dsDesc, DSSNoDepthWrite.GetAddressOf()));
    
    }
    
    

    场景绘制

    现在场景内有四面墙,一个平面镜,一面地板,一个篱笆盒和水面。

    开始绘制前,我们需要清空深度/模板缓冲区和渲染目标视图:

    md3dImmediateContext->ClearRenderTargetView(mRenderTargetView.Get(), reinterpret_cast<const float*>(&Colors::Black));
    md3dImmediateContext->ClearDepthStencilView(mDepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
    

    第1步: 镜面区域写入模板缓冲区

    这一步通过对镜面所在区域写入模板值1来标定镜面绘制区域。

    // *********************
    // 1. 给镜面反射区域写入值1到模板缓冲区
    // 
    
    // 裁剪掉背面三角形
    // 标记镜面区域的模板值为1
    // 不写入像素颜色
    m_pd3dImmediateContext->RSSetState(nullptr);
    m_pd3dImmediateContext->OMSetDepthStencilState(RenderStates::DSSMarkMirror.Get(), 1);
    m_pd3dImmediateContext->OMSetBlendState(RenderStates::BSNoColorWrite.Get(), nullptr, 0xFFFFFFFF);
    
    m_Mirror.Draw(m_pd3dImmediateContext.Get());
    

    通过VS图形调试器可以看到模板值为1的区域
    1172605-20180727225849959-1031316302.png

    第2步:绘制不透明的镜面反射物体

    理论上会有三面墙和地板可能会透过镜面看到,这里都需要绘制,但要注意在对顶点位置做反射变换时,原来平面向外的法向量变成了平面向内部,因此还需要额外对法向量做反射变换(龙书缺少了对法向量的反射变换)。并且原来按顺时针排布的三角形顶点也变成了逆时针排布。所以需要对顺时针排布的顶点做裁剪处理。

    image

    在做模板测试的时候,我们仅对模板值为1的像素点通过测试,这样保证限定绘制区域在镜面上。

    // ***********************
    // 2. 绘制不透明的反射物体
    //
    
    // 开启反射绘制
    m_CBStates.isReflection = true;
    D3D11_MAPPED_SUBRESOURCE mappedData;
    HR(m_pd3dImmediateContext->Map(m_pConstantBuffers[1].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
    memcpy_s(mappedData.pData, sizeof(CBDrawingStates), &m_CBStates, sizeof(CBDrawingStates));
    m_pd3dImmediateContext->Unmap(m_pConstantBuffers[1].Get(), 0);  
            
    // 绘制不透明物体,需要顺时针裁剪
    // 仅对模板值为1的镜面区域绘制
    m_pd3dImmediateContext->RSSetState(RenderStates::RSCullClockWise.Get());
    m_pd3dImmediateContext->OMSetDepthStencilState(RenderStates::DSSDrawReflection.Get(), 1);
    m_pd3dImmediateContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF);
        
    m_Walls[2].Draw(m_pd3dImmediateContext.Get());
    m_Walls[3].Draw(m_pd3dImmediateContext.Get());
    m_Walls[4].Draw(m_pd3dImmediateContext.Get());
    m_Floor.Draw(m_pd3dImmediateContext.Get());
    

    到这时候绘制效果如下:
    1172605-20180727230331257-2106158659.png

    第3步:绘制透明的镜面反射物体

    这一步需要绘制的透明反射物体有篱笆盒以及水面,绘制了这些透明物体后就可以连同镜面一起混合绘制了。其中篱笆盒要优于水面先行绘制:

    // ***********************
    // 3. 绘制透明的反射物体
    //
    
    // 关闭顺逆时针裁剪
    // 仅对模板值为1的镜面区域绘制
    // 透明混合
    m_pd3dImmediateContext->RSSetState(RenderStates::RSNoCull.Get());
    m_pd3dImmediateContext->OMSetDepthStencilState(RenderStates::DSSDrawReflection.Get(), 1);
    m_pd3dImmediateContext->OMSetBlendState(RenderStates::BSTransparent.Get(), nullptr, 0xFFFFFFFF);
    
    m_WireFence.Draw(m_pd3dImmediateContext.Get());
    m_Water.Draw(m_pd3dImmediateContext.Get());
    m_Mirror.Draw(m_pd3dImmediateContext.Get());
        
    // 关闭反射绘制
    m_CBStates.isReflection = false;
    HR(m_pd3dImmediateContext->Map(m_pConstantBuffers[1].Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));
    memcpy_s(mappedData.pData, sizeof(CBDrawingStates), &m_CBStates, sizeof(CBDrawingStates));
    m_pd3dImmediateContext->Unmap(m_pConstantBuffers[1].Get(), 0);
    
    

    绘制完后效果如下:
    1172605-20180727230422328-1244504664.png

    第4步:绘制不透明的正常物体

    这一步仅有墙体和地板需要绘制:

    // ************************
    // 4. 绘制不透明的正常物体
    //
    
    m_pd3dImmediateContext->RSSetState(nullptr);
    m_pd3dImmediateContext->OMSetDepthStencilState(nullptr, 0);
    m_pd3dImmediateContext->OMSetBlendState(nullptr, nullptr, 0xFFFFFFFF);
    
    for (auto& wall : m_Walls)
        wall.Draw(m_pd3dImmediateContext.Get());
    m_Floor.Draw(m_pd3dImmediateContext.Get());
    
    

    1172605-20180727230532105-872453900.png

    第5步:绘制透明的正常物体

    // ***********************
    // 5. 绘制透明的正常物体
    //
    
    // 关闭顺逆时针裁剪
    // 透明混合
    m_pd3dImmediateContext->RSSetState(RenderStates::RSNoCull.Get());
    m_pd3dImmediateContext->OMSetDepthStencilState(nullptr, 0);
    m_pd3dImmediateContext->OMSetBlendState(RenderStates::BSTransparent.Get(), nullptr, 0xFFFFFFFF);
    
    m_WireFence.Draw(m_pd3dImmediateContext.Get());
    m_Water.Draw(m_pd3dImmediateContext.Get());
    

    完成所有绘制后,显示效果如下:
    1172605-20180727225936692-1437807630.png

    先绘制镜面场景还是绘制主场景?

    一开始我是根据龙书的顺序先绘制主场景,再绘制镜面场景的。但是在绘制带有透明物体的场景时,会得到下面的结果:
    1172605-20180727230915205-1560702675.png

    可以看到镜面下面的部分有黑边,是因为在绘制主场景的时候,黑色背景和水面产生了混合,并且改写了深度值,导致在绘制镜面后面的物体(主要是地板部分)时水面以下的部分没有通过深度测试,地板也就没有被绘制。

    DirectX11 With Windows SDK完整目录

    Github项目源码

    欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报。

    posted on 2019-05-05 09:54 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/10811361.html

    展开全文
  • 固着磨料工艺主要针对某空间相机的高精度平面折反镜而开发,分别从微观结构的仿真计算和人工神经网络两个角度对此工艺加工碳化硅反射镜表面粗糙度进行分析。一方面引入了二维粗糙度的在微观结构仿真概念,在人工神...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,449
精华内容 2,579
关键字:

平面反射镜