unity android 反射,在Unity3D中创建反射纹理

本文详细介绍了在Unity3D中如何创建和使用动态反射CubeMap,包括预渲染CubeMap和通过六个相机捕捉不同方向场景创建动态CubeMap的方法,以及在Shader中应用反射的技术。通过实例展示了如何实现物体对周围环境的实时反射效果,并探讨了其在移动平台上的优化考虑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

距离上次技术相关的博文有半年了吧。。。这次回来了,会坚持下去。

说到反射纹理,本质上就是创建一个 CubeMap 立方体贴图, 把需要被反射的目标渲染的6个纹理上, 然后反射的物体根据自身的法线方向在对应的6个面上进行采样。

一步一步来

首先创建一个CubeMap纹理

在project面板上右键->Create->Legacy->CubeMap

然后在Inspector面板上将前后左右上下的纹理添加进去 like this..

cubemaptex.png

创建好后,不如把它作为天空盒吧,这样到时候反射物体可以直接反射周围的天空的说,说干就干。。

首选创建一个材质,设置材质的Shader为skybox->Cubemap,然后把刚才创建的纹理赋予它 like this

cubemapmat.png

打开菜单 Window->Lighting 将创建的材质放入 SkyBox槽位,我们就能看见天空啦

skyboxview.jpg

之后我们需要编写一个Shader来对天空盒的cubemap 进行采样,就是反射啦

Shader "Custom/CubeMap" {

Properties {

_Cube("Reflection Map", Cube) = "" {}

}

SubShader {

Pass

{

CGPROGRAM

#pragma  vertex vert

#pragma  fragment frag

#include "UnityCG.cginc"

uniform samplerCUBE _Cube;

struct vertexInput

{

float4 vertex : POSITION;

float3 normal : NORMAL;

};

struct vertexOutput

{

float4 pos : SV_POSITION;

float3 normalDir : TEXCOORD0;

float3 viewDir : TEXCOORD1;

};

vertexOutput vert(vertexInput input)

{

vertexOutput output;

float4x4 modelMatrix = _Object2World;

float4x4 modelMatrixInverse = _World2Object;

//计算视野方向,世界空间顶点与世界空间内相机位置相减

output.viewDir = mul(modelMatrix, input.vertex).xyz - _WorldSpaceCameraPos;

//将法线从模型空间也统一转换到世界空间

output.normalDir = normalize(mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);

output.pos = mul(UNITY_MATRIX_MVP, input.vertex);

return output;

}

float4 frag(vertexOutput input) :COLOR

{

//计算视线方向与法线法线方向的反射向量

float3 reflectDir = reflect(input.viewDir, input.normalDir);

//texCUBE是CubeMap采样,tex2D是2D纹理采样

return texCUBE(_Cube, reflectDir);

}

ENDCG

}

}

FallBack "Diffuse"

}

之后创建一个材质 叫CubeMapMat 使用上面的Shader

最后我们在场景上创建一个 Sphere 物件将 CubeMapMat 材质赋予它,运行看看效果

skyboxview1.jpg

=。= 是不是感觉很简单,因为它只能反射预设好的纹理,所以假设在游戏中,有个游戏人物路过这个反射体,游戏人物是无法被反射出来的。。所以很没意思,我们要更进一步。创建一个动态渲染的CubeMap.

话说,这里我做了个实验,但是失败了。。

我创建了6个相机,分别朝向 +X -X +Y -Y +Z -Z 然后再创建6个RenderTexture 将相机拍摄的6个方向的景物都渲染到对应的6个纹理上。。

然后问题来了。。我找不到方法将这6个纹理合并成CubeMap…无论是动态创建一个CubeMap Class 还是创建一个RenderTexture 然后设置 isCubeMap 都没有设置6个面的API…连设置UV都没有。 当年写Stage3D是可以这么干的。。看来Unity3D这部分封装掉了,连自己组装的机会都不给。。。

最后只好使用官方范例来实现了

大致流程创建一个隐藏的 DummyCamera, 然后使用它的API RenderToCubemap(CubeMap, FaceMask) 来动态创建CubeMap. 貌似调用了这个API, 这个DummyCamera 就会自动往6个方向拍。真是够智能,不过我不喜欢。。

准备工作是这样的

创建一个反射物件,就拿刚才的Sphere来用就行

创建一个CubeMap材质搭配上刚才的CubeMap Shader 但是这里不需要给材质选中特定的纹理,我们在脚本中会动态创建纹理赋予这个材质

具体C# Script如下

using UnityEngine;

using System.Collections;

public class CubeMap : MonoBehaviour

{

public int CubeMapSize = 128;

public bool onFacePerFrame = false;

private Camera cam;

private RenderTexture rtex;

private GameObject go;

// Use this for initialization

[ExecuteInEditMode]

void Start () {

UpdateCubeMap(63);

}

void LateUpdate()

{

if (onFacePerFrame)

{

int faceToRender = Time.frameCount % 6;

int faceMask = 1 << faceToRender;

//Debug.Log(faceMask);

UpdateCubeMap(faceMask);

}

else

{

UpdateCubeMap(63);

}

}

void UpdateCubeMap(int faceMask)

{

if (!cam)

{

go = new GameObject("CubemapCamera");

go.AddComponent(typeof(Camera));

go.hideFlags = HideFlags.HideAndDontSave;

go.transform.position = transform.position;

go.transform.rotation = Quaternion.identity;

cam = go.GetComponent();

cam.farClipPlane = 100;

cam.enabled = false;

}

if (!rtex)

{

rtex = new RenderTexture(CubeMapSize, CubeMapSize, 16);

rtex.isCubemap = true;

rtex.hideFlags = HideFlags.HideAndDontSave;

GetComponent().sharedMaterial.SetTexture("_Cube", rtex); //这里需要注意,在Shader中必须有个同名的属性 _Cube 才会有效果。

}

cam.transform.position = transform.position;

cam.RenderToCubemap(rtex, faceMask);

}

void OnDisable()

{

DestroyImmediate(cam);

DestroyImmediate(rtex);

}

// Update is called once per frame

void Update () {

}

}

很多人看到 Start() 函数中有 UpdateCubeMap(63);

会好奇为什么是63

实际上63表示渲染全部6个面

63实际上是个枚举值 6个面对应的facemask 是 1,2,4,8,16,32

它们相加的值就是63

在函数 LateUpdate()中有优化代码,即分帧渲染不同的面

int faceToRender = Time.frameCount % 6; //这里会输出 1 ~ 6

int faceMask = 1 << faceToRender; //这里会输出 1,2,4,8,16,32

好了,解惑完了,我们在场景上随便放2个Cube 看看效果。

skyboxend.png

see that? 这下可以动态反射周围的一切啦。。

but.. 根据我玩过的几款3A大作。。 比如。。。。 他们的反射做做到文章一开始的那种,即预渲染好的场景CubeMap,就是说照镜子看不到自己。。所以如果出移动平台游戏的话,还是不要作死的好。。

finally.. 我的windows8.1 装了 jdk 7079 后,玩 魔兽争霸3 dota 居然跟我崩溃了。。我勒个去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值