GLS.ParametricSurfaces.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.ParametricSurfaces;
  5. (*
  6. Parametric surface implementation (like Bezier and BSpline surfaces)
  7. Notes:
  8. The MOParametricSurface is a TGLMeshObject descendant that can be used
  9. to render parametric surfaces. The Renderer property defines if the
  10. surface should be rendered using OpenGL mesh evaluators (through GLU
  11. Nurbs for BSplines) or through GLScene using the CurvesAndSurfaces.pas
  12. routines to generate the mesh vertices and then rendered through the
  13. standard TGLMeshObject render routine. Please note that BSplines aren't
  14. correctly handled yet in the CurvesAndSurfaces unit so the output mesh
  15. in GLScene rendering mode is wrong. I'll have it fixed when I know
  16. what's going wrong. The GLU Nurbs and glMeshEval Beziers work well
  17. though.
  18. The FGBezierSurface is a face group decendant that renders the surface
  19. using mesh evaluators. The ControlPointIndices point to the mesh object
  20. vertices much the same as vertex indices for other face group flavours.
  21. The MinU, MaxU, MinV and MaxV properties allow for drawing specific
  22. parts of the bezier surface, which can be used to blend a patch with
  23. other patches.
  24. *)
  25. interface
  26. {$I GLScene.inc}
  27. uses
  28. Winapi.OpenGL,
  29. GLS.OpenGLTokens,
  30. GLS.OpenGLAdapter,
  31. GLS.VectorTypes,
  32. GLS.VectorFileObjects,
  33. GLS.CurvesAndSurfaces,
  34. GLS.VectorGeometry,
  35. GLS.VectorLists,
  36. GLS.PersistentClasses,
  37. GLS.Texture,
  38. GLS.State,
  39. GLS.Context,
  40. GLS.RenderContextInfo;
  41. type
  42. (* psrGLScene tells the surface to render using GLScene code to build
  43. the mesh, whereas, psrOpenGL uses glEvalMesh2 or gluNurbsRenderer
  44. calls to render the surface. *)
  45. TParametricSurfaceRenderer = (psrGLScene, psrOpenGL);
  46. (* psbBezier indicates building the surface with Bernstein basis
  47. functions, no knot or order properties are used.
  48. psbBSpline indicates building the surface using BSpline basis
  49. functions, these require orders and knot vectors to define the
  50. control point influences on the surface. *)
  51. TParametricSurfaceBasis = (psbBezier, psbBSpline);
  52. TMOParametricSurface = class(TGLMeshObject)
  53. private
  54. FControlPoints,
  55. FWeightedControlPoints: TGLAffineVectorList;
  56. FKnotsU,
  57. FKnotsV,
  58. FWeights: TGLSingleList;
  59. FOrderU,
  60. FOrderV,
  61. FCountU,
  62. FCountV,
  63. FResolution: Integer;
  64. FAutoKnots: Boolean;
  65. FContinuity: TBSplineContinuity;
  66. FRenderer: TParametricSurfaceRenderer;
  67. FBasis: TParametricSurfaceBasis;
  68. procedure SetControlPoints(Value: TGLAffineVectorList);
  69. procedure SetKnotsU(Value: TGLSingleList);
  70. procedure SetKnotsV(Value: TGLSingleList);
  71. procedure SetWeights(Value: TGLSingleList);
  72. procedure SetRenderer(Value: TParametricSurfaceRenderer);
  73. procedure SetBasis(Value: TParametricSurfaceBasis);
  74. public
  75. constructor Create; override;
  76. destructor Destroy; override;
  77. procedure WriteToFiler(writer: TGLVirtualWriter); override;
  78. procedure ReadFromFiler(reader: TGLVirtualReader); override;
  79. procedure BuildList(var mrci: TGLRenderContextInfo); override;
  80. procedure Prepare; override;
  81. procedure Clear; override;
  82. (* Generates a mesh approximation of the surface defined by the
  83. properties below. This is used to construct the mesh when using
  84. Renderer = psrGLScene. If you want to render using OpenGL calls
  85. but would like to obtain the mesh data also use this call to
  86. generate the mesh data. Fills in Vertices, Normals, etc. *)
  87. procedure GenerateMesh;
  88. // Control points define the parametric surface.
  89. property ControlPoints: TGLAffineVectorList read FControlPoints write SetControlPoints;
  90. (* KnotsU and KnotsV are the knot vectors in the U and V direction. Knots
  91. define the continuity of curves and how control points influence the
  92. parametric values to build the surface. *)
  93. property KnotsU: TGLSingleList read FKnotsU write SetKnotsU;
  94. property KnotsV: TGLSingleList read FKnotsV write SetKnotsV;
  95. // Weights define how much a control point effects the surface.
  96. property Weights: TGLSingleList read FWeights write SetWeights;
  97. // OrderU and OrderV defines the curve order in the U and V direction
  98. property OrderU: Integer read FOrderU write FOrderU;
  99. property OrderV: Integer read FOrderV write FOrderV;
  100. (* CountU and CountV describe the number of control points in the
  101. U and V direciton. Basically a control point width and height
  102. in (u,v) space. *)
  103. property CountU: Integer read FCountU write FCountU;
  104. property CountV: Integer read FCountV write FCountV;
  105. (* Defines how fine the resultant mesh will be. Higher values create
  106. finer meshes. Resolution = 50 would produce a 50x50 mesh.
  107. The GLU Nurbs rendering uses resolution as the U_STEP and V_STEP
  108. using the sampling method GLU_DOMAIN_DISTANCE, so the resolution
  109. works a little differently there. *)
  110. property Resolution: Integer read FResolution write FResolution;
  111. (* Automatically generate the knot vectors based on the Continuity.
  112. Only applies to BSpline surfaces. *)
  113. property AutoKnots: Boolean read FAutoKnots write FAutoKnots;
  114. property Continuity: TBSplineContinuity read FContinuity write FContinuity;
  115. (* Determines whether to use OpenGL calls (psrOpenGL) or the GLScene
  116. mesh objects (psrGLScene) to render the surface. *)
  117. property Renderer: TParametricSurfaceRenderer read FRenderer write SetRenderer;
  118. // Basis determines the style of curve, psbBezier or psbBSpline
  119. property Basis: TParametricSurfaceBasis read FBasis write SetBasis;
  120. end;
  121. (* A 3d bezier surface implemented through facegroups. The ControlPointIndices
  122. is an index to control points stored in the MeshObject.Vertices affine
  123. vector list. Similarly the TexCoordIndices point to the owner
  124. MeshObject.TexCoords, one for each control point.
  125. CountU and CountV define the width and height of the surface.
  126. Resolution sets the detail level of the mesh evaluation.
  127. MinU, MaxU, MinV and MaxV define the region of the surface to be rendered,
  128. this is especially useful for blending with neighbouring patches. *)
  129. TFGBezierSurface = class(TGLFaceGroup)
  130. private
  131. FCountU, FCountV: Integer;
  132. FControlPointIndices,
  133. FTexCoordIndices: TGLIntegerList;
  134. FResolution: Integer;
  135. FMinU, FMaxU,
  136. FMinV, FMaxV: Single;
  137. FTempControlPoints,
  138. FTempTexCoords: TGLAffineVectorList;
  139. protected
  140. procedure SetControlPointIndices(const Value: TGLIntegerList);
  141. procedure SetTexCoordIndices(const Value: TGLIntegerList);
  142. public
  143. constructor Create; override;
  144. destructor Destroy; override;
  145. procedure WriteToFiler(writer: TGLVirtualWriter); override;
  146. procedure ReadFromFiler(reader: TGLVirtualReader); override;
  147. procedure BuildList(var mrci: TGLRenderContextInfo); override;
  148. procedure Prepare; override;
  149. property CountU: Integer read FCountU write FCountU;
  150. property CountV: Integer read FCountV write FCountV;
  151. property Resolution: Integer read FResolution write FResolution;
  152. property MinU: Single read FMinU write FMinU;
  153. property MaxU: Single read FMaxU write FMaxU;
  154. property MinV: Single read FMinV write FMinV;
  155. property MaxV: Single read FMaxV write FMaxV;
  156. property ControlPointIndices: TGLIntegerList read FControlPointIndices write SetControlPointIndices;
  157. property TexCoordIndices: TGLIntegerList read FTexCoordIndices write SetTexCoordIndices;
  158. end;
  159. // ----------------------------------------------------------------------
  160. implementation
  161. // ----------------------------------------------------------------------
  162. // ------------------
  163. // ------------------ TMOParametricSurface ------------------
  164. // ------------------
  165. constructor TMOParametricSurface.Create;
  166. begin
  167. inherited;
  168. FControlPoints := TGLAffineVectorList.Create;
  169. FWeightedControlPoints := TGLAffineVectorList.Create;
  170. FKnotsU := TGLSingleList.Create;
  171. FKnotsV := TGLSingleList.Create;
  172. FWeights := TGLSingleList.Create;
  173. Resolution := 20;
  174. end;
  175. destructor TMOParametricSurface.Destroy;
  176. begin
  177. FControlPoints.Free;
  178. FWeightedControlPoints.Free;
  179. FKnotsU.Free;
  180. FKnotsV.Free;
  181. FWeights.Free;
  182. inherited;
  183. end;
  184. procedure TMOParametricSurface.WriteToFiler(writer: TGLVirtualWriter);
  185. begin
  186. inherited WriteToFiler(writer);
  187. with writer do
  188. begin
  189. WriteInteger(0); // Archive Version
  190. FControlPoints.WriteToFiler(writer);
  191. FKnotsU.WriteToFiler(writer);
  192. FKnotsV.WriteToFiler(writer);
  193. FWeights.WriteToFiler(writer);
  194. WriteInteger(FOrderU);
  195. WriteInteger(FOrderV);
  196. WriteInteger(FCountU);
  197. WriteInteger(FCountV);
  198. WriteInteger(FResolution);
  199. WriteBoolean(FAutoKnots);
  200. WriteInteger(Integer(FContinuity));
  201. WriteInteger(Integer(FRenderer));
  202. WriteInteger(Integer(FBasis));
  203. end;
  204. end;
  205. procedure TMOParametricSurface.ReadFromFiler(reader: TGLVirtualReader);
  206. var
  207. archiveVersion: Integer;
  208. begin
  209. inherited ReadFromFiler(reader);
  210. archiveVersion := reader.ReadInteger;
  211. if archiveVersion = 0 then
  212. with reader do
  213. begin
  214. FControlPoints.ReadFromFiler(reader);
  215. FKnotsU.ReadFromFiler(reader);
  216. FKnotsV.ReadFromFiler(reader);
  217. FWeights.ReadFromFiler(reader);
  218. FOrderU := ReadInteger;
  219. FOrderV := ReadInteger;
  220. FCountU := ReadInteger;
  221. FCountV := ReadInteger;
  222. FResolution := ReadInteger;
  223. FAutoKnots := ReadBoolean;
  224. FContinuity := TBSplineContinuity(ReadInteger);
  225. FRenderer := TParametricSurfaceRenderer(ReadInteger);
  226. FBasis := TParametricSurfaceBasis(ReadInteger);
  227. end
  228. else
  229. RaiseFilerException(archiveVersion);
  230. end;
  231. procedure TMOParametricSurface.BuildList(var mrci: TGLRenderContextInfo);
  232. var
  233. NurbsRenderer: PGLUNurbs;
  234. begin
  235. case FRenderer of
  236. psrGLScene: inherited;
  237. psrOpenGL:
  238. begin
  239. mrci.GLStates.PushAttrib([sttEnable, sttEval]);
  240. //gl.Enable(GL_MAP2_TEXTURE_COORD_3);
  241. gl.Enable(GL_MAP2_VERTEX_3);
  242. gl.Enable(GL_AUTO_NORMAL);
  243. gl.Enable(GL_NORMALIZE);
  244. case FBasis of
  245. psbBezier:
  246. begin
  247. gl.MapGrid2f(FResolution, 1, 0, FResolution, 0, 1);
  248. gl.Map2f(GL_MAP2_TEXTURE_COORD_3,
  249. 0, 1, 3, FOrderU,
  250. 0, 1, 3 * FCountU, FOrderV,
  251. @FWeightedControlPoints.List[0]);
  252. gl.Map2f(GL_MAP2_VERTEX_3, 0, 1, 3, FCountU, 0, 1, 3 * FCountU, FCountV, @FWeightedControlPoints.List[0]);
  253. gl.EvalMesh2(GL_FILL, 0, FResolution, 0, FResolution);
  254. end;
  255. psbBSpline:
  256. begin
  257. NurbsRenderer := gluNewNurbsRenderer;
  258. gluNurbsProperty(NurbsRenderer, GLU_DISPLAY_MODE, GLU_FILL);
  259. gluNurbsProperty(NurbsRenderer, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE);
  260. gluNurbsProperty(NurbsRenderer, GLU_U_STEP, FResolution);
  261. gluNurbsProperty(NurbsRenderer, GLU_V_STEP, FResolution);
  262. gluBeginSurface(NurbsRenderer);
  263. gluNurbsSurface(NurbsRenderer,
  264. FKnotsU.Count, @FKnotsU.List[0],
  265. FKnotsV.Count, @FKnotsV.List[0],
  266. 3, FCountU * 3,
  267. @FWeightedControlPoints.List[0],
  268. FOrderU, FOrderV,
  269. GL_MAP2_TEXTURE_COORD_3);
  270. gluNurbsSurface(NurbsRenderer,
  271. FKnotsU.Count, @FKnotsU.List[0],
  272. FKnotsV.Count, @FKnotsV.List[0],
  273. 3, FCountU * 3,
  274. @FWeightedControlPoints.List[0],
  275. FOrderU, FOrderV,
  276. GL_MAP2_VERTEX_3);
  277. gluEndSurface(NurbsRenderer);
  278. gluDeleteNurbsRenderer(NurbsRenderer);
  279. end;
  280. end;
  281. mrci.GLStates.PopAttrib;
  282. end;
  283. end;
  284. end;
  285. procedure TMOParametricSurface.Prepare;
  286. var
  287. i: integer;
  288. begin
  289. // We want to clear everything but the parametric surface
  290. // data (control points and knot vectors).
  291. inherited Clear;
  292. // Apply weights to control points
  293. FWeightedControlPoints.Assign(FControlPoints);
  294. if FWeights.Count = FControlPoints.Count then
  295. for i := 0 to FWeightedControlPoints.Count - 1 do
  296. FWeightedControlPoints[i] := VectorScale(FWeightedControlPoints[i], FWeights[i]);
  297. case FRenderer of
  298. psrGLScene:
  299. begin
  300. GenerateMesh;
  301. end;
  302. psrOpenGL:
  303. begin
  304. if (FAutoKnots) and (FBasis = psbBSpline) then
  305. begin
  306. GenerateKnotVector(FKnotsU, FCountU, FOrderU, FContinuity);
  307. GenerateKnotVector(FKnotsV, FCountV, FOrderV, FContinuity);
  308. end;
  309. end;
  310. end;
  311. end;
  312. procedure TMOParametricSurface.Clear;
  313. begin
  314. inherited;
  315. FControlPoints.Clear;
  316. FKnotsU.Clear;
  317. FKnotsV.Clear;
  318. FWeights.Clear;
  319. end;
  320. procedure TMOParametricSurface.GenerateMesh;
  321. var
  322. i, j: Integer;
  323. fg: TFGVertexIndexList;
  324. begin
  325. case FBasis of
  326. psbBezier:
  327. begin
  328. if FAutoKnots then
  329. begin
  330. FKnotsU.Clear;
  331. FKnotsV.Clear;
  332. end;
  333. GenerateBezierSurface(FResolution, FCountU, FCountV, FControlPoints, Vertices);
  334. end;
  335. psbBSpline:
  336. begin
  337. if FAutoKnots then
  338. begin
  339. GenerateKnotVector(FKnotsU, FCountU, FOrderU, FContinuity);
  340. GenerateKnotVector(FKnotsV, FCountV, FOrderV, FContinuity);
  341. end;
  342. GenerateBSplineSurface(FResolution, FOrderU, FOrderV, FCountU, FCountV, FKnotsU, FKnotsV, FControlPoints, Vertices);
  343. end;
  344. end;
  345. Mode := momFaceGroups;
  346. fg := TFGVertexIndexList.CreateOwned(FaceGroups);
  347. fg.Mode := fgmmTriangles;
  348. for j := 0 to FResolution - 2 do
  349. with fg do
  350. for i := 0 to FResolution - 2 do
  351. begin
  352. VertexIndices.Add(i + FResolution * j);
  353. VertexIndices.Add((i + 1) + FResolution * j);
  354. VertexIndices.Add(i + FResolution * (j + 1));
  355. VertexIndices.Add(i + FResolution * (j + 1));
  356. VertexIndices.Add((i + 1) + FResolution * j);
  357. VertexIndices.Add((i + 1) + FResolution * (j + 1));
  358. end;
  359. BuildNormals(fg.VertexIndices, momTriangles);
  360. end;
  361. procedure TMOParametricSurface.SetControlPoints(Value: TGLAffineVectorList);
  362. begin
  363. FControlPoints.Assign(Value);
  364. end;
  365. procedure TMOParametricSurface.SetKnotsU(Value: TGLSingleList);
  366. begin
  367. FKnotsU.Assign(Value);
  368. end;
  369. procedure TMOParametricSurface.SetKnotsV(Value: TGLSingleList);
  370. begin
  371. FKnotsV.Assign(Value);
  372. end;
  373. procedure TMOParametricSurface.SetWeights(Value: TGLSingleList);
  374. begin
  375. FWeights.Assign(Value);
  376. end;
  377. procedure TMOParametricSurface.SetRenderer(
  378. Value: TParametricSurfaceRenderer);
  379. begin
  380. if Value <> FRenderer then
  381. begin
  382. FRenderer := Value;
  383. Owner.Owner.StructureChanged;
  384. end;
  385. end;
  386. procedure TMOParametricSurface.SetBasis(Value: TParametricSurfaceBasis);
  387. begin
  388. if Value <> FBasis then
  389. begin
  390. FBasis := Value;
  391. Owner.Owner.StructureChanged;
  392. end;
  393. end;
  394. // ------------------
  395. // ------------------ TFGBezierSurface ------------------
  396. // ------------------
  397. constructor TFGBezierSurface.Create;
  398. begin
  399. inherited;
  400. FControlPointIndices := TGLIntegerList.Create;
  401. FTexCoordIndices := TGLIntegerList.Create;
  402. FTempControlPoints := TGLAffineVectorList.Create;
  403. FTempTexCoords := TGLAffineVectorList.Create;
  404. // Default values
  405. FCountU := 4;
  406. FCountV := 4;
  407. FResolution := 20;
  408. FMinU := 0;
  409. FMaxU := 1;
  410. FMinV := 0;
  411. FMaxV := 1;
  412. end;
  413. destructor TFGBezierSurface.Destroy;
  414. begin
  415. FControlPointIndices.Free;
  416. FTexCoordIndices.Free;
  417. FTempControlPoints.Free;
  418. FTempTexCoords.Free;
  419. inherited;
  420. end;
  421. procedure TFGBezierSurface.WriteToFiler(writer: TGLVirtualWriter);
  422. begin
  423. inherited WriteToFiler(writer);
  424. with writer do
  425. begin
  426. WriteInteger(0); // Archive Version 0
  427. FControlPointIndices.WriteToFiler(writer);
  428. FTexCoordIndices.WriteToFiler(writer);
  429. WriteInteger(FCountU);
  430. WriteInteger(FCountV);
  431. WriteInteger(FResolution);
  432. WriteFloat(FMinU);
  433. WriteFloat(FMaxU);
  434. WriteFloat(FMinV);
  435. WriteFloat(FMaxV);
  436. end;
  437. end;
  438. procedure TFGBezierSurface.ReadFromFiler(reader: TGLVirtualReader);
  439. var
  440. archiveVersion: Integer;
  441. begin
  442. inherited ReadFromFiler(reader);
  443. archiveVersion := reader.ReadInteger;
  444. if archiveVersion = 0 then
  445. with reader do
  446. begin
  447. FControlPointIndices.ReadFromFiler(reader);
  448. FTexCoordIndices.ReadFromFiler(reader);
  449. FCountU := ReadInteger;
  450. FCountV := ReadInteger;
  451. FResolution := ReadInteger;
  452. FMinU := ReadFloat;
  453. FMaxU := ReadFloat;
  454. FMinV := ReadFloat;
  455. FMaxV := ReadFloat;
  456. end
  457. else
  458. RaiseFilerException(archiveVersion);
  459. end;
  460. procedure TFGBezierSurface.BuildList(var mrci: TGLRenderContextInfo);
  461. begin
  462. if (FTempControlPoints.Count = 0)
  463. or (FTempControlPoints.Count <> FControlPointIndices.Count) then
  464. Exit;
  465. AttachOrDetachLightmap(mrci);
  466. mrci.GLStates.PushAttrib([sttEnable, sttEval]);
  467. mrci.GLStates.Enable(stAutoNormal);
  468. mrci.GLStates.Enable(stNormalize);
  469. gl.MapGrid2f(FResolution, MaxU, MinU, FResolution, MinV, MaxV);
  470. if FTempTexCoords.Count > 0 then
  471. begin
  472. gl.Enable(GL_MAP2_TEXTURE_COORD_3);
  473. gl.Map2f(GL_MAP2_TEXTURE_COORD_3,
  474. 0, 1, 3, FCountU,
  475. 0, 1, 3 * FCountU, FCountV,
  476. @FTempTexCoords.List[0]);
  477. end;
  478. gl.Enable(GL_MAP2_VERTEX_3);
  479. gl.Map2f(GL_MAP2_VERTEX_3,
  480. 0, 1, 3, FCountU,
  481. 0, 1, 3 * FCountU, FCountV,
  482. @FTempControlPoints.List[0]);
  483. gl.EvalMesh2(GL_FILL, 0, FResolution, 0, FResolution);
  484. mrci.GLStates.PopAttrib;
  485. end;
  486. procedure TFGBezierSurface.SetControlPointIndices(const Value: TGLIntegerList);
  487. begin
  488. FControlPointIndices.Assign(Value);
  489. end;
  490. procedure TFGBezierSurface.SetTexCoordIndices(const Value: TGLIntegerList);
  491. begin
  492. FTexCoordIndices.Assign(Value);
  493. end;
  494. procedure TFGBezierSurface.Prepare;
  495. var
  496. i, j: Integer;
  497. begin
  498. inherited;
  499. FTempControlPoints.Clear;
  500. FTempTexCoords.Clear;
  501. for j := 0 to CountV - 1 do
  502. for i := CountU - 1 downto 0 do
  503. begin
  504. FTempControlPoints.Add(Owner.Owner.Vertices[ControlPointIndices[i + CountU * j]]);
  505. if TexCoordIndices.Count = ControlPointIndices.Count then
  506. FTempTexCoords.Add(Owner.Owner.TexCoords[TexCoordIndices[i + CountU * j]]);
  507. end;
  508. end;
  509. end.