Is it possible to make a shader extend another shader in Unity - unity3d

I want to make a couple of GPU textures using perlin noise and whatnot, so I have this big shader that have all those perlin, simplex, voronoi noises functions and then just make a new shader that extends the big one having just one function with stuff like:
color = perlin(x, y, z) + perlin(x*10, y*10, z*10) / voronoi(x,y,z);
Is it possible? What is the best approach? I will end up making one shader per texture, so it will be a lot of shaders and I would prefer to avoid having to copy/paste all of these functions, especially if I ever need to remake one of them

Move the common code into .cginc or .glslinc files and include them with the #include statement. Also see this question on answers.unity3d.com.
Another approach is to use the UsePass command.

Related

Can we write our own sampling and wrapping logic in shader? what could be a problem?

There are some ideas I would like to do in shader that require me to make a weird texture topology, texture atlas packing for example. They could not be wrapped with common wrap mode, there would be glitch or bleeding on the edge of UV seam
And so I think, what if I just use tex2D() or tex2Dlod() for texture lookup with point filtering, and then rewrite all sampling and blending logic in the shader itself, look up for many points with custom wrapper and blend them with shader code
Is it possible and what could be a problem or disadvantage about this method?
Yes, this is possible and common. You will need to set the filter and/or wrap mode of the texture asset itself, in the project. (if using shader graph, you have the option to specify a custom sample state inside the shader itself). You can certainly modify the UV coordinates passed to your shader, and use those modified values to sample the texture(s).

Simply get the scaling of an object inside the Cg shader

Say you have a trivial Unity shader. It does not at all use any texture. It grabs simply the position ..
void vert (inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input,o);
o.localPos = v.vertex.xyz;
}
and then draws a square ..
the quad in the example has been stretch about 3:1 using the transform.
If in the shader we simply knew the scaling (or, just the ratios) we could very easily draw "square squares"
This is obviously a common, everyday technique for things like billboarding, 2D images and backgrounds etc.
In current unity (2018) how the heck do you simply get the current scaling of the object, in Cg?
This is one of those crazy Unity things that is (1) totally undocumented (2) where the only information available about it is as much as 13 years old, I mean some of the folks involved may be deceased (3) it has changed drastically in different Unity versions, so often discussion about it is just totally wrong. Sigh.
How to do it? Can you?
Currently I just have a trivial script pass in the value, which is OK but a bit shoddy.
The scale of the transform is baked into the world matrix. If your object is not rotated then you can fetch it directly with a little bit of swizzling, but most likely you want to do something like this:
half3 ObjectScale() {
return half3(
length(unity_ObjectToWorld._m00_m10_m20),
length(unity_ObjectToWorld._m01_m11_m21),
length(unity_ObjectToWorld._m02_m12_m22)
);
}
heads-up: this implementation is dependent on the API, you might need to use some DEFINE to deal with this in DX/OGL, since the matrix format is different (row vs column order).
there's also different way to access matrices components: https://learn.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-per-component-math
like the examples in this thread https://forum.unity.com/threads/can-i-get-the-scale-in-the-transform-of-the-object-i-attach-a-shader-to-if-so-how.418345/

Why in 3D game we need to separate a material into so many textures for a static object?

Perhaps the question is not that correct, the textures should be say a kind of channel? although I know they will be mixed in the shader finally.
I know the knowledge of the various textures is very important, but also a bit hard to understand completely.
From my understanding:
diffuse - the 'real' color of an object without light involved.
light - for static objects. render light effections into texture beforehand.
specular - the area where has direct reflection.
ao - to absorb indirect light for the different area of an object.
alpha - to 'shape' the object.
emissive - self illuminance.
normal - pixel normal vector to deal with the light ray.
bump - (dont' know the exact differences between normalmap).
height - stores Z range values, to generate terrain, modify vertex etc.
And the items below should be related to PBR material which I'm not familiar with:
translucency / cavity / metalness / roughness etc...
Please correct me if some misunderstandings there.
But whatever, my question is why we need to separate these textures apart for a material but not only render them together into the diffusemap directly for a static object?
It'll be appreciated if some examples (especially for PBR) , and thank you very much.
I can beforehand bake all things into the diffuse map and apply to my
mesh, why I need to apply so many different textures?
Re-usability:
Most games re-use textures to reduce the size of the game. You can't if you combine them together. For example, when you two similar objects but you want to randomize the looks of them(aging effect), you can make them share the-same color(albedo) map but use different ao map. This becomes important when there hundreds of objects, you can use different combination of texture maps on similar objects to create unique Objects. If you have combined this into one, it would be impossible to share it with other similar objects but you to slightly make to look different.
Customize-able:
If you separate them, you'll be able to change the amount of effect each texture will apply to the Object. For example, the slider on the metallic slot for the Standard shader. There are more of this sliders on other map slots but they only appear once you plug a texture into the slot. You can't do this when you combine the textures into one.
Shader:
The standard shader can't do this so you have to learn how to write shader since you can't use one image to get the effects you would with all those texture maps with the standard shader. A custom shader is required and you need a way to read the information about the maps in the combined shader.
This seems like a reasonable place to start:
https://en.wikipedia.org/wiki/Texture_mapping
A texture map is an image applied (mapped) to the surface of a shape or polygon. This may be a bitmap image or a procedural texture. They may be stored in common image file formats, referenced by 3d model formats or material definitions, and assembled into resource bundles.
I would add to this that the shape or a polygon don't have to belong to 3d objects as one may imagine it. If you render two triangles as a rectangle, you can run all sorts of computations and store it in a "live" texture.
Texture mapping is a method for defining high frequency detail, surface texture, or color information on a computer-generated graphic or 3D model. Its application to 3D graphics was pioneered by Edwin Catmull in 1974.
What this detail represents is either some agreed upon format to represent some property, (say "roughness" within some BRDF model) which you would encounter if you are using some kind of an engine.
Or whatever you decide that detail to be, if you are writing your own engine. You can decide to store whatever you want, however you want it.
You'll notice on the link that different "mapping" techniques are mentioned, each with their own page. This is the result of some person, or people who did some research and came up with a paper detailing the technique. Other people adopt it, and that's how they find their way into engines.
There is no rule saying these can't be combined.

HLSL (Unity-specific ok, not necessary) combining Stencil and worldspace "reverse" clipping

I've built a working surface shader (call it "wonderland") that renders as invisible unless a companion "lookingGlass" shader intersects with it from the viewpoint of the camera. Simple stencil shader arrangement.
Easy peasy.
I can add shader settings to specify a plane, or even just a minimum worldspace Z value, and use clip() to only render pixels on one side of that plane... (in other words, I could use that to trim the content that's allowed by the Stencil.)
What I want to do is use the stencil on surfaces "through the looking glass", (to reveal geometry that's inside the looking glass) and to always render those surfaces when they're on "our" side of the looking glass (to always show them if they're on this side of the looking glass portal). eg., if z<0, render if the Stencil Ref value is satisfied. if z>=0, render regardless.
Now, in Unity I can attach two materials to the MeshRenderer component (one with a stencil shader, one with a "plane cutoff" shader) - that works fine. It's pretty awesome, actually, at least visually. But while I haven't benchmarked it yet, I instinctively believe it's going to massively impact framerate if there are a number of objects, fairly complicated geometry, etc., set up with this arrangement.
(I can also manage shader attachment in code, and only do this when I expect something to transition, but I'm really hoping to get a unified shader out of this to avoid unnecessary draw calls.)
As it turns out, what I was looking to do is impossible.
The two shaders I wish to combine are both surface shaders. While you can combine multiple surface shaders into a multipass shader, you cannot combine multiple surface shaders, with a Stencil, and with a clip() where the clip is applied to passes that the Stencil is not and vice-versa.
There are combinations that can achieve parts of this, or can achieve the entire goal with surface and vert (or other non-surf) shaders, but the combination of requirements stipulated by this question isn't supported as desired.
While this does not answer the question, the workaround in Unity is to create two materials that provide each piece of functionality. They can both exist on the item that needs both pieces, and code can otherwise manage whether one or the other or both is actively in use.
Similar solutions would be available in other packages.

Do I have to use shared vertices in mesh in Unity?

I want to create procedurally generated landscape meshes with a flat shaded look in Unity3D.
I thought it would be the best to create three unique vertices per triangle and use one calculated normal for the vertices. Building this mesh would lead to redundant vertex position information. (Would it have an impact on render time?)
Anyway... the problem is that I would like to use shading techniques e.g. ambient occlusion on this mesh. I don't want to mess up the mesh topology that Unity3D expects for its shaders.
Is it better to create the meshwith shared vertices, add perhaps a custom vertex attribute e.g. 'flat_normal' and customize the shaders to use this?
The simple answer is
No,
Unity does not, in the slightest, "look for" shared verts. No 3D pipeline has anything to do with shared verts. Shared verts does not help or hinder the 3D pipeline in anyway at all.
(Very often, when for example we are making dynamic mesh, we just "never use shared verts at all" because, as you have probably found, it's often far simpler to not use shared verts.)
The one and only reason to use shared verts is if, for some reason, it happens to make it more convenient for you. In that case the 3D pipeline (Unity or elsewhere) "allows" shared verts, with no downside.
There might be 2 considerations for using shared vertices:
To reduce memory usage. (Only slightly, but if you need less UV1's, UV2's, normals, vertices it can add up)
to make it more convenient to share normals. (You only have to alter one normal of a vertex if you want to keep the surface smooth. )
These are no big reasons, but as most of the meshes from other 3D programs that you encounter, it's probably best to get used to shared vertices.