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

Pass lights into the shader in drawObject.ts. #11

Merged
merged 9 commits into from
May 3, 2018
62 changes: 51 additions & 11 deletions src/renderer/commands/drawObject.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// tslint:disable-next-line:import-name
import REGL = require('regl');
import { range } from 'lodash';

// tslint:disable:no-unsafe-any

Expand Down Expand Up @@ -33,11 +34,21 @@ export interface DrawObjectProps {
}

/*
* Shader to draw a single object with Phong shading to the screen
* Shader to draw a single object with Phong shading to the screen.
*
* @param {REGL.regl} regl: The regl object we're drawing.
Copy link
Member

Choose a reason for hiding this comment

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

nit: regl is like a factory to build a function to draw an object rather than the object being drawn

* @param {number} numLights: The number of light points we want filled.
* @param {number} maxLights: The maximum number of light points that may exist.
*/
export function drawObject(
regl: REGL.regl
regl: REGL.regl,
numLights: number = 1,
Copy link
Member

Choose a reason for hiding this comment

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

Do you think we can make numLights be a prop we pass in? so like the regl.prop( ... ) things from before. regl.prop('something') is a shortcut for (context, props, batchId) => props['something'], so we can maybe use a function like that to do the numLights assertion

maxLights: number = 1
): REGL.DrawCommand<REGL.DefaultContext, DrawObjectProps> {
if (numLights > maxLights) {
throw new RangeError('numLights must be less than or equal to maxLights.');
Copy link
Member

Choose a reason for hiding this comment

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

Can we put the actual number of lights at the end of the error message? And maybe the requested number of lights?
I'm not sure if it's bad practice to make the error message dynamic like that, but I think it would be useful to have
"numLights (24) must be less than or equal to maxLights (20)"

}

return regl<Uniforms, Attributes, DrawObjectProps>({
vert: `
precision mediump float;
Expand All @@ -64,7 +75,7 @@ export function drawObject(
frag: `
precision mediump float;

const int MAX_LIGHTS = 1; // TODO(davepagurek) [#10] Increase this to allow more lights
const int MAX_LIGHTS = ${maxLights};

varying vec3 vertexPosition;
varying vec3 vertexNormal;
Expand Down Expand Up @@ -108,15 +119,44 @@ export function drawObject(
projection: regl.prop('projectionMatrix'),
view: regl.prop('cameraTransform'),
model: regl.prop('model'),
numLights: 1, // Note: must be <= MAX_LIGHTS in the shader

// TODO(davepagurek): [#10] When we increase MAX_LIGHTS, Regl will expect a property
// in this object for each array element, even if less than MAX_LIGHTS lights are
// passed in, so the rest will have to be filled with zeroed data
'lightPositions[0]': [10, 10, 10],
'lightIntensities[0]': 256,
'lightColors[0]': [1, 1, 1]
numLights: numLights,
...buildLightMetadata(numLights, maxLights)
Copy link
Member

Choose a reason for hiding this comment

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

Can we also add information about lights to the parameters that get passed in? so like defining an interface for a light containing a position, intensity, and color that you can use when building metadata instead of always using multiple copies of the hardcoded light I had before

},
elements: regl.prop('indices')
});
}

/*
* Returns JSON metadata for lights to be passed into the `uniforms` object.
*
* NOTE: When we increase MAX_LIGHTS, Regl will expect a property in this object for each array
* element, even if less than MAX_LIGHTS lights are passed in, so the rest will have to be filled
* with zeroed data.
*
* @param {number} numLights: The number of light points we want filled.
* @param {number} maxLights: The maximum number of light points that may exist.
* @returns {{}} The JSON metadata for the lights.
*/
export function buildLightMetadata(numLights: number, maxLights: number): {} {
const numberOfBlankLights: number = maxLights - numLights;

const visibleLightsJSON: {}[] = range(numLights).map((index: number) => {
return {
[`lightPositions[${index}]`]: [10, 10, 10],
[`lightIntensities[${index}]`]: 256,
[`lightColors[${index}]`]: [1, 1, 1]
};
});

const nonVisibleLightsJSON: {}[] = range(numberOfBlankLights).map((index: number) => {
return {
[`lightPositions[${maxLights - index}]`]: [0, 0, 0],
[`lightIntensities[${maxLights - index}]`]: 0,
[`lightColors[${maxLights - index}]`]: [0, 0, 0]
}
});

return visibleLightsJSON
.concat(nonVisibleLightsJSON)
.reduce((accum: {}, obj: {}) => { return { ...accum, ...obj }; }, {});
Copy link
Member

Choose a reason for hiding this comment

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

👌

}