im making a mmo/open-world voxel game and are trying to optimize it as much as i can and i figured out a way but i need to make my own custom shader that uses vertex color and has to be URP Compatible. i am new to shader programming,
im using unity 2020.1.17 (it seems to be the only unity version built in release mode).
voxeldata:
[CreateAssetMenu(fileName = "VoxelData", menuName = "Voxel Engine/VoxelData")]
public class VoxelData : ScriptableObject
{
public Vector3[] vertices;
public int[] triangles;
public Color[] colors;
public Vector3 modelPosition;
public Vector3 modelScale;
}
voxelmodelprocessor:
public class VoxelModelProcessor : MonoBehaviour
{
public MeshFilter meshFilter; // Assign your FBX/model's MeshFilter here
public MeshRenderer meshRenderer; // Assign the model's MeshRenderer here
public VoxelData voxelData; // Assign the target VoxelData asset here
[ContextMenu("Process Model")]
public void ProcessModel()
{
if (meshFilter == null || voxelData == null || meshRenderer == null)
{
Debug.LogError("MeshFilter, MeshRenderer, or VoxelData is not assigned.");
return;
}
Mesh mesh = meshFilter.sharedMesh;
voxelData.vertices = mesh.vertices;
voxelData.triangles = mesh.triangles;
// Retrieve the base map texture
Texture2D baseMap = meshRenderer.material.mainTexture as Texture2D;
Vector2[] uvs = mesh.uv; // UV mapping for the vertices
// Ensure color array matches vertex count
voxelData.colors = new Color[mesh.vertexCount];
for (int i = 0; i < mesh.vertexCount; i++)
{
if (baseMap != null)
{
// Sample the texture color using UV coordinates
Vector2 uv = uvs[i];
voxelData.colors[i] = baseMap.GetPixelBilinear(uv.x, uv.y);
}
else
{
// If no texture, default to white
voxelData.colors[i] = Color.white;
}
}
// Store the model's position if needed
voxelData.modelPosition = transform.position;
voxelData.modelScale = transform.localScale;
Debug.Log("Model processed and voxel data saved with texture colors.");
}
}
voxelrenderer:
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class VoxelRenderer : MonoBehaviour
{
public VoxelData voxelData; // Reference to the processed VoxelData
private MeshFilter meshFilter;
private MeshRenderer meshRenderer;
void Start()
{
meshFilter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
if (voxelData != null)
{
RenderVoxelData();
}
}
private void RenderVoxelData()
{
Mesh mesh = new Mesh();
// Adjust vertex positions based on model scale
Vector3[] scaledVertices = new Vector3[voxelData.vertices.Length];
for (int i = 0; i < voxelData.vertices.Length; i++)
{
scaledVertices[i] = Vector3.Scale(voxelData.vertices[i], voxelData.modelScale);
}
mesh.vertices = scaledVertices;
mesh.triangles = voxelData.triangles;
mesh.colors = voxelData.colors;
mesh.RecalculateNormals();
meshFilter.mesh = mesh;
meshRenderer.material = CreateVertexColorMaterial();
}
private Material CreateVertexColorMaterial()
{
Shader shader = Shader.Find("Custom/URP/VertexColorShaderWithLighting");
if (shader == null)
{
Debug.LogError("Vertex color shader not found!");
return null;
}
return new Material(shader);
}
}
custom shader code:
Shader "Custom/URP/VertexColorShaderWithLighting"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 100
Pass
{
Name "ForwardLit"
Tags { "LightMode"="UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
// Texture and sampler declaration for URP
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 color : COLOR;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float3 normalWS : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float4 shadowCoord : TEXCOORD2; // For shadows
};
Varyings vert (Attributes IN)
{
Varyings OUT;
OUT.positionCS = TransformObjectToHClip(IN.positionOS);
OUT.worldPos = TransformObjectToWorld(IN.positionOS).xyz;
OUT.normalWS = TransformObjectToWorldNormal(IN.normalOS);
OUT.color = IN.color;
// Calculate shadow coordinates
OUT.shadowCoord = TransformWorldToShadowCoord(OUT.worldPos);
return OUT;
}
half4 frag (Varyings IN) : SV_Target
{
// Sample the vertex color
half4 color = IN.color;
// Apply simple Lambert lighting using main light direction and color
Light mainLight = GetMainLight(); // Get the main URP light
half3 lightDir = normalize(mainLight.direction);
half lambertTerm = saturate(dot(IN.normalWS, lightDir));
// Calculate shadow attenuation
half shadow = MainLightRealtimeShadow(IN.shadowCoord);
// Combine vertex color with lighting and shadow
color.rgb *= mainLight.color * lambertTerm * shadow;
return color;
}
ENDHLSL
}
}
FallBack "Diffuse"
}
i have gotten some shadow working but its not really looking how i want it to.
how it is looking

