opengl中极不一致和不正确的照明

tf7tbtn2  于 2022-12-18  发布在  其他
关注(0)|答案(2)|浏览(144)

我按照教程添加了简单的漫反射照明,但照明非常破碎:

除了不一致之外,所有漫反射组件在某些相机Angular 完全消失(相机位置似乎对此没有影响)
顶点着色器:

#version 450 core

layout (location = 0) in vec4 vPosition;
layout (location = 1) in vec4 vNormal;
layout (location = 2) out vec4 fNormal;
layout (location = 3) out vec4 fPos;

uniform mat4 MVMatrix;
uniform mat4 PMatrix;

void main()
{
    gl_Position = PMatrix * (MVMatrix * vPosition);
    fNormal = normalize(inverse(transpose(MVMatrix))*vNormal);
    fPos = MVMatrix * vPosition;
}

片段着色器:

#version 450 core

layout (location = 0) out vec4 fColor;
layout (location = 2) in vec4 fNormal;
layout (location = 3) in vec4 fPos;
uniform vec4 objColour;

void main()
{
    vec3 lightColour = vec3(0.5, 0.0, 0.8);
    vec3 lightPos = vec3(10, 20, 30);
    float ambientStrength = 0.4;
    vec3 ambient = ambientStrength * lightColour;

    vec3 diffLightDir = normalize(lightPos - vec3(fPos));
    float diff = max(dot(vec3(fNormal), diffLightDir), 0.0);
    vec3 diffuse = diff * lightColour;
    
    vec3 rgb = (ambient + diffuse) * objColour.rgb;
    fColor = vec4(rgb, objColour.a);
}

正常计算(由于Python的性质,我没有遵循教程,这可能是问题所在)

self.vertices = np.array([], dtype=np.float32)
self.normals = np.array([], dtype=np.float32)
data = Wavefront(r"C:\Users\cwinm\AppData\Local\Programs\Python\Python311\holder.obj", collect_faces=True)
all_vertices = data.vertices
for mesh in data.mesh_list:
    for face in mesh.faces:
        face_vertices = np.array([all_vertices[face[i]] for i in range(3)])
        
        normal = np.cross(face_vertices[0]-face_vertices[1], face_vertices[2] - face_vertices[1])
        normal /= np.linalg.norm(normal)

        self.vertices = np.append(self.vertices, face_vertices)
        for i in range(3): self.normals = np.append(self.normals, normal)
self.index = index_getter(len(self.vertices))
self.vertices.resize((len(self.vertices)//3, 3))
self.vertices = np.array(self.vertices * [0.5, 0.5, 0.5], dtype=np.float32)


(The局部顶点和法线随后被附加到全局顶点和法线缓冲区,该缓冲区在初始化后被推送到OpenGL)
创建VBO(也可能是个问题)

vPositionLoc = glGetAttribLocation(self.program, "vPosition")
vNormalLoc = glGetAttribLocation(self.program, "vNormal")

self.Buffers[self.PositionBuffer] = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.Buffers[self.PositionBuffer])
glBufferStorage(GL_ARRAY_BUFFER, self.vertices.nbytes, self.vertices, 0)
glVertexAttribPointer(vPositionLoc, 3, GL_FLOAT, False, 0, None)
glEnableVertexAttribArray(vPositionLoc)

self.Buffers[self.NormalBuffer] = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, self.Buffers[self.NormalBuffer])
glBufferStorage(GL_ARRAY_BUFFER, self.normals.nbytes, self.normals, 0)
glVertexAttribPointer(vNormalLoc, 3, GL_FLOAT, False, 0, None)
glEnableVertexAttribArray(vNormalLoc)

环境光,矩阵,顶点处理都是功能,事情只是打破了当我添加法线和(试图)漫射光

x3naxklr

x3naxklr1#

这里的问题是法线的类型是np.float64

normal = np.cross(face_vertices[0]-face_vertices[1], face_vertices[2] - face_vertices[1])
normal /= np.linalg.norm(normal)

下面代码中的self.normalsnp.float64,而不是您所期望的np.float32
要修复它,您可以执行以下操作:

normal = np.cross(face_vertices[0]-face_vertices[1], face_vertices[2] - face_vertices[1])
                normal /= np.linalg.norm(normal)
                flt_normal = np.array(normal, dtype=np.float32)
 
                self.vertices = np.append(self.vertices, face_vertices)
                for i in range(3): self.normals = np.append(self.normals, flt_normal)

关于着色器,你确实需要使用mat3x3来进行vec3法线变换。另外,对于旋转矩阵,transpose等于inverse,因此inverse(transpose(Rot)) = Rot。因此看起来有些多余,你可以将其重写为:

fNormal.xyz = mat3x3(MVMatrix) * normalize(vNormal.xyz);


别忘了检查片段着色器中的法线方向。它看起来应该是:

float diff = max(dot(-vec3(fNormal), diffLightDir), 0.0);
vc6uscn9

vc6uscn92#

vNormal是一个有3个分量的向量。你必须用法向矩阵来转换法向向量。法向矩阵是模型视图矩阵左上角3x3分量的逆转置(无平移):

vec3 normal = normalize(inverse(transpose(mat3(MVMatrix))) * vNormal.xyz);

这与以下内容相同:

fNormal = normalize(inverse(transpose(MVMatrix)) * vec4(vNormal.xyz, 0.0));

如果未指定或仅部分指定某个属性,则x、y和z分量默认为0.0,但w分量默认为1.0。
fNormal = normalize(inverse(transpose(MVMatrix)) * vec4(vNormal.xyz, 1.0));,这是错误的,因为您正在将模型视图矩阵的转换应用到法向量
此外,fNormal必须在片段着色器中规格化,因为通过插值,长度不会保持为1.0。

相关问题