- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我遇到了法线贴图问题。我在通过 ASSIMP 库加载的每个模型上都有一个纹理和一个法线纹理。我在 ASSIMP 库的帮助下计算每个对象的切线 vector ,所以这些应该没问题。这些对象与法线贴图完美配合,但一旦我开始翻译其中一个对象(从而影响模型矩阵的翻译),照明就会失败。正如您在图像中看到的,地板(沿 y 轴向下平移)似乎失去了大部分漫射照明,并且其镜面照明的方向错误(它应该在灯泡和玩家位置之间)
它可能与法线矩阵有关(尽管翻译应该会丢失),也可能与着色器中使用的错误矩阵有关。我没有想法,希望你能对这个问题有所了解。
顶点着色器:
#version 330
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 color;
layout(location = 4) in vec2 texCoord;
// fragment pass through
out vec3 Position;
out vec3 Normal;
out vec3 Tangent;
out vec3 Color;
out vec2 TexCoord;
out vec3 TangentSurface2Light;
out vec3 TangentSurface2View;
uniform vec3 lightPos;
uniform vec3 playerPos;
// vertex transformation
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
mat3 normalMatrix = mat3(transpose(inverse(model)));
Position = vec3(model * vec4(position, 1.0));
Normal = normalMatrix * normal;
Tangent = tangent;
Color = color;
TexCoord = texCoord;
gl_Position = projection * view * model * vec4(position, 1.0);
// Calculate tangent matrix and calculate fragment bump mapping coord space.
vec3 light = lightPos;
vec3 n = normalize(normalMatrix * normal);
vec3 t = normalize(normalMatrix * tangent);
vec3 b = cross(n, t);
// create matrix for tangent (from vertex to tangent-space)
mat3 mat = mat3(t.x, b.x ,n.x, t.y, b.y ,n.y, t.z, b.z ,n.z);
vec3 vector = normalize(light - Position);
TangentSurface2Light = mat * vector;
vector = normalize(playerPos - Position);
TangentSurface2View = mat * vector;
}
片段着色器
#version 330
in vec3 Position;
in vec3 Normal;
in vec3 Tangent;
in vec3 Color;
in vec2 TexCoord;
in vec3 TangentSurface2Light;
in vec3 TangentSurface2View;
out vec4 outColor;
uniform vec3 lightPos;
uniform vec3 playerPos;
uniform mat4 view;
uniform sampler2D texture0;
uniform sampler2D texture_normal; // normal
uniform float repeatFactor = 1;
void main()
{
vec4 texColor = texture(texture0, TexCoord * repeatFactor);
vec4 matColor = vec4(Color, 1.0);
vec3 light = vec3(vec4(lightPos, 1.0));
float dist = length(light - Position);
// float att = 1.0 / (1.0 + 0.01 * dist + 0.001 * dist * dist);
float att = 1.0;
// Ambient
vec4 ambient = vec4(0.2);
// Diffuse
// vec3 surface2light = normalize(light - Position);
vec3 surface2light = normalize(TangentSurface2Light);
// vec3 norm = normalize(Normal);
vec3 norm = normalize(texture(texture_normal, TexCoord * repeatFactor).xyz * 2.0 - 1.0);
float contribution = max(dot(norm, surface2light), 0.0);
vec4 diffuse = contribution * vec4(0.6);
// Specular
// vec3 surf2view = normalize(-Position); // Player is always at position 0
vec3 surf2view = normalize(TangentSurface2View);
vec3 reflection = reflect(-surface2light, norm); // reflection vector
float specContribution = pow(max(dot(surf2view, reflection), 0.0), 32);
vec4 specular = vec4(1.0) * specContribution;
outColor = (ambient + (diffuse * att)+ (specular * pow(att, 3))) * texColor;
// outColor = vec4(Color, 1.0) * texture(texture0, TexCoord);
}
编辑
编辑着色器代码以计算世界空间中的所有内容,而不是在世界空间和相机空间之间来回切换(更易于理解且不易出错)。
最佳答案
您正在对矩阵进行奇怪的操作。在 VS 中,您通过反向 View 世界转换法线(即模型空间)。那没有任何意义。在世界空间中进行计算可能更容易。我有一些工作示例代码,但它使用了一些不同的命名。
顶点着色器:
void main_vs(in A2V input, out V2P output)
{
output.position = mul(input.position, _worldViewProjection);
output.normal = input.normal;
output.binormal = input.binormal;
output.tangent = input.tangent;
output.positionWorld = mul(input.position, _world);
output.tex = input.tex;
}
这里我们将position转换为projection(screen)-space,TBN留在model-space中,后面会用到。我们还获得了用于光照评估的世界空间位置。
像素着色器:
void main_ps(in V2P input, out float4 output : SV_Target)
{
float3x3 tbn = float3x3(input.tangent, -input.binormal, input.normal);
//extract & decode normal:
float3 texNormal = _normalTexture.Sample(_normalSampler, input.tex).xyz * 2 - 1;
//now transform TBN-space texNormal to world space:
float3 normal = mul(texNormal, tbn);
normal = normalize(mul(normal, _world));
float3 lightDirection = -_lightPosition.xyz;//directional
float3 viewDirection = normalize(input.positionWorld - _camera);
float3 reflectedLight = reflect(lightDirection, normal);
float diffuseIntensity = dot(normal, lightDirection);
float specularIntensity = max(0, dot(reflectedLight, viewDirection)*1.3);
output = ((_ambient + diffuseIntensity * _diffuse) * _texture.Sample(_sampler, input.tex)
+ pow(specularIntensity, 7) * float4(1,1,1,1)) * _lightColor;
}
这里我使用定向光,你应该做类似的事情
float3 lightDirection = normalize(input.positionWorld - _lightPosition.xyz);//omni
这里我们首先从纹理中获取法线,即在 TBN 空间中。然后我们应用 TBN 矩阵将其转换到模型空间。然后应用世界矩阵将其转换为世界空间,如果我们已经有光位置、眼睛等。
一些其他的shader代码,上面省略了(DX11,不过好翻译):
cbuffer ViewTranforms
{
row_major matrix _worldViewProjection;
row_major matrix _world;
float3 _camera;
};
cbuffer BumpData
{
float4 _ambient;
float4 _diffuse;
};
cbuffer Textures
{
texture2D _texture;
SamplerState _sampler;
texture2D _normalTexture;
SamplerState _normalSampler;
};
cbuffer Light
{
float4 _lightPosition;
float4 _lightColor;
};
//------------------------------------
struct A2V
{
float4 position : POSITION;
float3 normal : NORMAL;
float3 binormal : BINORMAL;
float3 tangent : TANGENT;
float2 tex : TEXCOORD;
};
struct V2P
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float3 binormal : BINORMAL;
float3 tangent : TANGENT;
float3 positionWorld : NORMAL1;
float2 tex : TEXCOORD;
};
另外,这里我使用预先计算的双法线:你应该留下你的代码,计算它(通过 cross(normal, tangent))。希望这会有所帮助。
关于c++ - 法线贴图和平移扰乱了我的照明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18248951/
我想创建一个可以编译的 Java 项目的 jar 文件。我在互联网上查看过,但所有关于如何执行此操作的示例似乎都需要一个 java 文件并对其进行处理。我想将 java 项目的根目录打包到 jar 中
当我添加一个左连接来获取外部表的计数时,它将我的其他左连接表的总和值乘以计数,我也不能在这里使用不同的总和,因为两个值可以相同: SELECT c.id as company_id, SUM(ct.a
我在 AppEngine 上托管了一个简单的 ReSTLet 服务。这对字符串执行基本的 CRUD 操作,并且当我用 curl 测试它时(对于所有动词),它可以很好地处理各种 UTF-8 字符。 这由
我是一名优秀的程序员,十分优秀!