Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partially refactor JS utilities to support future webapps in separate folder structure #1364

Merged
merged 6 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/esp/bindings_js/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ if(BUILD_WEB_APPS)
modules/test_page.js
modules/vr_demo.js
modules/utils.js
modules/vr_utils.js
)

add_custom_command(
Expand Down
8 changes: 6 additions & 2 deletions src/esp/bindings_js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
import WebDemo from "./modules/web_demo";
import VRDemo from "./modules/vr_demo";
import ViewerDemo from "./modules/viewer_demo";
import { defaultScene, defaultPhysicsConfigFilepath } from "./modules/defaults";
import {
defaultScene,
defaultPhysicsConfigFilepath,
infoSemanticFileName
} from "./modules/defaults";
import "./bindings.css";
import {
checkWebAssemblySupport,
Expand Down Expand Up @@ -58,7 +62,7 @@ Module.preRun.push(() => {
preload(fileNoExtension + ".house");
preload(fileNoExtension + "_semantic.ply");
} else if (config.semantic === "replica") {
preload(getInfoSemanticUrl(config.scene));
preload(getInfoSemanticUrl(config.scene, infoSemanticFileName));
}
});

Expand Down
4 changes: 1 addition & 3 deletions src/esp/bindings_js/modules/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { infoSemanticFileName } from "./defaults";

// Copyright (c) Facebook, Inc. and its affiliates.
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
Expand Down Expand Up @@ -81,7 +79,7 @@ export function checkWebgl2Support() {
}
}

export function getInfoSemanticUrl(mainUrl) {
export function getInfoSemanticUrl(mainUrl, infoSemanticFileName) {
const splits = mainUrl.split("/");
const moreThanOne = splits.length > 1;
splits.pop();
Expand Down
199 changes: 199 additions & 0 deletions src/esp/bindings_js/modules/vr_utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Copyright (c) Facebook, Inc. and its affiliates.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any code redundancy between this file and the existing vr_demo.js?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, see here: #1364 (comment)

The existing vr_demo.js will be deleted in #1366, so this redundancy will be resolved as soon as that PR gets merged.

// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.

/* global Module */

export const VIEW_SENSORS = ["left_eye", "right_eye"];
const pointToArray = p => [p.x, p.y, p.z, p.w];

export function getEyeSensorSpecs(resolutionWidth, resolutionHeight) {
const specs = new Module.VectorSensorSpec();
{
const spec = new Module.CameraSensorSpec();
spec.uuid = "left_eye";
spec.sensorType = Module.SensorType.COLOR;
spec.sensorSubType = Module.SensorSubType.PINHOLE;
spec.resolution = [resolutionWidth, resolutionHeight];
specs.push_back(spec);
}
{
const spec = new Module.CameraSensorSpec();
spec.uuid = "right_eye";
spec.sensorType = Module.SensorType.COLOR;
spec.sensorSubType = Module.SensorSubType.PINHOLE;
spec.resolution = [resolutionWidth, resolutionHeight];
specs.push_back(spec);
}
return specs;
}

// Given the WebXR viewer pose, update the positions/orientations of the view
// sensors
export function updateHeadPose(pose, agent) {
const FWD = Module.Vector3.zAxis(1);
const FWD_ANGLE = Math.atan2(FWD.z(), FWD.x());
const DOWN = Module.Vector3.yAxis(-1);
const viewYawOffset = 0;

const headRotation = Module.toQuaternion(
pointToArray(pose.transform.orientation)
);
const pointingVec = headRotation.transformVector(FWD);
const pointingAngle =
Math.atan2(pointingVec.z(), pointingVec.x()) - FWD_ANGLE;

const agentQuat = Module.Quaternion.rotation(
new Module.Rad(pointingAngle + viewYawOffset),
DOWN
);
const inverseAgentRot = Module.Quaternion.rotation(
new Module.Rad(-pointingAngle),
DOWN
);

let state = new Module.AgentState();
agent.getState(state);
state.rotation = Module.toVec4f(agentQuat);
agent.setState(state, false);

for (var iView = 0; iView < pose.views.length; ++iView) {
const view = pose.views[iView];

const sensor = agent.getSubtreeSensors().get(VIEW_SENSORS[iView]);

const pos = pointToArray(view.transform.position).slice(0, -1); // don't need w for position
sensor.setLocalTransform(
Module.toVec3f(
inverseAgentRot.transformVector(new Module.Vector3(...pos))
),
Module.toVec4f(
Module.Quaternion.mul(
inverseAgentRot,
Module.toQuaternion(pointToArray(view.transform.orientation))
)
)
);
}
}

// GL stuff
let inds = null;
let tex = null;

// Pass in an html element with a webgl context
export function initGL(gl) {
if (gl === null) {
return null;
}
const vertSrc =
"attribute vec3 p;attribute vec2 u;varying highp vec2 v;void main(){gl_Position=vec4(p,1);v=u;}";
const fragSrc =
"uniform sampler2D t;varying highp vec2 v;void main(){gl_FragColor=texture2D(t,v);}";

// Compiles a GLSL shader. Returns null on failure
function compileShader(gl, src, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);

if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
return shader;
} else {
console.error("GLSL shader error: " + gl.getShaderInfoLog(shader));
return null;
}
}
const vert = compileShader(gl, vertSrc, gl.VERTEX_SHADER);
const frag = compileShader(gl, fragSrc, gl.FRAGMENT_SHADER);
if (vert === null || frag === null) {
console.log("Failed to compile shaders");
return null;
}

const program = gl.createProgram();

gl.attachShader(program, vert);
gl.attachShader(program, frag);

gl.linkProgram(program);

if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error("GLSL program error:" + gl.getProgramInfoLog(program));
return null;
}

gl.useProgram(program);

// Vertices
const verts = [
-1.0,
1.0,
0.0,
-1.0,
-1.0,
0.0,
1.0,
-1.0,
0.0,
1.0,
1.0,
0.0
];
const vertBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
// Position attribute
const posAttrib = gl.getAttribLocation(program, "p");
gl.vertexAttribPointer(posAttrib, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(posAttrib);

// UVs
const UVs = [0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0];
const uvBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, uvBuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(UVs), gl.STATIC_DRAW);
// UV attribute
const uvAttrib = gl.getAttribLocation(program, "u");
gl.vertexAttribPointer(uvAttrib, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(uvAttrib);

// Indices
inds = [3, 2, 1, 3, 1, 0];
const indBuf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indBuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(inds), gl.STATIC_DRAW);

// Texture uniform
const texUni = gl.getUniformLocation(program, "t");
gl.uniform1i(texUni, 0);
}

export function drawTextureData(gl, texRes, texData) {
if (tex === null) {
tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
}

gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(
gl.TEXTURE_2D,
0, // level
gl.RGBA, // internal format
texRes[1], // width
texRes[0], // height
0, // border
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
new Uint8Array(texData) // data
);

gl.activeTexture(gl.TEXTURE0);

gl.drawElements(gl.TRIANGLES, inds.length, gl.UNSIGNED_SHORT, 0);
}
5 changes: 4 additions & 1 deletion src/esp/bindings_js/tests/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getInfoSemanticUrl,
buildConfigFromURLParameters
} from "../modules/utils";
import { infoSemanticFileName } from "../modules/defaults";

test("throttle should work properly", () => {
let count = 0;
Expand Down Expand Up @@ -48,7 +49,9 @@ test("info semantic.json should have correct path", () => {
];

scenePaths.forEach((item, index) => {
expect(getInfoSemanticUrl(item)).toEqual(expectedInfoPaths[index]);
expect(getInfoSemanticUrl(item, infoSemanticFileName)).toEqual(
expectedInfoPaths[index]
);
});
});

Expand Down