您的位置:首页 > 移动开发 > Unity3D

Unity3d 基于物理渲染Physically-Based Rendering之最终篇

2015-03-11 20:57 369 查看
前情提要:

讲求基本算法

Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF

plus篇
Unity3d 基于物理渲染Physically-Based Rendering之实现


最后我们用fragment shader 实现,加上diffuse漫反射,代码和之前的surface差不多,只是多了reflect方向的计算,reflect方向的计算方法为用CG函数库中函数reflect,

float3 reflect(float3 i, float3 n);

i为in入射方向,n为normal发现方向,此处入射方向为view direction。

float3 refDir = reflect(-viewDir,N);


参考了下SIGGRAPH 2013中虚幻引擎的diffuse

他们的方法为new diffuse = diffuse color/π。

把π改为可控参数就好,调成我们想要的效果。

建立了一个外部变量_ReflAmount为cubeMap和diffuse的比重,_ReflAmount越高反射周围景物越明显

这是本文实现效果








_ReflAmount = 0.5




_ReflAmount = 0

有没有要滴出血的感觉?




_ReflAmount = 1

高大上的丝袜黑



_ReflAmount = 1




_ReflAmount = 0




_ReflAmount = 0.5

与unity作比较:

diffuse:



specular:



这是虚幻引擎在SIGGRAPH 2013发表的效果:







可惜我没有那么高大上的模型做实验,可惜了,就用人脸做代替

代码如下:

    Shader "Custom/reflect new ops3" {  
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_Maintint("Main Color", Color) = (1, 1, 1, 1)
_Cubemap("CubeMap", CUBE) = ""{}
_SC("Specular Color", Color) = (1, 1, 1, 1)
_GL("gloss", Range(0, 1)) = 0.5
_nMips("nMipsF", Range(0, 5)) = 0.5
_ReflAmount("Reflection Amount", Range(0.01, 1)) = 0.5
}
SubShader{
pass{//平行光的的pass渲染
Tags{ "LightMode" = "ForwardBase" }
Cull Back
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

float4 _LightColor0;
samplerCUBE _Cubemap;
float4 _SC;
float _GL;
float4 _Maintint;
float _nMips;
float _ReflAmount;
uniform sampler2D _MainTex;
float4 _MainTex_ST;
struct v2f {
float4 pos : SV_POSITION;
float2 uv_MainTex : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
float3 normal : TEXCOORD3;

};

v2f vert(appdata_full v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//切换到世界坐标
o.normal = v.normal;
o.lightDir = ObjSpaceLightDir(v.vertex);
o.viewDir = ObjSpaceViewDir(v.vertex);
o.uv_MainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
#define PIE 3.1415926535


float4 frag(v2f i) :COLOR
{
float3 viewDir = normalize(i.viewDir);
float3 lightDir = normalize(i.lightDir);
float3 H = normalize(lightDir + viewDir);
float3 N = normalize(i.normal);
float _SP = pow(8192, _GL);
float d = (_SP + 2) / (8 * PIE) * pow(dot(N, H), _SP);
// float f = _SC + (1 - _SC)*pow((1 - dot(H, lightDir)), 5);
float f = _SC + (1 - _SC)*pow(2, -10 * dot(H, lightDir));
float k = min(1, _GL + 0.545);
float v = 1 / (k* dot(viewDir, H)*dot(viewDir, H) + (1 - k));

float all = d*f*v;
// float3 refDir = N - lightDir / 2;//H
float3 refDir = reflect(-viewDir,N);
float3 ref = texCUBElod(_Cubemap, float4(refDir, _nMips - _GL*_nMips)).rgb;//* _ReflAmount;
float3 c = tex2D(_MainTex, i.uv_MainTex);
float3 diff = dot(lightDir, N);
// diff /= PIE;
diff = (1 - all)*diff;

// return float4(c *(diff + all), 1) * _LightColor0;
return float4(lerp(c, ref, _ReflAmount) *(diff*_Maintint + all), 1)*_LightColor0;
// return float4(ref*((_Maintint+0.2) * (1 - dot(lightDir, N))) + c *(diff*_Maintint + all), 1)*_LightColor0;
// return float4(lerp(c, ref, _ReflAmount) *(diff*(_Maintint + 0.2)* (1 - dot(lightDir, N)) + all), 1)*_LightColor0;
}
ENDCG
}
}
}


----- by wolf96 http://blog.csdn.net/wolf96
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: