[quote=“JTippetts”][quote=“vivienneanthony”]Hello,
I’m not sure if I have to change material, texture2d, or get two materials from the shader and create new material then apply it.
[/quote]
You don’t have to do any of that. All you need is a material that uses the TerrainBlend technique. You assign a texture for the blend texture, and give that texture an image. By modifying the colors of that image, you modify the terrain that is drawn. For example:
terrain = terrainNode:CreateComponent("Terrain")
terrain.patchSize = 64
terrain.spacing = Vector3(0.20, 0.08, 0.20)
terrain.smoothing = true
hmap=Image:new(context)
hmap:SetSize(1025,1025,3)
terrain.heightMap = hmap
terrain.material = cache:GetResource("Material", "Materials/TerrainEdit.xml")
blendtex=Texture2D:new(context)
blendtex:SetSize(0,0,0,TEXTURE_DYNAMIC)
terrain:GetMaterial():SetTexture(0,blendtex)
blend=Image(context)
blend:SetSize(512,512,4)
blend:Clear(Color(1,0,0,0))
blendtex:SetData(blend, false)
This creates a terrain, sets a blank heightmap, creates an image and a texture for the blend map. The terrain is given a material. That material specifies the 3 (or, in my case, 4) detail layers to use. The colors of the blend texture specify which detail layers to draw at a given location, with the blend texture being mapped across the entire terrain.
Now, the red channel of blend represents the 1st detail layer, the green channel represents the second, and so on. If a given pixel in blend is set to Color(1,0,0,0), that means it draws fully from the first detail layer. If set to Color(0,1,0,0) it draws fully from the second detail layer. If set to Color(0.5,0.5,0,0) then it mixes the first and second layers, each at 50% strength. So if your cliff texture is at the third detail layer, then setting the pixel to Color(0,0,1,0) will set it to full cliff.
As for the steepness, one simplification that you can make is that for terrain normals that are generated on a terrain that occupies the XZ plane, you can get the angle of the normal relative to the ground plane by dot product against the UP vector, (0,1,0). The simplification is that this is equal to (0normal.x + 1normal.y + 0*normal.z). Of course, the 0 multiplications equal zero, so the final result of the dot product operation is simply equal to the Y component of the normal vector. The dot product operation really isn’t necessary. You can just take the y and use that.
The Lerp operation (and Urho3D’s Color class implements a Lerp method) is simply a linear fade from one color to the next. The t parameter (in the range of 0 to 1) determines where on the gradient scale between color A and color B to get the result. So if A=Color(1,0,0,0) and B=Color(0,1,0,0), then the operation A:Lerp(B, 0.5) will result in the color value Color(0.5,0.5,0,0), or a 50% blend between layer 1 and layer 2. Similarly, the operation A:Lerp(B,0.7) will result in a 30%/70% blend between layer 1 and 2. The closer the interpolant factor gets to 1, the more you get from layer 0, and the closer it gets to 1 the more you get from layer 2.
Now, when generating slope-based cliffs, what I do is I read the blend image to get the pixel at the current location. Usually, this is some mix of colors representing the blend of terrain I have applied to the map. Then, assuming the cliff detail layer is layer 3, represented by blend’s blue channel, then I can do an operation like result=currentcol:Lerp(Color(0,0,1,0), normal.y) to get a smooth blend based entirely on the slope. Applying the change, then, is as simple as calling SetPixel() with the new color then, after the full pass is completed, calling blendtex:SetData(blend) to finalize the texture.
Of course, using a fade using the unmodified normal.y really isn’t that useful, so I apply the cutoff/fade factors I described to you earlier. It is important to note that the value of normal.y isn’t going to follow a linear progression. It represents the cosine of the angle, so as the angle decreases linearly the cosine follows the cosine curve. If you use a shallow terrain (not a large amount of Y variation) then a lot of your normal.y values will tend to cluster around the value of 1. For example, in this image, the terrain is relatively shallow, with not a lot of steep variation. Thus, the cliff blend is applied in only a few very small places. By steepening the terrain, though, I get a lot larger variance in the normal and thus the cliff terrain is applied over much larger areas. If you are seeing normal values mostly around the top end of the curve, then you might need to either steepen your terrain variance or adjust your cutoff value.[/quote]
- The code I have do that partially. The heightmap is created procedurally to a image that’s applied to the terrain component.
- Using the NormalToWorld function I can get a slope of any given point.
The last point is like you mentioned the material. Which I assume is?
[code] terrain.material = cache:GetResource(“Material”, “Materials/TerrainEdit.xml”)
blendtex=Texture2D:new(context)
blendtex:SetSize(0,0,0,TEXTURE_DYNAMIC)
terrain:GetMaterial():SetTexture(0,blendtex)
blend=Image(context)
blend:SetSize(512,512,4)
blend:Clear(Color(1,0,0,0))
blendtex:SetData(blend, false)[/code]
The cutoff function that I made should be able to determine the cliff mix based on a threshold which again.
[quote]Now, when generating slope-based cliffs, what I do is I read the blend image to get the pixel at the current location. Usually, this is some mix of colors representing the blend of terrain I have applied to the map. Then, assuming the cliff detail layer is layer 3, represented by blend’s blue channel, then I can do an operation like result=currentcol:Lerp(Color(0,0,1,0), normal.y) to get a smooth blend based entirely on the slope. Applying the change, then, is as simple as calling SetPixel() with the new color then, after the full pass is completed, calling blendtex:SetData(blend) to finalize the texture.
[/quote]
I would have to go through x=0 to x=imagesize and I guess take the cutoff function then put it through the loop. Probably to blend between Color(1,0,0) and Color(1,1,0);