1 unit ex4; 2 3 {$mode objfpc}{$H+} 4 5 interface 6 7 { This example demonstrate how to load 3D objects and show them with 8 appropriate material and color. 9 10 The LoadObjectFromFile returns an 3D object defined by an OBJ file. 11 Some things are ignored, like texture information or normal information. 12 But when a material name is used, the function UseMaterial is called. 13 So here it is overriden in order to give the best material possible. 14 15 Some objects have specific effects. For example, the teapot is defined 16 as Biface so that the reflected light is computed outside and inside 17 the glass. 18 19 The helicopter is divided into two parts. The upper part contains the 20 rotor in order to rotate it, so that the helicopter seems to fly. 21 22 The lamp contains in fact 4 lamps, and so 4 light sources are created. 23 24 } 25 26 uses 27 Classes, SysUtils, BGRAScene3D, BGRABitmapTypes, 28 BGRAOpenGL3D, BGRAOpenGL; 29 30 type 31 32 { TExample4 } 33 34 TExample4 = class(TBGLScene3D) 35 protected 36 lamp,shiny,reflect: IBGRAMaterial3D; 37 rotated: IBGRAPart3D; 38 rotateCenter: TPoint3D; 39 message: string; 40 procedure UseMaterial(materialname: string; face: IBGRAFace3D); override; 41 procedure CreateScene; 42 public 43 procedure Render; override; 44 procedure Elapse; 45 procedure RenderGL(ACanvas: TBGLCustomCanvas; AMaxZ: single=1000); override; 46 procedure NextModel; 47 constructor Create; 48 end; 49 50 implementation 51 52 uses BGRATextFX; 53 54 var 55 numObj: integer= 3; 56 57 const 58 objList: array[0..9] of string = ( 'ciseau.obj', 59 'fourche.obj', 'pelle.obj', 'helico.obj', 'mario.obj', 'helice.obj', 60 'lampe.obj', 'teapot.obj', 'roue.obj', 'trumpet.obj'); 61 62 { TExample4 } 63 64 constructor TExample4.Create; 65 begin 66 inherited Create; 67 68 //create shiny material using saturation of diffusion (1.3 .. 1.5) 69 shiny := CreateMaterial; 70 shiny.SaturationLow := 1.3; 71 shiny.SaturationHigh := 1.5; 72 reflect := CreateMaterial(50); 73 lamp := CreateMaterial; 74 lamp.LightThroughFactor := 0.05; 75 76 CreateScene; 77 end; 78 79 procedure TExample4.UseMaterial(materialname: string; face: IBGRAFace3D); 80 var color : TBGRAPixel; 81 begin 82 if (materialname = 'globes') then 83 begin 84 color := BGRA(255,240,220); 85 face.Material := lamp; 86 end else 87 if (materialname = 'bone') then 88 begin 89 color := BGRA(255,240,220); 90 end else 91 if (materialname = 'bronze') then 92 begin 93 color := CSSSaddleBrown; 94 face.Material := reflect; 95 end else 96 if materialname = 'grey' then 97 begin 98 color := BGRA(230,192,80); 99 face.Material := shiny; 100 end else 101 begin 102 color := StrToBGRA(materialname); 103 if (objList[numObj] <> 'helice.obj') and (color.red = color.green) and (color.green = color.blue) then 104 begin 105 if (color.alpha <> 255) or (color.red = 0) then 106 face.Material := reflect 107 else 108 face.Material := shiny; 109 end else 110 if color.alpha <> 255 then 111 face.Material := reflect; 112 end; 113 face.SetColor( color ); 114 end; 115 116 procedure TExample4.CreateScene; 117 var obj: IBGRAObject3D; 118 r: single; 119 i: integer; 120 filename: string; 121 begin 122 Clear; 123 124 filename := 'obj'+PathDelim+objList[numObj]; 125 if not fileexists(filename) and fileexists('..'+PathDelim+'..'+PathDelim+filename) then 126 filename := '..'+PathDelim+'..'+PathDelim+filename; 127 if not FileExists(filename) then 128 begin 129 message := 'File not found : '+ filename; 130 exit; 131 end; 132 133 obj := LoadObjectFromFile(filename, objList[numObj] <> 'teapot.obj'); 134 135 if objList[numObj] = 'helico.obj' then 136 begin 137 with obj.MainPart do 138 begin 139 rotated := CreatePart; 140 rotateCenter := Point3D(0,0,0); 141 for i := VertexCount-1 downto 0 do 142 if (Vertex[i].SceneCoord.y >= 22.2) then 143 begin 144 rotated.Add(Vertex[i]); 145 rotateCenter.Offset(Vertex[i].SceneCoord); 146 end; 147 rotateCenter.Scale(1/rotated.VertexCount); 148 obj.SeparatePart(rotated); 149 obj.MainPart.Scale(2,2,2); 150 end; 151 end else 152 rotated := nil; 153 154 obj.LightingNormal := lnVertex; 155 if objList[numObj] = 'teapot.obj' then 156 for i := 0 to obj.FaceCount-1 do 157 obj.Face[i].Biface := true; 158 159 with obj.MainPart.BoundingBox do 160 obj.MainPart.Translate((min+max)*(-1/2), False); 161 r := obj.MainPart.Radius; 162 if r <> 0 then obj.MainPart.Scale(40/r, False); 163 if objList[numObj] = 'lampe.obj' then 164 begin 165 obj.MainPart.RotateXDeg(180, False); 166 obj.MainPart.Scale(1.5,1.5,1.5); 167 end else 168 if objList[numObj] = 'mario.obj' then 169 obj.MainPart.RotateXDeg(90, False) 170 else 171 begin 172 obj.MainPart.RotateXDeg(180-20, False); 173 obj.MainPart.RotateYDeg(-20, False); 174 if objList[numObj] = 'trumpet.obj' then 175 obj.MainPart.Scale(2,2,2,False); 176 end; 177 178 if objList[numObj] = 'lampe.obj' then 179 begin 180 AmbiantLightness := 0.7; 181 AddPointLight(obj.MainPart.Add(0,7.7,0),10); 182 AddPointLight(obj.MainPart.Add(1.9,6.5,0),10); 183 AddPointLight(obj.MainPart.Add(-0.9,6.5,1.5),10); 184 AddPointLight(obj.MainPart.Add(-0.9,6.5,-1.7),10); 185 end 186 else 187 begin 188 //set ambiant lightness to dark (1 is normal lightness) 189 AmbiantLightness := 0.5; 190 if objList[numObj] = 'helice.obj' then 191 AddDirectionalLight(Point3D(1,1,1),0.75,-0.5) 192 else 193 AddDirectionalLight(Point3D(1,1,1),1,-0.5); //add a directional light from top-left, maximum lightness will be 0.5 + 1 = 1.5 194 end; 195 196 RenderingOptions.PerspectiveMode:= pmZBuffer; 197 if objList[numObj] = 'helice.obj' then 198 RenderingOptions.LightingInterpolation := liAlwaysHighQuality 199 else 200 RenderingOptions.LightingInterpolation := liSpecularHighQuality; 201 end; 202 203 procedure TExample4.Render; 204 var fx: TBGRATextEffect; 205 begin 206 if objList[numObj] = 'teapot.obj' then 207 Surface.GradientFill(0,0,Surface.Width,Surface.Height,BGRABlack,BGRA(70,100,100),gtLinear,PointF(0,0),PointF(0,Surface.Height),dmSet) else 208 if objList[numObj] = 'lampe.obj' then 209 Surface.Fill(BGRA(0,0,60)); 210 211 inherited Render; 212 213 if message <> '' then 214 begin 215 fx := TBGRATextEffect.Create(message,'Arial',20,True); 216 fx.DrawOutline(Surface,Surface.Width div 2,Surface.Height div 2-fx.TextHeight div 2,BGRABlack,taCenter); 217 fx.Draw(Surface,Surface.Width div 2,Surface.Height div 2-fx.TextHeight div 2,BGRAWhite,taCenter); 218 fx.Free; 219 end else 220 Surface.TextOut(Surface.Width,0,objList[numObj],BGRAWhite,taRightJustify); 221 end; 222 223 procedure TExample4.Elapse; 224 begin 225 if rotated <> nil then 226 begin 227 rotated.Translate(-rotateCenter,false); 228 rotated.RotateYDeg(20,False); 229 rotated.Translate(rotateCenter,false); 230 end; 231 end; 232 233 procedure TExample4.RenderGL(ACanvas: TBGLCustomCanvas; AMaxZ: single); 234 begin 235 if objList[numObj] = 'teapot.obj' then 236 ACanvas.FillRectLinearColor(0,0,BGLCanvas.Width,BGLCanvas.Height, 237 BGRABlack,BGRABlack, 238 BGRA(70,100,100),BGRA(70,100,100), 239 False) else 240 if objList[numObj] = 'lampe.obj' then 241 ACanvas.Fill(BGRA(0,0,60)); 242 243 inherited RenderGL(ACanvas, AMaxZ); 244 end; 245 246 procedure TExample4.NextModel; 247 begin 248 inc(numObj); 249 if numObj = length(objList) then numObj := 0; 250 251 CreateScene; 252 end; 253 254 end. 255 256