Announcement

Collapse
No announcement yet.

Generate Procedural Mesh

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    #46
    Originally posted by Rama View Post
    Yes you can, that's what most of these procedural mesh discussions have accomplished so far

    Here's a pic of my own procedural mesh, made at runtime and uv-mapped via algorithm!

    Notice that it has collision!
    Your procedural mesh, if I'm not mistaken, was created with UCustomMeshComponent.
    What I mean to do is a procedural creation of an UStaticMesh and assign it to an UStaticMeshComponent because, from what I have understood, UStaticMesh supports precomputed lighting, mesh Instancing and has better performance. Am I right?

    Comment


      #47
      Originally posted by ACCA software S.p.A. View Post
      Your procedural mesh, if I'm not mistaken, was created with UCustomMeshComponent.
      What I mean to do is a procedural creation of an UStaticMesh and assign it to an UStaticMeshComponent because, from what I have understood, UStaticMesh supports precomputed lighting, mesh Instancing and has better performance. Am I right?
      From what I understand, UStaticMesh requires an asset, so by definition it cannot be procedurally generated. You could generate an asset and save it (to be able to load), however. Not sure if you would need to reverse engineer how assets are created or reuse and ship some of the UEd code to import assets (there may be legal issues here).
      It is by will alone I set my code in motion.
      It is by coding that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning.
      It is by will alone I set my code in motion.

      Comment


        #48
        Has anyone been able to get vertex colours working with this?

        I've tried setting the Color variable for each vertex before it's added to the buffer (while using a VertexColor node in the material), but it doesn't seem to have any effect.

        Comment


          #49
          re: Vertex Color - make sure you include the underlined line in your VertexFactory, or the color data will never get copied:

          Code:
          			ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
          				InitChunkVertexFactory,
          				FChunkVertexFactory*, VertexFactory, this,
          				const FChunkVertexBuffer*, VertexBuffer, VertexBuffer,
          				{
          				DataType NewData;
          				NewData.PositionComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Position, VET_Float3);
          				NewData.TextureCoordinates.Add(FVertexStreamComponent(VertexBuffer, STRUCT_OFFSET(FDynamicMeshVertex, TextureCoordinate), sizeof(FDynamicMeshVertex), VET_Float2));
          				NewData.TangentBasisComponents[0] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentX, VET_PackedNormal);
          				NewData.TangentBasisComponents[1] = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, TangentZ, VET_PackedNormal);
          				NewData.ColorComponent = STRUCTMEMBER_VERTEXSTREAMCOMPONENT(VertexBuffer, FDynamicMeshVertex, Color, VET_Color);
          				VertexFactory->SetData(NewData);
          			});
          Check LocalVertexFactory.h for more info.
          Former Technical Designer @ Irrational Games, gone Indie.
          Technical Designer for: Bioshock Infinite, Mars 2030
          Programmer/VFX for: Perception, The Black Glove's Kickstarter
          Voiceover Editor for: Bioshock, Bioshock Infinite

          Comment


            #50
            Originally posted by Ryvar View Post
            re: Vertex Color - make sure you include the underlined line in your VertexFactory, or the color data will never get copied:
            Ah good catch, I'll make that fix in the code now. Thanks!
            Lead Programmer - UE4 Animation/Physics/Audio Team - Epic Games
            Twitter: @EpicJamesG

            Comment


              #51
              Originally posted by Ryvar View Post
              re: Vertex Color - make sure you include the underlined line in your VertexFactory, or the color data will never get copied:
              Added the fix to the wiki article on procedural mesh generation.

              EDIT: Anyone, feel free to update the code on that page. I haven't included Rama's code on UVs and bounds.
              It is by will alone I set my code in motion.
              It is by coding that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning.
              It is by will alone I set my code in motion.

              Comment


                #52
                Originally posted by dmacesic View Post
                Added the fix to the wiki article on procedural mesh generation.

                EDIT: Anyone, feel free to update the code on that page. I haven't included Rama's code on UVs and bounds.

                The reason I haven't updated the code for UVs is because the vertex struct that contains UVs is not UPROPERTY() compatible, so I can't make it a blueprint type struct any more.

                Code:
                //UPROPERTY() //<----- does not compile
                FDynamicMeshVertex MyUVFriendlyVertex;

                So if I made my UV update, it would break the code for anyone who wants to use it in Blueprints

                Of course I could make my own USTRUCT that did not have that limitation but I figured at that point it was getting pretty project-specific

                Rama
                Last edited by Rama; 05-19-2014, 04:39 PM.
                100+ UE4 C++ Tutorials on the UE4 Code Wiki, including UE4 Multi-Threading!

                UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

                Visit www.ue4code.com to see lots of videos about my C++ Creations! ♥ Rama

                Comment


                  #53
                  I would like to add some code that some may find useful.


                  With a slight change to the code you can improve the rendering quality of the Generatedmesh.

                  If you change the FGeneratedMeshSceneProxy constructor from
                  Code:
                  class FGeneratedMeshSceneProxy : public FPrimitiveSceneProxy
                  {
                  public:

                  FGeneratedMeshSceneProxy(UGeneratedMeshComponent* Component)
                  : FPrimitiveSceneProxy(Component)
                  , MaterialRelevance(Component->GetMaterialRelevance())
                  {
                  const FColor VertexColor(255,255,255);

                  // Add each triangle to the vertex/index buffer
                  for(int TriIdx=0; TriIdx<Component->GeneratedMeshTris.Num(); TriIdx++)
                  {
                  FGeneratedMeshTriangle& Tri = Component->GeneratedMeshTris[TriIdx];

                  const FVector Edge01 = (Tri.Vertex1 - Tri.Vertex0);
                  const FVector Edge02 = (Tri.Vertex2 - Tri.Vertex0);

                  const FVector TangentX = Edge01.SafeNormal();
                  const FVector TangentZ = (Edge02 ^ Edge01).SafeNormal();
                  const FVector TangentY = (TangentX ^ TangentZ).SafeNormal();

                  FDynamicMeshVertex Vert0;
                  Vert0.Position = Tri.Vertex0;
                  Vert0.Color = VertexColor;
                  Vert0.SetTangents(TangentX, TangentY, TangentZ);
                  int32 VIndex = VertexBuffer.Vertices.Add(Vert0);
                  IndexBuffer.Indices.Add(VIndex);

                  FDynamicMeshVertex Vert1;
                  Vert1.Position = Tri.Vertex1;
                  Vert1.Color = VertexColor;
                  Vert1.SetTangents(TangentX, TangentY, TangentZ);
                  VIndex = VertexBuffer.Vertices.Add(Vert1);
                  IndexBuffer.Indices.Add(VIndex);

                  FDynamicMeshVertex Vert2;
                  Vert2.Position = Tri.Vertex2;
                  Vert2.Color = VertexColor;
                  Vert2.SetTangents(TangentX, TangentY, TangentZ);
                  VIndex = VertexBuffer.Vertices.Add(Vert2);
                  IndexBuffer.Indices.Add(VIndex);
                  }

                  // Init vertex factory
                  VertexFactory.Init(&VertexBuffer);

                  // Enqueue initialization of render resource
                  BeginInitResource(&VertexBuffer);
                  BeginInitResource(&IndexBuffer);
                  BeginInitResource(&VertexFactory);

                  // Grab material
                  Material = Component->GetMaterial(0);
                  if(Material == NULL)
                  {
                  Material = UMaterial::GetDefaultMaterial(MD_Surface);
                  }
                  }
                  To
                  Code:
                  FGeneratedMeshSceneProxy(UGeneratedMeshComponent* Component)
                  : FPrimitiveSceneProxy(Component)
                  , Material(NULL)
                  , MaterialRelevance(Component->GetMaterialRelevance())
                  {
                  const FColor VertexColor(255, 255, 255);
                  TArray<FVector> Positions;

                  // Add each triangle to the vertex/index buffer
                  for (int TriIdx = 0; TriIdx<Component->GeneratedMeshTris.Num(); TriIdx++)
                  {
                  FGeneratedMeshTriangle& Tri = Component->GeneratedMeshTris[TriIdx];
                  int32 VIndex;

                  const FVector Edge01 = (Tri.Vertex1 - Tri.Vertex0);
                  const FVector Edge02 = (Tri.Vertex2 - Tri.Vertex0);

                  const FVector TangentX = Edge01.SafeNormal();
                  const FVector TangentZ = (Edge02 ^ Edge01).SafeNormal();
                  const FVector TangentY = (TangentX ^ TangentZ).SafeNormal();

                  FDynamicMeshVertex Vert0;
                  Vert0.Position = Tri.Vertex0;
                  Vert0.Color = VertexColor;
                  Vert0.SetTangents(TangentX, TangentY, TangentZ);

                  if (!Positions.Contains(Vert0.Position))
                  {
                  Positions.Add(Vert0.Position);
                  VIndex = VertexBuffer.Vertices.Add(Vert0);
                  IndexBuffer.Indices.Add(VIndex);
                  }
                  else
                  IndexBuffer.Indices.Add(Positions.Find(Vert0.Position));

                  FDynamicMeshVertex Vert1;
                  Vert1.Position = Tri.Vertex1;
                  Vert1.Color = VertexColor;
                  Vert1.SetTangents(TangentX, TangentY, TangentZ);

                  if (!Positions.Contains(Vert1.Position))
                  {
                  Positions.Add(Vert1.Position);
                  VIndex = VertexBuffer.Vertices.Add(Vert1);
                  IndexBuffer.Indices.Add(VIndex);
                  }
                  else
                  IndexBuffer.Indices.Add(Positions.Find(Vert1.Position));

                  FDynamicMeshVertex Vert2;
                  Vert2.Position = Tri.Vertex2;
                  Vert2.Color = VertexColor;
                  Vert2.SetTangents(TangentX, TangentY, TangentZ);

                  if (!Positions.Contains(Vert2.Position))
                  {
                  Positions.Add(Vert2.Position);
                  VIndex = VertexBuffer.Vertices.Add(Vert2);
                  IndexBuffer.Indices.Add(VIndex);
                  }
                  else
                  IndexBuffer.Indices.Add(Positions.Find(Vert2.Position));

                  }

                  // Init vertex factory
                  VertexFactory.Init(&VertexBuffer);

                  // Enqueue initialization of render resource
                  BeginInitResource(&VertexBuffer);
                  BeginInitResource(&IndexBuffer);
                  BeginInitResource(&VertexFactory);

                  // Grab material
                  Material = Component->GetMaterial(0);
                  if (Material == NULL)
                  {
                  Material = UMaterial::GetDefaultMaterial(MD_Surface);
                  }
                  }
                  The change will keep you from adding redundant vertices to the VertexBuffer and will change this

                  Click image for larger version

Name:	HighresScreenshot00001.jpg
Views:	1
Size:	43.7 KB
ID:	1050791

                  To

                  Click image for larger version

Name:	HighresScreenshot00000.jpg
Views:	1
Size:	41.3 KB
ID:	1050792


                  If You want to allow the GeneratedMeshComponent to cast a shadow you will need to change the CalcBounds function from

                  Code:
                  FBoxSphereBounds UGeneratedMeshComponent::CalcBounds(const FTransform & LocalToWorld) const
                  {
                  FBoxSphereBounds NewBounds;
                  NewBounds.Origin = FVector::ZeroVector;
                  NewBounds.BoxExtent = FVector(HALF_WORLD_MAX,HALF_WORLD_MAX,HALF_WORLD_MAX);
                  NewBounds.SphereRadius = FMath::Sqrt(3.0f * FMath::Square(HALF_WORLD_MAX));
                  return NewBounds;
                  }
                  To
                  Code:
                  FBoxSphereBounds UGeneratedMeshComponent::CalcBounds(const FTransform & LocalToWorld) const
                  {
                  FVector BoxPoint = FVector(10,10,10);
                  return FBoxSphereBounds(FVector(10,0,0), BoxPoint, BoxPoint.Size()).TransformBy(LocalToWorld);

                  }
                  Keep in mind that the changes to CalcBounds reflect the actually size of the geometry and will need to be changed if the geometry changes.

                  One last thing.
                  If you want to be able to assign a material in the editor you will have to make a change in GameGeneratedActor.cpp from
                  Code:
                  AGameGeneratedActor::AGameGeneratedActor(const class FPostConstructInitializeProperties& PCIP)
                  : Super(PCIP)
                  {

                  TSubobjectPtr<UGeneratedMeshComponent> mesh = PCIP.CreateDefaultSubobject<UGeneratedMeshComponent>(this, TEXT("GeneratedMesh"));

                  //Contains the points describing the polyline we are going to rotate
                  TArray<FVector> points;

                  points.Add(FVector(20, 5, 0));
                  points.Add(FVector(15, 6, 0));
                  points.Add(FVector(12, 7, 0));
                  points.Add(FVector(11, 8, 0));
                  points.Add(FVector(8, 7, 0));
                  points.Add(FVector(7, 6, 0));
                  points.Add(FVector(4, 5, 0));
                  points.Add(FVector(3, 4, 0));
                  points.Add(FVector(2, 3, 0));
                  points.Add(FVector(1, 4, 0));


                  TArray<FGeneratedMeshTriangle> triangles;
                  Lathe(points, triangles,128);
                  mesh->SetGeneratedMeshTriangles(triangles);

                  RootComponent = mesh;
                  }
                  To
                  Code:
                  AGameGeneratedActor::AGameGeneratedActor(const class FPostConstructInitializeProperties& PCIP)
                  : Super(PCIP)
                  {

                  mesh = PCIP.CreateDefaultSubobject<UGeneratedMeshComponent>(this, TEXT("GeneratedMesh"));

                  //Contains the points describing the polyline we are going to rotate
                  TArray<FVector> points;

                  points.Add(FVector(20, 5, 0));
                  points.Add(FVector(15, 6, 0));
                  points.Add(FVector(12, 7, 0));
                  points.Add(FVector(11, 8, 0));
                  points.Add(FVector(8, 7, 0));
                  points.Add(FVector(7, 6, 0));
                  points.Add(FVector(4, 5, 0));
                  points.Add(FVector(3, 4, 0));
                  points.Add(FVector(2, 3, 0));
                  points.Add(FVector(1, 4, 0));


                  TArray<FGeneratedMeshTriangle> triangles;
                  Lathe(points, triangles,128);
                  mesh->SetGeneratedMeshTriangles(triangles);

                  RootComponent = mesh;
                  }
                  Then add to GameGeneratedActor.h
                  Code:
                  class AGameGeneratedActor : public AActor
                  {
                  GENERATED_UCLASS_BODY()

                  TSubobjectPtr<class UGeneratedMeshComponent> mesh;

                  void Lathe(const TArray<FVector>& points, TArray<FGeneratedMeshTriangle>& triangles, int segments = 64);

                  };
                  Hope this helps out

                  Comment


                    #54
                    Originally posted by DayOfWar View Post
                    I would like to add some code that some may find useful.
                    (...)
                    Hope this helps out
                    Looks good! The actual code I am using has diverged from the wiki code quite a bit, since that was meant as an example. But what you provide is valuable, and when I have a bit of time I'll test it out and update the wiki.
                    It is by will alone I set my code in motion.
                    It is by coding that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning.
                    It is by will alone I set my code in motion.

                    Comment


                      #55
                      I've just copied the code from the wiki example into my project and can create the lathed object in my map. However, it shows up with the default grey material rather than the black which it should have. My code includes the ColorComponent by Ryvar above but it makes no difference. Has anyone else seen this or can anyone offer any advice?

                      Cheers.
                      WIP: Cubiquity for UE4 - A voxel terrain plugin

                      Comment


                        #56
                        Originally posted by milliams View Post
                        I've just copied the code from the wiki example into my project and can create the lathed object in my map. However, it shows up with the default grey material rather than the black which it should have. My code includes the ColorComponent by Ryvar above but it makes no difference. Has anyone else seen this or can anyone offer any advice?

                        Cheers.
                        In the Actor, define this Property:

                        Code:
                        	UPROPERTY(BlueprintReadWrite, Category = GeneratedActor)
                        	UMaterialInterface* Material;
                        Assign a material to the actor in a blue. In your actor, where you generate your mesh, use something like this:

                        Code:
                               GeneratedMeshComponent->SetMaterial(0, Material);
                        In the code from the wiki, you would need to have a separate function in the actor for generating the mesh. You could then do spawn actor, set material, generate mesh, mesh->SetMaterial(0, Material);

                        HTH
                        It is by will alone I set my code in motion.
                        It is by coding that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning.
                        It is by will alone I set my code in motion.

                        Comment


                          #57
                          Oh god, this is amazing!

                          I love how the Blueprints are very close to ICE inside Softimage, where you can manage data/arrays/geometry with visual data....sweet!!!!

                          Keep going guys, this is awesome!
                          ENTER REALITY

                          VR Solutions

                          Contact us for more informations

                          Comment


                            #58
                            Dear Dmacesic,

                            I modified the wiki code to change this

                            Code:
                            //#if WITH_EDITOR
                            		ModelBodySetup->InvalidatePhysicsData();
                            //#endif
                            to this

                            Code:
                            		ModelBodySetup->ClearPhysicsMeshes();
                            		ModelBodySetup->BodySetupGuid = FGuid::NewGuid();
                            InvalidatePhysicsData would not package for me, causing package fail.

                            The above solution does package correctly

                            And most importantly! We still have custom collision thanks to you research!

                            I hope you like my change!

                            Enjoy!

                            Rama
                            Last edited by Rama; 06-11-2014, 09:01 PM.
                            100+ UE4 C++ Tutorials on the UE4 Code Wiki, including UE4 Multi-Threading!

                            UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

                            Visit www.ue4code.com to see lots of videos about my C++ Creations! ♥ Rama

                            Comment


                              #59
                              Originally posted by Rama View Post
                              Dear Dmacesic,

                              I modified the wiki code to change this

                              Code:
                              //#if WITH_EDITOR
                              		ModelBodySetup->InvalidatePhysicsData();
                              //#endif
                              to this

                              Code:
                              		ModelBodySetup->ClearPhysicsMeshes();
                              		ModelBodySetup->BodySetupGuid = FGuid::NewGuid();
                              InvalidatePhysicsData would not package for me, causing package fail.

                              The above solution does package correctly

                              And most importantly! We still have custom collision thanks to you research!

                              I hope you like my change!

                              Enjoy!

                              Rama
                              Oh cool, they put in the cooking change. It's not a problem, the wiki belongs to everyone. And you are embarrassing me: the code is still Epic's that I have just rehashed a bit...

                              EDIT: Hmm, it's still in the Roadmap, funny... You still have collisions on a packaged game?
                              It is by will alone I set my code in motion.
                              It is by coding that thoughts acquire speed, the hands acquire shaking, the shaking becomes a warning.
                              It is by will alone I set my code in motion.

                              Comment


                                #60
                                Originally posted by dmacesic View Post
                                EDIT: Hmm, it's still in the Roadmap, funny... You still have collisions on a packaged game?
                                Well I got past package compiling , but I've been sorting through various asset errors for the past 2-3 hours, so i can't say for sure yet, but at least I can verify it compiles now!

                                Will let you know!

                                I'm taking a break from waiting 1 hour to find out 1 asset didn't make it and then fix that 1 asset and wait 1 hour again



                                Rama
                                100+ UE4 C++ Tutorials on the UE4 Code Wiki, including UE4 Multi-Threading!

                                UE4 Marketplace: Melee Weapon Plugin & Compressed Binary Save System Plugin | Rama's C++ AI Jumping Videos | Vertex Snap Editor Plugin

                                Visit www.ue4code.com to see lots of videos about my C++ Creations! ♥ Rama

                                Comment

                                Working...
                                X