Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
billboard [2020/01/10 12:22] – [Example: Grass Billboard] admin | billboard [Unknown date] (current) – removed - external edit (Unknown date) 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Billboard ====== | ||
- | A billboard controls proxy instances of a basis mesh (source object). | ||
- | |||
- | The billboard component is a mesh itself, into which proxies are merged. Much faster rendering is possible if proxy meshes are merge into one mesh, instead of rendering each mesh. | ||
- | |||
- | We typically use this technique for grass or trees. | ||
- | It is not suitable for animated meshes. | ||
- | |||
- | ===== Example: Grass Billboard ===== | ||
- | |||
- | In this example we will display grass on multiplied planes inside of the billboard component. | ||
- | After applying the TGorillaGrassMaterial we are able to render different textures onto those planes and to manipulate vertices. | ||
- | |||
- | The result should be a varying grass landscape with waving grass. | ||
- | |||
- | <file pascal Form1.pas> | ||
- | procedure TForm1.FormCreate(Sender: | ||
- | var LBillboard : TPlane; | ||
- | LPoolE : TGorillaBitmapPoolEntry; | ||
- | LGrassMat : TGorillaGrassMaterialSource; | ||
- | LAlg : TGorillaBillboardRectFilling; | ||
- | begin | ||
- | // creating the source object - here a plane | ||
- | LBillboard := TPlane.Create(fGorilla); | ||
- | LBillboard.Scale.Point := Point3D(4, 4, 4); | ||
- | | ||
- | // creating the grass material source | ||
- | FGrassMat := TGorillaGrassMaterialSource.Create(FGorilla); | ||
- | FGrassMat.Parent := FGorilla; | ||
- | | ||
- | // now we load a pool of grass textures, the material shader | ||
- | // randomly chooses from | ||
- | with FGrassMat do | ||
- | begin | ||
- | LPoolE := Bitmaps.Add() as TGorillaBitmapPoolEntry; | ||
- | LPoolE.DisplayName := ' | ||
- | LPoolE.Bitmap.LoadFromFile(' | ||
- | |||
- | LPoolE := Bitmaps.Add() as TGorillaBitmapPoolEntry; | ||
- | LPoolE.DisplayName := ' | ||
- | LPoolE.Bitmap.LoadFromFile(' | ||
- | |||
- | LPoolE := Bitmaps.Add() as TGorillaBitmapPoolEntry; | ||
- | LPoolE.DisplayName := ' | ||
- | LPoolE.Bitmap.LoadFromFile(' | ||
- | |||
- | LPoolE := Bitmaps.Add() as TGorillaBitmapPoolEntry; | ||
- | LPoolE.DisplayName := ' | ||
- | LPoolE.Bitmap.LoadFromFile(' | ||
- | end; | ||
- | |||
- | // creating the billboard control | ||
- | FGrass := TGorillaBillboard.Create(FGorilla); | ||
- | FGrass .Parent := FGorilla; | ||
- | FGrass.AddSourceObject(LBillboard); | ||
- | FGrass.MaterialSource := LGrassMat; | ||
- | FGrass.SetSize(GORILLA_BILLBOARD_SIZE, | ||
- | |||
- | // create an individual filling algorithm to multiply the grass planes | ||
- | // on elder Gorilla3D version TGorillaBillboardRectFilling | ||
- | LAlg := TGorillaBillboardFlatFilling.Create(FGrass); | ||
- | try | ||
- | LAlg.Count := 1000; | ||
- | FGrass.Fill(LAlg, | ||
- | finally | ||
- | FreeAndNil(LAlg); | ||
- | end; | ||
- | </ | ||
- | |||
- | ==== Interact with grass shader ==== | ||
- | |||
- | The default grass shader provides functionality to bend the grass planes at a certain point. | ||
- | To enable interaction, | ||
- | |||
- | <file pascal Form1.pas> | ||
- | FGrassMat.SpotRadius := 0.5; | ||
- | FGrassMat.SpotEnabled := true; | ||
- | </ | ||
- | |||
- | And in the OnMouseMove event we can set the current interaction point like this: | ||
- | |||
- | <file pascal Form1.pas> | ||
- | procedure TForm1.DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState; | ||
- | X, Y : Single); | ||
- | var LPt3D : TPoint3D; | ||
- | LRayPos, LRayDir : TVector3D; | ||
- | begin | ||
- | if FMove then | ||
- | begin | ||
- | if (ssLeft in AShiftState) then | ||
- | begin | ||
- | FGorilla.BeginUpdate(); | ||
- | try | ||
- | LPt3D := FGorilla.ScreenToWorld(PointF(X, | ||
- | FGorilla.Context.Pick(X, | ||
- | FGrass.RayCastIntersect(LRayPos, | ||
- | |||
- | // apply scaled light position | ||
- | FGrassMat.Spot := TPoint3D(LPt3D); | ||
- | finally | ||
- | FGorilla.EndUpdate(); | ||
- | end; | ||
- | end; | ||
- | |||
- | FLatest := PointF(X, Y); | ||
- | end; | ||
- | end; | ||
- | </ | ||
- | |||
- | ===== Example: Terrain Grass Billboard ===== | ||
- | |||
- | Since v0.8.1+ we've implemented a lot of new backend features (bounding volume hierarchy for TMeshDef, multiple billboard source objects, TGorillaModel support), which allows to multiple meshes and place those onto a terrain surface. | ||
- | |||
- | The following example will create 64 billboards, filled up with 64 copies of a grass template model. The billboards will be attached as childs to the terrain and rendered above. | ||
- | All billboards will be placed as grid above the complete terrain. | ||
- | |||
- | __Notice:__ We could multiply the template model into a single billboard component, but the idea behind it, is to use the performance optimization of frustum culling. | ||
- | By frustum culling only the visible billboard chunks will be rendered, therefore we can reduce vertex rendering a lot. | ||
- | |||
- | So at first we will load a grass template model. //Keep the mesh as simple as possible, because vertex count will increase fastly.// | ||
- | |||
- | To place a grass model copy in correct y-position on the terrain, we need to know vertices of the terrain. The new feature of bounding volume hierarchy (BVH) computation for TMeshDef' | ||
- | |||
- | For template model multiplication we use the new TGorillaBillboardTerrainFilling class, which automatically reads y-position from BVH. | ||
- | |||
- | <file pascal> | ||
- | const | ||
- | MAP_SIZE = 900; // terrain size (quadratic) | ||
- | MAP_HEIGHT = MAP_SIZE / 4; | ||
- | | ||
- | var FGrassTemps : Array[0..0] of TGorillaModel; | ||
- | |||
- | procedure TForm1.CreateGrass(ATerrain : TGorillaTerrain; | ||
- | const GORILLA_BILLBOARD_SIZE = 1; | ||
- | GORILLA_MODEL_GRASS_1 = ' | ||
- | |||
- | var LTexPath | ||
- | LGrass | ||
- | LFillAlg | ||
- | LChunks | ||
- | LChunksPerRow : Integer; | ||
- | i : Integer; | ||
- | LChunkSize | ||
- | LX, LZ : Single; | ||
- | begin | ||
- | if not Assigned(ATerrain) then | ||
- | raise Exception.Create(' | ||
- | |||
- | // load the grass templates | ||
- | LTexPath := IncludeTrailingPathDelimiter(AAssetsPath + ' | ||
- | FGrassTemps[0] := TGorillaModel.LoadNewModelFromFile(FViewport, | ||
- | LTexPath + GORILLA_MODEL_GRASS_1, | ||
- | FGrassTemps[0].Visible := false; // it do not need to be shown | ||
- | |||
- | // create a list for all 64 billboard chunks | ||
- | FGrassBillboards := TList< | ||
- | |||
- | // acquire a bounding volume hierarchy for much faster raytracing | ||
- | // after usage, it will be destroyed, because it consumes a lot memory | ||
- | // and we only need it for the moment | ||
- | TMeshDef(ATerrain.Def).AcquireBVH(); | ||
- | try | ||
- | LChunks := 64; | ||
- | LChunksPerRow := Ceil(Sqrt(LChunks)); | ||
- | |||
- | LChunkSize.X := (MAP_SIZE / LChunksPerRow); | ||
- | LChunkSize.Y := MAP_HEIGHT; | ||
- | LChunkSize.Z := (MAP_SIZE / LChunksPerRow); | ||
- | |||
- | for i := 0 to LChunks - 1 do | ||
- | begin | ||
- | // create multiple grass billboards to use frustum culling | ||
- | LGrass := TGorillaBillboard.Create(FViewport); | ||
- | LGrass.Parent := FViewport; | ||
- | LGrass.Opaque := false; // allow translucent rendering | ||
- | LGrass.TwoSide := true; | ||
- | LGrass.Name := ' | ||
- | |||
- | // add the grass model as source object | ||
- | // multiple source objects are possible and will be chosen randomly | ||
- | LGrass.AddSourceObject(FGrassTemps[0]); | ||
- | | ||
- | // set the size of billboard chunk | ||
- | LGrass.SetSize(LChunkSize.X, | ||
- | |||
- | LX := -(MAP_SIZE / 2) + ((i mod LChunksPerRow) * LChunkSize.X); | ||
- | LZ := (MAP_SIZE / 2) - (Floor(i / LChunksPerRow) * LChunkSize.Z); | ||
- | |||
- | // place billboard chunk over terrain | ||
- | LGrass.Position.Point := Point3D(LX, 0, LZ); | ||
- | LGrass.MaterialSource := FGrassTemps[0].Meshes[0].MaterialSource; | ||
- | FGrassBillboards.Add(LGrass); | ||
- | |||
- | // fill up billboard chunk with 64 copies of our grass template | ||
- | LFillAlg := TGorillaBillboardTerrainFilling.Create(LGrass, | ||
- | try | ||
- | LFillAlg.Count := 64; | ||
- | LGrass.Fill(LFillAlg, | ||
- | finally | ||
- | FreeAndNil(LFillAlg); | ||
- | end; | ||
- | |||
- | // we put grass billboard into terrain model | ||
- | LGrass.Parent := ATerrain; | ||
- | end; | ||
- | finally | ||
- | // at the end we destroy the bounding volume hierarchy again to free memory | ||
- | TMeshDef(ATerrain.Def).ReleaseBVH(); | ||
- | end; | ||
- | end; | ||
- | </ | ||
- | |||
- | Next step: [[inventory|Inventory]] |