【发布时间】:2021-02-14 15:47:18
【问题描述】:
在向具有变换模型的场景添加光时,我正在尝试解决模型与世界空间坐标的古老问题。
我有一个带有两个实例的房屋模型。一个头骨,我场景中的一个单点光源以及一些地形和一个天空盒。我注意到当对我的模型应用一些旋转时,点光源提供的照明会随之旋转。经过一番阅读,很明显我在模型空间中的着色器中进行了所有计算,但我的灯光位置/方向在世界空间中。
因此,我意识到我需要统一空间以进行计算,并且我认为将着色器保留在模型空间中并将灯光组件从世界转换为模型是有意义的。
当我不进行转换时,它看起来几乎是正确的(虽然我打赌的是不同空间的 b/c 并不完美)。我在灯光的位置渲染了一个小灯泡模型,房屋的顶部和地形都照我预期的相对较好。
当我将灯光位置转换回模型空间时,我预计灯光仍会从灯泡模型中照亮。但是它变得很不稳定。
我在模型上没有旋转,但有一些小的平移,所以我很困惑为什么光源似乎围绕 x 轴旋转了 90 度...
<model name="blackSmith" mesh="black_smith/">
<transform>
<position x="2" y="1" z="-2"></position>
<rotation x="0" y="0" z="0"></rotation>
<scale x="1" y="1" z="1"></scale>
</transform>
</model>
<model name="blackSmith2" mesh="black_smith/">
<transform>
<position x="-2" y="1" z="-2.5"></position>
<rotation x="0" y="0" z="0"></rotation>
<scale x="1" y="1" z="1"></scale>
</transform>
</model>
我将模型视图矩阵从我的顶点着色器传递到我的片段着色器,然后进行逆转置以将光位置的世界空间坐标转换为模型空间。我想就是这样,但显然我要么遗漏了什么,要么我做错了什么。
这是我的着色器(由标签分隔)。对于这个例子,它只是一个点光源,所以 u_isPointLight = true 和 u_isSpotLight = false
#type vertex
#version 330 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoord;
layout(location = 3) in mat4 aInstanceModelMatrix;
out vec3 outNormal;
out vec2 outTexCoord;
out vec3 outPos;
out mat4 outMat;
uniform mat4 u_Projection;
uniform mat4 u_View;
void main() {
vec4 worldPosition = aInstanceModelMatrix * vec4(a_Position, 1.0);
gl_Position = u_Projection * u_View * worldPosition;
outPos = vec3(aInstanceModelMatrix * vec4(a_Position, 1.0));
outNormal = aNormal;
outTexCoord = aTexCoord;
outMat = u_View * aInstanceModelMatrix;
}
#type fragment
#version 330 core
out vec4 color;
in vec3 outNormal; in vec2 outTexCoord; in vec3 outPos;
in mat4 outMat;
uniform bool u_DiffuseTextureValid;
uniform sampler2D u_DiffuseTexture;
uniform vec3 u_DiffuseColour;
uniform vec3 u_LightPosition;
uniform vec3 u_LightAttenuation;
uniform vec4 u_LightParams;
uniform vec3 u_SpotDirection;
uniform bool u_isSpotLight;
uniform bool u_isPointLight;
uniform float u_SpotInnerAngle;
uniform float u_SpotOuterAngle;
uniform vec4 uAmbientLight;
uniform bool u_AmbientTextureValid;
uniform sampler2D u_AmbientTexture;
uniform bool u_SpecularTextureValid;
uniform sampler2D u_SpecularTexture;
uniform vec4 u_Specular;
uniform sampler2D u_BumpTexture;
uniform bool u_BumpTextureValid;
uniform float u_MaterialAlpha;
void main() {
const float kGamma = 0.4545454;
const float kInverseGamma = 2.2;
// WorldSpace to ModelSpace conversion
vec3 lightPosition = (transpose(inverse(outMat)) * vec4(u_LightPosition, 1.0)).xyz;
vec3 norm;
if (u_BumpTextureValid) {
norm = normalize(texture(u_BumpTexture, outTexCoord).xyz);
} else {
norm = normalize(outNormal);
}
vec3 lightDir;
if (u_isPointLight || u_isSpotLight) {
lightDir = normalize(lightPosition - outPos);
} else {
lightDir = normalize(-u_SpotDirection);
}
vec3 viewFragmentDirection = normalize(outPos);
vec3 viewNormal = normalize(outNormal);
float lightDistance = length(lightPosition - outPos);
float attenuation = 1.0;
if (u_isPointLight) {
attenuation = 1.0 / (u_LightAttenuation.x + (lightDistance * u_LightAttenuation.y) + (lightDistance * lightDistance * u_LightAttenuation.z));
}
vec3 diffuse = u_LightParams.w * u_DiffuseColour * max(dot(norm, lightDir), 0.0) * u_LightParams.xyz;
vec3 reflectedLightDirection = reflect(-lightDir, viewNormal);
vec3 specular;
if (u_SpecularTextureValid) {
float spec = pow(max(dot(viewNormal, reflectedLightDirection), 0.0), u_Specular.w);
specular = u_LightParams.xyz * spec * vec3(texture(u_SpecularTexture, outTexCoord));
} else {
float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
specular = u_LightParams.w * u_Specular.rgb * pow(u_LightParams.w, u_Specular.w);
}
float spotFade = 1.0;
if (u_isSpotLight && u_isPointLight) {
float spotlightTheta = dot(lightDir, normalize(-u_SpotDirection));
spotFade = (u_SpotInnerAngle - spotlightTheta) / (u_SpotOuterAngle - u_SpotInnerAngle);
if (spotlightTheta < u_SpotInnerAngle) {
specular = vec3(0, 0, 0);
diffuse = vec3(0, 0, 0);
}
}
vec4 objectColor;
if (u_DiffuseTextureValid) {
objectColor = texture(u_DiffuseTexture, outTexCoord);
} else {
objectColor = vec4(1.0, 1.0, 1.0, 1.0);
}
objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma));
color.a = objectColor.a * u_MaterialAlpha;
vec3 ambient = uAmbientLight.a * uAmbientLight.rgb;
ambient *= attenuation;
diffuse *= attenuation * spotFade;
specular *= attenuation * spotFade;
if (u_DiffuseTextureValid) {
color.rgb = pow(objectColor.rgb + ambient + diffuse + specular, vec3(kGamma));
} else {
color.rgb = pow(objectColor.rgb * (ambient + diffuse) + specular, vec3(kGamma));
}
}
我的问题是:
- 我是否正确地将灯光位置从世界空间转换到模型空间?
- 如果我正在做一个纯粹的directional light(即 u_isSpotLight 和 u_isPointLight 都是错误的),那么通过相同的方法将 u_SpotDirection 转换为模型空间应该可以工作......对吗?
- 假设 1 是正确的,谁能告诉我为什么灯光似乎出现了奇怪的旋转?
【问题讨论】: