【发布时间】:2016-10-06 06:14:02
【问题描述】:
我做了这个非常简单、完美的工作,实现了Phong Relflection Model(目前还没有实现氛围,但现在这不会打扰我)。功能应该是自我解释的。
/**
* Implements the classic Phong illumination Model using a reflected light
* vector.
*/
public class PhongIllumination implements IlluminationModel {
@RGBParam(r = 0, g = 0, b = 0)
public Vec3 ambient;
@RGBParam(r = 1, g = 1, b = 1)
public Vec3 diffuse;
@RGBParam(r = 1, g = 1, b = 1)
public Vec3 specular;
@FloatParam(value = 20, min = 1, max = 200.0f)
public float shininess;
/*
* Calculate the intensity of light reflected to the viewer .
*
* @param P = The surface position expressed in world coordinates.
*
* @param V = Normalized viewing vector from surface to eye in world
* coordinates.
*
* @param N = Normalized normal vector at surface point in world
* coordinates.
*
* @param surfaceColor = surfaceColor Color of the surface at the current
* position.
*
* @param lights = The active light sources in the scene.
*
* @return Reflected light intensity I.
*/
public Vec3 shade(Vec3 P, Vec3 V, Vec3 N, Vec3 surfaceColor, Light lights[]) {
Vec3 surfaceColordiffused = Vec3.mul(surfaceColor, diffuse);
Vec3 totalintensity = new Vec3(0, 0, 0);
for (int i = 0; i < lights.length; i++) {
Vec3 L = lights[i].calcDirection(P);
N = N.normalize();
V = V.normalize();
Vec3 R = Vec3.reflect(L, N); // reflection vector
float diffuseLight = Vec3.dot(N, L);
float specularLight = Vec3.dot(V, R);
if (diffuseLight > 0) {
totalintensity = Vec3.add(Vec3.mul(Vec3.mul(
surfaceColordiffused, lights[i].calcIntensity(P)),
diffuseLight), totalintensity);
if (specularLight > 0) {
Vec3 Il = lights[i].calcIntensity(P);
Vec3 Ilincident = Vec3.mul(Il, Math.max(0.0f, Vec3
.dot(N, L)));
Vec3 intensity = Vec3.mul(Vec3.mul(specular, Ilincident),
(float) Math.pow(specularLight, shininess));
totalintensity = Vec3.add(totalintensity, intensity);
}
}
}
return totalintensity;
}
}
现在我需要将其调整为Blinn-Phong illumination model
我使用了hearn 和 baker 的公式,遵循伪代码并尝试根据维基百科的文章以多种语言多次实现它,但它从未奏效。 我只是没有得到镜面反射,或者它们太弱和/或位于错误的位置和/或颜色错误。
从众多错误的实现中,我发布了一些似乎已经错误的小代码。 所以我计算我的中途矢量和我的新镜面光,如下所示:
Vec3 H = Vec3.mul(Vec3.add(L.normalize(), V), Vec3.add(L.normalize(), V).length());
float specularLight = Vec3.dot(H, N);
有了这些小改动,它应该已经可以工作了(可能没有正确的强度,但基本上它应该是正确的)。但结果是错误的。
这里有两张图片。左下应该如何正确渲染,右下如何渲染。
如果我降低光泽系数,您可以在右上角看到一点镜面光:
尽管我了解 Phong 照明的概念以及 blinn phong 的简化更高效的改编,但我尝试了几天但无法让它工作。任何帮助都会得到帮助。
编辑:
this answer 告诉我一个错误,我在计算 H 时将乘以 |L+V| 而不是除以它。我改为这样做:
Vec3 H = Vec3.mul(Vec3.add(L.normalize(), V), 1/Vec3.add(L.normalize(), V).length());
不幸的是,这并没有太大变化。结果如下所示:
如果我提高镜面反射常数并降低光泽度,您可以以错误的方式更清楚地看到效果:
但是这种划分只是标准化。
我想我错过了一步。因为像这样的公式对我来说没有意义。
如果你看这张图:http://en.wikipedia.org/wiki/File:Blinn-Phong_vectors.svg
H 到 N 的投影远小于 V 到 R。如果你想象改变图片中的向量 V,当观察向量在“左侧”时,角度是相同的。往右走就越来越不一样了。
我个人会将整个投影乘以 2 以成为类似的东西(孔点是为了避免计算 R)。尽管我没有读过任何关于我要尝试的内容...
结果:镜面光的强度太大(白色区域)并且位置仍然错误。
我认为我在搞砸别的东西,因为反射只是在错误的地方。但是什么?
编辑:现在我在维基百科上的注释中读到 N/H 的角度实际上大约是一半或 V/R。为了弥补这一点,我应该将我的光泽指数乘以 4 而不是我的投影。如果我这样做,我最终将没有可见的镜面光。
【问题讨论】:
标签: java graphics 3d vector-graphics