Skip to content

Commit

Permalink
Merge pull request #333 from simularium/feature/transform-fibers
Browse files Browse the repository at this point in the history
add translation and rotation to fiber agents
  • Loading branch information
toloudis authored Oct 17, 2023
2 parents cd75a2a + bfacea0 commit b193be3
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 6 deletions.
2 changes: 2 additions & 0 deletions examples/CurveSimulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,6 @@ export default class CurveSim implements IClientSimulatorImpl {
},
};
}

updateSimulationState(data: Record<string, unknown>) {}
}
2 changes: 2 additions & 0 deletions examples/MetaballSimulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,6 @@ export default class MetaballSimulator implements IClientSimulatorImpl {
},
};
}

updateSimulationState(data: Record<string, unknown>) {}
}
2 changes: 2 additions & 0 deletions examples/PdbSimulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,6 @@ export default class PdbSim implements IClientSimulatorImpl {
},
};
}

updateSimulationState(data: Record<string, unknown>) {}
}
2 changes: 2 additions & 0 deletions examples/PointSimulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,6 @@ export default class PointSim implements IClientSimulatorImpl {
},
};
}

updateSimulationState(data: Record<string, unknown>) {}
}
160 changes: 160 additions & 0 deletions examples/SingleCurveSimulator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import {
IClientSimulatorImpl,
ClientMessageEnum,
} from "../src/simularium/localSimulators/IClientSimulatorImpl";
import {
EncodedTypeMapping,
TrajectoryFileInfo,
VisDataMessage,
} from "../src/simularium/types";
import VisTypes from "../src/simularium/VisTypes";
import { DEFAULT_CAMERA_SPEC } from "../src/constants";

export default class SingleCurveSim implements IClientSimulatorImpl {
curveData: number[];
nPointsPerCurve: number;
currentFrame: number;

constructor() {
this.nPointsPerCurve = 5;
this.curveData = this.makeCurveBundle(1, this.nPointsPerCurve);
this.currentFrame = 0;
}

private randomFloat(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return Math.random() * (max - min) + min;
}

private randomSpherePoint(x0, y0, z0, radius): number[] {
const u = Math.random();
const v = Math.random();
const theta = 2 * Math.PI * u;
const phi = Math.acos(2 * v - 1);
const x = x0 + radius * Math.sin(phi) * Math.cos(theta);
const y = y0 + radius * Math.sin(phi) * Math.sin(theta);
const z = z0 + radius * Math.cos(phi);
return [x, y, z];
}
private randomPtInBox(xmin, xmax, ymin, ymax, zmin, zmax) {
return [
this.randomFloat(xmin, xmax),
this.randomFloat(ymin, ymax),
this.randomFloat(zmin, zmax),
];
}

private makeCurveBundle() {
// make one curve w/5 pts
const curves: number[] = [];
let p: number[];
p = this.randomPtInBox(-4, -3, -2, 2, -2, 2);
curves.push(p[0]);
curves.push(p[1]);
curves.push(p[2]);
p = this.randomPtInBox(-2.5, -2, -1, 1, -1, 1);
curves.push(p[0]);
curves.push(p[1]);
curves.push(p[2]);
p = this.randomPtInBox(-1, 1, -0.5, 0.5, -0.5, 0.5);
curves.push(p[0]);
curves.push(p[1]);
curves.push(p[2]);
p = this.randomPtInBox(2, 2.5, -1, 1, -1, 1);
curves.push(p[0]);
curves.push(p[1]);
curves.push(p[2]);
p = this.randomPtInBox(3, 4, -2, 2, -2, 2);
curves.push(p[0]);
curves.push(p[1]);
curves.push(p[2]);
return curves;
}

public update(_dt: number): VisDataMessage {
const nFloatsPerCurve = this.nPointsPerCurve * 3;
//const dt_adjusted = dt / 1000;
const amplitude = 0.05;
for (let jj = 0; jj < this.nPointsPerCurve; ++jj) {
this.curveData[jj * 3 + 0] += this.randomFloat(
-amplitude,
amplitude
);
this.curveData[jj * 3 + 1] += this.randomFloat(
-amplitude,
amplitude
);
this.curveData[jj * 3 + 2] += this.randomFloat(
-amplitude,
amplitude
);
}
// fill agent data.
const agentData: number[] = [];
agentData.push(VisTypes.ID_VIS_TYPE_FIBER); // vis type
agentData.push(0); // instance id
agentData.push(0); // type
agentData.push(3.0 * Math.sin(this.currentFrame / 50)); // x
agentData.push(0); // y
agentData.push(0); // z
agentData.push(0); // rx
agentData.push(0); // ry
agentData.push(this.currentFrame / 50); // rz
agentData.push(0.3); // collision radius
agentData.push(nFloatsPerCurve);
for (let jj = 0; jj < nFloatsPerCurve; ++jj) {
agentData.push(this.curveData[jj]);
}

const frameData: VisDataMessage = {
// TODO get msgType and connId out of here
msgType: ClientMessageEnum.ID_VIS_DATA_ARRIVE,
bundleStart: this.currentFrame,
bundleSize: 1, // frames
bundleData: [
{
data: agentData,
frameNumber: this.currentFrame,
time: this.currentFrame,
},
],
fileName: "hello world",
};
this.currentFrame++;
return frameData;
}

public getInfo(): TrajectoryFileInfo {
const typeMapping: EncodedTypeMapping = {};
typeMapping[0] = { name: "fiber0" };
return {
// TODO get msgType and connId out of here
connId: "hello world",
msgType: ClientMessageEnum.ID_TRAJECTORY_FILE_INFO,
version: 2,
timeStepSize: 1,
totalSteps: 1000,
// bounding volume dimensions
size: {
x: 12,
y: 12,
z: 12,
},
cameraDefault: DEFAULT_CAMERA_SPEC,
typeMapping: typeMapping,
spatialUnits: {
magnitude: 1,
name: "m",
},
timeUnits: {
magnitude: 1,
name: "s",
},
};
}

updateSimulationState(data: Record<string, unknown>) {}
}
9 changes: 9 additions & 0 deletions examples/Viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import PointSimulatorLive from "./PointSimulatorLive";
import PdbSimulator from "./PdbSimulator";
import SinglePdbSimulator from "./SinglePdbSimulator";
import CurveSimulator from "./CurveSimulator";
import SingleCurveSimulator from "./SingleCurveSimulator";
import ColorPicker from "./ColorPicker";
import {
SMOLDYN_TEMPLATE,
Expand Down Expand Up @@ -536,6 +537,13 @@ class Viewer extends React.Component<InputParams, ViewerState> {
},
playbackFile
);
} else if (playbackFile === "TEST_SINGLE_FIBER") {
simulariumController.changeFile(
{
clientSimulator: new SingleCurveSimulator(),
},
playbackFile
);
} else if (playbackFile === "TEST_PDB") {
simulariumController.changeFile(
{
Expand Down Expand Up @@ -671,6 +679,7 @@ class Viewer extends React.Component<InputParams, ViewerState> {
</option>
<option value="TEST_SINGLE_PDB">TEST SINGLE PDB</option>
<option value="TEST_PDB">TEST PDB</option>
<option value="TEST_SINGLE_FIBER">TEST SINGLE FIBER</option>
<option value="TEST_FIBERS">TEST FIBERS</option>
<option value="TEST_POINTS">TEST POINTS</option>
<option value="TEST_METABALLS">TEST METABALLS</option>
Expand Down
13 changes: 7 additions & 6 deletions src/visGeometry/VisAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,18 @@ export default class VisAgent {
}

public getFollowPosition(): Vector3 {
const pos = new Vector3(
this.agentData.x,
this.agentData.y,
this.agentData.z
);
if (
this.agentData["vis-type"] === VisTypes.ID_VIS_TYPE_FIBER &&
this.fiberCurve
) {
return this.fiberCurve.getPoint(0.5);
return this.fiberCurve.getPoint(0.5).add(pos);
} else {
return new Vector3(
this.agentData.x,
this.agentData.y,
this.agentData.z
);
return pos;
}
}
}
3 changes: 3 additions & 0 deletions src/visGeometry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,9 @@ class VisGeometry {
agentData.y,
agentData.z,
agentData.cr * scale * 0.5,
agentData.xrot,
agentData.yrot,
agentData.zrot,
visAgent.agentData.instanceId,
visAgent.signedTypeId()
);
Expand Down
27 changes: 27 additions & 0 deletions src/visGeometry/rendering/InstancedFiber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import {
BufferAttribute,
BufferGeometry,
CylinderGeometry,
Euler,
InstancedBufferAttribute,
InstancedBufferGeometry,
Mesh,
Quaternion,
DataTexture,
RGBAFormat,
FloatType,
Expand All @@ -21,6 +23,9 @@ import {
updateProjectionMatrix,
} from "./MultipassMaterials";

const tmpQuaternion = new Quaternion();
const tmpEuler = new Euler();

function createTubeGeometry(
numSides = 8,
subdivisions = 50,
Expand Down Expand Up @@ -128,6 +133,7 @@ class InstancedFiber {
private instancedGeometry: InstancedBufferGeometry;

private positionAttribute: InstancedBufferAttribute; // x,y,z,scale
private rotationAttribute: InstancedBufferAttribute; // quaternion
private instanceAttribute: InstancedBufferAttribute; // instance id, type id (color index)

// holds control points for all the curves
Expand Down Expand Up @@ -156,6 +162,10 @@ class InstancedFiber {
Uint8Array.from([]),
1
);
this.rotationAttribute = new InstancedBufferAttribute(
Uint8Array.from([]),
1
);
this.instanceAttribute = new InstancedBufferAttribute(
Uint8Array.from([]),
1
Expand Down Expand Up @@ -242,6 +252,11 @@ class InstancedFiber {
this.positionAttribute
);

const newRot = new Float32Array(4 * n);
newRot.set(this.rotationAttribute.array);
this.rotationAttribute = new InstancedBufferAttribute(newRot, 4, false);
this.instancedGeometry.setAttribute("rotation", this.rotationAttribute);

const newInst = new Float32Array(3 * n);
newInst.set(this.instanceAttribute.array);
this.instanceAttribute = new InstancedBufferAttribute(
Expand Down Expand Up @@ -290,12 +305,17 @@ class InstancedFiber {
y: number,
z: number,
scale: number,
rx: number,
ry: number,
rz: number,
uniqueAgentId: number,
typeId: number
): void {
const offset = this.currentInstance;
this.checkRealloc(this.currentInstance + 1);
this.positionAttribute.setXYZW(offset, x, y, z, scale);
const q = tmpQuaternion.setFromEuler(tmpEuler.set(rx, ry, rz));
this.rotationAttribute.setXYZW(offset, q.x, q.y, q.z, q.w);
this.instanceAttribute.setXYZ(
offset,
uniqueAgentId,
Expand All @@ -320,6 +340,7 @@ class InstancedFiber {
// assumes the entire buffers are invalidated.
this.instanceAttribute.needsUpdate = true;
this.positionAttribute.needsUpdate = true;
this.rotationAttribute.needsUpdate = true;
this.curveData.needsUpdate = true;
this.isUpdating = false;
}
Expand Down Expand Up @@ -373,6 +394,9 @@ class InstancedFiberGroup {
y: number,
z: number,
scale: number,
rx: number,
ry: number,
rz: number,
uniqueAgentId: number,
typeId: number
): void {
Expand All @@ -386,6 +410,9 @@ class InstancedFiberGroup {
y,
z,
scale,
rx,
ry,
rz,
uniqueAgentId,
typeId
);
Expand Down
7 changes: 7 additions & 0 deletions src/visGeometry/rendering/InstancedFiberShader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ in vec2 uv;
// per instance attributes
in vec4 translateAndScale; // xyz trans, w scale
in vec4 rotation; // quaternion
// instanceID, typeId, and which row of texture contains this curve
in vec3 instanceAndTypeId;
Expand Down Expand Up @@ -305,6 +306,10 @@ void createTube (float t, vec2 volume, out vec3 offset, out vec3 normal) {
}
#endif
vec3 applyQuaternionToVector( vec4 q, vec3 v ) {
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}
void main() {
// load the curve
for (int i = 0; i < NUM_POINTS; ++i) {
Expand All @@ -329,6 +334,8 @@ void main() {
// vUv = uv.yx; // swizzle this to match expectations
// project our vertex position
transformed = applyQuaternionToVector(rotation, transformed);
transformed += translateAndScale.xyz;
vec4 mvPosition = modelViewMatrix * vec4(transformed, 1.0);
IN_viewPos = mvPosition.xyz;
Expand Down

0 comments on commit b193be3

Please sign in to comment.