理想情况下,三角形如果偏移量抵消了三角形内的任何可用空间(例如第二张图片的第二个三角形),则将被剔除(如背面/未渲染)。
我正在使用THREE.BufferGeometry()作为我的数据结构。
这是我要达到的效果的屏幕截图:
#1 楼
给定三角形▲ABC,我们将角∠BAC与线AD平分,由角平分定理得出:BA / BD = CA / CD
点E代表我们的目标定位在所需的最终插入三角形上。由于它位于等分线AD上,因此与BA和CA边等距,形成相同的直角三角形▲AFE和▲AGE。现在,我们可以对正三角形使用Sine来查找AE的长度:
AE = EG / Sin(∠EAG)
这就是我们需要的所有数学知识,让我们做饭
我们从所有典型属性入手:位置,法线和变换矩阵,但是由于顶点着色器仅在单个顶点上起作用,因此我们需要添加相邻顶点作为附加顶点属性。这样,每个顶点将找到自己的“点E”,从而创建最终的插入三角形。 (注意:由于它们还不在屏幕空间中,因此我在这里不称其为“ B”和“ C”。)
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
谈到屏幕空间,我还包括了显示器的宽高比,(并在调整窗口大小时使其均匀。)
为片段着色器准备了不同的法线后,将面部转换为剪裁空间,我们可以开始应用上述数学:
attribute vec3 left; //vertex to the left of this vertex
attribute vec3 right; //vertex to the right of this vertex
uniform float aspect;
varying vec3 vNormal;
varying vec2 vUv;
void main() {
vNormal = normal;
vUv = uv;
mat4 xform= projectionMatrix * modelViewMatrix;
vec4 A = xform * vec4( position, 1.0 );
vec4 B = xform * vec4( left, 1.0 );
vec4 C = xform * vec4( right, 1.0 );
vec3 CB = C.xyz - B.xyz;
vec2 BA = B.xy - A.xy;
vec2 CA = C.xy - A.xy;
float lengthBA = length(BA);
float lengthCA = length(CA);
float ratio = lengthBA / ( lengthBA + lengthCA );
vec3 D = B.xyz + ratio * CB.xyz;
vec3 AD = D - A.xyz;
vec3 bisect = normalize(AD);
float theta = acos( dot(BA, CA) / (lengthBA * lengthCA) ) / 2.0;
float AE = 1.0/(sin(theta)*aspect);
newPos.z += AE/length(AD) * (D.z - A.z);
newPos.x += bisect.x*AE;
newPos.y += bisect.y*AE;
gl_Position = newPos;
}
这段代码为我们提供了以下结果。
请注意,一些边缘情况与该过程翻转了几乎背面刻有三角形的三角形有关,我开始在代码中解决此问题,但决定暂时避免出现这些情况。完成这个项目后,也许我会重新审视它。
评论
$ \ begingroup $
很好的解决了这个问题!真的很像一开始的数学描述。
$ \ endgroup $
–user1118321
17年5月13日在3:36
#2 楼
如果没有三角函数,则可以通过缩小三角形的内切面来实现。incircle()
计算由顶点A,B,C
形成的三角形的内切面,它将中心和半径返回为vec4
。然后,将顶点X=A,B,C
向内移动到与圆弧中心的距离的一部分(Q-X
),该距离等于所需余量与圆弧半径(m/Q.w
)的比。 vec4 incircle(vec3 A, vec3 B, vec3 C) {
float a = length(B - C), b = length(C - A), c = length(A - B);
float abc = a + b + c;
// http://mathworld.wolfram.com/Incenter.html
vec3 I = (a * A + b * B + c * C) / abc;
// http://mathworld.wolfram.com/Inradius.html
float r = 0.5
* sqrt((-a + b + c) * (a - b + c) * (a + b - c) / abc);
return vec4(I, r);
}
vec3 A,B,C; // vertices
float m; // margin
vec4 Q = incircle(A,B,C);
A += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - A);
B += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - B);
C += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - C);
评论
$ \ begingroup $
非常有趣,亚当!我还没有听说过这个功能。
$ \ endgroup $
–杰卡洛普
19年5月22日在5:51
评论
您能否为更广泛的背景添加更多内容?偏移三角形是否仍保持原始网格中的状态? “剔除”是指放弃了原始三角形,还是仅仅放弃了偏移,使三角形保持其原始大小?那么...这如何与网格一起工作?因为在网格中,一个顶点有两个以上的邻居。还是仅用于单个三角形?
我的实现方式是将所有三角形都放置在连续缓冲区中:[P1.x,P1.y,P1.z,P2.x,P2.y,P2.z ... Pn.x,Pn.y, [Pn.z]和相邻点也在属性上明确列出。这样,可以计算和操纵每个面的每个顶点,而不会影响相邻面。 Nicol Bolas,是的,分别处理每个三角形。
trichoplax-“剔除”是指抛出而不是渲染,如在背面的单面图元中。
@Jackalope:“你们两个人似乎都建议GPU认为人脸与其他人脸是“拴在一起的”。”这是因为,一般而言,这是正确的。大多数网格不仅仅让相邻的三角形使用“相同的属性”,还包括其他的三角形。他们重复使用相同的顶点。这可能是通过多次使用相同索引的三角形列表,或者是通过三角形带,等等。但一般来说,网格会重用相邻的顶点。您的网格不会,但是您的特定情况不会更改一般情况。这就是为什么我要求澄清。