哈珀朋友
2021-09-23
基本等同于把计算机图形学复习了一遍哦
2
量子蔷薇
2022-11-02
来自上海
小试牛刀,这是圆形探照灯的实现: // 探照灯 for (int i = 0; i < MAX_LIGHT_COUNT; i++) { vec3 decay = searchLightDecay[i]; if (decay.x == 0.0 && decay.y == 0.0 && decay.z == 0.0) { continue; } vec3 dir = (viewMatrix * vec4(searchLightDirection[i], 0.0)).xyz; dir = normalize(-dir); float c = max(dot(dir, normal), 0.0); vec3 v = (viewMatrix * vec4(searchLightPosition[i], 1.0)).xyz - pos; float l = dot(v, dir); float d = min(1.0, 1.0 / (decay.x * pow(l, 2.0) + decay.y * l + decay.z)); float r = step(length(v - dir * l), searchLightRadius[i]) * step(0.0, dot(v, dir)); vec3 color = searchLightColor[i]; diffuse += c * d * r * color; specular += getSpecular(dir, normal, eye) * d * r * color; } 注意我的 specular 是 vec3 和老师的不一样。 入射光的方向 dir 的计算类似平行光,不受光源位置的影响。 v 是当前坐标到探照灯圆心的向量,与 dir 点乘后就可以得到 v 平行于 dir 方向的分量的长度 l(因为 dir 是单位向量,所以省去了 除以 length(dir) 的操作)。 d 是和老师一样的算法得到的衰减系数。 r 是实现圆形光照范围的关键,前面已经得到了 v 平行于 dir 的分量的长度 l,dir * l 就可以得到真正的分量 v∥,再用 v - v∥ 得到 v⊥,也就是 v 垂直于 dir 的分量,比较 v⊥ 的长度与探照灯半径的大小就能知道当前坐标是否在探照灯的范围内(以上其实就是点乘在向量分解上的应用)。 至此,还没有结束,探照灯是有 position 属性的,因此位于探照灯照射方向背面180°范围内的物体不应该被照亮,这是探照灯与平行光的另一个区别。所以需要判断探照灯圆心到当前坐标的向量也就是 -v 与照射方向也就是 -dir(dir 在 normalize 时取反了,所以这里再取反表示照射的方向)是否同向,或者说夹角是否小于 90°,也就是判断 dot(-v, -dir) 是否大于零,dot(v, dir) 与 dot(-v, -dir) 的结果是相同的,所以省去了取反的操作。
展开
1
Geek_00734e
2022-01-19
void main() { // 光线到点坐标的方向 vec3 invLight = (viewMatrix * vec4(searchLightPosition, 1.0)).xyz - vPos; // vec3 invLight = searchLightPosition - vPos; vec3 invNormal = normalize(invLight); // 光线到点坐标的距离,用来计算衰减 float dis = length(invLight); // 求光线中心与法线夹角的余弦 float cosmid = max(dot(normalize(vDir), vNormal), 0.0); // 求光线与法线夹角的余弦 float cosa = max(dot(invNormal, vNormal), 0.0); // 照射范围半径 float radius = searchLightRadius / cosmid; // 光线中心射线与射线夹角 float cosb = max(dot(normalize(vDir), invNormal), 0.0); // 根据正弦定理求对应边长度 float sinb = sqrt(1.0 - cosb * cosb); float sinc = sin(PI/2.0 - acos(cosa) - acos(cosb)); float lenb = dis * sinb / sinc; // 边长度小于半径的为1.0 float r = step(lenb, radius); // 计算衰减 float decay = min(1.0, 1.0 / (searchLightDecayFactor.x * pow(dis, 2.0) + searchLightDecayFactor.y * dis + searchLightDecayFactor.z)); // 计算漫反射 vec3 diffuse = r * decay * cosmid * searchLightColor; // 合成颜色 gl_FragColor.rgb = (ambientLight + diffuse) * materialReflection; gl_FragColor.a = 1.0; } 探照灯 但是感觉算法 不够完美,实在找不到合适的思路了
展开
Geek_00734e
2022-01-18
探照灯那个课后作业有答案吗?思来想去做不出来,我的思路是求光源中心射线跟界面的交点,光线照射到的范围为 r/cos(θ) (θ为光线与界面法线夹角), 可是这个思路要求射线与平面交点,这个不知道怎么求,是不是我思路有问题,感觉不大对。 我的理解光源方向 searchLightDirection这个参数可以参照平行光的方式、光源位置 searchLightPosition用于计算距离衰减、光源半径 searchLightRadius 用于确定照射到的范围 这个逻辑怎么算