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

Cg Programming/Unity/Lighting Textured Surfaces光照纹理表面

2017-11-01 19:36 495 查看


本教程涵盖了纹理表面的逐顶点光照。

它结合了章节“纹理球体”和章节“镜面高光”的着色器代码,使用由一张贴图决定的漫反射材质颜色来计算光照。如果你没有读过那些章节,这会是一个非常棒的机会来阅读它们。

纹理及漫反射逐顶点光照

在章节“纹理球体”中,纹理颜色被用作片元着色器的输出。但是,也有可能使用纹理颜色作为光照计算中的任意参数,特别是对于漫反射中的材质常量

,它在章节“漫反射”中有过介绍。它出现在Phong反射模型中的漫射部分:



这个方程中对于三个颜色分量红、绿和蓝使用了不同的材质常量。通过使用一张贴图来决定这些材质常量,它们可以在表面上变化。

着色器代码

跟章节“镜面高光”中的逐顶点光照相比,这里的顶点着色器计算了额外的输出颜色:漫射颜色和镜面颜色,它们使用语义TEXCOORD1和TEXCOORD2。

在片元着色器中,参数diffuseColor跟贴图颜色相乘,并且specularColor就是镜面反射项,它不应该乘以纹理颜色。这是完全有道理的,但出于历史原因(也就是老的图形硬件不支持),它有时也被称作“单独的镜面颜色”;实际上,Unity的ShaderLab有一个选项“SeparateSpecular” 会激活或者禁用它。

注意属性_Color会被包含,它会乘以漫射颜色的所有部分(分量);因此,它作为一个有用的颜色过滤器来着色或者阴影纹理颜色。

此外,有这个名字的属性必须使得备用着色器生效(也可以查看章节“漫反射”中关于备用着色器的讨论)。

Shader "Cg per-vertex lighting with texture" {
Properties {
_MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
_Color ("Overall Diffuse Color Filter", Color) = (1,1,1,1)
_SpecColor ("Specular Material Color", Color) = (1,1,1,1)
_Shininess ("Shininess", Float) = 10
}
SubShader {
Pass {
Tags { "LightMode" = "ForwardBase" }
// 环境光和第一个光源的通道

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 tex : TEXCOORD0;
float3 diffuseColor : TEXCOORD1;
float3 specularColor : TEXCOORD2;
};

vertexOutput vert(vertexInput input)
{
vertexOutput output;

float4x4 modelMatrix = _Object2World;
float4x4 modelMatrixInverse = _World2Object;

float3 normalDirection = normalize(
mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
float3 viewDirection = normalize(_WorldSpaceCameraPos
- mul(modelMatrix, input.vertex).xyz);
float3 lightDirection;
float attenuation;

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
- mul(modelMatrix, input.vertex).xyz;
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}

float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.rgb * _Color.rgb;

float3 diffuseReflection =
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 * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), _Shininess);
}

output.diffuseColor = ambientLighting + diffuseReflection;
output.specularColor = specularReflection;
output.tex = input.texcoord;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return output;
}

float4 frag(vertexOutput input) : COLOR
{
return float4(input.specularColor +
input.diffuseColor * tex2D(_MainTex, input.tex.xy),
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 tex : TEXCOORD0;
float3 diffuseColor : TEXCOORD1;
float3 specularColor : TEXCOORD2;
};

vertexOutput vert(vertexInput input)
{
vertexOutput output;

float4x4 modelMatrix = _Object2World;
float4x4 modelMatrixInverse = _World2Object;

float3 normalDirection = normalize(
mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
float3 viewDirection = normalize(_WorldSpaceCameraPos
- mul(modelMatrix, input.vertex).xyz);
float3 lightDirection;
float attenuation;

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
- mul(modelMatrix, input.vertex).xyz;
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance; // linear attenuation
lightDirection = normalize(vertexToLightSource);
}

float3 diffuseReflection =
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 * pow(max(0.0, dot(
reflect(-lightDirection, normalDirection),
viewDirection)), _Shininess);
}

output.diffuseColor = diffuseReflection; // no ambient
output.specularColor = specularReflection;
output.tex = input.texcoord;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return output;
}

float4 frag(vertexOutput input) : COLOR
{
return float4(input.specularColor +
input.diffuseColor * tex2D(_MainTex, input.tex.xy),
1.0);
}

ENDCG
}
}
Fallback "Specular"
}


In order to assign a texture image to this shader, you should follow the steps discussed in Section “Textured Spheres”.

为了把纹理贴图指定到这个着色器,你应该遵循“纹理球体”中讨论的步骤。

总结

Congratulations, you have reached the end. We have looked at:

How texturing and per-vertex lighting are usually combined.

What a “separate specular color” is.

恭喜,你学完了本章。我们知道了:

纹理和逐顶点光照通常是如何结合的。

“独立镜面颜色”是什么。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: