diff --git a/src/graphics/programlib/chunks/normalMap.frag b/src/graphics/programlib/chunks/normalMap.frag index 00e430dc498..4eef1169ddf 100644 --- a/src/graphics/programlib/chunks/normalMap.frag +++ b/src/graphics/programlib/chunks/normalMap.frag @@ -1,5 +1,5 @@ uniform sampler2D texture_normalMap; -uniform float material_bumpMapFactor; +uniform float material_bumpiness; void getNormal(inout psInternalData data) { vec3 normalMap = unpackNormal(texture2D(texture_normalMap, $UV)); data.normalMap = normalMap; diff --git a/src/graphics/programlib/chunks/normalMapFloat.frag b/src/graphics/programlib/chunks/normalMapFloat.frag index 0d4e5c45cef..4ecafdaee98 100644 --- a/src/graphics/programlib/chunks/normalMapFloat.frag +++ b/src/graphics/programlib/chunks/normalMapFloat.frag @@ -1,9 +1,9 @@ uniform sampler2D texture_normalMap; -uniform float material_bumpMapFactor; +uniform float material_bumpiness; void getNormal(inout psInternalData data) { vec3 normalMap = unpackNormal(texture2D(texture_normalMap, $UV)); data.normalMap = normalMap; - normalMap = normalize(mix(vec3(0.0, 0.0, 1.0), normalMap, material_bumpMapFactor)); + normalMap = normalize(mix(vec3(0.0, 0.0, 1.0), normalMap, material_bumpiness)); data.normalW = data.TBN * normalMap; } diff --git a/src/graphics/programlib/chunks/normalMapFloatTBNfast.frag b/src/graphics/programlib/chunks/normalMapFloatTBNfast.frag index 184659757e0..cbb10b38a48 100644 --- a/src/graphics/programlib/chunks/normalMapFloatTBNfast.frag +++ b/src/graphics/programlib/chunks/normalMapFloatTBNfast.frag @@ -1,9 +1,9 @@ uniform sampler2D texture_normalMap; -uniform float material_bumpMapFactor; +uniform float material_bumpiness; void getNormal(inout psInternalData data) { vec3 normalMap = unpackNormal(texture2D(texture_normalMap, $UV)); data.normalMap = normalMap; - normalMap = mix(vec3(0.0, 0.0, 1.0), normalMap, material_bumpMapFactor); + normalMap = mix(vec3(0.0, 0.0, 1.0), normalMap, material_bumpiness); data.normalW = normalize(data.TBN * normalMap); } diff --git a/src/graphics/programlib/chunks/reflectionCube.frag b/src/graphics/programlib/chunks/reflectionCube.frag index e7fde0badd9..44d31d73289 100644 --- a/src/graphics/programlib/chunks/reflectionCube.frag +++ b/src/graphics/programlib/chunks/reflectionCube.frag @@ -1,7 +1,7 @@ uniform samplerCube texture_cubeMap; -uniform float material_reflectionFactor; +uniform float material_reflectivity; void addReflection(inout psInternalData data) { vec3 lookupVec = fixSeams(cubeMapProject(data.reflDirW)); lookupVec.x *= -1.0; - data.reflection += vec4($textureCubeSAMPLE(texture_cubeMap, lookupVec).rgb, material_reflectionFactor); + data.reflection += vec4($textureCubeSAMPLE(texture_cubeMap, lookupVec).rgb, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/reflectionDpAtlas.frag b/src/graphics/programlib/chunks/reflectionDpAtlas.frag index 63f1586bcce..b1a15ad277d 100644 --- a/src/graphics/programlib/chunks/reflectionDpAtlas.frag +++ b/src/graphics/programlib/chunks/reflectionDpAtlas.frag @@ -1,5 +1,5 @@ uniform sampler2D texture_sphereMap; -uniform float material_reflectionFactor; +uniform float material_reflectivity; vec2 getDpAtlasUv(vec2 uv, float mip) { @@ -50,7 +50,7 @@ void addReflection(inout psInternalData data) { tex1 = mix(tex1, tex2, fract(bias)); tex1 = processEnvironment(tex1); - data.reflection += vec4(tex1, material_reflectionFactor); + data.reflection += vec4(tex1, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/reflectionPrefilteredCube.frag b/src/graphics/programlib/chunks/reflectionPrefilteredCube.frag index 1a596c15add..16ce108f357 100644 --- a/src/graphics/programlib/chunks/reflectionPrefilteredCube.frag +++ b/src/graphics/programlib/chunks/reflectionPrefilteredCube.frag @@ -4,7 +4,7 @@ uniform samplerCube texture_prefilteredCubeMap32; uniform samplerCube texture_prefilteredCubeMap16; uniform samplerCube texture_prefilteredCubeMap8; uniform samplerCube texture_prefilteredCubeMap4; -uniform float material_reflectionFactor; +uniform float material_reflectivity; void addReflection(inout psInternalData data) { @@ -56,6 +56,6 @@ void addReflection(inout psInternalData data) { vec4 cubeFinal = mix(cube[0], cube[1], fract(bias)); vec3 refl = processEnvironment($DECODE(cubeFinal).rgb); - data.reflection += vec4(refl, material_reflectionFactor); + data.reflection += vec4(refl, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/reflectionPrefilteredCubeLod.frag b/src/graphics/programlib/chunks/reflectionPrefilteredCubeLod.frag index f24e0bf82f7..dffd6b43e77 100644 --- a/src/graphics/programlib/chunks/reflectionPrefilteredCubeLod.frag +++ b/src/graphics/programlib/chunks/reflectionPrefilteredCubeLod.frag @@ -1,7 +1,7 @@ #extension GL_EXT_shader_texture_lod : enable uniform samplerCube texture_prefilteredCubeMap128; -uniform float material_reflectionFactor; +uniform float material_reflectivity; void addReflection(inout psInternalData data) { @@ -11,6 +11,6 @@ void addReflection(inout psInternalData data) { vec3 refl = processEnvironment($DECODE( textureCubeLodEXT(texture_prefilteredCubeMap128, fixedReflDir, bias) ).rgb); - data.reflection += vec4(refl, material_reflectionFactor); + data.reflection += vec4(refl, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/reflectionSphere.frag b/src/graphics/programlib/chunks/reflectionSphere.frag index 4fc69a35070..fde5188acbc 100644 --- a/src/graphics/programlib/chunks/reflectionSphere.frag +++ b/src/graphics/programlib/chunks/reflectionSphere.frag @@ -1,6 +1,6 @@ uniform mat4 matrix_view; uniform sampler2D texture_sphereMap; -uniform float material_reflectionFactor; +uniform float material_reflectivity; void addReflection(inout psInternalData data) { vec3 reflDirV = (mat3(matrix_view) * data.reflDirW).xyz; @@ -8,7 +8,7 @@ void addReflection(inout psInternalData data) { float m = 2.0 * sqrt( dot(reflDirV.xy, reflDirV.xy) + (reflDirV.z+1.0)*(reflDirV.z+1.0) ); vec2 sphereMapUv = reflDirV.xy / m + 0.5; - data.reflection += vec4($texture2DSAMPLE(texture_sphereMap, sphereMapUv).rgb, material_reflectionFactor); + data.reflection += vec4($texture2DSAMPLE(texture_sphereMap, sphereMapUv).rgb, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/reflectionSphereLow.frag b/src/graphics/programlib/chunks/reflectionSphereLow.frag index d38416cb7cb..a119fa0fded 100644 --- a/src/graphics/programlib/chunks/reflectionSphereLow.frag +++ b/src/graphics/programlib/chunks/reflectionSphereLow.frag @@ -1,10 +1,10 @@ uniform sampler2D texture_sphereMap; -uniform float material_reflectionFactor; +uniform float material_reflectivity; void addReflection(inout psInternalData data) { vec3 reflDirV = vNormalV; vec2 sphereMapUv = reflDirV.xy * 0.5 + 0.5; - data.reflection += vec4($texture2DSAMPLE(texture_sphereMap, sphereMapUv).rgb, material_reflectionFactor); + data.reflection += vec4($texture2DSAMPLE(texture_sphereMap, sphereMapUv).rgb, material_reflectivity); } diff --git a/src/graphics/programlib/chunks/refraction.frag b/src/graphics/programlib/chunks/refraction.frag index 2c0f3615bd1..fa1c92565fa 100644 --- a/src/graphics/programlib/chunks/refraction.frag +++ b/src/graphics/programlib/chunks/refraction.frag @@ -1,4 +1,4 @@ -uniform float material_refraction, material_refractionIor; +uniform float material_refraction, material_refractionIndex; vec3 refract2(vec3 viewVec, vec3 Normal, float IOR) { float vn = dot(viewVec, Normal); @@ -13,7 +13,7 @@ void addRefraction(inout psInternalData data) { vec3 tmp = data.reflDirW; vec4 tmp2 = data.reflection; data.reflection = vec4(0.0); - data.reflDirW = refract2(-data.viewDirW, data.normalW, material_refractionIor); + data.reflDirW = refract2(-data.viewDirW, data.normalW, material_refractionIndex); addReflection(data); diff --git a/src/graphics/programlib/chunks/specularAaToksvigFloat.frag b/src/graphics/programlib/chunks/specularAaToksvigFloat.frag index b421fc05d02..d134524bb21 100644 --- a/src/graphics/programlib/chunks/specularAaToksvigFloat.frag +++ b/src/graphics/programlib/chunks/specularAaToksvigFloat.frag @@ -1,6 +1,6 @@ float antiAliasGlossiness(inout psInternalData data, float power) { float rlen = 1.0 / saturate(length(data.normalMap)); float toksvig = 1.0 / (1.0 + power * (rlen - 1.0)); - return power * mix(1.0, toksvig, material_bumpMapFactor); + return power * mix(1.0, toksvig, material_bumpiness); } diff --git a/src/graphics/programlib/programlib_programlib.js b/src/graphics/programlib/programlib_programlib.js index 72d135a2bd8..7cb32f0cc76 100644 --- a/src/graphics/programlib/programlib_programlib.js +++ b/src/graphics/programlib/programlib_programlib.js @@ -115,7 +115,7 @@ pc.programlib = { // V, the view vector (vertex to eye) code += ' vec3 map = texture2D( texture_normalMap, uv ).xyz;\n'; code += ' map = map * 255./127. - 128./127.;\n'; - code += ' map.xy = map.xy * material_bumpMapFactor;\n'; + code += ' map.xy = map.xy * material_bumpiness;\n'; code += ' mat3 TBN = cotangent_frame( N, -V, uv );\n'; code += ' return normalize( TBN * map );\n'; code += '}\n\n'; diff --git a/src/scene/scene_material.js b/src/scene/scene_material.js index e696fb59da4..f6d22b03526 100644 --- a/src/scene/scene_material.js +++ b/src/scene/scene_material.js @@ -220,7 +220,22 @@ pc.extend(pc, function () { * @name {number|Array|pc.Texture} data The value for the specified parameter. * @author Will Eastcott */ - Material.prototype.setParameter = function (name, data) { + Material.prototype.setParameter = function (arg, data) { + + var name; + if (data===undefined) { + var uniformObject = arg; + if (uniformObject.length) { + for(var i=0; i 0) obj[privMapChannel] = channels > 1? "rgb" : "g"; obj[privMapVertexColor] = false; @@ -173,7 +174,12 @@ pc.extend(pc, function () { this[privMap] = value; } }); - Object.defineProperty(PhongMaterial.prototype, privMapTiling.substring(1), { + + var mapTiling = privMapTiling.substring(1); + var mapOffset = privMapOffset.substring(1); + + + Object.defineProperty(PhongMaterial.prototype, mapTiling, { get: function() { this.dirtyShader = true; return this[privMapTiling]; @@ -183,7 +189,17 @@ pc.extend(pc, function () { this[privMapTiling] = value; } }); - Object.defineProperty(PhongMaterial.prototype, privMapOffset.substring(1), { + _prop2Uniform[mapTiling] = function (mat, val, changeMat) { + var tform = mat._updateMapTransform( + changeMat? mat[mapTransform] : null, + val, + mat[privMapOffset] + ); + return {name:("texture_" + mapTransform), value:tform.data}; + } + + + Object.defineProperty(PhongMaterial.prototype, mapOffset, { get: function() { this.dirtyShader = true; return this[privMapOffset]; @@ -193,6 +209,16 @@ pc.extend(pc, function () { this[privMapOffset] = value; } }); + _prop2Uniform[mapOffset] = function (mat, val, changeMat) { + var tform = mat._updateMapTransform( + changeMat? mat[mapTransform] : null, + mat[privMapTiling], + val + ); + return {name:("texture_" + mapTransform), value:tform.data}; + } + + Object.defineProperty(PhongMaterial.prototype, privMapUv.substring(1), { get: function() { return this[privMapUv]; }, set: function (value) { @@ -221,13 +247,15 @@ pc.extend(pc, function () { _propsSerial.push(privMapUv); _propsSerial.push(privMapChannel); _propsSerial.push(privMapVertexColor); - _propsInternalNull.push(privMapTransform) + _propsInternalNull.push(mapTransform) }; var _propsColor = []; - var _defineColor = function (obj, name, defaultValue) { + var _defineColor = function (obj, name, defaultValue, hasMultiplier) { var priv = "_" + name; var uform = name + "Uniform"; + var mult = name + "Intensity"; + var pmult = "_" + mult; obj[priv] = defaultValue; obj[uform] = new Float32Array(3); Object.defineProperty(PhongMaterial.prototype, name, { @@ -248,9 +276,53 @@ pc.extend(pc, function () { _propsSerial.push(name); _propsInternalVec3.push(uform); _propsColor.push(name); + _prop2Uniform[name] = function (mat, val, changeMat) { + var arr = changeMat? mat[uform] : new Float32Array(3); + var scene = mat._scene || pc.Application.getApplication().scene; + for(var c=0; c<3; c++) { + if (scene.gammaCorrection) { + arr[c] = Math.pow(val.data[c], 2.2); + } else { + arr[c] = val.data[c]; + } + if (hasMultiplier) arr[c] *= mat[pmult]; + } + return {name:("material_" + name), value:arr} + } + + if (hasMultiplier) { + obj[pmult] = 1; + Object.defineProperty(PhongMaterial.prototype, mult, { + get: function() { + return this[pmult]; + }, + set: function (value) { + var oldVal = this[pmult]; + var wasBw = oldVal===0 || oldVal===1; + var isBw = value===0 || value===1; + if (wasBw || isBw) this.dirtyShader = true; + this.dirtyColor = true; + this[pmult] = value; + } + }); + _propsSerial.push(mult); + _prop2Uniform[mult] = function (mat, val, changeMat) { + var arr = changeMat? mat[uform] : new Float32Array(3); + var scene = mat._scene || pc.Application.getApplication().scene; + for(var c=0; c<3; c++) { + if (scene.gammaCorrection) { + arr[c] = Math.pow(mat[priv].data[c], 2.2); + } else { + arr[c] = mat[priv].data[c]; + } + arr[c] *= mat[pmult]; + } + return {name:("material_" + name), value:arr} + } + } }; - var _defineFloat = function (obj, name, defaultValue) { + var _defineFloat = function (obj, name, defaultValue, func) { var priv = "_" + name; obj[priv] = defaultValue; Object.defineProperty(PhongMaterial.prototype, name, { @@ -264,9 +336,12 @@ pc.extend(pc, function () { } }); _propsSerial.push(name); + _prop2Uniform[name] = func!==undefined? func : (function (mat, val, changeMat) { + return {name:("material_" + name), value:val} + }); }; - var _defineObject = function (obj, name) { + var _defineObject = function (obj, name, func) { var priv = "_" + name; obj[priv] = null; Object.defineProperty(PhongMaterial.prototype, name, { @@ -278,6 +353,7 @@ pc.extend(pc, function () { } }); _propsSerial.push(name); + _prop2Uniform[name] = func; }; var _defineChunks = function (obj) { @@ -443,6 +519,14 @@ pc.extend(pc, function () { } }, + getUniform: function(varName, value, changeMat) { + var func = _prop2Uniform[varName]; + if (func) { + return func(this, value, changeMat); + } + return null; + }, + update: function () { this.clearParameters(); @@ -462,14 +546,7 @@ pc.extend(pc, function () { } } - // Shininess is 0-100 value - // which is actually a 0-1 glosiness value. - // Can be converted to specular power using exp2(shininess * 0.01 * 11) - if (this.shadingModel===pc.SPECULAR_PHONG) { - this.setParameter('material_shininess', Math.pow(2, this.shininess * 0.01 * 11)); // legacy: expand back to specular power - } else { - this.setParameter('material_shininess', this.shininess * 0.01); // correct - } + this.setParameter(this.getUniform("shininess", this.shininess, true)); if (!this.emissiveMap || this.emissiveMapTint) { this.setParameter('material_emissive', this.emissiveUniform); @@ -477,7 +554,7 @@ pc.extend(pc, function () { if (this.refraction>0) { this.setParameter('material_refraction', this.refraction); - this.setParameter('material_refractionIor', this.refractionIndex); + this.setParameter('material_refractionIndex', this.refractionIndex); } this.setParameter('material_opacity', this.opacity); @@ -487,32 +564,23 @@ pc.extend(pc, function () { } if (this.cubeMapProjection===pc.CUBEPROJ_BOX) { - this.cubeMapMinUniform[0] = this.cubeMapProjectionBox.center.x - this.cubeMapProjectionBox.halfExtents.x; - this.cubeMapMinUniform[1] = this.cubeMapProjectionBox.center.y - this.cubeMapProjectionBox.halfExtents.y; - this.cubeMapMinUniform[2] = this.cubeMapProjectionBox.center.z - this.cubeMapProjectionBox.halfExtents.z; - - this.cubeMapMaxUniform[0] = this.cubeMapProjectionBox.center.x + this.cubeMapProjectionBox.halfExtents.x; - this.cubeMapMaxUniform[1] = this.cubeMapProjectionBox.center.y + this.cubeMapProjectionBox.halfExtents.y; - this.cubeMapMaxUniform[2] = this.cubeMapProjectionBox.center.z + this.cubeMapProjectionBox.halfExtents.z; + this.setParameter(this.getUniform("cubeMapProjectionBox", this.cubeMapProjectionBox, true)); + } - this.setParameter('envBoxMin', this.cubeMapMinUniform); - this.setParameter('envBoxMax', this.cubeMapMaxUniform); + for(var p in pc._matTex2D) { + this._updateMap(p); } if (this.ambientSH) { this.setParameter('ambientSH[0]', this.ambientSH); } - for(var p in pc._matTex2D) { - this._updateMap(p); - } - if (this.normalMap) { - this.setParameter('material_bumpMapFactor', this.bumpiness); + this.setParameter('material_bumpiness', this.bumpiness); } if (this.heightMap) { - this.setParameter('material_heightMapFactor', this.heightMapFactor * 0.025); + this.setParameter(this.getUniform('heightMapFactor', this.heightMapFactor, true)); } if (this.cubeMap) { @@ -543,7 +611,7 @@ pc.extend(pc, function () { this.setParameter('texture_sphereMap', this.dpAtlas); } //if (this.sphereMap || this.cubeMap || this.prefilteredCubeMap128) { - this.setParameter('material_reflectionFactor', this.reflectivity); + this.setParameter('material_reflectivity', this.reflectivity); //} if (this.dirtyShader || !this._scene) { @@ -802,24 +870,51 @@ pc.extend(pc, function () { _defineColor(obj, "ambient", new pc.Color(0.7, 0.7, 0.7)); _defineColor(obj, "diffuse", new pc.Color(1, 1, 1)); _defineColor(obj, "specular", new pc.Color(0, 0, 0)); - _defineColor(obj, "emissive", new pc.Color(0, 0, 0)); + _defineColor(obj, "emissive", new pc.Color(0, 0, 0), true); - _defineFloat(obj, "shininess", 25); + _defineFloat(obj, "shininess", 25, function(mat, shininess) { + // Shininess is 0-100 value + // which is actually a 0-1 glosiness value. + // Can be converted to specular power using exp2(shininess * 0.01 * 11) + var value; + if (mat.shadingModel===pc.SPECULAR_PHONG) { + value = Math.pow(2, shininess * 0.01 * 11); // legacy: expand back to specular power + } else { + value = shininess * 0.01; // correct + } + return {name:"material_shininess", value:value}; + }); + _defineFloat(obj, "heightMapFactor", 1, function(mat, height) { + return {name:'material_heightMapFactor', value:height * 0.025}; + }); _defineFloat(obj, "opacity", 1); _defineFloat(obj, "alphaTest", 0); _defineFloat(obj, "bumpiness", 1); - _defineFloat(obj, "heightMapFactor", 1); _defineFloat(obj, "reflectivity", 1); _defineFloat(obj, "occludeSpecularIntensity", 1); - _defineFloat(obj, "emissiveIntensity", 1); _defineFloat(obj, "refraction", 0); _defineFloat(obj, "refractionIndex", 1.0 / 1.5); // approx. (air ior / glass ior) _defineFloat(obj, "metalness", 1); - _defineFloat(obj, "aoUvSet", 0); // legacy + _defineFloat(obj, "aoUvSet", 0, null); // legacy + + _defineObject(obj, "ambientSH", function (mat, val, changeMat) { + return {name:"ambientSH[0]", value:val}; + }); - _defineObject(obj, "ambientSH"); + _defineObject(obj, "cubeMapProjectionBox", function (mat, val, changeMat) { + var bmin = changeMat? mat.cubeMapMinUniform : new Float32Array(3); + var bmax = changeMat? mat.cubeMapMaxUniform : new Float32Array(3); - _defineObject(obj, "cubeMapProjectionBox"); + bmin[0] = val.center.x - val.halfExtents.x; + bmin[1] = val.center.y - val.halfExtents.y; + bmin[2] = val.center.z - val.halfExtents.z; + + bmax[0] = val.center.x + val.halfExtents.x; + bmax[1] = val.center.y + val.halfExtents.y; + bmax[2] = val.center.z + val.halfExtents.z; + + return [{name:"envBoxMin", value:bmin}, {name:"envBoxMax", value:bmax}]; + }); _defineChunks(obj);