您的位置:首页 > 其它

Directx11教程三十之ProjectiveTexturing(投影纹理)

2016-11-01 21:33 267 查看
这节教程是介绍有关ProjectiveTexturing(投影纹理)技术的,结构如下



一,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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: