- Home /
Need a Shader Solution for lighting a flat vertical mesh horizontally
I'm trying to figure out how to get my grass to blend in correctly with the ground under it. I'll start out by saying I'm not using unity's terrain, just a normal (if not very large) mesh for the ground, and lots of flat small plane meshes with transparency for the grass. When they are not lit they match up perfectly (the colors match very well) and it looks great, the problem is that when lights are involved they are always lit very differently. The ground is horizontal and the light hits it from that angle, and the grass meshes are vertical, causing the lighting to look extremely different and making the grass very obviously not part of the ground.
So my question is what is the best work around for this? I was thinking of two ways this might work, but Im not sure either are possible.
My first idea would be to write a shader that uses light information from a separate mesh and apply it to the grass mesh. So basically I would have two meshes for each clump of grass, one that is horizontal and invisible and one that is vertical and visible. The visible one would take the lighting information from the horizontal invisible one.
The second idea would be to have the grass model sitting horizontal and then write a script on it that would somehow it make it appear vertical at runtime, like not changing the information, just the way it is viewed, like just flipping the x rot by 90 of only the image, not the information that is processed, if that makes any sense...
There will have to be quite a bit of grass, so the solution can't be extremely taxing to run. If anyone knows of a way to accomplish either of these things, or has a better easier solution I would be greatly appreciative. This thing has been vexing for quite some time. Also it would be helpful if someone could point in the direction of where I could go to look for possible solutions, or even what language I should be using so I know how to search for an answer, like what do you call using a lighting a mesh with the information from a different mesh?
Thanks again, sorry if this was a little longwinded, Im having trouble figuring out how to explain the problem.
Okay I have poked around a bit and found a bit of a solution, though it's just kind of the first step I think. So I figured out how to get transparent cutout unlit material to have an instanced color value through scripting, so I can assign each grass mesh its own color without having a thousand different materials.
The next step would be to find out to access the color / light values of a separate mesh and apply it to the grass mesh, so either take it from the giant ground mesh itself at a the pixels closest to the grass meshes, or like I said earlier have a separate mesh for each grass mesh that sits flat on the ground that it could pull the light and color info from, that way if a dynamic light came through or a shadow is cast by the player the grass would reflect it, and I could just place the grass and not have to worry about tweaking the color for each mesh to match it by hand.
So my question is, what do you call that light / color information? Are they two separate things, or can they one color value that I could then apply to the unlit mesh's main color variable? After I figure that out, how would I access that information? Again any help or nudges in the right direction would be very helpful.
you could try and change the normal vectors of the mesh to point upwards. Either in the mesh directly or in a vertex shader
Hmm, I hadn't thought about this. Can you point somewhere that explains how I can do this?
Something like this
Shader "NormalsUp" {
Properties {
_$$anonymous$$ainTex ("Texture", 2D) = "white" {}
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
Blend SrcAlpha One$$anonymous$$inusSrcAlpha
Cull Off
CGPROGRA$$anonymous$$
#pragma surface surf Lambert alpha
struct Input {
float2 uv_$$anonymous$$ainTex;
};
sampler2D _$$anonymous$$ainTex;
void surf (Input IN, inout SurfaceOutput o) {
float4 col = tex2D (_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex).rgba;
o.Albedo = col.rgb;
o.Alpha = col.a;
o.Normal = float4(0,1,0,1);
}
ENDCG
}
Fallback "Diffuse"
}
Or transform the up vector from object to world space:
o.Normal = mul(float4(0,1,0,1), _Object2World);
You could put the grass into a separate layer and setup some light affecting only the 'grass layer' (for example a light shining more in horizontal direction or a 'greener' light).
This was the first solution I tried, but I got pretty tedious quickly. Worrying about which way the grass was pointing and trying to get the lights set up to mimic the actual scene lighting in a realistic way that was dynamic was too complicated for me. Changing the color on an unlit got a similar effect in a much quicker and easier way for me.
Your answer
![](https://koobas.hobune.stream/wayback/20220612072546im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
Shader Color 1 Answer
Where do I put this shader code? Getting weird error? 1 Answer
Fog not working in my Shader~ 0 Answers
Addition to Standard Shader stopping it from batching? 0 Answers
Updating a shader from Unity 3.3 0 Answers