В шейдерной программе есть простая проблема. Сначала опечатка. Это должно быть lightPosition
, а не lightPostion
. Но это не единственная проблема.
Тип lightPosition[i]
- vec4
, а опечатка vertPos
- vec3
. Это вызывает и ошибку, когда vertPos
вычитается из lightPosition[i]
.
Либо вы должны построить vec3
из lightPosition[i]
:
vec3 lightDir = normalize(lightPostion[i] - vertPos);
vec3 lightDir = normalize(vec3(lightPosition[i]) - vertPos);
Или Вы должны получить x, y и z компонент вида lightPosition[i]
(см. Swizzling ):
vec3 lightDir = normalize(lightPosition[i].xyz - vertPos);
Оба решения приводят к одному и тому же результату.
Конечно, Положение света должно быть установлено относительно объекта. Обратите внимание, что при вызове spotLight()
положение и направление источника света преобразуется с помощью матрицы вида текущей модели.
См. Пример:
![](https://i.stack.imgur.com/JrPZb.gif)
Вершинный шейдер
uniform mat4 modelview;
uniform mat4 transform;
uniform mat3 normalMatrix;
attribute vec4 position;
attribute vec4 color;
attribute vec3 normal;
varying vec3 normalInterp;
varying vec3 vertPos;
varying vec4 vertColor;
void main() {
gl_Position = transform * position;
vertPos = vec3(modelview * position);
normalInterp = normalize(normalMatrix * normal);
}
Фрагментный шейдер
precision mediump float;
varying vec3 normalInterp;
varying vec3 vertPos;
uniform int lightCount;
uniform vec4 lightPosition[8];
uniform vec3 lightNormal[8];
uniform vec3 lightDiffuse[8];
uniform vec3 lightSpecular[8];
uniform vec2 lightSpot[8];
const vec3 ambientColor = vec3(0.2);
const vec3 diffuseColor = vec3(1.0);
const vec3 specColor = vec3(1.0);
const float n = 30.0;
void main() {
vec3 lightColor = vec3(0.0, 0.0, 0.0);
for (int i = 0; i < lightCount; i++)
{
// ambient
lightColor += lightDiffuse[i] * ambientColor;
vec3 normal = normalize(normalInterp);
vec3 lightDir = normalize(lightPosition[i].xyz - vertPos);
float spot = dot(-lightNormal[i], lightDir);
if (spot < lightSpot[i].x)
continue;
//diffuse
float diffuse = max(dot(lightDir,normal), 0.0);
lightColor += diffuse * lightDiffuse[i] * diffuseColor;
//specular
if(diffuse > 0.0) {
vec3 viewDir = normalize(-vertPos);
vec3 reflectDir = reflect(-lightDir, normal);
float specAngle = max(dot(reflectDir, viewDir), 0.0);
float specular = pow(specAngle, n);
lightColor += specular * lightSpecular[i] * specColor;
}
}
gl_FragColor = vec4(lightColor.rgb, 1.0);
}
Код
PShader lightShader;
void setup() {
size(800, 600, P3D);
lightShader = loadShader("fragment.glsl","vertex.glsl");
}
float ry = 0.0;
void draw() {
background(0);
shader(lightShader);
translate(width/2.0, height/2.0);
spotLight(255, 0, 0, 0, 500, 500, 0, -1, -1, PI/25, 2);
spotLight(0, 0, 255, 500, 0, 500, -1, 0, -1, PI/25, 2);
rotateY(ry);
rotateX(-0.5);
ry += 0.02;
noStroke();
box(200);
}