Material - draw a line between two coordinates?

Just wondering if it is possible to do with materials, something similar to the draw debug line in blueprint, from one point to another

Thanks

I’m trying to make a scrolling minimap that can draw a line between the player and a specific location, i am able to do it in blueprint with draw debug line, but i wouldn’t know how to prevent the line from going out of the minimap’s frame when the specific location is out of range

I can easily make a scrolling material but i’m not sure how i could draw a line between two coordinates

Are there any other alternatives?

By the way this is not a HUD, the minimap will be viewable on a LCD monitor actor, here is an example of what i’m trying to achieve

Hey guys,

Yes it is possible but not simple or cheap as Jamsh suggested. That said it was pretty quick for me to knock this out since I mess around with these type of coordinate based shapes pretty often. I did get thrown off by the missing -X after the swizzle for a bit though (DanW reminded me that y,-x is perpendicular to x,y which is how the transform here works).

This works by drawing a line between P0 and P1. You can specify line thickness and edge hardness. It costs around 17 instructions. You could make this into a material function and use it a few times. I might do that and toss is into engine\functions.

In the left preview the line goes from 0.1,0.1 to 0.9,0.9, showing that there is also end point cutoff on the line drawing.

A simpler approach is to use a single quad mesh and use the worldpositionoffset shader to move the top 2 verts (using UV-Y coord) to the P0 location, and the bottom 2 verts to the P1 location. Then you project using the UV-X coordinate along the vector between your points for thickness.

That is how we do alot of fake shadows for things like the hexmap in Fortnite where the objects are too small to cast nice real shadows. Then you just spawn one of these meshes, make a material instance dynamic and set the point locations.

Here’s what my setup looks like, the LCD background is a simple material, the boat, player dot icon are small planes that i placed close to the screen, they get offset as the player moves around, and i can draw a debug line between them

But if i wanted to go further in the world where point A wouldn’t be in range, the line would stick out from the LCD screen, unless i could somehow mask the actors and the line in the shape of the screen

I’m not sure what to do

@RyanB, i have to give this a try, it looks very promising

I’ll see what i can come up with and will report back

Thanks everyone

With the material rendered line approach, the line drawing-out-of bounds issue goes away since it can only draw in the UVs of your hud material. Masking the separate actors would have to be done by creating a square shaped mask using worldposition info.

All you really need is a way to convert your locations into the 0-1 UV space of your screen, if you haven’t done so already.

@RyanB, That’s exactly why i’m trying to do it with materials only, the masking issue wouldn’t be a problem anymore

I already converted the locations, my player’s world location offsets the heightmap background and the boat icon 1:1 with a constant 2 parameter, all that was missing was a way to replace the draw debug line between my player and the ship

It works perfectly, i appreciate the time you took to help out, i couldn’t have come up with this by myself, sometime i wonder how some of you guys get so good with maths

Thanks!

I am glad it worked! Once you mess around with this sort of thing a lot it starts to get easier. Messing around in the math hall content example map can help familiarize you with the basic vector math that shows up over and over in this stuff.

You could think of it working by first Rotating the UVs to match the angle of the line, and then its just a simple distance calculation for the line width. capping the line at the endpoints is the more Nodey part. But all that happens in the rotated Y-coordinate which makes it pretty easy.

Here’s the final result, it took a bit of trial and error to match all the vectors

Venturing away from the ship

96fe54760395c9e31255815f700388c276c88732.jpeg

Venturing further away

d712afd534c8a4b984aa8920a40187c47490bcf3.jpeg

Thanks again

haha, once again he proves the impossible possible… Ryan I haven’t seen the Hexmap thing, but that sounds like you are drawing multiple (maybe 6?) lines in the material based on the same method. Is that correct?

If so, I’m wondering if I could use it to draw a series of 2D Lines in UMG, rather than creating a custom Spline-based Widget Component perhaps.

Actually for the fortnite hexmap I was talking about something different. I was talking about using vertex shaders to project a line using light vector to make fake shadows. The advantage to doing a bunch of lines that way, is that it doesnt make any master material more expensive with each new line that needs to overlap. We did this because tiny objects would not cast a very visible shadow due to how the camera is setup for the hexmap. We also used that same trick to fake the volumetric shadows of the kites at the end of the GDC kite demo since the kites were too thin to actually show a volumetric shadow.

The basic gist of this technique is to use the mesh UVs to isolate various parts of the mesh and use vector math to push them around. I will make a quick example in a second.

Ok super quick example using EditorPlane mesh.

Material:

Result, two of “EditorPlane” mesh in the scene, on the left has the LineWPO material, on the right has default material:

So by using a global parameter for lightvector and some soft texture alphas, it is possible to make nice fake projected blob shadows from things. This has a variety of uses.

I used the word “Projected” because with this method you essentially shrink all the verts to 0 (the 0 - worldpos node) and then “push” them in the direction of your desired line. UV-Y masks a push along the line length, UV-X masks a push along the line width vector (which is generated via cross with 0,0,1). UV-X gets biased into -1 to 1 to center it on the line. As 0-1 it would be off to one side a bit.

It’s also really easy to redo the math to go between endpoints instead. Just replace “ActorPosition” with your P0, and for “linelength” instead use the vector Length function to get length of P0-P1.
Vector becomes P1-P0 normalized.

Heres an example from a fortnite skybox. This scene is all unlit and all the shadows are fake since the skybox would be way beyond the dynamic shadow distance.

Each shadow under the small rocks and bushes is a single quad with a blob shadow on it, set up almost identical to the above material example:

The larger rock shadow is also very similar but uses a box instead of a plane and uses “worldpositionbehindtranslucency” to map the shadow which is a bit more complicated:

Because lightvector is stored in a global parameter, all these fake shadows move with the time of day cycle.

Mind = Blown.

That’s a pretty awesome technique. Since you’re using it in Fortnite and the Kite demo I’m guessing it’s fine, but my only concern is does it create significant overdraw with all those translucent quads over everything? I guess whatever performance you’d lose by using Dynamic Shadows you gain back in spades using this approach anyway.

The result are pretty spectacular actually, without knowing this I’d never have seen anything out-of-place with the shadows at all.

The little rock shadows on the ground are not bad since they are tiny and almost never overlap.

The big rock mesa shadows on the other hand do get pretty slow since they are boxes which means you see the overdraw even where the box hits the sky.

To mitigate that, the vertex material has a parameter to deform the box to be as small as possible from the side. Here is an example.

With the optimization off, you can see how the projected box gets pretty huge:
c716dd0730de1e0fc4b026daec473e92a62c7ba8.jpeg

With the optimization on about 50%:
56d7a2f912588cc7d66980f07667a7a1dc6e7beb.jpeg

On as much as it can go for this shape:
611b258b7da7c63fb0c5d542998f8de6e3cb2dbd.jpeg

If that ‘shrink’ parameter was turned up any higher, you would see part of the “self shadowing” of the pillar missing either on its backside or where the ground begins to raise up a bit.

Thx

Hi Ryan,

Thanks a lot for this function.
Not only I found it quite useful as is but it helped me a lot to do a function drawer shader.

In my implementation I added some inputs to allow the segment to be continued as a line. You can download it here, for those who are interested.
The function drawer is here: http://werwackfx.com/index.php/graphictools/ue4-main/ue4-articles/35-shaderwkfunctiondrawer

Best regards

Note: I tried to attach the file to this tread but I got this message:
MF_WkDrawLineBetween2Coords.zip - Your file of 98.0 KB bytes exceeds the forum’s limit of 97.7 KB for this filetype.
:S Maybe the attachment size could be increased a bit, don’t you think so?

Thats pretty cool.

Out of curiosity have you seen the material functions “Plot Function on Graph” and the content example level Math_Hall.umap? looks like you build something similar.

Not sure if this is relevant (or if it has been suggested before), if so then please disregard.

If you are looking for a method to create a dynamic line (with a wide range of visual fx capabilities and control), why not make a shader that does this to a line mesh attached to your HUD object?

I put this together in just a few minutes. It is incredibly easy but really dynamic and utilizes the full UV point array so advanced visual effects can be easily applied (as well as motion). Even curve edits and additional points may be blended in for a relatively cheap cost.

155999e362d06362a3f03711045caa249b350db5.jpeg

Gee!!! :eek:
Indeed! I didn’t know about that map! It’s awesome, there are plenty of things there! The plot function material is incredible, the interactivity is really nice and the examples are really really cool!!

I have many things coming to my mind when looking at all this.

First I see there is an example for Sine (1.11). It says that the period of the implemented Sine is 1, which is quite unusual. Is there a reason for this?
I mean, maybe it is an optimization for many things, but the time we waste, as user, to check and double check our code before discovering that!!! Is is also very disturbing because the documentation says that the implementation is in radians (cf Sine Documentation). Maybe you should fix the documentation.

Beside at the end of the level there is the following panel about trigonometry:


Well, strictly speaking, from a math point of view, this is not consistent with the implementation. You should mention there that the unit of X is in turns, not in radians.

The way the functions PlotFunctionOnGraph_Setup_Input and PlotFunctionOnGraph_Derivative expose their plugs is really interesting. By using a re-entry of the value it avoids to have 2 nodes, one before the function and one after, as I did. Clever.

The implementation I did to draw the graph is quite similar to PlotFunctionOnGraph_Setup_Input. I didn’t do any correction for the thickness though. This function has some code in it for that but it looks disconnected and I have some trouble to understand if it works or if this is a rest of some code from PlotFunctionOnGraph_Derivative.
I wasn’t able to get any change on the result when I tried to change the range. It works as expected on PlotFunctionOnGraph_Derivative though. Is there something special to take the range in account?

PlotFunctionOnGraph_Derivative is really interesting too. I think by tweaking it a bit we could make it draw parametric functions.
In practice it is nice not to have to provide the derivative of the function to draw. Nevertheless giving 2 times the same function (x) is not always easy: inside a shader the function may be quite complex and we may not want to duplicate it, even for debug purpose. That’s one of the reasons why I choose to have a pre-function and a post-function in my implementation (at the price of some lack of usability).

It would be nice to have a true documentation page for these 2 functions, with some basic examples (after a very quick search I didn’t find one for PlotFunctionOnGraph_Setup_Input).

Ho and I forgot to say the dynamic display of the values on the graph, in the scene, is great too. I will check that in details!

Thanks a lot for these references, they will be very helpful!

Julien