【发布时间】:2018-11-07 10:44:27
【问题描述】:
我正在开发一个简单的 java 渲染引擎,它可以将 OBJ 文件渲染到屏幕上。我目前正在研究用于照亮屏幕上的模型的照明系统。在介绍照明系统之前,我能够轻松地将模型加载到屏幕上:
但是,当我将灯光添加到屏幕时,模型不再显示。我正在使用以下着色器来渲染灯光:
顶点着色器:
#version 150
in vec3 position;
in vec2 textureCoordinates;
in vec3 normals;
out vec2 passTextureCoordinates;
out vec3 surfaceNormal;
out vec3 toLightVector;
uniform mat4 transformationMatrixTextured;
uniform mat4 projectionMatrixTextured;
uniform mat4 viewMatrixTextured;
uniform vec3 lightLocation;
void main(void){
vec4 worldPosition = transformationMatrixTextured * vec4(position,1.0);
gl_Position = projectionMatrixTextured * viewMatrixTextured * worldPosition;
passTextureCoordinates = textureCoordinates;
surfaceNormal = (transformationMatrixTextured * vec4(normals,0.0)).xyz;
toLightVector = lightLocation - worldPosition.xyz;
}
片段着色器:
#version 150
in vec2 passTextureCoordinates;
in vec3 surfaceNormal;
in vec3 toLightVector;
out vec4 out_Color;
uniform sampler2D textureSampler;
uniform vec3 lightColor;
void main(void){
vec3 unitNormal = normalize(surfaceNormal);
vec3 unitLightVector = normalize(toLightVector);
float nDot1 = dot(unitNormal, unitLightVector);
float brightness = max(nDot1, 0.0);
vec3 diffuse = brightness * lightColor;
out_Color = vec4(diffuse, 1.0) * texture(textureSampler,passTextureCoordinates);
}
我一直在使用tutorial series by ThinMatrix 来帮助我创建这个程序。然而,一个很大的区别是我还希望能够加载以编程方式创建的模型,就像只使用由 OBJLoader 加载的模型一样。因此,我必须创建一种方法来计算给定顶点数组和索引数组的法线。
我解决这个问题的方法是这样的:
/**
* Sum.
*
* @param arg1 the arg 1
* @param arg2 the arg 2
* @return the vector 3 f
*/
public static Vector3f sum(Vector3f arg1, Vector3f arg2) {
return new Vector3f(arg1.x + arg2.x, arg1.y + arg2.y, arg1.z + arg2.z);
}
/**
* Subtract.
*
* @param arg1 the arg 1
* @param arg2 the arg 2
* @return the vector 3 f
*/
public static Vector3f subtract(Vector3f arg1, Vector3f arg2) {
return new Vector3f(arg1.x - arg2.x, arg1.y - arg2.y, arg1.z - arg2.z);
}
/**
* Cross product.
*
* @param arg1 the arg 1
* @param arg2 the arg 2
* @return the vector 3 f
*/
public static Vector3f crossProduct(Vector3f arg1, Vector3f arg2) {
return new Vector3f(arg1.y * arg2.z - arg2.y * arg1.z, arg2.x * arg1.z - arg1.x * arg2.z, arg1.x * arg2.y - arg2.x * arg1.y);
}
/**
* Gets the normals.
*
* @param vertices the vertices
* @param indexes the indexes
* @return the normals
*/
public static float[] getNormals(float[] vertices, int[] indexes) {
vertices = convertToIndexless(vertices, indexes);
Vector3f tmp;
float[] tmpArray = new float[vertices.length / 3];
int tmpArrayCounter = 0;
for(int i = 0; i < vertices.length; i+=9) {
Vector3f edge1 = subtract(new Vector3f(vertices[i], vertices[i + 1], vertices[i + 2]) , new Vector3f(vertices[i + 3], vertices[i + 4], vertices[i + 5]));
Vector3f edge2 = subtract(new Vector3f(vertices[i], vertices[i + 1], vertices[i + 2]) , new Vector3f(vertices[i + 6], vertices[i + 7], vertices[i + 8]));
tmp = crossProduct(edge1, edge2);
tmpArray[tmpArrayCounter++] = tmp.getX();
tmpArray[tmpArrayCounter++] = tmp.getY();
tmpArray[tmpArrayCounter++] = tmp.getZ();
}
return tmpArray;
}
/**
* Convert to indexless.
*
* @param vertices the vertices
* @param indexes the indexes
* @return the float[]
*/
private static float[] convertToIndexless(float[] vertices, int[] indexes) {
float[] tmpArray = new float[indexes.length * 3];
for(int i = 0; i < indexes.length; i++) {
tmpArray[i * 3] = vertices[indexes[i] * 3];
tmpArray[i * 3 + 1] = vertices[indexes[i] * 3 + 1];
tmpArray[i * 3 + 2] = vertices[indexes[i] * 3 + 2];
}
return tmpArray;
}
我基于this question 计算法线的这种方法。正如我之前所说,在程序中添加灯光时,我无法渲染模型。我在计算中做错了吗?
【问题讨论】:
-
您的法线向量应该类似于
vec4 unitNormal = normalize( vec4(surfaceNormal, 0.0) )和片段着色器中的光向量。 -
@Victor 不,那部分代码很好。为什么要 4D 法线?
-
你能展示你对计算出的法线做了什么吗?您正在计算每个三角形一个法线,因此您不能直接将它们作为顶点属性上传。
-
叉积 不可交换,改变顺序会改变结果向量的符号。这将通过更改其符号来影响
dot(normal, lightdirection),从而影响max(nDot1, 0.0)。您应该选择顶点的顺序,使法线始终朝外。 -
如果您激活了face culling,您可以测试使用
max(-nDot1, 0.0)(注意“-”号)是否会改变事情。
标签: java opengl lwjgl normals wavefront