- Home /
Procedural UV map on a procedural mesh
Hi. I've got a plane that I generated procedurally:
From no experience with texture mapping I've been trying to map a texture to the plane, however I'd like each quad or tri to be coloured based on its y coordinates like this (brown is the lowest area, yellow is the highest area etc.):
I have only realised recently that this might not be possible as apparently UV seams require duplicate vertices, of which there aren't any in my mesh.
Is there a better way to map parts of a texture to individual quads or tris? If not, is there a way for create duplicate vertices, after the array of vertices for the mesh has been generated?
Thank you for any help in advance. Any information will help point me in the right direction.
You have to dublicate the vertices indeed. You could get away with keeping four (ins$$anonymous$$d of six) per quad if that's what you want.
Is there a way to do that after the mesh and tris have been generated?
Why not just create the vertex and triangle array correctly the first time? If you generate the mesh procedurally anyway, it sohuld be trivial to change the code. In fact, not having to share vertices between quads or triangles is much easier.
Answer by Alistair401 · Dec 15, 2016 at 08:22 AM
I've found a way to do this without using a tile map as the texture of the plane. Instead I generate a new texture and piece together parts of a tile map, which avoids having to use complicated UVs and then I can just stretch the texture across the plane.
I still think this is an interesting question though and will leave it open. My solution is better for quads than tris and means a possibly vast texture has to be generated to stretch across the mesh.
If I understand you correctly then I have experimented with the same solution. I quickly found out that it eats lots of memory to create huge textures on the fly, so I suggest keeping an eye on the memory footprint.
I agree it's not ideal. For my purposes I think it works however if possible I'd love to optimise it in the future. For reference the texture I generate is about 85$$anonymous$$b (4096x4096), which is pretty big but as I'm using it as the texture for the terrain, it'll be the biggest texture in the game anyway and it'll only be generated once.
Answer by Glurth · Dec 16, 2016 at 03:43 AM
I realize this doesn't answer the questin about UV stuff but this is how I make "each quad or tri to be coloured based on its y coordinates " edit: actually that's only for flat/horizontal tris- otherwise it by pixel, NOT triangle. (sorry realized after I posted- still might be useful)
I use a shader, that is applied to the material of the plane. Here is my current elevation map shader incarnation, it's a WIP so may have some flaws. (Copy the below code into a file named map.shader, in your asset folder. Now you can use this shader in a material.)
Shader "Unlit/HeightMap"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Tiling ("Tiling", Float) = 1.0
_Height("Height", Float) =4.0
}
// no Properties block this time!
SubShader
{
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// include file that contains UnityObjectToWorldNormal helper function
#include "UnityCG.cginc"
//#include "UnityLightingCommon.cginc" // for _LightColor0
#include "Lighting.cginc"
// compile shader into multiple variants, with and without shadows
// (we don't care about any lightmaps yet, so skip these variants)
#pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
// shadow helper functions and macros
#include "AutoLight.cginc"
struct v2f {
// we'll output world space normal as one of regular ("texcoord") interpolators
half3 worldNormal : TEXCOORD0;
SHADOW_COORDS(1) // put shadows data into TEXCOORD1
half2 uv : TEXCOORD3;
half4 worldCoord : TEXCOORD2;
float4 pos : SV_POSITION;
fixed4 diff : COLOR0; // diffuse lighting color
};
float _Tiling;
float _Height;
//sampler2D _MainTex;
v2f vert (float4 vertex : POSITION, float3 normal : NORMAL,float2 uv : TEXCOORD0)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, vertex);
o.worldNormal = UnityObjectToWorldNormal(normal);
o.worldCoord = vertex;
o.worldCoord.y /= _Height;
o.worldCoord.xz *= _Tiling;
o.worldCoord.xz+=float2(0.5,0.5);
o.uv = ((uv-float2(0.5,0.5))* _Tiling)+float2(0.5,0.5);
half3 worldNormal = UnityObjectToWorldNormal(normal);
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
o.diff = nl * _LightColor0;
o.diff.rgb += ShadeSH9(half4(worldNormal,1));
TRANSFER_SHADOW(o)
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = 0;
c.rgb = i.worldNormal.y;
c.rb *= i.worldCoord.y;
c.rgb *= tex2D(_MainTex, i.uv).r;
fixed shadow = SHADOW_ATTENUATION(i);
// darken light's illumination with shadow, keep ambient intact
fixed3 lighting = i.diff * shadow ;
c.rgb *= lighting;
return c;
}
ENDCG
}
// shadow casting support
UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}
}
Now that's a nice solution. I haven't messed with shaders yet but after seeing your rather beautiful result I feel like giving it a go. Not sure if I can mark this as the answer or not as it doesn't use UVs but since the UV solution is basically: you've got to use duplicate vertices in your mesh, this seems like a great alternative.
Glad you like it! feel free to use/ modify email me question about it, and up-vote the answer. But no, I don't think you should mark this as the answer to the Original Question, since it doesn't actually answer it.