// `計算點光源, 它和頂點位置, 頂點面向, 光源位置有關.` void CalculatePointLight(Vertex_VCN *pVertices, int num_vertices) { for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點位置` Vector4 vPosition = pVertices[i].m_Position * g_world_matrix; // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 vNormal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `計算出頂點位置到光源的方向跟長度` Vector4 vVertex_to_Light = g_vLightPosition - vPosition; float light_distance = vVertex_to_Light.NormalizeAndGetLength(); // `vDistance用來計算光線隨距離衰減公式中1/(a*1 + b*d + c*d^2)分母的(1, d, d^2)` Vector4 vDistance(1.0f, light_distance, light_distance * light_distance); // `g_vLightAttenuation里記錄了計算衰減公式1/(a + b*d + c*d^2)里的(a,b,c)` // `Vector3Dot(vDistance, g_vLightAttenuation) = (a,b,c) dot (1,d,d^2) = (a + b*d + c*d^2)` Vector4 vAttenuation = Vector3Dot(vDistance, g_vLightAttenuation); // `頂點面向跟光線方向的交角, 決定反射光的強度.` Vector4 vIntensity = Vector3Dot(vNormal, vVertex_to_Light); // `把intensity局限在永遠大於0的范圍` vIntensity.Clamp_to_0(); // `累加上隨距離衰減的光線強度` pVertices[i].m_Color += vIntensity * g_vLightColor / vAttenuation; pVertices[i].m_Color.Clamp_to_1(); } }
// `計算點光源, 它和頂點位置, 頂點面向, 光源位置, 光源方向, 光柱交角有關.` void CalculateSpotLight(Vertex_VCN *pVertices, int num_vertices) { float fSpotLightCutoffCos = FastMath::Cos( FastMath::DegreeToRadian(g_fSpotLightCutoff) ); for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點位置` Vector4 vPosition = pVertices[i].m_Position * g_world_matrix; // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 vNormal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `計算出頂點位置到光源的方向跟長度` Vector4 vVertex_to_Light = g_vLightPosition - vPosition; float light_distance = vVertex_to_Light.NormalizeAndGetLength(); // `頂點面向跟光線方向的交角, 可以決定反射光的強度.` Vector4 vCosine = Vector3Dot(g_vLightDirection, vVertex_to_Light); // `把vCosine局限在永遠大於0的范圍` vCosine.Clamp_to_0(); float fCosine = vCosine.GetX(); if ( fCosine >= fSpotLightCutoffCos ) { // `頂點跟光線的交角小於fSpotightCutoffCos時, 才落在光柱范圍內.` Vector4 vDistance(1.0f, light_distance, light_distance * light_distance); // `g_vLightAttenuation里記錄了計算衰減公式1/(a + b*d + c*d^2)里的(a,b,c)` // `Vector3Dot(vDistance, g_vLightAttenuation) = (a,b,c) dot (1,d,d^2) = (a + b*d + c*d^2)` Vector4 vAttenuation = Vector3Dot(vDistance, g_vLightAttenuation); // `比較靠近光柱外圍部分的頂點, 光線會衰減.` float fFalloff = pow(fCosine, g_fSpotLightExponent); Vector4 vIntensity = Vector3Dot(vNormal, vVertex_to_Light); pVertices[i].m_Color += fFalloff * vIntensity * g_vLightColor / vAttenuation; pVertices[i].m_Color.Clamp_to_1(); } } }
// `計算方向光, 它只跟頂點面向和光源方向有關.` void CalculateDirectionalLight(Vertex_VCN *pVertices, int num_vertices) { for ( int i=0; i<num_vertices; i++ ) { // `求出轉換後在世界座標系的頂點面向, RotateVector函式只做旋轉, 忽略位移.` Vector4 normal = g_world_matrix.RotateVector(pVertices[i].m_Normal); // `頂點面向跟光線方向的交角, 決定反射光的強度.` Vector4 intensity = Vector3Dot(normal, g_vLightDirection); // `把intensity局限在永遠大於0的范圍` intensity.Clamp_to_0(); // `累加上計算出來方向光的強度` pVertices[i].m_Color += intensity * g_vLightColor; pVertices[i].m_Color.Clamp_to_1(); } }