Directx11教程三十之ProjectiveTexturing(投影纹理)
2016-11-01 21:33
267 查看
这节教程是介绍有关ProjectiveTexturing(投影纹理)技术的,结构如下
D3D11教程十九之PlannarReflection(基于RTT技术和投影纹理技术)都是投影纹理技术搭配RTT技术使用的典型例子,那两个教程中折射的物体和反射的物体的实现其实是投影纹理.
在来看看一个使用投影纹理的例子:
看上面这张有一个骷颅头的2D纹理贴图,利用这张2D纹理贴图我们可以生成下面的图形效果:
看这张图里面的骷髅头实际上仅仅是一张2D纹理贴图的效果,而不是真正地将一个3D骷颅头进行渲染的效果。
为了下面更好地讲述有关概念,我只好自创两个概念, ViewCamera(观察照相机)和ProjectorCamera(投影照相机或者投影幻灯机)
ViewCamera提供了我们在3D程序中的人眼观察的视角。
ProjectorCamera提供了投影机观察3D物体的角度,决定了世界空间(WorldSpace)中每个顶点对应于投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V).
在世界空间中(WorldSpace),我们是如何得到每个顶点对应于投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V)呢?
来看一张图:
看图中,这个视截体是ProjectorCamera(投影幻灯机)的视截体,点P是在世界空间的一个点(Xp,Yp,Zp,1.0),如何求出相应的(u,v)坐标呢?
要求投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V),首先得熟悉D3D11的3D渲染流水线:
我在D3D11教程二十五之DepthBuffer(深度缓存)论述过3D渲染流水线,求纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V)分为两步:
(1) 假设在世界空间上,点P坐标为(Xp,Yp,Zp,1.0),乘以ProjectorCamera(注意不是ViewCamera)生成的相机变换矩阵和透视投影矩阵,变换到齐次裁剪空间
在齐次裁剪空P点相应的坐标值为
(Xp,Yp,Zp,Wp) -Wp=<Xp<=Wp -Wp=<Yp<=Wp 0=<Zp<=Wp,
(2)由于我们不标记“”SV_POSITION“”,显卡不会自动进行透视除法(当然显卡也不会自动进行裁剪算法),所以我们手动计算
-1<=Xp/Wp<=1 -1<=Yp/Wp<=1,
0=<{0.5*(Xp/Wp)+0.5}<=1, 0=<{-0.5*(Yp/Wp)+0.5}<=1
又由于投影纹理坐标系中 0=<U<=1 0=<V<=1,并且U坐标方向和X坐标方向相同,而V坐标方向和Y坐标相反,所以我们得出结果: U= 0.5*(Xp/Wp)+0.5;
V=-0.5*(Yp/Wp)+0.5;
下面我们放出投影幻灯机的类:
ViewPointClass.h
ViewPointClass.CPP
ColorShader.fx
下面是我将用到的投射到3D物体上的2D纹理:
这是没用投射纹理技术的
这是我们用了投影纹理技术的:观察相机位置A(0.0f,
6.0f, -12.0f) 投影相机(投影机)的位置B(2.0f, 5.0f, -2.0f),好吧,
在下图我做出辅助线来,观察相机A点的视截体我就不作辅助线了,作投影相机B的辅助线,红色的点为投影相机的视截体和平面的交点,画画水平有点糟糕,请见谅:
最后注意的是,在Shader可以看到我们的判定:由于我们 float4 ProjPos:POSITION 没标记“”POSTION“” 而不是“”SV_POSITION“”,显卡不会进行视截体内外面部分的裁剪,所以求得的UV坐标值可能超过[0,1]范围,所以有下面的判定
下面给我的源代码:
http://download.csdn.net/detail/qq_29523119/9670555
一,ProjectiveTexturing(投影纹理)的简介.
ProjectiveTexturing(投影纹理)是实现3D实时渲染的最重要的技术之一,很多高级效果,如SoftShadow(软弱阴影),Water,ProjecvtiveLightMap(投影光照图),Reflection等效果都需要用到投影纹理技术。投影纹理意思就是将一张2D纹理投影到3D物体上或者换一个说法就是用一个特别的相机(建立单独的相机变换矩阵和透视投影矩阵)来获取世界空间3D物体投射在某张2D纹理上的UV坐标值。纹理投影技术经常和RTT(渲染到纹理技术)一起搭配使用,可以看看教程:D3D11教程二十一之Water(水的实现)以及D3D11教程三十一之ShadowMap(阴影贴图)之聚光灯成影,还有D3D11教程十九之PlannarReflection(基于RTT技术和投影纹理技术)都是投影纹理技术搭配RTT技术使用的典型例子,那两个教程中折射的物体和反射的物体的实现其实是投影纹理.
在来看看一个使用投影纹理的例子:
看上面这张有一个骷颅头的2D纹理贴图,利用这张2D纹理贴图我们可以生成下面的图形效果:
看这张图里面的骷髅头实际上仅仅是一张2D纹理贴图的效果,而不是真正地将一个3D骷颅头进行渲染的效果。
为了下面更好地讲述有关概念,我只好自创两个概念, ViewCamera(观察照相机)和ProjectorCamera(投影照相机或者投影幻灯机)
ViewCamera提供了我们在3D程序中的人眼观察的视角。
ProjectorCamera提供了投影机观察3D物体的角度,决定了世界空间(WorldSpace)中每个顶点对应于投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V).
在世界空间中(WorldSpace),我们是如何得到每个顶点对应于投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V)呢?
来看一张图:
看图中,这个视截体是ProjectorCamera(投影幻灯机)的视截体,点P是在世界空间的一个点(Xp,Yp,Zp,1.0),如何求出相应的(u,v)坐标呢?
要求投影纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V),首先得熟悉D3D11的3D渲染流水线:
我在D3D11教程二十五之DepthBuffer(深度缓存)论述过3D渲染流水线,求纹理坐标系(ProjectiveTextureCoordinate)相应的2D纹理坐标(U,V)分为两步:
(1) 假设在世界空间上,点P坐标为(Xp,Yp,Zp,1.0),乘以ProjectorCamera(注意不是ViewCamera)生成的相机变换矩阵和透视投影矩阵,变换到齐次裁剪空间
在齐次裁剪空P点相应的坐标值为
(Xp,Yp,Zp,Wp) -Wp=<Xp<=Wp -Wp=<Yp<=Wp 0=<Zp<=Wp,
(2)由于我们不标记“”SV_POSITION“”,显卡不会自动进行透视除法(当然显卡也不会自动进行裁剪算法),所以我们手动计算
-1<=Xp/Wp<=1 -1<=Yp/Wp<=1,
0=<{0.5*(Xp/Wp)+0.5}<=1, 0=<{-0.5*(Yp/Wp)+0.5}<=1
又由于投影纹理坐标系中 0=<U<=1 0=<V<=1,并且U坐标方向和X坐标方向相同,而V坐标方向和Y坐标相反,所以我们得出结果: U= 0.5*(Xp/Wp)+0.5;
V=-0.5*(Yp/Wp)+0.5;
下面我们放出投影幻灯机的类:
ViewPointClass.h
#pragma once #ifndef _VIEW_POINT_CLASS_H #define _VIEW_POINT_CLASS_H #include<Windows.h> #include<xnamath.h> class ViewPointClass { private: XMFLOAT3 mPostion; //投影相机的位置 XMFLOAT3 mLookAt; //投影相机看到的位置 XMMATRIX mProjectorViewMatirx, mProjectorProjMatrix; //投影相机的相机变换矩阵和投影矩阵 float mFieldOfView; //Fov视角大小 float mAspectRatio; //屏幕宽高比 float mNearPlane, mFarPlane; //视截体的近截面和远截面 public: ViewPointClass(); ViewPointClass(const ViewPointClass&); ~ViewPointClass(); public: //Set函数 void SetPostion(float,float,float); void SetLookAt(float,float,float); void SetProjectionParameters(float, float, float, float); //生成相机矩阵和投影矩阵 void GenerateViewMatrix(); void GenerateProjMatrix(); //Get函数 XMMATRIX GetViewMatrix(); XMMATRIX GetProjMatrix(); }; #endif
ViewPointClass.CPP
#include"ViewPointClass.h" ViewPointClass::ViewPointClass() { } ViewPointClass::~ViewPointClass() { } ViewPointClass::ViewPointClass(const ViewPointClass&other) { } void ViewPointClass::SetPostion(float x, float y, float z) { mPostion = XMFLOAT3(x, y, z); } void ViewPointClass::SetLookAt(float x, float y, float z) { mLookAt = XMFLOAT3(x, y, z); } void ViewPointClass::SetProjectionParameters(float FieldOfView, float AspectRatio, float NearPlane, float FarPlane) { mFieldOfView = FieldOfView; mAspectRatio = AspectRatio; mNearPlane = NearPlane; mFarPlane = FarPlane; } void ViewPointClass::GenerateViewMatrix() { XMVECTOR EyePostion = XMLoadFloat3(&mPostion); XMVECTOR LookAt = XMLoadFloat3(&mLookAt); XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f,0.0f); mProjectorViewMatirx = XMMatrixLookAtLH(EyePostion,LookAt,Up); } //近平面不变的条件下,远平面只影响远处看到物体的范围 void ViewPointClass::GenerateProjMatrix() { mProjectorProjMatrix = XMMatrixPerspectiveFovLH(mFieldOfView,mAspectRatio,mNearPlane,mFarPlane); } XMMATRIX ViewPointClass::GetViewMatrix() { return mProjectorViewMatirx; } XMMATRIX ViewPointClass::GetProjMatrix() { return mProjectorProjMatrix; }
ColorShader.fx
Texture2D BaseTexture:register(t0); //基础纹理 Texture2D ProjectiveTexture:register(t1); //投影纹理 SamplerState SampleType:register(s0); //采样方式 //VertexShader cbuffer CBMatrix:register(b0) { matrix World; matrix View; matrix Proj; matrix WorldInvTranspose; matrix ProjectorView; matrix ProjectorProj; }; cbuffer CBLight:register(b1) { float4 DiffuseColor; float3 LightDirection; float pad; } struct VertexIn { float3 Pos:POSITION; float2 Tex:TEXCOORD0; //多重纹理可以用其它数字 float3 Normal:NORMAL; }; struct VertexOut { float4 Pos:SV_POSITION; float4 ProjPos:POSITION; //投影坐标,投影在齐次裁剪空间 float2 Tex:TEXCOORD0; float3 W_Normal:NORMAL; //世界空间的法线 }; VertexOut VS(VertexIn ina) { VertexOut outa; //将坐标变换到观察相机下的齐次裁剪空间 outa.Pos = mul(float4(ina.Pos,1.0f), World); outa.Pos = mul(outa.Pos, View); outa.Pos = mul(outa.Pos, Proj); //将顶点法向量由局部坐标变换到世界坐标 outa.W_Normal = mul(ina.Normal, (float3x3)WorldInvTranspose); //此事世界逆转置矩阵的第四行本来就没啥用 //对世界空间的顶点法向量进行规格化 outa.W_Normal = normalize(outa.W_Normal); //获取纹理坐标 outa.Tex= ina.Tex; //将坐标变换到投影相机下的齐次裁剪空间 outa.ProjPos= mul(float4(ina.Pos, 1.0f), World); outa.ProjPos = mul(outa.ProjPos, ProjectorView); outa.ProjPos = mul(outa.ProjPos, ProjectorProj); return outa; } float4 PS(VertexOut outa) : SV_Target { float4 TexColor; //采集基础纹理颜色 float2 ProjTex; //投影纹理坐标 float4 color = {0.0f,0.0f,0.0f,0.0f}; //最终输出的颜色 //第一,获取采样颜色 TexColor = BaseTexture.Sample(SampleType, outa.Tex); //第二,获取投影相机下的投影纹理空间的坐标值[0.0,1.0] u=0.5*x+0.5; v=-0.5*y+0.5; -w<=x<=w -w<=y<=w ProjTex.x =(outa.ProjPos.x/outa.ProjPos.w)*0.5f + 0.5f; ProjTex.y= (outa.ProjPos.y/outa.ProjPos.w)*(-0.5f) + 0.5f; //第三,由于3D模型可能超出投影相机下的视截体,其投影纹理可能不在[0.0,1.0],所以得进行判定这个3D物体投影的部分是否在视截体内 (没SV_POSITION签名 显卡不会进行裁剪) if (saturate(ProjTex.x) == ProjTex.x&&saturate(ProjTex.y) == ProjTex.y) { TexColor= ProjectiveTexture.Sample(SampleType, ProjTex); } color = TexColor; return color; }
下面是我将用到的投射到3D物体上的2D纹理:
这是没用投射纹理技术的
这是我们用了投影纹理技术的:观察相机位置A(0.0f,
6.0f, -12.0f) 投影相机(投影机)的位置B(2.0f, 5.0f, -2.0f),好吧,
在下图我做出辅助线来,观察相机A点的视截体我就不作辅助线了,作投影相机B的辅助线,红色的点为投影相机的视截体和平面的交点,画画水平有点糟糕,请见谅:
最后注意的是,在Shader可以看到我们的判定:由于我们 float4 ProjPos:POSITION 没标记“”POSTION“” 而不是“”SV_POSITION“”,显卡不会进行视截体内外面部分的裁剪,所以求得的UV坐标值可能超过[0,1]范围,所以有下面的判定
//第三,由于3D模型可能超出投影相机下的视截体,其投影纹理可能不在[0.0,1.0],所以得进行判定这个3D物体投影的部分是否在视截体内 (没SV_POSITION签名 显卡不会进行裁剪) if (saturate(ProjTex.x) == ProjTex.x&&saturate(ProjTex.y) == ProjTex.y) { TexColor= ProjectiveTexture.Sample(SampleType, ProjTex); }
下面给我的源代码:
http://download.csdn.net/detail/qq_29523119/9670555
相关文章推荐
- 【Visual C++】游戏开发笔记三十 DirectX11 2D纹理映射知识全攻略
- Directx11教程36 纹理映射(6)
- Directx11教程三十四之ProjectiveLightMap(投影光照图)
- Directx11教程(43) 纹理映射(13)-动态纹理映射
- Directx11教程九之多重纹理和纹理数组
- Directx11教程37 纹理映射(7)
- Directx11教程(65) 渲染到纹理
- Directx11教程(35) 纹理映射(5)
- 【Visual C++】游戏开发笔记三十 DirectX11 2D纹理映射知识全攻略
- Directx11教程38 纹理映射(8)
- Directx11教程(31) 纹理映射(1)
- Directx11教程(32) 纹理映射(2)
- Directx11教程41 纹理映射(11)
- Directx11教程(42) 纹理映射(12)-简单的bump mapping
- Directx11教程(33) 纹理映射(3)
- 【Visual C++】游戏开发笔记三十 DirectX11 2D纹理映射知识全攻略
- Directx11教程39 纹理映射(9)
- Directx11基础教程四之Texture(纹理)
- 【Visual C++】游戏开发笔记三十 DirectX11 2D纹理映射知识全攻略
- Directx11教程40 纹理映射(10)