我在使用Google Poly抓取的obj模型的照明方面遇到了一些问题。在这个模型中,定义了一堆没有法线的面。因此,我用于漫反射颜色的计算返回0.有没有办法估计法线如果没有提供或我需要解析obj并手动注入法线?
这是我的片段着色器:
precision mediump float;
uniform bool u_UseTexAmbient;
uniform bool u_UseTexDiffuse;
uniform bool u_UseTexSpecular;
uniform sampler2D u_TexAmbient;
uniform sampler2D u_TexDiffuse;
uniform sampler2D u_TexSpecular;
uniform vec3 u_MtlAmbient;
uniform vec3 u_MtlDiffuse;
uniform vec3 u_MtlSpecular;
uniform float u_D;
uniform float u_SpecularPower;
uniform vec4 u_LightingParameters;
varying vec3 v_ViewPosition;
varying vec3 v_ViewNormal;
varying vec2 v_TexCoord;
vec4 getColor(bool useTex, sampler2D tex, vec3 mtl);
vec3 computeDiffuse(vec3 viewNormal, vec3 rawDiffuseColor);
vec3 computeSpecular(vec3 viewNormal, vec3 viewFragmentDirection, vec3 rawSpecularColor);
void main() {
const float kGamma = 0.4545454;
vec3 viewFragmentDirection = normalize(v_ViewPosition);
vec3 viewNormal = normalize(v_ViewNormal);
vec4 rawAmbientColor = getColor(u_UseTexAmbient, u_TexAmbient, u_MtlAmbient);
vec4 rawDiffuseColor = getColor(u_UseTexDiffuse, u_TexDiffuse, u_MtlDiffuse);
vec4 rawSpecularColor = getColor(u_UseTexSpecular, u_TexSpecular, u_MtlSpecular);
vec3 diffuse = computeDiffuse(viewNormal, rawDiffuseColor.rgb);
vec3 specular = computeSpecular(viewNormal, viewFragmentDirection, rawSpecularColor.rgb);
gl_FragColor.a = rawDiffuseColor.a * u_D;
gl_FragColor.rgb = pow(rawAmbientColor.rgb + diffuse + specular, vec3(kGamma));
}
vec4 getColor(bool useTex, sampler2D tex, vec3 mtl) {
const float kInverseGamma = 2.2;
vec4 color;
if (useTex) {
color = texture2D(tex, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y));
} else {
color = vec4(mtl.r, mtl.g, mtl.b, 1.0);
}
color.rgb = pow(color.rgb, vec3(kInverseGamma));
return color;
}
vec3 computeDiffuse(vec3 viewNormal, vec3 rawDiffuseColor) {
vec3 diffuse = u_LightingParameters.w * rawDiffuseColor
* max(dot(u_LightingParameters.xyz, viewNormal), 0.0);
return clamp(diffuse, 0.0, 1.0);
}
vec3 computeSpecular(vec3 viewNormal, vec3 viewFragmentDirection, vec3 rawSpecularColor) {
vec3 reflectedLightDirection = reflect(u_LightingParameters.xyz, viewNormal);
float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection));
vec3 specular = u_LightingParameters.w * rawSpecularColor *
pow(specularStrength, u_SpecularPower);
return clamp(specular, 0.0, 1.0);
}
这个顶点着色器取自Google的ARCore示例:
uniform mat4 u_ModelView;
uniform mat4 u_ModelViewProjection;
attribute vec4 a_Position;
attribute vec3 a_Normal;
attribute vec2 a_TexCoord;
varying vec3 v_ViewPosition;
varying vec3 v_ViewNormal;
varying vec2 v_TexCoord;
void main() {
v_ViewPosition = (u_ModelView * a_Position).xyz;
v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz);
v_TexCoord = a_TexCoord;
gl_Position = u_ModelViewProjection * a_Position;
}
基本上我所看到的是某些模型无法为我提供a_Normal
,因此我希望能够以某种方式在顶点着色器中生成v_ViewNormal
。这甚至可能吗?
以下是完整模型的链接:https://poly.google.com/view/eydI4__jXpi
答案 0 :(得分:0)
通过使用偏导数函数dFdx
, dFdy
请注意,在OpenGL ES 2.0中,OES_standard_derivatives
扩展名是必需的,因为衍生函数只是自OpenGL ES 3.0以来才成为标准。
请参阅OpenGL ES Shading Language 3.00 Specification; 8.9 Fragment Processing Functions; page 104:
genType dFdx (genType p)
使用输入参数
p
的局部差分返回 x 中的导数。
genType dFdy (genType p)
使用输入参数
p
的局部差分返回 y 中的导数。
代码可能看起来像这样:
#extension GL_OES_standard_derivatives : enable
varying vec3 view_pos;
void main
{
vec3 dX = dFdx(view_pos);
vec3 dY = dFdy(view_pos);
vec3 normal = normalize(cross(dX, dY));
....
}
请参阅An introduction to shader derivative functions - Face normal computation (flat shader)