x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Assign a material to UProceduralMesh in C++

Hi, I'm trying to render a generated mesh, and I don't understand how to create a material and assign it to my mesh component, using C++. Here's my header:

 #include "GameFramework/Actor.h"
 #include "ProceduralMeshComponent.h"
 #include "MyActor.generated.h"
 
 
 UCLASS()
 class PROCEDURALMESH_API AMyActor : public AActor
 {
     GENERATED_BODY()
     
 public:    
     // Sets default values for this actor's properties
     AMyActor();
 
     // Called when the game starts or when spawned
     virtual void BeginPlay() override;
     
     // Called every frame
     virtual void Tick( float DeltaSeconds ) override;
 
     UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = General) UProceduralMeshComponent* mesh;
     USphereComponent* SphereComponent;
 
     TArray<FVector> vertices;
     TArray<int32> triangles;
     TArray<FVector> normals;
     TArray<FVector2D> UV0;
     TArray<FColor> vertexColors;
     TArray<FProcMeshTangent> tangents;
     const int segs = 10;
     const int divs = 24;
     const float segHeight = 250;
     const float baseRadius = 500;
     
 };
 

Here's my class:

 #include "ProceduralMesh.h"
 #include "MyActor.h"
 
 
 // Sets default values
 AMyActor::AMyActor()
 {
      // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
     PrimaryActorTick.bCanEverTick = true;
     //UPROPERTY(EditAnywhere);
     SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
     RootComponent = SphereComponent;
 
     
     mesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh"));
 }
 // Called when the game starts or when spawned
 void AMyActor::BeginPlay()
 {
     int a = 0;
     int d = 0;
     float radius = baseRadius;
 
     //generate cylinder vertices
     for (int i = 0; i <= divs*segs; i++)
     {
         //random chance to alter the radius
         int chance = FMath::FRandRange(0, 3);
         if (chance == 1)
         {
             radius += baseRadius / 100;
         }
         else if (chance == 2)
         {
             radius -= baseRadius / 100;
         }
         else if (chance == 3)
         {
             //increment back to baseRadius
             radius += (baseRadius - radius) / 3;
         }
         //generate points in a circle
         float angle = (2 * PI) / divs * a;
         float z = (radius*sin(angle));
         float y = (radius*cos(angle));
         float x = d;
         vertices.Add(FVector(x, y, z));
         a += 1;
         if (a == divs)
         {
             a = 0;
             d += segHeight;
         }
     }
 
     //create triangles from vertices
     for (int i = 0; i < vertices.Num(); i++)
     {
         if (i > divs && i%divs == 0)
         {
             triangles.Add(i - divs);
             triangles.Add(i - 1);
             triangles.Add(i - (divs + 1));
 
             triangles.Add(i - divs * 2);
             triangles.Add(i - divs);
             triangles.Add(i - (divs + 1));
         }
         else if (i > divs)
         {
             triangles.Add(i);
             triangles.Add(i - 1);
             triangles.Add(i - (divs + 1));
 
             triangles.Add(i);
             triangles.Add(i - (divs + 1));
             triangles.Add(i - divs);
         }
     }

     //displace verts to resemble cave
     for (int i = 0; i < vertices.Num(); i++)
     {
         if (vertices[i].Z < 0 - baseRadius / 2)
         {
             vertices[i].Z = FMath::FRandRange(0 - (baseRadius + baseRadius / 4), 0 - baseRadius / 3);
         }
         vertices[i].Y += FMath::FRandRange(0 - baseRadius / 20, baseRadius / 20);
 
     }
     mesh->CreateMeshSection(1, vertices, triangles, TArray<FVector>(), TArray<FVector2D>(), TArray<FColor>(), TArray<FProcMeshTangent>(), true);

     mesh->AttachTo(RootComponent);
     Super::BeginPlay();
 }

The mesh generates and renders in-game, but it's just this default gray, and I was hoping to use a custom material for it. If someone could teach me how to add a custom material into this code, it'd be much appreciated! Thanks! alt text

Product Version: UE 4.9
Tags:
capture.png (425.1 kB)
more ▼

asked Nov 21 '15 at 01:41 PM in C++ Programming

avatar image

ToaTom
1 1 2 4

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

1 answer: sort voted first

You have a few options: First, you're going to need to assign or in your material, use the Absolute World Position node. You'll also need a way to assign your material to your mesh. In your header file add:

 UPROPERTY(EditAnywhere)
 UMaterialInterface* Material;

then in your cpp after you have created the mesh section:

 mesh->SetMaterial(1, Material);

The "1" parameter is your mesh section index. At this point, you'll probably need to wrap your AMyActor with a blueprint. When you do that, you get access to your Material variable that you created.

Material

Now all you need to do is create your material, and set it.

capture.png (5.6 kB)
more ▼

answered Nov 21 '15 at 04:46 PM

avatar image

MJ_01
822 38 39 241

avatar image ToaTom Nov 21 '15 at 05:47 PM

Hi, thanks for the swift reply! That's helped a lot. After I applied the default M_Rock_Basalt material the colour changed, but there's no detail to the texture. I'm thinking this is to do with UVs, though I don't know how to add UVs. Any ideas on how to continue?

avatar image Craig Ferguson Dec 15 '15 at 07:33 PM

You are correct about needing UVs. I had the same results with my procedural mesh before adding them - my grassy cube was just all the same shade of green.

Each vertex needs a matching UV0 element. These map a point on a texture to the vertex. UV0 X and Y between 0 and 1 are for one tile. A larger UV0 would be a new tile. e.g. (1.5, 0.5) would be the center of the texture, but on the second tile on the X axis.

In your code above I would add a new line after line 47 of your .cpp:

UV0.Add(FVector2D(x/(2.0f * segHeight), a/8.0f));

I think this would make it so you had a tile covering every two sections and three tiles around the circle (24 div / 8).

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question