c++ 行进立方体和纹理坐标的问题

qnyhuwrf  于 2022-12-01  发布在  其他
关注(0)|答案(3)|浏览(170)

我正在OpenGL中实现MC算法。
一切都很顺利,直到我到达了纹理坐标点。
我想不出如何实现它们!
我的进度:

编辑:我想归档的是在我生成的MC三角形上放一些纹理。据我所知我需要告诉OpenGL UV坐标,但不知道如何计算它们。

xe55xuns

xe55xuns1#

Marching Cube算法中一种典型的纹理坐标生成算法是使用环境Map。
简而言之,通过平均所有邻接面的面法线来计算每个顶点处的顶点法线,然后丢弃法线的z坐标并使用(x/2+0.5,y/2+0.5)作为(u,v)纹理坐标。
设置一个纹理,中间有一个漂亮的白点,纹理的其余部分有一些结构填充,你就得到了终结者2银色机器人的外观。

fnx2tebb

fnx2tebb2#

我需要告诉OpenGL紫外线坐标,但不知道如何计算它们。
你现在面临着一个大问题从MC中产生的拓扑可以是任何东西。OpenGL中纹理的拓扑可以是(超)圆环(GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D)或球体(GL_TEXTURE_CUBE_MAP)。
所以不可避免地你必须把你的表面切割成所谓的Map。这是一个不平凡的任务,但一个好的策略是沿着高曲率的区域切割。见论文

"最小二乘保角Map用于自动纹理Map集生成"

布鲁诺·莱维、西尔万·佩蒂让、尼古拉斯·雷和杰罗姆·马约
http://alice.loria.fr/index.php/publications.html?Paper=lscm@2002
肮脏的细节。

zf2sa74q

zf2sa74q3#

给出的第一个答案是部分正确的,只是您还需要检查从哪个平面投影最好,而不是总是从z平面投影,如以下C# Unity示例所示:

Vector2[] getUVs(Vector3 a, Vector3 b, Vector3 c)
{
    Vector3 s1 = b - a;
    Vector3 s2 = c - a;
    Vector3 norm = Vector3.Cross(s1, s2).Normalize(); // the normal

    norm.x = Mathf.Abs(norm.x);
    norm.y = Mathf.Abs(norm.y);
    norm.z = Mathf.Abs(norm.z);

    Vector2[] uvs = new Vector2[3];
    if (norm.x >= norm.z && norm.x >= norm.y) // x plane
    {
        uvs[0] = new Vector2(a.z, a.y);
        uvs[1] = new Vector2(b.z, b.y);
        uvs[2] = new Vector2(c.z, c.y);
    }
    else if (norm.z >= norm.x && norm.z >= norm.y) // z plane
    {
        uvs[0] = new Vector2(a.x, a.y);
        uvs[1] = new Vector2(b.x, b.y);
        uvs[2] = new Vector2(c.x, c.y);
    }
    else if (norm.y >= norm.x && norm.y >= norm.z) // y plane
    {
        uvs[0] = new Vector2(a.x, a.z);
        uvs[1] = new Vector2(b.x, b.z);
        uvs[2] = new Vector2(c.x, c.z);
    }

    return uvs;
}

虽然最好在GPU的着色器中执行此操作,尤其是如果您计划使用非常动态的体素,例如在玩家周围不断生成的无限生成的世界中,或者在涉及大量挖掘和构建的游戏中,您不必每次都计算UV,而且需要发送到GPU的数据也更少。我修改了一个基本的三平面着色器,我发现在互联网上的一段时间前,不幸的是,我不能再找到它,但我的修改版本基本上是一个三平面贴图着色器,除了没有混合和它只采样一次,所以它应该和基本的无光着色器一样快,看起来和上面的图片完全一样。我这样做是因为正常的三平面着色器混合在45度角的砖墙纹理上看起来不太好。

Shader "Triplanar (no blending)"
{
    Properties
    {
        _DiffuseMap("Diffuse Map ", 2D) = "white" {}
        _TextureScale("Texture Scale",float) = 1
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
        #pragma target 3.0
        #pragma surface surf Lambert

        sampler2D _DiffuseMap;
        float _TextureScale;

        struct Input
        {
            float3 worldPos;
            float3 worldNormal;
        };

        void surf(Input IN, inout SurfaceOutput o)
        {
            IN.worldNormal.x = abs(IN.worldNormal.x);
            IN.worldNormal.y = abs(IN.worldNormal.y);
            IN.worldNormal.z = abs(IN.worldNormal.z);

            if (IN.worldNormal.x >= IN.worldNormal.z && IN.worldNormal.x >= IN.worldNormal.y) // x plane
            {
                o.Albedo = tex2D(_DiffuseMap, IN.worldPos.zy / _TextureScale);
            }
            else if (IN.worldNormal.y >= IN.worldNormal.x && IN.worldNormal.y >= IN.worldNormal.z) // y plane
            {
                o.Albedo = tex2D(_DiffuseMap, IN.worldPos.xz / _TextureScale);
            }
            else if (IN.worldNormal.z >= IN.worldNormal.x && IN.worldNormal.z >= IN.worldNormal.y) // z plane
            {
                o.Albedo = tex2D(_DiffuseMap, IN.worldPos.xy / _TextureScale);
            }
        }
        ENDCG
    }
}

最后看起来很像立方体贴图,虽然我不认为这是一个技术立方体贴图,因为我们只使用三个面,而不是六个。
编辑:我后来意识到,你可能希望它在片段着色器中像这样,但就我的目的而言,它的工作原理完全相同,理论上在顶点着色器中会更快:

Shader "NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                
                v.normal.x = abs(v.normal.x);
                v.normal.y = abs(v.normal.y);
                v.normal.z = abs(v.normal.z);

                if (v.normal.x >= v.normal.z && v.normal.x >= v.normal.y) // x plane
                {
                    o.uv = v.vertex.zy;
                }
                else if (v.normal.y >= v.normal.x && v.normal.y >= v.normal.z) // y plane
                {
                    o.uv = v.vertex.xz;
                }
                else if (v.normal.z >= v.normal.x && v.normal.z >= v.normal.y) // z plane
                {
                    o.uv = v.vertex.xy;
                }

                UNITY_TRANSFER_FOG(o, o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

相关问题