EDIT: CHANGING FIRST POST, because this is done.
Here is a procedural rock generator. It takes any mesh, and randomizes the distance of its vertices from the center. Use this on a sphere, and you get a rock of random shape. This should work pretty decently, and is a good free alternative to some of the assets available in the store that do the same thing. All I ask is that you give credit to me, Ramaraunt (Daniel Valcour), as the creator.
Here is the code:
EDIT: Improved smoothness
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class rockRandomizer : MonoBehaviour {
public int seed = 37823787;
private Material mat;
private List<Vector3> vertices = new List<Vector3>();
private List<Vector3> doneVerts = new List<Vector3>();
private Vector3 center;
void Start()
{
Random.InitState(seed);
float offset = Random.Range(0, 20);
Mesh mesh = GetComponent<MeshFilter>().mesh;
for (int s = 0; s < mesh.vertices.Length; s ++)
{
vertices.Add(mesh.vertices[s]);
}
center = GetComponent<Renderer>().bounds.center;
for (int v = 0; v < vertices.Count; v++)
{
bool used = false;
for (int k = 0; k < doneVerts.Count; k++)
{
if (doneVerts[k] == vertices[v])
{
used = true;
}
}
if (!used)
{
Vector3 curVector = vertices[v];
doneVerts.Add(curVector);
int smoothing = Random.Range(4, 6);
Vector3 changedVector = (curVector + ((curVector - center) * (Mathf.PerlinNoise((float) v / offset, (float)v / offset)/smoothing)));
for (int s = 0; s < vertices.Count; s ++)
{
if (vertices[s] == curVector)
{
vertices[s] = changedVector;
}
}
}
}
mesh.SetVertices(vertices);
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
}
Here is an example:
EDIT: To make the rock different each time, don’t forget to change the seed value of each rock!
EDIT: Moss shader! Use this for free, just give credit to me!
Shader "Custom/MossySnowShader" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_MossTex("Moss or Snow (RGBA)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows vertex:vert
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
sampler2D _MossTex;
struct Input {
float2 uv_MainTex;
float2 uv_MossTex;
float3 VertexDirection;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
void vert(inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);
o.VertexDirection = v.normal;
}
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
//Now grab the moss texture
fixed4 m = tex2D(_MossTex, IN.uv_MossTex) * _Color;
//now lets make the texture!
o.Albedo =(m.rgb *m.a ) + (c.rgb * (1 - m.a));
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
The moss texture needs to have alpha blotches, which will be where you can see the rock underneath!
EDIT: Another Shader! This one only renders moss on top of the rock!
Taken from this forum post. I made some changes to it to allow transparency on the moss, so you still need to credit me! This also works nicely with snow.
Shader "Custom/BlendSamplersByDirection" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_MainBump("MainBump", 2D) = "bump" {}
_LayerTex("Layer (RGB)", 2D) = "white" {}
_LayerBump("LayerBump", 2D) = "bump" {}
_LayerStrength("Layer Strength", Range(0, 1)) = 0
_LayerDirection("Layer Direction", Vector) = (0, 1, 0)
_LayerDepth("Layer Depth", Range(0, 0.005)) = 0.0005
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma target 3.0
#pragma surface surf Lambert vertex:vert
sampler2D _MainTex;
sampler2D _MainBump;
sampler2D _LayerTex;
sampler2D _LayerBump;
float _LayerStrength;
float3 _LayerDirection;
float _LayerDepth;
struct Input {
float2 uv_MainTex;
float2 uv_MainBump;
float2 uv_LayerTex;
float2 uv_LayerBump;
float3 worldNormal;
INTERNAL_DATA
};
void vert(inout appdata_full v) {
// Convert the normal to world coordinates/world space
float3 sn = mul((float3x3)_World2Object, _LayerDirection);
if (dot(v.normal, sn.xyz) >= lerp(1, -1, (_LayerStrength * 2) / 3))
{
v.vertex.xyz += (sn.xyz + v.normal) * _LayerDepth * _LayerStrength;
}
}
void surf(Input IN, inout SurfaceOutput o) {
// Diffuse color of pixel
half4 mainDiffuse = tex2D(_MainTex, IN.uv_MainTex);
half4 layerDiffuse = tex2D(_LayerTex, IN.uv_LayerTex);
// Normal vector of pixel
o.Normal = UnpackNormal(tex2D(_MainBump, IN.uv_MainBump));
half3 layerNormal = half3(0, 0, 0);
// Snow mask
half sm = dot(WorldNormalVector(IN, o.Normal), _LayerDirection);
sm = pow(0.5 * sm + 0.5, 2.0);
if (sm >= lerp(1, 0, _LayerStrength))
{
o.Albedo = (layerDiffuse.rgb *(layerDiffuse.a)) + (mainDiffuse.rgb * (1 - layerDiffuse.a));
layerNormal = UnpackNormal(tex2D(_LayerBump, IN.uv_LayerBump));
o.Normal = normalize(o.Normal + layerNormal);
}
else
{
o.Albedo = mainDiffuse.rgb;
}
o.Alpha = mainDiffuse.a;
}
ENDCG
}
FallBack "Diffuse"
}
EDIT: The final product! Use this at will, just give credit to me!
Shader "Custom/BlendSamplersByDirection" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_MainBump("MainBump", 2D) = "bump" {}
_LayerTex("Layer (RGB)", 2D) = "white" {}
_LayerBump("LayerBump", 2D) = "bump" {}
_LayerStrength("Layer Strength", Range(0, 1)) = 0
_LayerDirection("Layer Direction", Vector) = (0, 1, 0)
_LayerDepth("Layer Depth", Range(0, 0.005)) = 0.0005
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma target 3.0
#pragma surface surf Lambert vertex:vert
sampler2D _MainTex;
sampler2D _MainBump;
sampler2D _LayerTex;
sampler2D _LayerBump;
float _LayerStrength;
float3 _LayerDirection;
float _LayerDepth;
struct Input {
float2 uv_MainTex;
float2 uv_MainBump;
float2 uv_LayerTex;
float2 uv_LayerBump;
float3 worldNormal;
INTERNAL_DATA
};
void vert(inout appdata_full v) {
// Convert the normal to world coordinates/world space
float3 sn = mul((float3x3)_World2Object, _LayerDirection);
if (dot(v.normal, sn.xyz) >= lerp(1, -1, (_LayerStrength * 2) / 3))
{
v.vertex.xyz += (sn.xyz + v.normal) * _LayerDepth * _LayerStrength;
}
}
void surf(Input IN, inout SurfaceOutput o) {
// Diffuse color of pixel
half4 mainDiffuse = tex2D(_MainTex, IN.uv_MainTex);
half4 layerDiffuse = tex2D(_LayerTex, IN.uv_LayerTex);
// Normal vector of pixel
o.Normal = UnpackNormal(tex2D(_MainBump, IN.uv_MainBump));
half3 layerNormal = half3(0, 0, 0);
// Snow mask
half sm = dot(WorldNormalVector(IN, o.Normal), _LayerDirection);
sm = pow(0.5 * sm + 0.5, 2.0);
half difference = 1 - pow((clamp(lerp(1, 0, _LayerStrength),0,1) / sm),3);
o.Albedo = (layerDiffuse.rgb *clamp(layerDiffuse.a * difference,0,1)) + (mainDiffuse.rgb * (clamp(1 - layerDiffuse.a * difference,0,1)));
layerNormal = UnpackNormal(tex2D(_LayerBump, IN.uv_LayerBump));
o.Normal = normalize(o.Normal + layerNormal);
o.Alpha = mainDiffuse.a;
}
ENDCG
}
FallBack "Diffuse"
}