Cg Programming/Unity/Glossy Textures光泽纹理
来源:互联网 发布:iphone搞怪视频软件 编辑:程序博客网 时间:2024/06/06 15:34
从国际空间站(ISS)看到的太平洋上空带有镜面高光的日没。
本教程涵盖了部分光滑纹理表面的逐像素光照。
译者注:通过普通的镜面高光(specular light)方程,可以使得模型在某个角度看起来具有光泽。 但是有时候我们想使得模型的高光区域是不规则的。您可以使用光泽贴图(Gloss Map)控制反射高光显示位置。指定给光泽度材质组件的贴图决定整个曲面的哪些区域更有光泽,哪些区域不太有光泽,具体情况取决于贴图中颜色的强度。贴图中的黑色像素将产生全面的光泽。白色像素将完全消除光泽,中间值会减少高光的大小。
光泽贴图是一张黑白纹理,我们使用这张纹理控制特定顶点的反射程度,黑白纹理让我们可以很容易地做到这点
扩展阅读
它结合章节“纹理球体”和“光滑镜面高光”中的着色器代码来计算带有一个材质颜色的逐像素光照,对于漫反射它是由纹理的RGB分量决定的,镜面反射的强度是由相同纹理的A分量决定的。如果你没有读过这些章节,这会是一个非常好的机会来了解它们。
光泽映射
在章节“光照纹理表面”中,漫反射的材质常量是由纹理贴图的RGB分量决定的。这里我们延伸一下这个技术,然后通过相同纹理贴图的A (alpha)分量来决定镜面反射的强度。只使用一张纹理就提供了显著的性能优势,特别是因为RGBA纹理查找代价在某种情况下跟RGB纹理查找同样昂贵(译者注:为什么昂贵可以参考以上的扩展阅读)。
如果纹理贴图的“光泽度”(即镜面反射的强度)被编码在RGBA纹理贴图的A (alpha)中,我们可以简单地把镜面反射材质常量与纹理贴图的alpha分量进行相乘。在章节“镜面高光”中介绍过,并且它出现在Phone反射模型的镜面反射项中:
如果乘以纹理贴图的alpha分量,这个值就会在alpha为1时达到最大(也就是表面是光泽的),在alpha为0时等于0(也就是表面没有任何光泽)。
逐像素光照代码
带有透明水的地球地图,也就是水的alpha分量为0,陆地的alpha分量为1。
下面这段着色器代码结合了章节“光滑镜面高光”的逐像素光照和章节“纹理球体”中的纹理映射。跟章节“光照纹理表面”类似,在textureColor中纹理颜色的RGB分量乘以漫射材质颜色_Color。
在上图中,水的alpha分量为0,陆地的alpha分量为1。但是,水应该是有光泽的而陆地没有。因此,在这个特定的图片中,我们应该用(1.0 - textureColor.a)乘以镜面材质颜色。另一方面,通常光泽映射会需要跟textureColor.a相乘。(注意对于着色器编程来讲这种改变有多简单。)
Shader "Cg per-pixel lighting with texture" { Properties { _MainTex ("RGBA Texture For Material Color", 2D) = "white" {} _Color ("Diffuse Material Color", Color) = (1,1,1,1) _SpecColor ("Specular Material Color", Color) = (1,1,1,1) _Shininess ("Shininess", Float) = 10 } SubShader { Pass { Tags { "LightMode" = "ForwardBase" } // pass for ambient light and first light source CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4 _LightColor0; // color of light source (from "Lighting.cginc") // User-specified properties uniform sampler2D _MainTex; uniform float4 _Color; uniform float4 _SpecColor; uniform float _Shininess; struct vertexInput { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct vertexOutput { float4 pos : SV_POSITION; float4 posWorld : TEXCOORD0; float3 normalDir : TEXCOORD1; float4 tex : TEXCOORD2; }; vertexOutput vert(vertexInput input) { vertexOutput output; float4x4 modelMatrix = _Object2World; float4x4 modelMatrixInverse = _World2Object; output.posWorld = mul(modelMatrix, input.vertex); output.normalDir = normalize( mul(float4(input.normal, 0.0), modelMatrixInverse).xyz); output.tex = input.texcoord; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); return output; } float4 frag(vertexOutput input) : COLOR { float3 normalDirection = normalize(input.normalDir); float3 viewDirection = normalize( _WorldSpaceCameraPos - input.posWorld.xyz); float3 lightDirection; float attenuation; float4 textureColor = tex2D(_MainTex, input.tex.xy); if (0.0 == _WorldSpaceLightPos0.w) // directional light? { attenuation = 1.0; // no attenuation lightDirection = normalize(_WorldSpaceLightPos0.xyz); } else // point or spot light { float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz; float distance = length(vertexToLightSource); attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource); } float3 ambientLighting = textureColor.rgb * UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb; float3 diffuseReflection = textureColor.rgb * attenuation * _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDirection, lightDirection)); float3 specularReflection; if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side? { specularReflection = float3(0.0, 0.0, 0.0); // no specular reflection } else // light source on the right side { specularReflection = attenuation * _LightColor0.rgb * _SpecColor.rgb * (1.0 - textureColor.a) // for usual gloss maps: "... * textureColor.a" * pow(max(0.0, dot( reflect(-lightDirection, normalDirection), viewDirection)), _Shininess); } return float4(ambientLighting + diffuseReflection + specularReflection, 1.0); } ENDCG } Pass { Tags { "LightMode" = "ForwardAdd" } // pass for additional light sources Blend One One // additive blending CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" uniform float4 _LightColor0; // color of light source (from "Lighting.cginc") // User-specified properties uniform sampler2D _MainTex; uniform float4 _Color; uniform float4 _SpecColor; uniform float _Shininess; struct vertexInput { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; }; struct vertexOutput { float4 pos : SV_POSITION; float4 posWorld : TEXCOORD0; float3 normalDir : TEXCOORD1; float4 tex : TEXCOORD2; }; vertexOutput vert(vertexInput input) { vertexOutput output; float4x4 modelMatrix = _Object2World; float4x4 modelMatrixInverse = _World2Object; output.posWorld = mul(modelMatrix, input.vertex); output.normalDir = normalize( mul(float4(input.normal, 0.0), modelMatrixInverse).xyz); output.tex = input.texcoord; output.pos = mul(UNITY_MATRIX_MVP, input.vertex); return output; } float4 frag(vertexOutput input) : COLOR { float3 normalDirection = normalize(input.normalDir); float3 viewDirection = normalize( _WorldSpaceCameraPos - input.posWorld.xyz); float3 lightDirection; float attenuation; float4 textureColor = tex2D(_MainTex, input.tex.xy); if (0.0 == _WorldSpaceLightPos0.w) // directional light? { attenuation = 1.0; // no attenuation lightDirection = normalize(_WorldSpaceLightPos0.xyz); } else // point or spot light { float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - input.posWorld.xyz; float distance = length(vertexToLightSource); attenuation = 1.0 / distance; // linear attenuation lightDirection = normalize(vertexToLightSource); } float3 diffuseReflection = textureColor.rgb * attenuation * _LightColor0.rgb * _Color.rgb * max(0.0, dot(normalDirection, lightDirection)); float3 specularReflection; if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side? { specularReflection = float3(0.0, 0.0, 0.0); // no specular reflection } else // light source on the right side { specularReflection = attenuation * _LightColor0.rgb * _SpecColor.rgb * (1.0 - textureColor.a) // for usual gloss maps: "... * textureColor.a" * pow(max(0.0, dot( reflect(-lightDirection, normalDirection), viewDirection)), _Shininess); } return float4(diffuseReflection + specularReflection, 1.0); // no ambient lighting in this pass } ENDCG } } Fallback "Specular"}
对于以上特定的图像的着色器,一个有意义的修改就是在alpha分量为0时设置漫反射材质颜色为深蓝色。
逐顶点光照着色器
就像在章节“光滑镜面高光”中讨论的一样,用逐顶点光照的镜面高光通常渲染得不是很好。但是,有时因为性能上限制我们并没有其它选择。为了在章节“光照纹理表面”中的着色器包含光泽映射,两个通道的片元着色器应该被以下的代码替换:
float4 frag(vertexOutput input) : COLOR { float4 textureColor = tex2D(_MainTex, input.tex.xy); return float4(input.specularColor * (1.0 - textureColor.a) + input.diffuseColor * textureColor.rgb, 1.0); }
注意通常的光泽映射应该需要跟textureColor.a相乘而不是(1.0 - textureColor.a)。
总结
恭喜,你完成了关于光泽映射最重要一章的学习。我们学到了:
- 什么是光泽映射
- 如何用逐顶点光照实现光泽映射
- 如何用逐像素光照实现光泽映射
扩展阅读
- 关于逐像素光照(没有纹理),你应该阅读章节“光滑镜面高光”。
- 关于纹理映射,你应该阅读章节“纹理球体”。
- 关于纹理映射的逐顶点光照,你应该阅读章节“光照纹理表面”。
- Cg Programming/Unity/Glossy Textures光泽纹理
- Cg Programming/Unity/Transparent Textures透明纹理
- Cg Programming/Unity/Layers of Textures纹理的层级
- Cg Programming/Unity/Textured Spheres纹理球体
- Cg Programming/Unity/Lighting Textured Surfaces光照纹理表面
- Cg Programming/Unity 目录
- Cg Programming/Unity/Transparency
- Cg Programming/Unity
- Cg Programming/Unity/Cutaways
- Cg Programming/Unity/Cookies
- wiki/Cg Programming/Unity/Cutaways
- Cg Programming/Unity/Transparency透明度
- Cg Programming/Unity/Billboards广告牌
- 纹理(Textures)
- 《CG Programming in Unity》笔记1-基础知识
- wiki/Cg Programming/Unity/shder_理解准备
- Cg Programming in Unity - 3.2 Specular Highlights
- Cg Programming/Unity/Order-Independent Transparency
- jQuery的鼠标移入与移出事件
- 第二十五天 文件的操作
- cGIS for Android 自定义地图比例尺
- CentOS 第 一次使用
- html&css---------css简介(11/2)
- Cg Programming/Unity/Glossy Textures光泽纹理
- 美解决Android在listview添加checkbox实现单选多选操作问题
- Python的set集合详解
- 学习hibernate遇到的问题及解决方案
- ios下点击label包含的input checkbox或radio无效问题
- DIV+CSS规范命名大全集合
- Java 基础巩固:再谈抽象类和接口
- python学习-Day14-高阶函数
- 将本地仓库文件上传到git