Download

widget button to change object material - where to script the actions?

Widgets have a Event Construct instead of Begin Play. But you cannot create an object from within itself.

Not the worst idea (especially if it’s a stand alone 3d menu) but could be done better. You could choose one of the framework classes (player controller, game mode, game instance) and create the widgets there. This allows you to store their references which, in turn, makes gaining access to them easy since the aforementioned classes are available from any other blueprint, including Level Blueprint.

I particularly like using the HUD class for this as it has a couple of extra features - like drawing lines, for example. And it comes across as logical to use it as a communication hub for the widgets.

What I mentioned above regarding references will give you a direct way to gain access to an object without relaying on the *get all of something *nodes which I see misused way too often. [HR][/HR]
Try creating your menu in the GameMode (check this out if you’ve yet to set one up), don’t forget to store a menu reference by promoting the Return Value of the Create Widget node. Then, any time you need access to the menu, you can Get Game Mode > Cast (to your own GameMode > get Menu Reference > access buttons and variables in the widget.

So basically what you want is some object (i.e. a sphere or whatever) with a material, and you want some UMG widgets on screen that can manipulate that sphere.

What i’d do is split it up between the player controller, the UMG widget and the actor that is going to be manipulated:

In the Widget, say “UMGSphereInterfaceWidget”

  1. Add a “SuperSphere” actor reference and click “editable” and “expose on spawn”. That makes it so when you create the widget you have an additional parameter so you can add the actor this widget is supposed to manipulate. That way you’ll never have to “get all actors of class” when using this widget.

CustomPlayerController :

  1. Add function “CreateSphereWidget”, having a SuperSphere reference as input.
    In that function simply call “Create Widget” and create your UMGSphereInterfaceWidget and plug in/forward the reference from the function input to the create widget node

Create the object to manipulate, say “SuperSphere”.

  1. Create some function “ChangeMaterial” with the desired parameters and behavior to change the material
  2. On Begin Play make it get the player controller index 0, cast it to your custom player controller call custom player controllers function “CreateSphereWidget” and give it “reference to self” as input.

Then in the Widget again, add your desired function “OnButtonPressed”.
In this function ,get your reference to the sphere that you saved in the widget, check if its valid (never hurts to check). If its valid, call the references “ChangeMaterial” and pass in the desired parameters

Now you have your logic split up in a logical fashion :
When the game begins, the SuperSphere actor gets the current players player controller, the player controller creates the widget.
If the UMGButton is pressed, the buttons only responsibility is to tell the referenced SuperSphere “hey, do something with parameters a, x and z”. The SuperSphere actor then itself has the functionality to do something with the input, aka change the material based on input.

Alternatively, instead of using BeginPlay on the SuperSphere to spawn the widget, you can add a trigger box to the SuperSphere actor,and add an OnActorOverlap so only when the player comes close to it it’ll create the widget on screen. And you can also make it so when the player moves away the UMG widget gets removed.

thanks guys.

this makes sense, what I’m making is a product viewer, and the menu interface thing I said is actually just a 2d interface on top of the window, that will always be there. it has some sort of expand and collapse actions to open more buttons, but that’s all UMG, the interface is always on top.

yeah I figured that this “get all of something” couldn’t be the best way, but it’s the only way I managed to call for the object. I know I must be doing something wrong, but I looked for it and still can’t add an actor reference to my object. clicking and draggin into the variable doesn’t work, a red dashed line appears, and the picker button is grayed out, so basically I’m struggling on the first step

I always overlooked game modes, since I do mostly archviz, and this product configurator is some sort of spin off for me, but still not really a game. I’ve read that documentation but I’m not sure if I need to set up a game mode for this, are there any particular reasons I should?

I’m trying to do this, but as I mentioned above, I’m struggling in the first step for some reason. my actor reference doesn’t seem to work or I don’t understand it well enough, even though I’ve read quite a few things about it

Having your own custom game mode allows you to have custom framework classes - without those, communication is much, much harder.

So I made a hud blueprint creating the widget there, and created a game mode blueprint. didn’t set anything on it but my base pawn as the default pawn class and the hud blueprint as the hud class. it displays the widget, but I still can’t get my object actor reference from any blueprints

Game Mode:

Untitled.png

Create widget in the MyHud:

intheHud.PNG

And in the LevelBlueprint, for example:

lb.PNG
[HR][/HR]
You can, of course, create the widget directly in the level blueprint - but then accessing it from inside of other blueprints is a bit more difficult.

yep, this I managed to do. only difference is that I’ve set my game mode in the project settings, not in the world override, but it’s working, the hud is being displayed, no problem

the problem is that the hud isn’t actually doing anything, I can’t give the buttons any kind of interaction with my object from inside my widget blueprint.

my intention is to change the material of my object in my scene, named “SuperSphere”. it’s an actor class blueprint with a sphere mesh positioned in the world

so in my widget blueprint I have some “on buton xx clicked” events, but I’d have to tell them do do something to my SuperSphere, but I can’t call it from inside the widget blueprint to make the buttons do anything to it

For something that simple you should honestly just create the widget in the SuperSphere object:

SuperSphere creates the widget which has a reference exposed on spawn. This will link these two together.

This is precisely what @StefanHohnwald said:

huh, now for some reason I managed to get that super sphere reference variable into the widget. I really tried doing it in every blueprint on the scene and couldn’t.

but that turned into another problem, the code worked with a “get all actors of class” node followed by a for “each loop”, but with the reference it doesn’t. btw teapot below is my supersphere

did I miss something?

Show us how you set the teapot reference. It’s the first pic in my previous post - the create widget node has an extra SphereRef pin.

Could you briefly tell what it’s going to be all about - a showroom with items the user can interact with, change their looks? Anything else?

When you do it with the reference and end the play with Escape, does the editor give any kind of error message, akin to “Got None while trying to get reference in node SetMaterial”?
If the reference doesn’t work, chances are that you didn’t set the reference variable properly to point to the SuperSphere actor.

I agree with Everynone, please show us how you set the TeapotRef in the widget, aka how you set the TeapotRef to point to the SuperSphere actor.

What you can do for debugging : Use a “IsValid”-node to check if the TeapotRef actually points to a valid actor. if not, you can print out an error message. If the error message gets printed, you know that your reference is invalid.

it returns two different errors:


Blueprint Runtime Error: "Accessed None trying to read property TeapotRef". Blueprint:  MaterialSelector Function:  Execute Ubergraph Material Selector Graph:  EventGraph Node:  Set Material
Blueprint Runtime Error: "Accessed None". Blueprint:  MaterialSelector Function:  Execute Ubergraph Material Selector Graph:  EventGraph Node:  Set Material

I also did what you suggested with the isvalid node, and turns out the TeapotRef is invalid. I really thought it should work, only managed to get that ref after some time burning my brain. I must be doing something very wrong

I just added a variable inside my widget blueprint side panel, and found the teapot there. like this:

then the moment I exposed it, “teapot ref” appeared on the HUD blueprint where the widget is being created, last item on the create widget node. i didn’t pin a reference to self there cuz it’s in the hud, not the actor, but since it says “teapot ref” i thought it was already referring to the correct thing.

right, so this is a product configurator for the costumer to be able to see the product in 3d with different materials and colors, cause it’s a little dificult sometimes for them to imagine just from a picture of the product and a fabric sample, how the product would look like with the materials they have chosen. it’s also impracticable to do renders with combinations of all the materials.

right now this is just a proof of concept, it will have only one chair spawned into the world, that is basically an infinite plane, and a 2d interface with two buttons, and when clicked each will show a sub menu with a few more buttons with material options for the seat or the structure. you can orbit/pan/zoom the camera around the chair, aswell as move the chair around.

if that works, it’ll probably grow from there to all our products, implement on website, have an app for vendors with all the products, have an app for costumers to download and place the products with AR into their homes, and finally, an add to cart option with the selected materials.

not quite a brief description, but that kinda explains why I’m being cautious with some aspects of this. I’m not sure where I want to have the widget created because maybe somewhere along the way I’ll try to test a way to add two different products into the scene and still be able to change their materials. maybe each product is going to have their own interfaces anyways cause the materials and parts are different for each product, but I’m not sure right now, so I’m trying not to commit, and even though I’m in the early stages, it’s a lot of work for me to try to figure this all out with little knowledge of ue4.

right now I have it working with a teapot, an interface to change the material of the body and the lid separately, and just finished adjusting the camera controls. the material changing code is not perfect as I’m using the get all actors of class node, but you know, I’m trying. I also think I got a working code for changing just some aspects of the materials dynamically, for example, instead of having a material for a black leather and a blue leather, only changing the base color parameter of the material.

You’re not putting anything in the Teapot ref… it’s stays invalid. The widget does know which teapot you mean - what if you have 5 teapots? If you’re doing this in the Teapot object just plug in self. This method of direct communication is OK when you need 1 to 1 comms - anything that grows in scope will need a different approach or will drive you mad when you need to rewire things for the nth time. Also, if you will never have more than 1 object at a time, (it hurts to say but here we go;) it’s probably OK with Get All Actors of Class.

Your description makes perfect sense, btw. A couple of extra question, will the widget that controls the visuals of the object be unique for every object or differ a lot? How does the user skip to the next item?

well it’s not in the teapot itself, it’s in the hud blueprint, so “self” doesn’t work, and I’m still no able to properly reference the teapot anywhere, really don’t know why or how.

so eventually I’ll have more than one object in the scene, and they will have different options in the interface, but the interface will be essentially the same, Not sure how it works yet but I was thinking of storing information on the objects regarding how many elements they have and the different material options that those elements can have, and then from the widget I’d just read those variables in order to create the appropriate interface for each object. should be easier (maybe not easier, but less work) than having a different interface for each object.

since in this proof of concept ther will be only one object and thus one interface, I’m not worrying too much about this for now, but I’m concerned on where the widget will be created, cause from what I’ve seen, there are many different ways to call for a reference deppending on what blueprint class you are doing it.

If you look at my example #9, you’ll see that I’m doing it inside of the SuperSphere - or Teapot, in your case. It’s the teapot that creates the widget and sends *self *reference.

Alternatively, you can use last pic in example #7 and have teapot access the HUD, grab the widget reference present there and store it for itself.

ok so I mistakenly thought that having the widget created inside the teapot would need a different widget for each object whenever I decided to try to place more than one object in the scene, but I suppose it’s just the creation, it could point to the same widget that would be created based on the object’s specifications, right? so I’m gonna try to have the object itself create the widget.

I assume that it’s a better choice than making it in the hud blueprint as it is currently?

EDIT: so I tried creating the widget from the teapot with a reference to self and it worked.

it’s really funny for me because I get really confused by this kind of interaction. like, inside the widget blueprint I created a variable, pointing it to the teapot actor class blueprint, and I thought that it would be enough to use it as a reference inside the widget blueprint, but that variable meant nothing for some reason. guess I had to define it? but then, the “create widget” node, which is in another blueprint, “found” that variable and added a connector with that variable in the node, even though I had just created and exposed the variable, didn’t drag it to the widget blueprint, didn’t connect it anywhere, but it appeared in the node anyway. cool I guess, but how did it find it and why? so I could define it? each time I want to make something interact cross blueprints it’s a totally different method.

It’s hard for me to make sense of these things, I’ve been watching quite a few videos about blueprints from the basics to more intermediate cases, but each case is so specific, I can’t seem to find a logic for these kinds of interactions.

On the contrary, you were right, this approach would indeed require one widget per one object. It’s a ham-fisted approach but it’s exceptionally easy too implement. Do note that one widget here mean one widget instance - it’s still the same widget blueprint, of course.

It is not a bad approach if you want the widget to remember the settings as the user scrubs through items and fiddles with the sliders and whatnot. When you come back to the previous item, the settings will be still applied, no need to save anything.

well I guess that’s what I meant, I thought I would have to code a separate widget for each object.

so how would you approach it? I want to make a material selector that works like this:

when I have one object in my scene, a simple button (let’s say button 1) will appear on the botom, and it will display the name of the object I have in my scene, and the behaviour will be related to that object. if I add another object, another button that behaves the same will appear, but with information from the second object. (didn’t figure out how I’m gonna add the object yet, but it doesn’t matter right now)

these single buttons when clicked will open another series of buttons above them, and their behaviour doesn’t matter, what matters is that the widget will work the same for every object, but the text displayed in the butons (product name, material name) and the number of buttons (number of elements in the object) will be generated dynamically based on information from the object.

would you make one widget and script this behaviour based on variables set on object construction?

It makes perfect sense. I would definitely use 1 widget for this and feed it data from the currently selected object. This widget would have a second hidden panel with additional buttons. I’ll try to put an example for you if you can wait until Monday. Stay tuned. :slight_smile:

**@fael097 **Sent you a private message. Let me know if it makes any sense to you.