I've been having some trouble with randomly perturbing the surface of a sphere with a bump map in Unity (v2021.3.18f1) for a VR application. Here are the steps I've taken so far:
- created a sphere with radius of 30
- created a material with maximum opacity (albedo=255) and assigned it to the sphere; the color of the material is green
- written a custom shader (template=Standard Surface Shader) which does the following things:
- creates a visible interior surface for the
sphere by:
- duplicating the mesh on the exterior face
- flipping the normals
- turning off backface culling
- applies a bump map to the exterior surface
- creates a visible interior surface for the
sphere by:
- created a bump map in GIMP (100x100 noisy grayscale .png image)
- imported the bump map as an asset and linked it to the abovementioned material; set the texture type of the bump map to "normal map"
- set the bump scale to 1.0 to maximize its effect
ChatGPT suggests that the mesh geometry may not be detailed enough to render the bumps. The mesh has over 700 polygons and seems detailed enough but not totally sure, this is my first time using Unity or doing anything with graphics. A screenshot of the wireframe rendering is below. Also, there is a screenshot of the bump map itself.
The environment has a directional light pointing at the sphere at somewhat of an angle. I've tried to create shadows on the surface of the sphere to accentuate any tiny bumps to no avail.
Below the images is the shader code.
Shader "Custom/SphereShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
// START MODS
_BumpMap ("Bump Map", 2D) = "bump" {}
_BumpScale ("Bump Scale", Range(0, 1)) = 1.0
// END MODS
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
// START MODS
sampler2D _BumpMap;
//END MODS
struct Input
{
float2 uv_MainTex;
// START MODS
float3 worldNormal;
float3 worldPos;
INTERNAL_DATA
// END MODS
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assume uniform scaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
// START MODS
// function to perturb surface normal
inline float3 perturb_normal(float3 normal, float3 pos, float3 worldNormal, float3 worldTangent)
{
float3 map = UnpackNormal(tex2D(_BumpMap, pos.xy));
map = 2.0 * map - 1.0;
map.xy *= 1.0; // adjust the bump map strength here
map = normalize(map);
// calculate tangent space basis
float3 worldBinormal = cross(worldNormal, worldTangent);
float3x3 tangentSpace = float3x3(worldTangent, worldBinormal, worldNormal);
// perturb normal
return normalize(mul(tangentSpace, map));
}
void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
// apply bump map to surface normal
float3 worldNormal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex) * 2.0 - 1.0);
worldNormal = normalize(worldNormal);
// use the worldNormal to perturb the surface normal
o.Normal = perturb_normal(o.Normal, IN.worldPos, worldNormal, IN.worldNormal);
}
// END MODS
ENDCG
// START MODS
// turn off backface culling
Cull Off
// make the mesh double-sided
Pass
{
Name "FORWARD"
Tags { "LIGHTMODE" = "ForwardBase" }
ZWrite On
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float NORMALIZING_CONST = 255.0;
float R = 30.0 / NORMALIZING_CONST;
float G = 245.0 / NORMALIZING_CONST;
float B = 90.0 / NORMALIZING_CONST;
return fixed4(R, G, B, 1);
}
// END MODS
ENDCG
}
}
FallBack "Diffuse"
}
Why aren't there any bumps on the sphere's surface? What can I do to move towards that goal?