CubeMap shader problem / assistance.

I’m trying to code a shader that uses two cubemaps, one for diffuse and one for vertex deformation. There going to be used on a quad sphere.

My shader skills are yet to be…refined shall we say. I can grasp the basic logic but I still need to get my head around how these things work…

From what I understand about shaders, I managed to combine and modify what I could to get this result…

Shader "Custom/Test"
{
	Properties
	{
		_CubeDiffuse ("Cubemap Diffuse Map", CUBE) = "" {}
		_CubeHeight ("Cubemap Height Map", CUBE) = "" {}
		_Amount ("Extrusion Amount", Range(-1,1)) = 0.5 //This should act as a multiplier for _CubeHeight rather than a dedicated setting.
    }
    
    SubShader
    {
		Tags { "RenderType" = "Opaque" }
      
		CGPROGRAM
		#pragma surface surf Lambert vertex:vert
		
		struct Input
		{
			float3 worldRefl; //PROBLEM 1 - I think this this input is causing the diffuse to distort like a reflective cubemap would.
		};

		float _Amount; //I need this 'Amount' to read the values from _CubeHeight not _Amount.
		
		void vert (inout appdata_full v)
		{
			v.vertex.xyz += v.normal * _Amount;
		}

      	samplerCUBE _CubeDiffuse;
      
      	void surf (Input IN, inout SurfaceOutput o)
      	{
			o.Albedo = texCUBE (_CubeDiffuse, IN.worldRefl).rgb; //PROBEM 1 - It's applied here.
		}
		
		ENDCG
    } 
    Fallback "Diffuse"
}

The diffuse part works, but it acts like a reflection cube map and distorts as the object rotates. And adjusting the ‘Amount’ value leads to every vertex moving the exact same amount as expected.

Problem1 - I need to solve the distortion issue.
Problem2 - I need the amount value to read from the greyscale value of the _CubeHeight Texture.

I’ve searched everywhere on the net for something similar and found this one shader which takes care of the diffuse but not the vertex deformation. And it also does not respond to lighting…

Shader "Custom/PlanetShader"
{
	Properties
	{
        _CubeTex("Cubemap", CUBE) = "" {}
    }
    
    SubShader
    {
        Tags { "RenderType"="Opaque" }
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
 
            #include "UnityCG.cginc"
 
            samplerCUBE _CubeTex;
 
            struct appdata_t
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
 
            struct v2f
            {
                float4 vertex : POSITION;
                float3 texcoord : TEXCOORD0;
            };
 
            v2f vert(appdata_t v)
            {
                v2f OUT;
                OUT.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                OUT.texcoord = v.normal;
                return OUT;
            }
 
            half4 frag(v2f IN) : COLOR
            {
                return texCUBE(_CubeTex, IN.texcoord);
            }
            ENDCG 
        }
    }
    
    FallBack "Diffuse"
}

This shader just confuses me completely. Here are the cube maps I’m using…
1231951--51932--$CubeDiffuseMap.jpg1231951--51933--$CubeHeightMap.jpg

Any help or guidance would be greatly appreciated.

If you use the regular texture coordinates (like in the second shader), instead of the reflection vector, in the first shader, it should be a lit version of the second shader.

The first shader is called a surface shader. It compiles into regular vertex and fragment shaders, but handles all the lighting for you. By default when you create a new shader, it is a surface shader. The second shader is one of those regular shaders, which might be why it confuses you.

The vertex shader is where each vertex of the model is given a position relative to the screen, which is what you see in the second shader (it also calculates or -in this case- passes along the texture coordinates used in the fragment shader). The surface shader automatically generates that code, so in the first shader you only see the vertex displacement that is done before.

To move the vertices according to the values in the texture, you need to do what is called a Vertex Texture Fetch (often abbreviated to simply VTF), which is still kind of tricky, depending on the Operating System and hardware. The NVidia Cg Documentation says that texCUBE is available in vertex profile vp40 and newer, but it says the same about tex2D, and that doesn’t work in Unity. Normally we use tex2Dlod instead, for regular textures (we have to provide the level of detail argument, because it can’t automatically determine which mip map level to choose, like in the fragment shader).

In short: I haven’t tried sampling cubemaps from the vertex shader, but I’m guessing it won’t work :frowning:

P.S.: The last I heard about Matthew Scott was that he was stuck on an Ancient starship across the universe. Glad to see you managed to dial a gate back to earth.

Lol, Thanks for the explanation that helps a lot, I guess I’ll have to keep searching!

Can you recommend a good book on unity shaders? Or cg or whatever?

I tried using a texcoord it didn’t like it at all. After reading into things a little more I tried float3 worldNormal; and o.albedo…blah blah IN.worldNormal

That’s now taken care of the diffuse part and I have lighting on it too, now if I could just figure out this damn vertex problem. Surely there must be a way, I find it difficult to believe there isn’t a solution to all of the worlds problems…including my shader ones =P

The Nvidia Cg tutorial is great for general shader programming and Cg specific stuff. For everything related to Unity, check the shaderlab documentation, it will give you a lot of useful information (a lot of new information too, actually, since Unity 4). MSDN doesn’t always apply to Unity and Cg, but it can be helpful sometimes.

Well, there’s always the option to create your own graphics chip, with its own custom instructions, and graphics API ;). There’s actually plenty of work that could be done, and there aren’t always enough people to do the work. Creating good workarounds is half the fun though.

Does the displacement texture have to be a cubemap? Planets are often rendered as divided into tiles. You can apply a regular texture to those individual tiles. Makes it easier to have a dynamic level of detail too. If you search for Planet Rendering, you should get a good idea of how other people made the magic happen.

My original thoughts of approach where to create six tiles and deform them in such a way they could be placed together into a sphere. My fear was that where the planes meet, you would get holes in the ‘terrain’ when the vertices are moved outwards along their normals. I wouldn’t have a clue as to how to go about then stitching those gaps together or ‘welding’ them across the average distance of the gap or ‘stitching’

You could create a ‘border’ where vertices share their coordinates, to make sure both ends displace by the same amount.