Surface shader, ignore everything other than 'o.Normal'

Hello, I’m playing with surface shaders, and I want to do the following:

I would like ‘myNormal’ to be the sole influence on the lighting. So none of the vertex normals are used, or anything else.

o.Normal = half3( myNormal );
o.Albedo = half3(1.0, 1.0, 1.0);;
o.Alpha = 1.0;
o.Emission = half3(0.0, 0.0, 0.0);
o.Specular = 0.0;
o.Gloss = 0.0;

Is this possible? I can’t find a combination of ‘#pragma surface surf’ switches that will do that, and I wondered if there was a different way.
I realize I can just do a vertex/fragment shader, but using a ‘surface’ seemed a great way to access other lighting features.

Thanks,
Dave H.

You probably want to use a Custom Lighting Model for your surface shader

Thanks Rld_,

It appears that the shader wants tangent and normal data, giving a load of errors. I don’t what I want to pass these as I’m generating normal data in the shader.
Can I remove this kind geometry from the shader input?

If you only want certain data to be passed to your custom shader, make sure you use a custom structure which only takes in your normal information.
Then in the custom lighting model, you can use this normal value to do with as you wish.

struct SurfaceOutputCustom
{
    // Other things you may need
    float3 normal;
}
... 
half4 LightingCustomLighting (SurfaceOutputCustom s, half3 lightDir, half atten) {
    // do something with the s.normal
}

void surf (Input IN, inout SurfaceOutputCustom o) {
    o.normal = //your normal here
}

Thank-you Duney.
How are you setting up the above code in:-
#pragma surface ?

Because it’s still complaining about the missing items. First it complains about the missing Emission, then the Specular, then the Alpha. Until I end up with having to put everything back in. And in the ‘surf’, when I finally set o.Normal to something it complains about the missing Tangent!
So I’m back to where I started.

#pragma CustomLighting should do it. However, I’m not entirely sure what the surface shader needs under the hood and that is a very basic idea of what you will need to be doing to use your own normal. However, does supplying your own normal in o.normal not do what you need?

There’s plenty of examples here

Hi, this is the bare bones of my problem with custom shader, sorry for being a such new guy on the Unity board, but I’m tearing what’s left of my hair out(!). Here is the shader that complains that Alpha and Emission are missing, what am I doing wrong please? I realize it might be obvious to some. :slight_smile:

Shader error in ‘Custom/LandSurface’: Program ‘SurfShaderInternalFunc’, expression left of .“Emission” is not a struct or array at line 214

Shader "Custom/Test" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Custom

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		struct SurfaceOutputCustom
		{
			half3 Normal;
			half3 Albedo;
			//half3 Emission;
			//float	Specular;
			//float	Alpha;
		};

		half4 LightingCustom (SurfaceOutputCustom s, half3 lightDir, half atten)
		{
			half4 c;
			c.rgb = half3(1.0, 1.0, 0.0);
			c.a = 1.0;
		  return c;
		}

		void surf (Input IN, inout SurfaceOutputCustom o)
		{
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
       			o.Normal = half3(0.0, 1.0, 0.0);
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

Not sure why that error is showing? Is that the only error you are getting? It says that error is from Custom/LandSurface and not this shader here?

Sorry , just copied the wrong results:-

Shader error in ‘Custom/Test’: Program ‘SurfShaderInternalFunc’, expression left of .“Emission” is not a struct or array at line 53

Here’s the compiled shader:-
BTW - this is using Unit Free, would that make a difference?

Shader "Custom/Test" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		// surface shader with errors was here
Pass { }
/*// error compiling initial surface function 'surf':
#include "HLSLSupport.cginc"
#include "UnityShaderVariables.cginc"
#include "Lighting.cginc"
#include "UnityCG.cginc"
#include "Lighting.cginc"

#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal
#line 1
#line 10

		#pragma surface surf Custom

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		struct SurfaceOutputCustom
		{
			half3 Normal;
			half3 Albedo;
			//half3 Emission;
			//float	Specular;
			//float	Alpha;
		};

		half4 LightingCustom (SurfaceOutputCustom s, half3 lightDir, half atten)
		{
			half4 c;
			c.rgb = half3(1.0, 1.0, 0.0);
			c.a = 1.0;
		  return c;
		}

		void surf (Input IN, inout SurfaceOutputCustom o)
		{
			half4 c = tex2D (_MainTex, IN.uv_MainTex);
			o.Albedo = c.rgb;
			o.Normal = half3(0.0, 1.0, 0.0);
		}
		
*/
#LINE 41

	} 
	FallBack "Diffuse"
}

So, to use a surface shader I NEED to have normals and tangents in my meshes! Which is a massive waste as I’m ignoring them all in the shader and creating others internally.
I don’t think there’s a way around this, is there?

There’s nothing really pro specific you are trying to do here.

Under the hood, surface shaders are just being parsed to “regular” shaders, they’re basically just an abstracted interface for the real thing and so it makes sense it complains about missing stuff it might depend on. I haven’t done that much with surface shaders and what specifics it requires, so it might just be another error though.

If you want to do anything that changes how the lighting behaves, you can’t change the fact that you will need to make this custom lighting model with a surface shader. Can you tell us exactly what you are trying to do so perhaps we can suggest some other methods for this.

I can suggest 2 options for now though that simply alters the mesh data in a script should that better suit you: Pass in the data you want in the vertex colors if you’re not using them, or simply do that for the already existing normals.

What I’m doing is using fractals to create the normals from WITHIN the shader. So I don’t need the Mesh to hold those 7 extra floats of data per vertex (normals / tangents).
I wanted to pass on the normals from my surface shader to the rest of the rendering pipeline, without this unnecessary burden in the mesh. But I don’t think it’s possible.

Cheers,
Dave.

Is calculating the normals a better trade off than passing them from the mesh data? Or are you doing something more specific with the normals that you need to calculate them?

You can probably get away with defining a vertex program in your surface shader and adjust the normals in there, I am assuming the vertex program is executed before the lighting pass anyway. (you can find an example on the surface shaders example page, near the bottom)

If that doesn’t work, you might need to dive into making a vertex/fragment shader.

I guess I’ll have to show it. I’m converting this: http://youtu.be/qzkBnCBpQAM to run in Unity, it only renders about 100k triangles and everything is uniquely created on the fly. So there are no textures loaded other than the font.
The fractal is placed on the underlying meshes, of which there are 1024 of them at varying res. I don’t need the normals as they are entirely created through the fractal code.

It looks like I may have to. Or just stick with creating the superfluous data. :slight_smile:

Oh, I’ve just discovered that I still have access to all the internal lighting positions in Unity etc from within a fragment shader anyway. So I can integrate it with other models and lighting.
So that’s cool!! I can minimize the mesh as much as I like now.

Cheers,
Dave.