content/hifi-content/luis/domainUtils/SoccerDomain/cameraRig.js
2022-02-14 02:04:11 +01:00

310 lines
No EOL
14 KiB
JavaScript

//
// Created by Luis Cuenca on 10/27/18
// Copyright 2018 High Fidelity, Inc.
//
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
/* jslint bitwise: true */
/* global Script, Overlays, Controller, Entities, MyAvatar, Quat, Vec3, AvatarList, Tablet, Render
*/
(function() {
var shown = false;
// ["{0b3f7741-9d91-4313-a01c-e857f68d71a0}", "{90143a7c-c83f-4ab7-b208-df4826ed03b1}", "{c15b9c1b-2d7a-4003-a23d-e10c74e47dfc}","{139ca1f2-7f7c-4238-a5ac-8b2f97a20853}"];
var fieldID = "{dbb98a91-749b-4681-a465-1767776d0313}";
var fieldProps = Entities.getEntityProperties(fieldID, ["position", "dimensions"]);
var fieldPosition = fieldProps.position;
var fieldDimensions = fieldProps.dimensions;
var monitorsIDs = Entities.findEntitiesByName("Monitor", fieldPosition, 1.5 * Math.max(fieldDimensions.x, fieldDimensions.z));
var ballIDs = Entities.findEntitiesByName("Soccer Ball", fieldPosition, 1.5 * Math.max(fieldDimensions.x, fieldDimensions.z));
var createMonitors = false;
var spectatorCameraConfig = Render.getConfig("SecondaryCamera");
var camera;
var cameraPosition;
var cameraRotation;
var CAMERA_FOLLOW_ENTITY = 0;
var CAMERA_FOLLOW_AVATAR = 1;
var CAMERA_CONSTRAINT_NONE = 0;
var CAMERA_CONSTRAINT_POINT = 1;
var CAMERA_CONSTRAINT_LINE = 2;
var CAMERA_CONSTRAINT_PLANE = 3;
var cameraRig;
var CameraFollow = function(type, id) {
this.type = type;
this.id = id;
}
var CameraConstraint = function(type, vector){
var self = this;
this.type = type;
this.vector = Vec3.normalize(vector);
this.uVector;
this.vVector;
this.calculatePlaneUV = function() {
if (vector.x === 0 && vector.y === 1 && vector.z === 0) {
self.uVector = {x: 1, y: 0, z: 0};
self.vVector = {x: 0, y: 0, z: 1};
} else {
self.vVector = Vec3.normalize(Vec3.cross(self.vector, {x: 1, y: 0, z: 0}));
self.uVector = Vec3.normalize(Vec3.cross(self.vVector, self.vector));
}
}
if (type === CAMERA_CONSTRAINT_PLANE) {
self.calculatePlaneUV();
}
}
var CameraNode = function(position, orientation, constraint, follows) {
var self = this;
this.follows = follows;
this.constraint = constraint;
this.followPoint;
this.position = position;
this.orientation = orientation;
this.distanceVector;
this.velocityVector;
this.computeFollowPoint = function() {
self.followPoint = Vec3.Zero;
for (var i = 0; i < self.follows.length; i++) {
var follow = self.follows[i];
if (follow.type === CAMERA_FOLLOW_AVATAR) {
self.followPoint = Vec3.sum(self.followPoint, AvatarList.getAvatar(follow.id).position);
} else if (follow.type === CAMERA_FOLLOW_ENTITY) {
self.followPoint = Vec3.sum(self.followPoint, Entities.getEntityProperties(follow.id, ["position"]).position);
}
self.followPoint = Vec3.multiply(self.followPoint, 1.0/self.follows.length);
}
}
this.computePosition = function() {
self.distanceVector = Vec3.subtract(self.followPoint, self.position);
if (self.constraint.type != CAMERA_CONSTRAINT_POINT) {
if (self.constraint.type === CAMERA_CONSTRAINT_NONE) {
self.velocityVector = 0.2 * self.distanceVector;
} else if (self.constraint.type === CAMERA_CONSTRAINT_LINE) {
self.velocityVector = Vec3.multiply(self.constraint.vector, 0.01 * Vec3.dot(self.distanceVector, self.constraint.vector));
} else if (self.constraint.type === CAMERA_CONSTRAINT_PLANE) {
var uvec = Vec3.multiply(self.constraint.uVector ,0.01 * Vec3.dot(self.distanceVector, self.constraint.uVector));
var vvec = Vec3.multiply(self.constraint.vVector ,0.01 * Vec3.dot(self.distanceVector, self.constraint.vVector));
self.velocityVector = Vec3.sum(uvec, vvec);
}
}
self.position = Vec3.sum(self.position, self.velocityVector);
}
this.computeOrientation = function() {
self.distanceVector = Vec3.subtract(self.followPoint, self.position);
var lookAtVector = Vec3.normalize(self.distanceVector);
self.orientation = Quat.lookAtSimple({x:0, y:0, z:0}, lookAtVector);
}
this.update = function() {
self.computeFollowPoint();
self.computePosition();
self.computeOrientation();
}
}
var Monitor = function(entityID, position, rotation, dimensions) {
var self = this;
this.position = position;
this.rotation = rotation;
this.dimensions = dimensions;
this.entityID = entityID;
this.overlayID;
this.created = false;
this.remove = function() {
if (self.entityID && self.created) {
Entities.deleteEntity(self.entityID);
}
if (self.overlayID) {
Overlays.deleteOverlay(self.overlayID);
}
}
this.create = function() {
self.remove();
if (!self.entityID) {
self.entityID = Entities.addEntity({
name: "Monitor",
type: "Box",
dimensions: self.dimensions,
position: self.position,
rotation: self.rotation
})
self.created = true;
} else {
var props = Entities.getEntityProperties(self.entityID, ["dimensions", "position", "rotation"]);
self.dimensions = props.dimensions;
self.position = props.position;
self.rotation = props.rotation;
}
var overlayDimensions = { x: self.dimensions.x, y: self.dimensions.x, z: 0.0};
self.overlayID = Overlays.addOverlay("image3d", {
url: "resource://spectatorCameraFrame",
emissive: true,
parentID: self.entityID,
localRotation: { w: 0, x: 0, y: 0, z: 1.0 },
localPosition: { x: 0.0, y: 0.0, z: -0.6 * self.dimensions.z },
alpha: 1,
dimensions: overlayDimensions
});
}
self.create();
}
var CameraRig = function(length, width, monitorLength, yOffset) {
var self = this;
this.length = length;
this.width = width;
this.cameraRotation;
this.cameraPosition;
this.cameraNodes = [];
this.monitors = [];
this.emitIndex = 0;
this.monitorDimensions = { x: monitorLength, y: 0.66 * monitorLength, z: 0.03 * monitorLength };
this.frontVector = {x: 1, y: 0, z: 0};
this.backVector = {x: -1, y: 0, z: 0};
this.rightVector = {x: 0, y: 0, z: 1};
this.leftVector = {x: 0, y: 0, z: -1};
this.offset = {x: 0, y: yOffset, z: 0};
/*
this.frontVector = Quat.getFront(MyAvatar.orientation);
this.backVector = Vec3.multiply(self.frontVector, -1);
this.rightVector = Quat.getRight(MyAvatar.orientation);
this.leftVector = Vec3.multiply(self.rightVector, -1);
*/
this.changeCount = 500;
this.changeTimer = 0;
this.createRig = function() {
var follow = new CameraFollow(CAMERA_FOLLOW_ENTITY, ballIDs[0]);
var constraint1 = new CameraConstraint(CAMERA_CONSTRAINT_LINE, self.rightVector);
var position1 = Vec3.sum(Vec3.sum(self.center, Vec3.multiply(self.frontVector, 10.0)), {x: 0, y: 2.0, z: 0});
var orientation1 = Quat.lookAtSimple({x:0, y:0, z:0}, self.leftVector);
var node1 = new CameraNode(position1, orientation1, constraint1, [follow]);
var constraint2 = new CameraConstraint(CAMERA_CONSTRAINT_PLANE, Vec3.sum(self.frontVector, {x: 0, y: 5, z: 0}));
var position2 = Vec3.sum(Vec3.sum(self.center, Vec3.multiply(self.frontVector, 10.0)), {x: 0, y: 5.0, z: 0});
var orientation2 = Quat.lookAtSimple({x:0, y:0, z:0}, self.backVector);
var node2 = new CameraNode(position2, orientation2, constraint2, [follow]);
var constraint3 = new CameraConstraint(CAMERA_CONSTRAINT_LINE, Vec3.sum(self.rightVector, self.frontVector));
var position3 = Vec3.sum(self.center, {x: 0, y: 0.5, z: 0});
var orientation3 = Quat.lookAtSimple({x:0, y:0, z:0}, self.leftVector);
var node3 = new CameraNode(position3, orientation3, constraint3, [follow]);
self.cameraNodes.push(node1);
self.cameraNodes.push(node2);
self.cameraNodes.push(node3);
}
this.createMonitors = function() {
if (createMonitors) {
var centerPosition = Vec3.sum(MyAvatar.position, self.offset);
centerPosition.y += 0.5 * (self.monitorDimensions.y - MyAvatar.getHeight());
var pos1 = Vec3.sum(centerPosition, Vec3.multiply(self.frontVector, 0.5 * self.length));
var pos2 = Vec3.sum(centerPosition, Vec3.multiply(self.rightVector, 0.5 * self.width));
var pos3 = Vec3.sum(centerPosition, Vec3.multiply(self.backVector, 0.5 * self.length));
var pos4 = Vec3.sum(centerPosition, Vec3.multiply(self.leftVector, 0.5 * self.width));
var ori1 = Quat.lookAtSimple({x:0, y:0, z:0}, Vec3.multiply(self.frontVector, -1));
var ori2 = Quat.lookAtSimple({x:0, y:0, z:0}, Vec3.multiply(self.rightVector, -1));
var ori3 = Quat.lookAtSimple({x:0, y:0, z:0}, Vec3.multiply(self.backVector, -1));
var ori4 = Quat.lookAtSimple({x:0, y:0, z:0}, Vec3.multiply(self.leftVector, -1));
self.monitors.push(new Monitor(undefined, pos1, ori1, self.monitorDimensions));
self.monitors.push(new Monitor(undefined, pos2, ori2, self.monitorDimensions));
self.monitors.push(new Monitor(undefined, pos3, ori3, self.monitorDimensions));
self.monitors.push(new Monitor(undefined, pos4, ori4, self.monitorDimensions));
} else {
for (var i = 0; i < monitorsIDs.length; i++) {
self.monitors.push(new Monitor(monitorsIDs[i]));
}
}
if (!fieldPosition) {
self.center = {x: 0, y: 0, z: 0};
for (var i = 0; i < self.monitors.length; i++) {
self.center = Vec3.sum(self.center, self.monitors[i].position);
}
self.center = Vec3.multiply(self.center, 1.0/self.monitors.length);
} else {
self.center = fieldPosition;
}
}
this.create = function() {
self.createMonitors();
self.createRig();
}
this.cleanup = function() {
for (var i = 0; i < self.monitors.length; i++) {
self.monitors[i].remove();
}
self.monitors = [];
}
this.emitFromCamera = function(index) {
if (index < self.cameraNodes.length) {
self.emitIndex = index;
}
}
this.update = function() {
self.changeTimer += 1;
if (self.emitIndex < self.cameraNodes.length) {
for (var i = 0; i < self.cameraNodes.length; i++) {
self.cameraNodes[i].update();
}
spectatorCameraConfig.setPosition(self.cameraNodes[self.emitIndex].position);
spectatorCameraConfig.setOrientation(self.cameraNodes[self.emitIndex].orientation);
}
if (self.changeTimer > self.changeCount) {
self.changeTimer = 0;
self.emitIndex = self.emitIndex + 1 >= self.cameraNodes.length ? 0 : self.emitIndex + 1;
ballIDs = Entities.findEntitiesByName("Soccer Ball", fieldPosition, 1.5 * Math.max(fieldDimensions.x, fieldDimensions.z));
}
self.emitFromCamera(self.emitIndex);
}
self.create();
}
function spectatorCameraOn() {
spectatorCameraConfig.enableSecondaryCameraRenderConfigs(true);
spectatorCameraConfig.resetSizeSpectatorCamera(Window.innerWidth, Window.innerHeight);
cameraRig = new CameraRig(45, 90, 20.0, 3.0);
}
function spectatorCameraOff() {
spectatorCameraConfig.attachedEntityId = false;
spectatorCameraConfig.enableSecondaryCameraRenderConfigs(false);
if (cameraRig) {
cameraRig.cleanup();
}
}
function shutdownTabletApp() {
spectatorCameraOff();
}
function onDomainChanged() {
spectatorCameraOff();
}
spectatorCameraOn();
Script.scriptEnding.connect(shutdownTabletApp);
Script.update.connect(function() {
if (cameraRig) {
cameraRig.update();
}
});
Window.domainChanged.connect(onDomainChanged);
})()