Skip to content

Commit

Permalink
Add AmbientCubemap light. Shader manage texture slot
Browse files Browse the repository at this point in the history
  • Loading branch information
pissang committed Jan 5, 2017
1 parent 164a352 commit 652ad56
Show file tree
Hide file tree
Showing 15 changed files with 329 additions and 64 deletions.
10 changes: 10 additions & 0 deletions package.json
Expand Up @@ -10,6 +10,16 @@
"name": "Yi Shen",
"url": "https://github.com/pissang"
}],
"watch": {
"essl2js": {
"patterns": ["src"],
"extensions": "essl"
},
"amd2common": {
"patterns": ["src"],
"extensions": "js"
}
},
"scripts": {
"genentry": "node build/genentry.js",
"essl2js": "node build/essl2js.js",
Expand Down
101 changes: 47 additions & 54 deletions src/Material.js
Expand Up @@ -76,10 +76,15 @@ define(function(require) {

bind: function(_gl, prevMaterial) {

var slot = 0;

var sameShader = prevMaterial && prevMaterial.shader === this.shader;
// FIXME Null texture may cause weird error in console

var shader = this.shader;

if (sameShader) {
// shader may use some slot by others before material bind.
shader.resetTextureSlot(prevMaterial.__textureSlotBase || 0);
}

// Set uniforms
for (var u = 0; u < this._enabledUniforms.length; u++) {
var symbol = this._enabledUniforms[u];
Expand All @@ -88,8 +93,6 @@ define(function(require) {
// When binding two materials with the same shader
// Many uniforms will be be set twice even if they have the same value
// So add a evaluation to see if the uniform is really needed to be set
//
// FIXME Small possibility enabledUniforms are not the same
if (sameShader) {
if (prevMaterial.uniforms[symbol].value === uniformValue) {
continue;
Expand All @@ -100,35 +103,28 @@ define(function(require) {
console.warn('Uniform value "' + symbol + '" is undefined');
continue;
}
else if (uniformValue === null) {
// if (uniform.type == 't') {
// // PENDING
// _gl.bindTexture(_gl.TEXTURE_2D, null);
// _gl.bindTexture(_gl.TEXTURE_CUBE, null);
// }
else if (uniformValue === null && uniform.type !== 't') {
continue;
}
else if (uniformValue instanceof Array
&& !uniformValue.length) {
continue;
}
else if (uniformValue instanceof Texture) {
var res = this.shader.setUniform(_gl, '1i', symbol, slot);
// FIXME Assume material with same shader have same order uniforms
// Or if different material use same textures,
// the slot will be different and still skipped because optimization
if (uniformValue === null) {
// Still occupy the slot to make sure same texture in different materials have same slot.
shader.useCurrentTextureSlot(_gl, null);
}

var slot = shader.currentTextureSlot();
var res = shader.setUniform(_gl, '1i', symbol, slot);
if (!res) { // Texture is not enabled
continue;
}
var texture = uniformValue;
_gl.activeTexture(_gl.TEXTURE0 + slot);
// Maybe texture is not loaded yet;
if (texture.isRenderable()) {
texture.bind(_gl);
}
else {
// Bind texture to null
texture.unbind(_gl);
}

slot++;
shader.useCurrentTextureSlot(_gl, uniformValue);
}
else if (uniformValue instanceof Array) {
if (uniformValue.length === 0) {
Expand All @@ -138,35 +134,32 @@ define(function(require) {
var exampleValue = uniformValue[0];

if (exampleValue instanceof Texture) {
if (!this.shader.hasUniform(symbol)) {
if (!shader.hasUniform(symbol)) {
continue;
}

var arr = [];
for (var i = 0; i < uniformValue.length; i++) {
var texture = uniformValue[i];
_gl.activeTexture(_gl.TEXTURE0 + slot);
// Maybe texture is not loaded yet;
if (texture.isRenderable()) {
texture.bind(_gl);
}
else {
texture.unbind(_gl);
}

arr.push(slot++);
var slot = shader.currentTextureSlot();
arr.push(slot);

shader.useCurrentTextureSlot(_gl, texture);
}

this.shader.setUniform(_gl, '1iv', symbol, arr);
shader.setUniform(_gl, '1iv', symbol, arr);
}
else {
this.shader.setUniform(_gl, uniform.type, symbol, uniformValue);
shader.setUniform(_gl, uniform.type, symbol, uniformValue);
}
}
else{
this.shader.setUniform(_gl, uniform.type, symbol, uniformValue);
shader.setUniform(_gl, uniform.type, symbol, uniformValue);
}
}

this.__textureSlotBase = shader.currentTextureSlot();
},

/**
Expand Down Expand Up @@ -198,23 +191,23 @@ define(function(require) {
* It only have effect on the uniform exists in shader.
* @param {string} symbol
*/
enableUniform: function (symbol) {
if (this.uniforms[symbol] && !this.isUniformEnabled(symbol)) {
this._enabledUniforms.push(symbol);
}
},

/**
* Disable a uniform
* It will not affect the uniform state in the shader. Because the shader uniforms is parsed from shader code with naive regex. When using micro to disable some uniforms in the shader. It will still try to set these uniforms in each rendering pass. We can disable these uniforms manually if we need this bit performance improvement. Mostly we can simply ignore it.
* @param {string} symbol
*/
disableUniform: function (symbol) {
var idx = this._enabledUniforms.indexOf(symbol);
if (idx >= 0) {
this._enabledUniforms.splice(idx, 1);
}
},
// enableUniform: function (symbol) {
// if (this.uniforms[symbol] && !this.isUniformEnabled(symbol)) {
// this._enabledUniforms.push(symbol);
// }
// },

// /**
// * Disable a uniform
// * It will not affect the uniform state in the shader. Because the shader uniforms is parsed from shader code with naive regex. When using micro to disable some uniforms in the shader. It will still try to set these uniforms in each rendering pass. We can disable these uniforms manually if we need this bit performance improvement. Mostly we can simply ignore it.
// * @param {string} symbol
// */
// disableUniform: function (symbol) {
// var idx = this._enabledUniforms.indexOf(symbol);
// if (idx >= 0) {
// this._enabledUniforms.splice(idx, 1);
// }
// },

/**
* @param {string} symbol
Expand Down
18 changes: 16 additions & 2 deletions src/Scene.js
Expand Up @@ -190,7 +190,8 @@ define(function (require) {
if (child.isRenderable()) {
if (child.material.transparent || sceneMaterialTransparent) {
this.transparentQueue[this._transparentObjectCount++] = child;
} else {
}
else {
this.opaqueQueue[this._opaqueObjectCount++] = child;
}
}
Expand Down Expand Up @@ -228,6 +229,7 @@ define(function (require) {
switch (uniformTpl.type) {
case '1i':
case '1f':
case 't':
lu.value.push(value);
break;
case '2f':
Expand Down Expand Up @@ -269,7 +271,19 @@ define(function (require) {
setLightUniforms: function (shader, _gl) {
for (var symbol in this._lightUniforms) {
var lu = this._lightUniforms[symbol];
shader.setUniform(_gl, lu.type, symbol, lu.value);
if (lu.type === 'tv') {
for (var i = 0; i < lu.value.length; i++) {
var texture = lu.value[i];
var slot = shader.currentTextureSlot();
var result = shader.setUniform(_gl, '1i', symbol, slot);
if (result) {
shader.useCurrentTextureSlot(_gl, texture);
}
}
}
else {
shader.setUniform(_gl, lu.type, symbol, lu.value);
}
}
},

Expand Down
39 changes: 38 additions & 1 deletion src/Shader.js
Expand Up @@ -180,15 +180,17 @@ define(function (require) {
'EXT_shader_texture_lod'
],

// Glue code
// Defines the each type light number in the scene
// AMBIENT_LIGHT
// AMBIENT_SH_LIGHT
// AMBIENT_CUBEMAP_LIGHT
// POINT_LIGHT
// SPOT_LIGHT
// AREA_LIGHT
lightNumber: {},

_textureSlot: 0,

_attacheMaterialNumber: 0,

_uniformList: [],
Expand Down Expand Up @@ -242,6 +244,9 @@ define(function (require) {

this._currentLocationsMap = cache.get('locations');

// Reset slot
this._textureSlot = 0;

if (cache.isDirty()) {
var availableExts = [];
var extensions = this.extensions;
Expand Down Expand Up @@ -480,6 +485,38 @@ define(function (require) {
return location !== null && location !== undefined;
},

currentTextureSlot: function () {
return this._textureSlot;
},

resetTextureSlot: function (slot) {
this._textureSlot = slot || 0;
},

useCurrentTextureSlot: function (_gl, texture) {
var textureSlot = this._textureSlot;

this.useTextureSlot(_gl, texture, textureSlot);

this._textureSlot++;

return textureSlot;
},

useTextureSlot: function (_gl, texture, slot) {
if (texture) {
_gl.activeTexture(_gl.TEXTURE0 + slot);
// Maybe texture is not loaded yet;
if (texture.isRenderable()) {
texture.bind(_gl);
}
else {
// Bind texture to null
texture.unbind(_gl);
}
}
},

setUniform: function (_gl, type, symbol, value) {
var locationMap = this._currentLocationsMap;
var location = locationMap[symbol];
Expand Down
86 changes: 86 additions & 0 deletions src/light/AmbientCubemap.js
@@ -0,0 +1,86 @@
// https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/AmbientCubemap/define(function(require) {
define(function(require) {

'use strict';

var Light = require('../Light');
var cubemapUtil = require('../util/cubemap');

/**
* @constructor qtek.light.AmbientCubemap
* @extends qtek.Light
*/
var AmbientCubemapLight = Light.extend({

/**
* @type {qtek.TextureCube}
*/
cubemap: null,

// TODO
// range: 100,

castShadow: false,

_normalDistribution: null,
_brdfLookup: null

}, {

type: 'AMBIENT_CUBEMAP_LIGHT',

prefilter: function (renderer) {
if (!this._brdfLookup) {
this._normalDistribution = cubemapUtil.generateNormalDistribution();
this._brdfLookup = cubemapUtil.integrateBRDF(renderer, this._normalDistribution);
}
var cubemap = this.cubemap;
if (cubemap.__prefiltered) {
return;
}

var result = cubemapUtil.prefilterEnvironmentMap(
renderer, cubemap, {
encodeRGBM: true
}, this._normalDistribution, this._brdfLookup
);
this.cubemap = result.environmentMap;
this.cubemap.__prefiltered = true;

cubemap.dispose(renderer.gl);
},

uniformTemplates: {
ambientCubemapLightColor: {
type: '3f',
value: function (instance) {
var color = instance.color;
var intensity = instance.intensity;
return [color[0]*intensity, color[1]*intensity, color[2]*intensity];
}
},

ambientCubemapLightCubemap: {
type: 't',
value: function (instance) {
return instance.cubemap;
}
},

ambientCubemapLightBRDFLookup: {
type: 't',
value: function (instance) {
return instance._brdfLookup;
}
}
}
/**
* @method
* @name clone
* @return {qtek.light.AmbientCubemap}
* @memberOf qtek.light.AmbientCubemap.prototype
*/
});

return AmbientCubemapLight;
});
3 changes: 2 additions & 1 deletion src/qtek.js
Expand Up @@ -54,6 +54,7 @@ define(function(require) {
"core": {
"Base": require('./core/Base'),
"Cache": require('./core/Cache'),
"env": require('./core/env'),
"Event": require('./core/Event'),
"glenum": require('./core/glenum'),
"glinfo": require('./core/glinfo'),
Expand Down Expand Up @@ -148,7 +149,7 @@ define(function(require) {
"Scene": require('./Scene'),
"Shader": require('./Shader'),
"shader": {
"buildin": require('./shader/buildin'),
"builtin": require('./shader/builtin'),
"library": require('./shader/library'),
"source": {
"header": {
Expand Down

0 comments on commit 652ad56

Please sign in to comment.