news 2026/5/26 12:50:16

【光照】Unity如何在Cubemap中采样反射信息?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【光照】Unity如何在Cubemap中采样反射信息?

介绍与发展历史

Cubemap(立方体贴图)是一种由六个独立的正方形纹理组成的集合,它将多个纹理组合起来映射到一个单一纹理。Cubemap包含6个2D纹理,每个2D纹理代表立方体的一个面,形成一个有贴图的立方体。

Cubemap技术起源于早期的3D图形学,最初用于实现天空盒效果。随着硬件性能的提升和图形API的发展,Cubemap逐渐被广泛应用于环境映射、反射和折射等高级渲染效果中。

应用领域

Cubemap在Unity中主要有以下应用场景:

‌环境反射‌:用于模拟金属、玻璃等具有反射属性物体的反射效果

‌天空盒‌:创建环境背景,提供场景的全局光照信息

‌折射效果‌:模拟透明材质的折射现象

‌全局光照‌:作为间接光照的来源之一

采样反射信息原理

基本原理

Cubemap采样的核心原理是使用方向向量进行索引和采样。想象一个1×1×1的单位立方体,中心位于原点。当从原点发出一个方向向量时,该向量会与立方体的某个面相交,交点处的纹理就是采样结果。

反射计算原理

反射效果的计算过程如下:

计算相机指向物体表面点的向量(视线向量)

根据表面法线计算反射向量

使用反射向量在Cubemap中进行采样(URP中使用宏SAMPLE_TEXTURECUBE实现采样,这个宏实际调用PLATFORM_SAMPLE_TEXTURECUBE宏来处理不同图形API的采样方法,下面有详细讲原理讲解。)

将采样颜色与物体本身的颜色混合

数学上,反射向量R可以通过以下公式计算:

R = I - 2 * dot(N, I) * N

其中I是入射向量(视线向量取反),N是表面法线。

PLATFORM_SAMPLE_TEXTURECUBE的实现原理

PLATFORM_SAMPLE_TEXTURECUBE是Unity URP中用于跨平台Cubemap采样的关键宏,它封装了不同图形API(Direct3D、OpenGL、Metal)下Cubemap采样的实现差异,为开发者提供统一的采样接口。

数学原理基础

Cubemap是一个由6个2D纹理组成的立方体,每个面代表一个方向(±X, ±Y, ±Z)。使用反射向量作为方向索引,可以获取立方体相应位置的纹理颜色

1. 方向向量确定采样面

Cubemap采样基于3D方向向量,通过以下步骤确定采样面:

数学表达式:

主面 = max(|x|, |y|, |z|)

if (主面 == |x|)

if (x > 0) → +X面

else → -X面

else if (主面 == |y|)

if (y > 0) → +Y面

else → -Y面

else

if (z > 0) → +Z面

else → -Z面

## **2. 方向向量到UV坐标转换**

确定采样面后,将3D方向向量转换为2D UV坐标的数学过程:

对于+X面(右面):

u = 0.5 * (1 - (z / |x|))

v = 0.5 * (1 - (y / |x|))

对于-Y面(下面):

u = 0.5 * (1 - (x / |y|))

v = 0.5 * (1 + (z / |y|))

其他面的转换类似,但需要考虑不同面的坐标系差异。

## **URP中的具体实现**

### **PLATFORM_SAMPLE_TEXTURECUBE宏定义**

在URP Core.hlsl中,该宏通常定义为:

```c

hlsl

#define PLATFORM_SAMPLE_TEXTURECUBE(textureName, samplerName, coord3) \

SampleTexture(textureName, samplerName, coord3)

实际采样函数会根据平台不同而有所区别,但对外提供统一接口。

反射向量计算示例

在URP Shader中计算反射向量并采样Cubemap的完整过程:

计算视线向量(从表面点到相机):

hlsl

float3 viewDir = GetWorldSpaceViewDir(positionWS);

计算反射向量:

hlsl

float3 reflectDir = reflect(-viewDir, normalWS);

采样Cubemap:

hlsl

float4 cubemapColor = PLATFORM_SAMPLE_TEXTURECUBE(_Cubemap, sampler_Cubemap, reflectDir);

解码HDR颜色(如果需要):

hlsl

float3 reflection = DecodeHDREnvironment(cubemapColor, _Cubemap_HDR);

混合反射颜色与表面颜色:

hlsl

float3 finalColor = lerp(diffuseColor, reflection, _ReflectAmount);

不同图形API的实现差异

Direct3D

面顺序:+X, -X, +Y, -Y, +Z, -Z

UV坐标系:左上角为(0,0),右下角为(1,1)

需要特别注意Y轴的朝向

OpenGL

面顺序:+X, -X, +Y, -Y, +Z, -Z

UV坐标系:左下角为(0,0),右上角为(1,1)

通常需要翻转Y轴坐标

Metal

使用MTLTextureTypeCube类型

面顺序与Direct3D类似

采样时需要考虑坐标系转换

数学示例:具体采样过程

假设有一个方向向量(0.5, -0.3, 0.8),计算其在Cubemap中的采样位置:

确定主分量:

|x|=0.5, |y|=0.3, |z|=0.8 → 主分量为z

确定采样面:

z=0.8 > 0 → +Z面

计算UV坐标:

u = 0.5 * (1 + (x/|z|)) = 0.5 * (1 + (0.5/0.8)) ≈ 0.8125

v = 0.5 * (1 - (y/|z|)) = 0.5 * (1 - (-0.3/0.8)) ≈ 0.6875

在+Z面纹理上采样(0.8125, 0.6875)处的颜色

性能优化考虑

‌粗糙度与Mipmap‌:根据表面粗糙度选择适当的Mipmap级别,粗糙表面使用更高层级的Mipmap

float perceptualRoughness = 1.0 - _Smoothness;

float mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);

float4 envColor = SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, reflectDir, mip);

URP中的PLATFORM_SAMPLE_TEXTURECUBE宏通过统一这些复杂操作,使开发者能够专注于材质效果本身,而无需关心底层平台差异

实现示例

以下是一个简单的反射Cubemap的Shader实现:

定义Shader属性,包括颜色、反射颜色、反射强度和Cubemap纹理

顶点着色器计算世界空间的位置、法线、视线方向和反射方向

片元着色器计算环境光、漫反射和反射颜色

使用lerp函数混合漫反射和反射颜色,控制反射强度

最终输出混合后的颜色

URPReflection.shader

Shader "Custom/URPReflection"

{

Properties

{

_BaseColor("Base Color", Color) = (1,1,1,1)

_ReflectColor("Reflection Color", Color) = (1,1,1,1)

_ReflectAmount("Reflect Amount", Range(0,1)) = 0.5

_Cubemap("Reflection Cubemap", Cube) = "_Skybox" {}

_Smoothness("Smoothness", Range(0,1)) = 0.5

}

SubShader

{

Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }

HLSLINCLUDE

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

struct Attributes

{

float4 positionOS : POSITION;

float3 normalOS : NORMAL;

};

struct Varyings

{

float4 positionHCS : SV_POSITION;

float3 positionWS : TEXCOORD0;

float3 normalWS : TEXCOORD1;

float3 viewDirWS : TEXCOORD2;

float3 reflectDir : TEXCOORD3;

};

CBUFFER_START(UnityPerMaterial)

half4 _BaseColor;

half4 _ReflectColor;

half _ReflectAmount;

half _Smoothness;

CBUFFER_END

TEXTURECUBE(_Cubemap);

SAMPLER(sampler_Cubemap);

Varyings vert(Attributes IN)

{

Varyings OUT;

// 顶点变换

OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);

OUT.positionWS = TransformObjectToWorld(IN.positionOS.xyz);

OUT.normalWS = TransformObjectToWorldNormal(IN.normalOS);

// 计算视线方向(从表面点到相机)

OUT.viewDirWS = GetWorldSpaceViewDir(OUT.positionWS);

// 计算反射方向

float3 viewDir = normalize(OUT.viewDirWS);

OUT.reflectDir = reflect(-viewDir, normalize(OUT.normalWS));

return OUT;

}

half4 frag(Varyings IN) : SV_Target

{

// 标准化法线和反射方向

float3 normalWS = normalize(IN.normalWS);

float3 reflectDir = normalize(IN.reflectDir);

// 计算漫反射光照

Light light = GetMainLight();

float3 lightDir = normalize(light.direction);

float NdotL = saturate(dot(normalWS, lightDir));

half3 diffuse = _BaseColor.rgb * light.color * NdotL;

// 采样Cubemap

half perceptualRoughness = 1.0 - _Smoothness;

half mip = PerceptualRoughnessToMipmapLevel(perceptualRoughness);

half4 cubemapColor = SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, reflectDir, mip);

half3 reflection = DecodeHDREnvironment(cubemapColor, unity_SpecCube0_HDR) * _ReflectColor.rgb;

// 混合漫反射和反射

half3 color = lerp(diffuse, reflection, _ReflectAmount);

return half4(color, 1.0);

}

ENDHLSL

}

}

Cubemap生成方法

在Unity中可以通过以下步骤生成Cubemap:

创建空物体作为观察位置

在Project视图右键创建Legacy/Cubemap

使用脚本调用Camera.RenderToCubemap方法生成

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/26 5:51:06

Visio终极形状库:免费完整版一键导入技巧

Visio终极形状库:免费完整版一键导入技巧 【免费下载链接】史上最全Visio形状库分享 你是否在使用Microsoft Visio时,发现内置的形状库无法满足你的需求?你是否在寻找一个更全面、更丰富的形状库来提升你的绘图效率?那么&#xff…

作者头像 李华
网站建设 2026/5/25 23:42:51

多角度AI视觉革命:自然语言重塑图像视角控制新纪元

多角度AI视觉革命:自然语言重塑图像视角控制新纪元 【免费下载链接】Qwen-Edit-2509-Multiple-angles 项目地址: https://ai.gitcode.com/hf_mirrors/dx8152/Qwen-Edit-2509-Multiple-angles 在数字创意日益重要的今天,图像视角控制已成为内容创…

作者头像 李华
网站建设 2026/5/25 14:00:11

5大实战技巧:重新定义DeepSeek大模型推理性能

5大实战技巧:重新定义DeepSeek大模型推理性能 【免费下载链接】DeepSeek-V3.2-Exp DeepSeek-V3.2-Exp是DeepSeek推出的实验性模型,基于V3.1-Terminus架构,创新引入DeepSeek Sparse Attention稀疏注意力机制,在保持模型输出质量的同…

作者头像 李华
网站建设 2026/5/25 12:22:49

【Web第三周】『12.9-12.14』

【Web第三周】『12.9-12.14』 1.初步了解数据库(MySQL) 2.初步了解sql注入漏洞 3.练习sql语句 4.搭建sql靶场,找不到的,靶场文件群文件有 1、MySQL …

作者头像 李华
网站建设 2026/5/25 23:42:41

RustDesk隐私模式:实现远程操作完全隐藏的专业解决方案

RustDesk隐私模式:实现远程操作完全隐藏的专业解决方案 【免费下载链接】rustdesk 一个开源的远程桌面,是TeamViewer的替代选择。 项目地址: https://gitcode.com/GitHub_Trending/ru/rustdesk 在当今数字化工作环境中,远程桌面协助已…

作者头像 李华
网站建设 2026/5/25 23:42:38

如何快速掌握Lottie-web:提升开发效率的完整指南

如何快速掌握Lottie-web:提升开发效率的完整指南 【免费下载链接】lottie-web 项目地址: https://gitcode.com/gh_mirrors/lot/lottie-web 你是否曾经为网页动画效果而苦恼?手动编写复杂的CSS动画代码,调试各种浏览器兼容性问题&…

作者头像 李华