我需要使用顶点着色器偏移所有(蓝色)三角形,每个三角形彼此独立。为了操纵整个三角形,我为每个表示左侧(紫色)和右侧(绿色)相邻顶点的顶点(红色)创建了自定义(vec3)属性。由此,我需要从两个相邻边缘等距(在屏幕空间中)得出橙色点。从每个三角形派生三个这样的橙色点,将经过处理的(橙色)三角形传递到片段着色器。




理想情况下,三角形如果偏移量抵消了三角形内的任何可用空间(例如第二张图片的第二个三角形),则将被剔除(如背面/未渲染)。

我正在使用THREE.BufferGeometry()作为我的数据结构。

这是我要达到的效果的屏幕截图:



评论

您能否为更广泛的背景添加更多内容?偏移三角形是否仍保持原始网格中的状态? “剔除”是指放弃了原始三角形,还是仅仅放弃了偏移,使三角形保持其原始大小?

那么...这如何与网格一起工作?因为在网格中,一个顶点有两个以上的邻居。还是仅用于单个三角形?

我的实现方式是将所有三角形都放置在连续缓冲区中:[P1.x,P1.y,P1.z,P2.x,P2.y,P2.z ... Pn.x,Pn.y, [Pn.z]和相邻点也在属性上明确列出。这样,可以计算和操纵每个面的每个顶点,而不会影响相邻面。 Nicol Bolas,是的,分别处理每个三角形。

trichoplax-“剔除”是指抛出而不是渲染,如在背面的单面图元中。

@Jackalope:“你们两个人似乎都建议GPU认为人脸与其他人脸是“拴在一起的”。”这是因为,一般而言,这是正确的。大多数网格不仅仅让相邻的三角形使用“相同的属性”,还包括其他的三角形。他们重复使用相同的顶点。这可能是通过多次使用相同索引的三角形列表,或者是通过三角形带,等等。但一般来说,网格会重用相邻的顶点。您的网格不会,但是您的特定情况不会更改一般情况。这就是为什么我要求澄清。

#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