LUADOC - Farming Simulator 17

Printable Version

VehicleCamera

Description
Class for vehicle camera
Functions

new

Description
Creating vehicle camera
Definition
new(boolean isServer, boolean isClient, table customMt)
Arguments
booleanisServeris server
booleanisClientis client
tablecustomMtcustom metatable
Return Values
tableinstanceInstance of object
Code
25function VehicleCamera:new(vehicle, customMt)
26
27 local instance = {};
28 if customMt ~= nil then
29 setmetatable(instance, customMt);
30 else
31 setmetatable(instance, VehicleCamera_mt);
32 end;
33
34
35 instance.vehicle = vehicle;
36 instance.isActivated = false;
37
38 instance.limitRotXDelta = 0;
39
40 instance.raycastDistance = 0;
41 instance.normalX = 0;
42 instance.normalY = 0;
43 instance.normalZ = 0;
44
45 instance.raycastNodes = {};
46 instance.disableCollisionTime = -1;
47
48 instance.lookAtPosition = {0,0,0};
49 instance.lookAtLastTargetPosition = {0,0,0};
50 instance.position = {0,0,0};
51 instance.lastTargetPosition = {0,0,0};
52
53 instance.isCollisionEnabled = not g_modIsLoaded["disableVehicleCameraCollision"]
54
55 return instance;
56end;

loadFromXML

Description
Load vehicle camera from xml file
Definition
loadFromXML(integer xmlFile, string key)
Arguments
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccesssuccess
Code
63function VehicleCamera:loadFromXML(xmlFile, key)
64 local camIndexStr = getXMLString(xmlFile, key .. "#index");
65 self.cameraNode = Utils.indexToObject(self.vehicle.components, camIndexStr);
66 if self.cameraNode == nil or not getHasClassId(self.cameraNode, ClassIds.CAMERA) then
67 print("Error loading camera "..key..": invalid camera node");
68 return false;
69 end;
70
71 self.fovy = calculateFovy(self.cameraNode)
72 setFovy(self.cameraNode, self.fovy)
73
74 self.isRotatable = Utils.getNoNil(getXMLBool(xmlFile, key .. "#rotatable"), false);
75 self.limit = Utils.getNoNil(getXMLBool(xmlFile, key .. "#limit"), false);
76 if self.limit then
77 self.rotMinX = getXMLFloat(xmlFile, key .. "#rotMinX");
78 self.rotMaxX = getXMLFloat(xmlFile, key .. "#rotMaxX");
79
80 self.transMin = getXMLFloat(xmlFile, key .. "#transMin");
81 self.transMax = getXMLFloat(xmlFile, key .. "#transMax");
82 if self.rotMinX == nil or self.rotMaxX == nil or self.transMin == nil or self.transMax == nil then
83 print("Error loading camera "..key..": missing limit values");
84 return false;
85 end;
86 end;
87
88 self.isInside = Utils.getNoNil(getXMLBool(xmlFile, key .. "#isInside"), false);
89 if self.isInside then
90 self.defaultLowPassGain = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#defaultLowPassGain"), 0.5);
91 self.defaultVolume = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#defaultVolume"), 0.9);
92 else
93 self.defaultLowPassGain = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#defaultLowPassGain"), 1.0);
94 self.defaultVolume = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#defaultVolume"), 1.0);
95 end
96 self.allowHeadTracking = Utils.getNoNil(getXMLBool(xmlFile, key .. "#allowHeadTracking"), self.isInside);
97
98
99 if self.isRotatable then
100 self.rotateNode = Utils.indexToObject(self.vehicle.components, getXMLString(xmlFile, key .. "#rotateNode"));
101 end;
102 self.allowTranslation = (self.rotateNode ~= nil and self.rotateNode ~= self.cameraNode);
103
104 self.useMirror = Utils.getNoNil(getXMLBool(xmlFile, key .. "#useMirror"), false);
105 self.useWorldXZRotation = getXMLBool(xmlFile, key .. "#useWorldXZRotation"); -- overrides the ingame setting
106 self.resetCameraOnVehicleSwitch = getXMLBool(xmlFile, key .. "#resetCameraOnVehicleSwitch"); -- overrides the ingame setting
107
108 self.positionSmoothingParameter = 0;
109 self.lookAtSmoothingParameter = 0;
110 local useDefaultPositionSmoothing = Utils.getNoNil(getXMLBool(xmlFile, key .. "#useDefaultPositionSmoothing"), true);
111 if useDefaultPositionSmoothing then
112 if self.isInside then
113 self.positionSmoothingParameter = 0.128; -- 0.095;
114 self.lookAtSmoothingParameter = 0.176; -- 0.12;
115 else
116 self.positionSmoothingParameter = 0.016;
117 self.lookAtSmoothingParameter = 0.022;
118 end
119 end
120 self.positionSmoothingParameter = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#positionSmoothingParameter"), self.positionSmoothingParameter);
121 self.lookAtSmoothingParameter = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#lookAtSmoothingParameter"), self.lookAtSmoothingParameter);
122
123 local useHeadTracking = g_gameSettings:getValue("isHeadTrackingEnabled") and isHeadTrackingAvailable() and self.allowHeadTracking
124 if useHeadTracking then
125 self.positionSmoothingParameter = 0;
126 self.lookAtSmoothingParameter = 0;
127 end
128
129 self.cameraPositionNode = self.cameraNode;
130 if self.positionSmoothingParameter > 0 then
131 -- create a node which indicates the target position of the camera
132 self.cameraPositionNode = createTransformGroup("cameraPositionNode");
133 local camIndex = getChildIndex(self.cameraNode);
134 link(getParent(self.cameraNode), self.cameraPositionNode, camIndex);
135 local x,y,z = getTranslation(self.cameraNode);
136 local rx,ry,rz = getRotation(self.cameraNode);
137 setTranslation(self.cameraPositionNode, x,y,z);
138 setRotation(self.cameraPositionNode, rx,ry,rz);
139
140 unlink(self.cameraNode);
141 end;
142 self.rotYSteeringRotSpeed = math.rad(Utils.getNoNil(getXMLFloat(xmlFile, key .. "#rotYSteeringRotSpeed"), 0));
143
144 if self.rotateNode == nil or self.rotateNode == self.cameraNode then
145 self.rotateNode = self.cameraPositionNode;
146 end;
147
148 if useHeadTracking then
149 local dx,_,dz = localDirectionToLocal(self.cameraPositionNode, getParent(self.cameraPositionNode), 0,0,-1);
150 self.headTrackingNode = createTransformGroup("headTrackingNode");
151 link(getParent(self.cameraPositionNode), self.headTrackingNode);
152 setTranslation(self.headTrackingNode, 0,0,0);
153 if math.abs(dx)+math.abs(dz) > 0.0001 then
154 setDirection(self.headTrackingNode, dx, 0, dz, 0,1,0);
155 else
156 setRotation(self.headTrackingNode, 0,0,0);
157 end
158 end
159
160 self.origRotX, self.origRotY, self.origRotZ = getRotation(self.rotateNode);
161 self.rotX = self.origRotX;
162 self.rotY = self.origRotY;
163 self.rotZ = self.origRotZ;
164
165 self.origTransX, self.origTransY, self.origTransZ = getTranslation(self.cameraPositionNode);
166 self.transX = self.origTransX;
167 self.transY = self.origTransY;
168 self.transZ = self.origTransZ;
169
170 local transLength = Utils.vector3Length(self.origTransX, self.origTransY, self.origTransZ);
171 self.zoom = transLength
172 self.zoomTarget = transLength;
173 self.zoomLimitedTarget = -1;
174
175 local trans1OverLength = 1.0/transLength;
176 self.transDirX = trans1OverLength*self.origTransX;
177 self.transDirY = trans1OverLength*self.origTransY;
178 self.transDirZ = trans1OverLength*self.origTransZ;
179 if self.allowTranslation then
180 if transLength <= 0.01 then
181 print("Warning: Invalid camera translation in "..key..". Distance needs to be bigger than 0.01");
182 end
183 end
184
185 table.insert(self.raycastNodes, self.rotateNode);
186 local i=0;
187 while true do
188 local raycastKey = key..string.format(".raycastNode(%d)", i);
189 if not hasXMLProperty(xmlFile, raycastKey) then
190 break;
191 end;
192
193 local node = Utils.indexToObject(self.vehicle.components, getXMLString(xmlFile, raycastKey .. "#index"));
194 if node ~= nil then
195 table.insert(self.raycastNodes, node);
196 end;
197
198 i=i+1;
199 end;
200
201 local sx,sy,sz = getScale(self.cameraNode);
202 if sx ~= 1 or sy ~= 1 or sz ~= 1 then
203 print("Warning: Vehicle camera with scale found in "..self.vehicle.configFileName.." ("..key.."). Resetting to scale 1");
204 setScale(self.cameraNode, 1,1,1);
205 end
206
207 self.headTrackingPositionOffset = {0, 0, 0};
208 self.headTrackingRotationOffset = {0, 0, 0};
209
210 return true;
211end;

delete

Description
Deleting vehicle camera
Definition
delete()
Code
215function VehicleCamera:delete()
216 if self.cameraNode ~= nil and self.positionSmoothingParameter > 0 then
217 delete(self.cameraNode);
218 self.cameraNode = nil
219 end;
220end;

zoomSmoothly

Description
Zoom camera smoothly
Definition
zoomSmoothly(float offset)
Arguments
floatoffsetoffset
Code
225function VehicleCamera:zoomSmoothly(offset)
226 self.zoomTarget = self.zoomTarget+offset;
227 if self.limit then
228 self.zoomTarget = math.min(self.transMax, math.max(self.transMin, self.zoomTarget));
229 end;
230 self.zoomTarget = math.max(self.zoomTarget, 0.01);
231end;

mouseEvent

Description
Mouse event
Definition
mouseEvent(float posX, float posY, boolean isDown, boolean isUp, integer button)
Arguments
floatposXmouse position x (0-1)
floatposYmouse position y (0-1)
booleanisDownbutton is down
booleanisUpbutton is up
integerbuttonacting button
Code
240function VehicleCamera:mouseEvent(posX, posY, isDown, isUp, button)
241 if self.isActivated then
242
243 local translateMode = Input.isMouseButtonPressed(Input.MOUSE_BUTTON_LEFT) or Input.isMouseButtonPressed(Input.MOUSE_BUTTON_RIGHT) or Input.isMouseButtonPressed(Input.MOUSE_BUTTON_MIDDLE);
244 if self.isRotatable and not translateMode then -- only rotate if neither left or right mouse button is pressed
245 local mouseMovementY = InputBinding.mouseMovementY*g_gameSettings:getValue("cameraSensitivity")
246 if g_gameSettings:getValue("invertYLook") then
247 mouseMovementY = -mouseMovementY;
248 end
249 if self.limitRotXDelta > 0.001 then
250 self.rotX = math.min(self.rotX + mouseMovementY, self.rotX);
251 elseif self.limitRotXDelta < -0.001 then
252 self.rotX = math.max(self.rotX + mouseMovementY, self.rotX);
253 else
254 self.rotX = self.rotX + mouseMovementY;
255 end;
256 self.rotY = self.rotY - InputBinding.mouseMovementX*g_gameSettings:getValue("cameraSensitivity");
257 end;
258 end;
259end;

raycastCallback

Description
Raycast callback
Definition
raycastCallback(integer transformId, float x, float y, float z, float distance, float nx, float ny, float nz)
Arguments
integertransformIdid raycasted object
floatxx raycast position
floatyy raycast position
floatzz raycast position
floatdistancedistance to raycast position
floatnxnormal x
floatnynormal y
floatnznormal z
Code
274function VehicleCamera:raycastCallback(transformId, x, y, z, distance, nx, ny, nz)
275 self.raycastDistance = distance;
276 self.normalX = nx;
277 self.normalY = ny;
278 self.normalZ = nz;
279 self.raycastTransformId = transformId;
280end;

update

Description
Update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
285function VehicleCamera:update(dt)
286 local target = self.zoomTarget;
287 if self.zoomLimitedTarget >= 0 then
288 target = math.min(self.zoomLimitedTarget, self.zoomTarget);
289 end;
290 self.zoom = target + math.pow(0.99579, dt)*(self.zoom-target);
291 if self.isActivated and not g_gui:getIsGuiVisible() then
292 if self.isRotatable then
293
294 local rotSpeed = 0.001*dt;
295 local inputW = InputBinding.getDigitalInputAxis(InputBinding.AXIS_LOOK_UPDOWN_VEHICLE);
296 local inputZ = InputBinding.getDigitalInputAxis(InputBinding.AXIS_LOOK_LEFTRIGHT_VEHICLE);
297 if InputBinding.isAxisZero(inputW) then
298 inputW = InputBinding.getAnalogInputAxis(InputBinding.AXIS_LOOK_UPDOWN_VEHICLE);
299 end;
300 if InputBinding.isAxisZero(inputZ) then
301 inputZ = InputBinding.getAnalogInputAxis(InputBinding.AXIS_LOOK_LEFTRIGHT_VEHICLE);
302 end;
303 if g_gameSettings:getValue("invertYLook") then
304 inputW = -inputW;
305 end
306
307 inputW = inputW*g_gameSettings:getValue("cameraSensitivity")
308 inputZ = inputZ*g_gameSettings:getValue("cameraSensitivity")
309
310 if self.limitRotXDelta > 0.001 then
311 self.rotX = math.min(self.rotX - rotSpeed*inputW, self.rotX);
312 elseif self.limitRotXDelta < -0.001 then
313 self.rotX = math.max(self.rotX - rotSpeed*inputW, self.rotX);
314 else
315 self.rotX = self.rotX - rotSpeed*inputW;
316 end;
317 self.rotY = self.rotY - rotSpeed*inputZ;
318 end;
319 end;
320
321 if self.limit then
322 self.rotX = math.min(self.rotMaxX, math.max(self.rotMinX, self.rotX));
323 end;
324
325 if g_gameSettings:getValue("isHeadTrackingEnabled") and isHeadTrackingAvailable() and self.allowHeadTracking and self.headTrackingNode ~= nil then
326 local tx,ty,tz = getHeadTrackingTranslation();
327 local roll,pitch,yaw = getHeadTrackingRotation();
328 if roll ~= nil then
329 pitch = math.max(-math.pi/2, math.min(math.pi/2, pitch));
330 -- roll is dimsissed due to a 'bug' in the trackIr software: https://forums.naturalpoint.com/viewtopic.php?f=60&t=13466&p=61293
331
332 --setRotation(self.headTrackingNode, pitch,yaw,0);
333
334 local camParent = getParent(self.cameraNode);
335 local ctx, cty, ctz = localToLocal(self.headTrackingNode, camParent, tx/100, ty/100, tz/100);
336 local crx, cry, crz = localRotationToLocal(self.headTrackingNode, camParent, pitch,yaw,0);
337
338 setRotation(self.cameraNode, crx, cry, crz);
339 rotateAboutLocalAxis(self.cameraNode, math.pi, 0,1,0);
340
341 setTranslation(self.cameraNode, self.origTransX + ctx, self.origTransY + cty, self.origTransZ - ctz);
342 end
343 else
344
345 self:updateRotateNodeRotation();
346
347
348 if self.limit then
349 -- adjust rotation to avoid clipping with terrain
350 if self.isRotatable and ((self.useWorldXZRotation == nil and g_gameSettings:getValue("useWorldCamera")) or self.useWorldXZRotation) then
351
352 local numIterations = 4;
353 for i=1, numIterations do
354 local transX, transY, transZ = self.transDirX*self.zoom, self.transDirY*self.zoom, self.transDirZ*self.zoom;
355 local x,y,z = localToWorld(getParent(self.cameraPositionNode), transX, transY, transZ);
356
357 local terrainHeight = TipUtil.getHeightAtWorldPos(x,0,z)
358
359 local minHeight = terrainHeight + 0.9;
360 if y < minHeight then
361 local h = math.sin(self.rotX)*self.zoom;
362 local h2 = h-(minHeight-y);
363 self.rotX = math.asin(Utils.clamp(h2/self.zoom, -1, 1));
364 self:updateRotateNodeRotation();
365 else
366 break;
367 end;
368 end;
369 end;
370
371 -- adjust zoom to avoid collision with objects
372 if self.allowTranslation then
373
374 self.limitRotXDelta = 0;
375 local hasCollision, collisionDistance, nx,ny,nz, normalDotDir = self:getCollisionDistance();
376 if hasCollision then
377 local distOffset = 0.1;
378 if normalDotDir ~= nil then
379 local absNormalDotDir = math.abs(normalDotDir)
380 distOffset = Utils.lerp(1.2, 0.1, absNormalDotDir*absNormalDotDir*(3-2*absNormalDotDir));
381 end
382 collisionDistance = math.max(collisionDistance-distOffset, 0.01);
383 self.disableCollisionTime = g_currentMission.time+400;
384 self.zoomLimitedTarget = collisionDistance;
385 if collisionDistance < self.zoom then
386 self.zoom = collisionDistance;
387 end;
388 if self.isRotatable and nx ~= nil and collisionDistance < self.transMin then
389 local lnx,lny,lnz = worldDirectionToLocal(self.rotateNode, nx,ny,nz);
390 if lny > 0.5 then
391 self.limitRotXDelta = 1;
392 elseif lny < -0.5 then
393 self.limitRotXDelta = -1;
394 end;
395 end;
396 else
397 if self.disableCollisionTime <= g_currentMission.time then
398 self.zoomLimitedTarget = -1;
399 end;
400 end;
401 end;
402
403 end;
404 self.transX, self.transY, self.transZ = self.transDirX*self.zoom, self.transDirY*self.zoom, self.transDirZ*self.zoom;
405 setTranslation(self.cameraPositionNode, self.transX, self.transY, self.transZ);
406
407 if self.positionSmoothingParameter > 0 then
408
409 local interpDt = g_physicsDt;
410 if g_server == nil then
411 -- on clients, we interpolate the vehicles with g_physicsDtUnclamped, thus we need to use the same for camera interpolation
412 interpDt = g_physicsDtUnclamped;
413 end
414 if interpDt > 0 then
415 local xlook,ylook,zlook = getWorldTranslation(self.rotateNode);
416 local lookAtPos = self.lookAtPosition;
417 local lookAtLastPos = self.lookAtLastTargetPosition;
418 lookAtPos[1],lookAtPos[2],lookAtPos[3] = self:getSmoothed(self.lookAtSmoothingParameter, lookAtPos[1],lookAtPos[2],lookAtPos[3], xlook,ylook,zlook, lookAtLastPos[1],lookAtLastPos[2],lookAtLastPos[3], interpDt);
419 lookAtLastPos[1],lookAtLastPos[2],lookAtLastPos[3] = xlook,ylook,zlook;
420
421 local x,y,z = getWorldTranslation(self.cameraPositionNode);
422 local pos = self.position;
423 local lastPos = self.lastTargetPosition;
424 pos[1],pos[2],pos[3] = self:getSmoothed(self.positionSmoothingParameter, pos[1],pos[2],pos[3], x,y,z, lastPos[1],lastPos[2],lastPos[3], interpDt)
425 lastPos[1],lastPos[2],lastPos[3] = x,y,z;
426
427 self:setSeparateCameraPose();
428 end
429 end;
430
431 end
432
433end;

getSmoothed

Description
Get smooth camera position
Definition
getSmoothed(float alpha, float curX, float curY, float curZ, float targetX, float targetY, float targetZ, float lastTargetX, float lastTargetY, float lastTargetZ, float dt)
Arguments
floatalphaalpha
floatcurXcurrent x position
floatcurYcurrent y position
floatcurZcurrent z position
floattargetXtarget x position
floattargetYtarget y position
floattargetZtarget z position
floatlastTargetXlast target x position
floatlastTargetYlast target y position
floatlastTargetZlast target z position
floatdttime since last call in ms
Return Values
floatnewXnew x position
floatnewYnew y position
floatnewZnew z position

onActivate

Description
Called on activate
Definition
onActivate()
Code
483function VehicleCamera:onActivate()
484 self.isActivated = true;
485 if (self.resetCameraOnVehicleSwitch == nil and g_gameSettings:getValue("resetCamera")) or self.resetCameraOnVehicleSwitch then
486 self:resetCamera();
487 end
488 setCamera(self.cameraNode);
489
490
491 if self.positionSmoothingParameter > 0 then
492 local xlook,ylook,zlook = getWorldTranslation(self.rotateNode);
493 self.lookAtPosition[1] = xlook;
494 self.lookAtPosition[2] = ylook;
495 self.lookAtPosition[3] = zlook;
496 self.lookAtLastTargetPosition[1] = xlook;
497 self.lookAtLastTargetPosition[2] = ylook;
498 self.lookAtLastTargetPosition[3] = zlook;
499 local x,y,z = getWorldTranslation(self.cameraPositionNode);
500 self.position[1] = x;
501 self.position[2] = y;
502 self.position[3] = z;
503 self.lastTargetPosition[1] = x;
504 self.lastTargetPosition[2] = y;
505 self.lastTargetPosition[3] = z;
506
507
508 local rx,ry,rz = getWorldRotation(self.rotateNode);
509
510 setRotation(self.cameraNode, rx,ry,rz);
511 setTranslation(self.cameraNode, x,y,z);
512 end;
513end;

onDeactivate

Description
Called on deactivate
Definition
onDeactivate()
Code
517function VehicleCamera:onDeactivate()
518 self.isActivated = false;
519end;

resetCamera

Description
Reset camera to original pose
Definition
resetCamera()
Code
523function VehicleCamera:resetCamera()
524 self.rotX = self.origRotX;
525 self.rotY = self.origRotY;
526 self.rotZ = self.origRotZ;
527
528 self.transX = self.origTransX;
529 self.transY = self.origTransY;
530 self.transZ = self.origTransZ;
531
532 local transLength = Utils.vector3Length(self.origTransX, self.origTransY, self.origTransZ);
533 self.zoom = transLength
534 self.zoomTarget = transLength;
535 self.zoomLimitedTarget = -1;
536
537 self:updateRotateNodeRotation();
538 setTranslation(self.cameraPositionNode, self.transX, self.transY, self.transZ);
539
540 if self.positionSmoothingParameter > 0 then
541 local xlook,ylook,zlook = getWorldTranslation(self.rotateNode);
542 self.lookAtPosition[1] = xlook;
543 self.lookAtPosition[2] = ylook;
544 self.lookAtPosition[3] = zlook;
545 local x,y,z = getWorldTranslation(self.cameraPositionNode);
546 self.position[1] = x;
547 self.position[2] = y;
548 self.position[3] = z;
549
550 self:setSeparateCameraPose();
551 end;
552end;

updateRotateNodeRotation

Description
Update rotation node rotation
Definition
updateRotateNodeRotation()
Code
556function VehicleCamera:updateRotateNodeRotation()
557 local rotY = self.rotY;
558 if self.rotYSteeringRotSpeed ~= nil and self.rotYSteeringRotSpeed ~= 0 and self.vehicle.interpolatedRotatedTime ~= nil then
559 rotY = rotY + self.vehicle.interpolatedRotatedTime*self.rotYSteeringRotSpeed;
560 end;
561
562 if (self.useWorldXZRotation == nil and g_gameSettings:getValue("useWorldCamera")) or self.useWorldXZRotation then
563 local upx,upy,upz = 0,1,0;
564
565 local dx,_,dz = localDirectionToWorld(getParent(self.rotateNode), 0,0,1);
566 local invLen = 1/math.sqrt(dx*dx + dz*dz);
567 dx = dx*invLen;
568 dz = dz*invLen;
569
570
571
572 local newDx = math.cos(self.rotX) * (math.cos(rotY)*dx + math.sin(rotY)*dz);
573 local newDy = -math.sin(self.rotX);
574 local newDz = math.cos(self.rotX) * (-math.sin(rotY)*dx + math.cos(rotY)*dz);
575
576
577 newDx,newDy,newDz = worldDirectionToLocal(getParent(self.rotateNode), newDx,newDy,newDz);
578 upx,upy,upz = worldDirectionToLocal(getParent(self.rotateNode), upx,upy,upz);
579
580 -- worst case check
581 if math.abs(Utils.dotProduct(newDx,newDy,newDz, upx,upy,upz)) > ( 0.99 * Utils.vector3Length(newDx,newDy,newDz) * Utils.vector3Length(upx,upy,upz) ) then
582 setRotation(self.rotateNode, self.rotX, rotY, self.rotZ);
583 else
584 setDirection(self.rotateNode, newDx,newDy,newDz, upx,upy,upz);
585 end
586 else
587 setRotation(self.rotateNode, self.rotX, rotY, self.rotZ);
588 end;
589end;

setSeparateCameraPose

Description
Set separate camera pose
Definition
setSeparateCameraPose()
Code
593function VehicleCamera:setSeparateCameraPose()
594 if self.rotateNode ~= self.cameraPositionNode then
595 local dx = self.position[1] - self.lookAtPosition[1];
596 local dy = self.position[2] - self.lookAtPosition[2];
597 local dz = self.position[3] - self.lookAtPosition[3];
598
599 local upx,upy,upz = 0,1,0;
600 if math.abs(dx) < 0.001 and math.abs(dz) < 0.001 then
601 upx = 0.1;
602 end;
603
604 setDirection(self.cameraNode, dx,dy,dz, upx,upy,upz);
605 else
606 local rx,ry,rz = getWorldRotation(self.rotateNode);
607 setRotation(self.cameraNode, rx,ry,rz);
608 end
609 setTranslation(self.cameraNode, self.position[1],self.position[2],self.position[3]);
610end;

getCollisionDistance

Description
Get distance to collision
Definition
getCollisionDistance()
Return Values
booleanhasCollisionhas collision
floatcollisionDistancedistance to collision
floatnormalXnormal x
floatnormalYnormal y
floatnormalZnormal z
floatnormalDotDirnormal dot direction
Code
620function VehicleCamera:getCollisionDistance()
621 if not self.isCollisionEnabled then
622 return false, nil, nil, nil, nil, nil;
623 end
624
625 local raycastMask = 32+64+128+256+4096;
626
627 local targetCamX, targetCamY, targetCamZ = localToWorld(self.rotateNode, self.transDirX*self.zoomTarget, self.transDirY*self.zoomTarget, self.transDirZ*self.zoomTarget);
628
629 local hasCollision = false;
630 local collisionDistance = -1;
631 local normalX,normalY,normalZ;
632 local normalDotDir;
633 for _, raycastNode in ipairs(self.raycastNodes) do
634
635 hasCollision = false;
636
637 local nodeX, nodeY, nodeZ = getWorldTranslation(raycastNode);
638 local dirX, dirY, dirZ = targetCamX-nodeX, targetCamY-nodeY, targetCamZ-nodeZ;
639 local dirLength = Utils.vector3Length(dirX, dirY, dirZ);
640 dirX = dirX / dirLength;
641 dirY = dirY / dirLength;
642 dirZ = dirZ / dirLength;
643
644 local startX = nodeX;
645 local startY = nodeY;
646 local startZ = nodeZ;
647 local currentDistance = 0;
648 local minDistance = self.transMin;
649
650 while (true) do
651 if (dirLength-currentDistance) <= 0 then
652 break;
653 end;
654 self.raycastDistance = 0;
655 raycastClosest(startX, startY, startZ, dirX, dirY, dirZ, "raycastCallback", dirLength-currentDistance, self, raycastMask, true);
656
657 if self.raycastDistance ~= 0 then
658 currentDistance = currentDistance + self.raycastDistance+0.001;
659 local ndotd = Utils.dotProduct(self.normalX, self.normalY, self.normalZ, dirX, dirY, dirZ);
660
661 if self.vehicle.getIsAttachedVehicleNode == nil or self.vehicle.getIsDynamicallyMountedNode == nil then
662 break;
663 end
664
665 if self.vehicle:getIsAttachedVehicleNode(self.raycastTransformId) or self.vehicle:getIsDynamicallyMountedNode(self.raycastTransformId) then
666 if ndotd > 0 then
667 minDistance = math.max(minDistance, currentDistance);
668 end;
669 else
670 hasCollision = true;
671 -- we take the distance from the rotate node
672 if raycastNode == self.rotateNode then
673 normalX,normalY,normalZ = self.normalX, self.normalY, self.normalZ;
674 collisionDistance = math.max(self.transMin, currentDistance);
675 normalDotDir = ndotd
676 end;
677 break;
678 end;
679 startX = nodeX+dirX*currentDistance;
680 startY = nodeY+dirY*currentDistance;
681 startZ = nodeZ+dirZ*currentDistance;
682 else
683 break;
684 end;
685 end;
686 if not hasCollision then
687 break;
688 end;
689 end;
690 return hasCollision, collisionDistance, normalX,normalY,normalZ, normalDotDir;
691end;