为什么基本的镜面遮光液,而不是锯齿状?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么基本的镜面遮光液,而不是锯齿状?相关的知识,希望对你有一定的参考价值。

简单的问题,我只是让我的第一个镜面着色器工作,并查看数学,我不能帮助认为每个边缘之间的角度应该导致“镜面反射”尖峰/变成锯齿状。但它完全是流体/球形。

我们的想法是计算顶点法线的角度,但是只有这么多,并且“镜面阴影”仍然完美无缺。

我无法看到gpu如何根据顶点法线单独知道片段的角度。

enter image description here

编辑:vert着色器

#version 400 core

layout ( location = 0 ) in vec3 vertex_position;
layout ( location = 2 ) in vec2 tex_cord;
layout ( location = 3 ) in vec3 vertex_normal;

uniform mat4 transform; //identity matrix
uniform mat3 lmodelmat; //inverse rotation

out vec2 UV;
out vec3 normal;

void main()
{
  UV=tex_cord;
  normal=normalize(vertex_normal*lmodelmat);  //normalize to keep brightness

  gl_Position=transform*vec4(vertex_position,1.0);
}

和碎片

#version 400 core

in vec2 UV;
in vec3 normal;

uniform sampler2D mysampler;
uniform vec3 lightpos; //lights direction

out vec4 frag_colour;

in vec3 vert2cam; //specular test

void main()
{
  //skip invis frags
  vec4 alphatest=texture(mysampler,UV);
  if(alphatest.a<0.00001)discard; 

  //diffuse'ing fragment
  float diffuse=max(0.1,dot(normal,lightpos));

  //specular'izing fragment
  vec3 lpnorm=normalize(lightpos);  //vector from fragment to light
  vec3 reflection=normalize(reflect(-lpnorm,normal)); //reflection vector
  float specularity=max(0,dot(lpnorm,reflection));
  specularity=pow(specularity,50);

  frag_colour=alphatest*diffuse+specularity;
}

//编辑

我找到了这个btw(一年后)的答案:Vertice法线(vn)是连接到它的每个面/三角形的组合值。也就是说,连接到多个面的1个顶点在标准化时将具有组合的面法线。该值vn被计算为相邻面法线的平均值。当计算该值以指示亮度时,GPU将提供“阴影”,其是每个附近边的标准化叉积。

我在重新计算项目的正常情况时想出了这个:

用于重新计算顶点法线的伪代码:

for (for each face/triangle, find face-normal and add to adjacent vn's) 
vec3 face_normal=cross(face[1]-face[0],face[2]-face[0]);
vn[0]+=face_normal; //notice +=
vn[1]+=face_normal;
vn[2]+=face_normal;

//then just normalize them to get the weighted average
for(auto&x:vn)x=normalize(x);

对于渲染器,这将等同于平均曲线,而不是锯齿状边缘(平面阴影)

答案

没有代码.etc。很难准确回答你的问题,但假设一个简单的矢量着色器 - >片段着色器管道。将为每个顶点运行矢量着色器。它将典型地设置标记为“变化”的参数(例如纹理坐标)。

每3个顶点将被分组以形成多边形,并且片段着色器运行以确定多边形内每个点的颜色。由顶点着色器设置的“变化”参数将基于片段距多边形的3个边缘的距离进行插值(参见:重心插值)。

例如:

gl_FragColor = texture2D(myUniformSampler, vec2(myTextureCoord.s,myTextureCoord.t));

将为每个像素正确地采样纹理。假设您正在使用每片段光照,则可能会根据您在顶点着色器中设置的值为每个片段着色器插值。如果为每条边设置相同的法线,您将获得不同的效果。

编辑(根据您添加的代码):

out vec2 UV;
out vec3 normal;
out vec3 color;

在顶点着色器中按顶点设置。每三个顶点定义一个多边形。然后对多边形内的每个点(例如像素)运行片段着色器以确定颜色.etc。每一点。

这些参数的值:

in vec3 color; /// <<-- You don't seem to be actually using this
in vec2 UV;
in vec3 normal;

在片段着色器中,基于从每个顶点“绘制”的多边形上的点的距离进行插值(参见:重心插值)。因此,法线在顶点着色器定义的顶点之间变化。

如果对于由三个顶点定义的给定多边形,您将法线设置为朝向相同方向,则会得到不同的效果。

以上是关于为什么基本的镜面遮光液,而不是锯齿状?的主要内容,如果未能解决你的问题,请参考以下文章

虹吸到 Pixelflow 捕获液中

对特定绘制调用应用多重采样/消除锯齿,而不是全部

让 JTextArea 显示固定宽度的字体而不进行抗锯齿

为啥使用片段,以及何时使用片段而不是活动?

人体的水液代谢

BottomNavigation popBackStack() 导航到 startDestination 而不是上一个片段