我正在OpenGL中实现MC算法。一切都很顺利,直到我到达了纹理坐标点。我想不出如何实现它们!我的进度:
编辑:我想归档的是在我生成的MC三角形上放一些纹理。据我所知我需要告诉OpenGL UV坐标,但不知道如何计算它们。
xe55xuns1#
Marching Cube算法中一种典型的纹理坐标生成算法是使用环境Map。简而言之,通过平均所有邻接面的面法线来计算每个顶点处的顶点法线,然后丢弃法线的z坐标并使用(x/2+0.5,y/2+0.5)作为(u,v)纹理坐标。设置一个纹理,中间有一个漂亮的白点,纹理的其余部分有一些结构填充,你就得到了终结者2银色机器人的外观。
fnx2tebb2#
我需要告诉OpenGL紫外线坐标,但不知道如何计算它们。你现在面临着一个大问题从MC中产生的拓扑可以是任何东西。OpenGL中纹理的拓扑可以是(超)圆环(GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D)或球体(GL_TEXTURE_CUBE_MAP)。所以不可避免地你必须把你的表面切割成所谓的Map。这是一个不平凡的任务,但一个好的策略是沿着高曲率的区域切割。见论文
布鲁诺·莱维、西尔万·佩蒂让、尼古拉斯·雷和杰罗姆·马约http://alice.loria.fr/index.php/publications.html?Paper=lscm@2002肮脏的细节。
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 } } }
3条答案
按热度按时间xe55xuns1#
Marching Cube算法中一种典型的纹理坐标生成算法是使用环境Map。
简而言之,通过平均所有邻接面的面法线来计算每个顶点处的顶点法线,然后丢弃法线的z坐标并使用(x/2+0.5,y/2+0.5)作为(u,v)纹理坐标。
设置一个纹理,中间有一个漂亮的白点,纹理的其余部分有一些结构填充,你就得到了终结者2银色机器人的外观。
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
肮脏的细节。
zf2sa74q3#
给出的第一个答案是部分正确的,只是您还需要检查从哪个平面投影最好,而不是总是从z平面投影,如以下C# Unity示例所示:
虽然最好在GPU的着色器中执行此操作,尤其是如果您计划使用非常动态的体素,例如在玩家周围不断生成的无限生成的世界中,或者在涉及大量挖掘和构建的游戏中,您不必每次都计算UV,而且需要发送到GPU的数据也更少。我修改了一个基本的三平面着色器,我发现在互联网上的一段时间前,不幸的是,我不能再找到它,但我的修改版本基本上是一个三平面贴图着色器,除了没有混合和它只采样一次,所以它应该和基本的无光着色器一样快,看起来和上面的图片完全一样。我这样做是因为正常的三平面着色器混合在45度角的砖墙纹理上看起来不太好。
最后看起来很像立方体贴图,虽然我不认为这是一个技术立方体贴图,因为我们只使用三个面,而不是六个。
编辑:我后来意识到,你可能希望它在片段着色器中像这样,但就我的目的而言,它的工作原理完全相同,理论上在顶点着色器中会更快: