From 814aeaad5c1764ce52e5e8690d91154fc58ca784 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 18:14:53 -0700 Subject: [PATCH 01/27] add new examples refactor modified refactor GLTFLoader --- examples/js/loaders/GLTFLoader.js | 245 +++++-------------------- examples/webgl_materials_modified.html | 38 ++-- src/renderers/WebGLRenderer.js | 55 +++++- src/renderers/webgl/WebGLProgram.js | 15 +- src/renderers/webgl/WebGLPrograms.js | 14 +- 5 files changed, 129 insertions(+), 238 deletions(-) diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index b0353d1954ab62..ea907316859455 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -565,7 +565,9 @@ THREE.GLTFLoader = ( function () { getMaterialType: function () { - return THREE.ShaderMaterial; + // return THREE.ShaderMaterial; + // return THREE.MeshStandardMaterial + return 'SPEC_GLOSS'; }, @@ -573,22 +575,6 @@ THREE.GLTFLoader = ( function () { var pbrSpecularGlossiness = material.extensions[ this.name ]; - var shader = THREE.ShaderLib[ 'standard' ]; - - var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); - - var specularMapParsFragmentChunk = [ - '#ifdef USE_SPECULARMAP', - ' uniform sampler2D specularMap;', - '#endif' - ].join( '\n' ); - - var glossinessMapParsFragmentChunk = [ - '#ifdef USE_GLOSSINESSMAP', - ' uniform sampler2D glossinessMap;', - '#endif' - ].join( '\n' ); - var specularMapFragmentChunk = [ 'vec3 specularFactor = specular;', '#ifdef USE_SPECULARMAP', @@ -615,29 +601,18 @@ THREE.GLTFLoader = ( function () { 'material.specularColor = specularFactor.rgb;', ].join( '\n' ); - var fragmentShader = shader.fragmentShader - .replace( 'uniform float roughness;', 'uniform vec3 specular;' ) - .replace( 'uniform float metalness;', 'uniform float glossiness;' ) - .replace( '#include ', specularMapParsFragmentChunk ) - .replace( '#include ', glossinessMapParsFragmentChunk ) - .replace( '#include ', specularMapFragmentChunk ) - .replace( '#include ', glossinessMapFragmentChunk ) - .replace( '#include ', lightPhysicalFragmentChunk ); - - delete uniforms.roughness; - delete uniforms.metalness; - delete uniforms.roughnessMap; - delete uniforms.metalnessMap; - - uniforms.specular = { value: new THREE.Color().setHex( 0x111111 ) }; - uniforms.glossiness = { value: 0.5 }; - uniforms.specularMap = { value: null }; - uniforms.glossinessMap = { value: null }; - - params.vertexShader = shader.vertexShader; - params.fragmentShader = fragmentShader; - params.uniforms = uniforms; - params.defines = { 'STANDARD': '' }; + params.shaderUniforms = { + specular: { value: new THREE.Color().setHex( 0x111111 ), type: 'vec3' }, //atm these end up in both vert and frag :/ + glossiness: { value: 0.5, type: 'float' }, + glossinessMap: { value: null, type: 'sampler2D' }, + specularMap: { value: null, type: 'sampler2D' }, + }; + + params.shaderIncludes = { + roughnessmap_fragment: specularMapFragmentChunk, + metalnessmap_fragment: glossinessMapFragmentChunk, + lights_physical_fragment: lightPhysicalFragmentChunk, + }; params.color = new THREE.Color( 1.0, 1.0, 1.0 ); params.opacity = 1.0; @@ -683,19 +658,17 @@ THREE.GLTFLoader = ( function () { createMaterial: function ( params ) { - // setup material properties based on MeshStandardMaterial for Specular-Glossiness - - var material = new THREE.ShaderMaterial( { - defines: params.defines, - vertexShader: params.vertexShader, - fragmentShader: params.fragmentShader, - uniforms: params.uniforms, + var material = new THREE.MeshStandardMaterial( { fog: true, - lights: true, opacity: params.opacity, transparent: params.transparent } ); + console.log( material ); + + material.shaderIncludes = params.shaderIncludes; + material.shaderUniforms = params.shaderUniforms; + material.isGLTFSpecularGlossinessMaterial = true; material.color = params.color; @@ -722,11 +695,23 @@ THREE.GLTFLoader = ( function () { material.displacementScale = 1; material.displacementBias = 0; - material.specularMap = params.specularMap === undefined ? null : params.specularMap; - material.specular = params.specular; + if ( params.specularMap ) { + + material.shaderUniforms.specularMap.value = params.glossinessMap; + material.defines.USE_SPECULARMAP = ''; + + } + + material.shaderUniforms.specular.value = params.specular; + + if ( params.glossinessMap ) { + + material.shaderUniforms.glossinessMap.value = params.glossinessMap; + material.defines.USE_GLOSSINESSMAP = ''; + + } - material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap; - material.glossiness = params.glossiness; + material.shaderUniforms.glossiness.value = params.glossiness; material.alphaMap = null; @@ -735,8 +720,6 @@ THREE.GLTFLoader = ( function () { material.refractionRatio = 0.98; - material.extensions.derivatives = true; - return material; }, @@ -771,157 +754,13 @@ THREE.GLTFLoader = ( function () { }, - // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer. - refreshUniforms: function ( renderer, scene, camera, geometry, material, group ) { - - if ( material.isGLTFSpecularGlossinessMaterial !== true ) { - - return; - - } - - var uniforms = material.uniforms; - var defines = material.defines; - - uniforms.opacity.value = material.opacity; - - uniforms.diffuse.value.copy( material.color ); - uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); - - uniforms.map.value = material.map; - uniforms.specularMap.value = material.specularMap; - uniforms.alphaMap.value = material.alphaMap; - - uniforms.lightMap.value = material.lightMap; - uniforms.lightMapIntensity.value = material.lightMapIntensity; - - uniforms.aoMap.value = material.aoMap; - uniforms.aoMapIntensity.value = material.aoMapIntensity; - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. normal map - // 4. bump map - // 5. alpha map - // 6. emissive map - - var uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.glossinessMap ) { - - uvScaleMap = material.glossinessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - var offset; - var repeat; - - if ( uvScaleMap.matrix !== undefined ) { - - // > r88. - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - offset = uvScaleMap.offset; - repeat = uvScaleMap.repeat; - var rotation = uvScaleMap.rotation; - var center = uvScaleMap.center; - - uvScaleMap.matrix.setUvTransform( offset.x, offset.y, repeat.x, repeat.y, rotation, center.x, center.y ); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } else { - - // <= r87. Remove when reasonable. - - offset = uvScaleMap.offset; - repeat = uvScaleMap.repeat; - - uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); - - } - - } - - uniforms.envMap.value = material.envMap; - uniforms.envMapIntensity.value = material.envMapIntensity; - uniforms.flipEnvMap.value = ( material.envMap && material.envMap.isCubeTexture ) ? - 1 : 1; - - uniforms.refractionRatio.value = material.refractionRatio; - - uniforms.specular.value.copy( material.specular ); - uniforms.glossiness.value = material.glossiness; - - uniforms.glossinessMap.value = material.glossinessMap; - - uniforms.emissiveMap.value = material.emissiveMap; - uniforms.bumpMap.value = material.bumpMap; - uniforms.normalMap.value = material.normalMap; - - uniforms.displacementMap.value = material.displacementMap; - uniforms.displacementScale.value = material.displacementScale; - uniforms.displacementBias.value = material.displacementBias; - - if ( uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined ) { - - defines.USE_GLOSSINESSMAP = ''; - // set USE_ROUGHNESSMAP to enable vUv - defines.USE_ROUGHNESSMAP = ''; - - } - - if ( uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined ) { - - delete defines.USE_GLOSSINESSMAP; - delete defines.USE_ROUGHNESSMAP; - - } - + refreshUniforms: function () { + /*NOOP*/ } }; + } /*********************************/ @@ -2219,8 +2058,8 @@ THREE.GLTFLoader = ( function () { return Promise.all( pending ).then( function () { var material; - - if ( materialType === THREE.ShaderMaterial ) { + // if ( materialType === THREE.ShaderMaterial ) { + if ( materialType === 'SPEC_GLOSS' ) { material = extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ].createMaterial( materialParams ); diff --git a/examples/webgl_materials_modified.html b/examples/webgl_materials_modified.html index 57ab38e1e86966..8f34c8ca8e772e 100644 --- a/examples/webgl_materials_modified.html +++ b/examples/webgl_materials_modified.html @@ -54,7 +54,7 @@ var camera, scene, renderer, stats; - var mesh, materialShader; + var mesh, material; var mouseX = 0; var mouseY = 0; @@ -75,29 +75,20 @@ scene = new THREE.Scene(); - var material = new THREE.MeshNormalMaterial(); - material.onBeforeCompile = function ( shader ) { + material = new THREE.MeshNormalMaterial(); //no need to create a uniform at some obscure compile time, it's available now (obsucure because its both onBeforeParse and onBeforeCompile`) - // console.log( shader ) + var my_begin_vertex = [ + 'float theta = sin( time + position.y ) / 2.0;', + 'float c = cos( theta );', + 'float s = sin( theta );', + 'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );', + 'vec3 transformed = vec3( position ) * m;', + 'vNormal = vNormal * m;' + ].join( '\n' ); - shader.uniforms.time = { value: 0 }; + material.shaderIncludes = { begin_vertex: my_begin_vertex }; - shader.vertexShader = 'uniform float time;\n' + shader.vertexShader; - shader.vertexShader = shader.vertexShader.replace( - '#include ', - [ - 'float theta = sin( time + position.y ) / 2.0;', - 'float c = cos( theta );', - 'float s = sin( theta );', - 'mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );', - 'vec3 transformed = vec3( position ) * m;', - 'vNormal = vNormal * m;' - ].join( '\n' ) - ); - - materialShader = shader; - - }; + material.shaderUniforms = { time: { value: 0, type: 'float' } }; var loader = new THREE.JSONLoader(); loader.load( 'models/json/leeperrysmith/LeePerrySmith.json', function( geometry ) { @@ -174,11 +165,8 @@ } - if ( materialShader ) { + material.shaderUniforms.time.value = performance.now() / 1000; //doesnt defer creating the uniform, no need to check - materialShader.uniforms.time.value = performance.now() / 1000; - - } renderer.render( scene, camera ); diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 891c8e43b56bcd..dda001d8b9555c 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1474,11 +1474,41 @@ function WebGLRenderer( parameters ) { var shader = ShaderLib[ parameters.shaderID ]; + var combinedUniforms = undefined !== material.shaderUniforms ? + UniformsUtils.merge( [ UniformsUtils.clone( shader.uniforms ), material.shaderUniforms ] ) : + UniformsUtils.clone( shader.uniforms ); + + var shaderUniformsGLSLFrag = ''; //collect the GLSL in here + var shaderUniformsGLSLVert = ''; //collect the GLSL in here + + for ( var uniformName in material.shaderUniforms ) { + + var uniform = material.shaderUniforms[ uniformName ]; + var type = uniform.type; + var stage = uniform.stage; + + if ( type ) { + + if ( stage === 'vertex' ) { + + shaderUniformsGLSLVert += 'uniform ' + type + ' ' + uniformName + ';\n'; + + } else { + + shaderUniformsGLSLFrag += 'uniform ' + type + ' ' + uniformName + ';\n'; + + } + + } + + } + materialProperties.shader = { name: material.type, - uniforms: UniformsUtils.clone( shader.uniforms ), - vertexShader: shader.vertexShader, - fragmentShader: shader.fragmentShader + uniforms: combinedUniforms, + vertexShader: shaderUniformsGLSLVert + shader.vertexShader, + fragmentShader: shaderUniformsGLSLFrag + shader.fragmentShader //maybe not use the same + }; } else { @@ -1797,8 +1827,14 @@ function WebGLRenderer( parameters ) { } - // refresh uniforms common to several materials + //refresh custom provided uniforms + if ( undefined !== material.shaderUniforms ) { + + refreshUniformsCustom( m_uniforms, material ); + } + + // refresh uniforms common to several materials if ( fog && material.fog ) { refreshUniformsFog( m_uniforms, fog ); @@ -2041,6 +2077,17 @@ function WebGLRenderer( parameters ) { } + //refresh custom provided uniforms + function refreshUniformsCustom( uniforms, material ) { + + for ( var uniform in material.shaderUniforms ) { + + uniforms[ uniform ].value = material.shaderUniforms[ uniform ].value; + + } + + } + function refreshUniformsLine( uniforms, material ) { uniforms.diffuse.value = material.color; diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index b2ffa49f26971b..f4e4c778725d3f 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -158,13 +158,15 @@ function replaceClippingPlaneNums( string, parameters ) { } -function parseIncludes( string ) { +//consider provided dictionary when parsing the includes (not just THREE.ShaderChunk) +function parseIncludes( string, materialIncludes ) { var pattern = /^[ \t]*#include +<([\w\d.]+)>/gm; function replace( match, include ) { - var replace = ShaderChunk[ include ]; + //if there are material includes provided use those instead of the default chunks: + var replace = undefined !== materialIncludes[ include ] ? materialIncludes[ include ] : ShaderChunk[ include ]; if ( replace === undefined ) { @@ -208,6 +210,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters var defines = material.defines; + var materialIncludes = material.shaderIncludes; //custom chunks + var vertexShader = shader.vertexShader; var fragmentShader = shader.fragmentShader; @@ -289,6 +293,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters var customDefines = generateDefines( defines ); + var customIncludes = undefined !== materialIncludes ? materialIncludes : {}; //user is not aware of this feature, fine + // var program = gl.createProgram(); @@ -503,11 +509,12 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters } - vertexShader = parseIncludes( vertexShader ); + // provide optional chunk dictionary customIncludes + vertexShader = parseIncludes( vertexShader, customIncludes ); vertexShader = replaceLightNums( vertexShader, parameters ); vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); - fragmentShader = parseIncludes( fragmentShader ); + fragmentShader = parseIncludes( fragmentShader, customIncludes ); fragmentShader = replaceLightNums( fragmentShader, parameters ); fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index 633a3397e7c7a1..f1f13c68d5f238 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -241,10 +241,20 @@ function WebGLPrograms( renderer, extensions, capabilities ) { } - array.push( material.onBeforeCompile.toString() ); - array.push( renderer.gammaOutput ); + // if there is this dictionary present + if ( material.shaderIncludes !== undefined ) { + + for ( var include in material.shaderIncludes ) { + + // hash with chunks? + array.push( material.shaderIncludes[ include ] ); + + } + + } + return array.join(); }; From c772c4a88cb4c2a385a92fb537703a3cf276ee26 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 20:04:20 -0700 Subject: [PATCH 02/27] add example for sg and channel transforms --- examples/files.js | 1 + .../js/SpecGlossMultiUVInstanceExample.js | 220 ++++++++++++++++++ examples/webgl_materials_modified.html | 2 +- examples/webgl_materials_modified2.html | 187 +++++++++++++++ src/renderers/WebGLRenderer.js | 2 +- 5 files changed, 410 insertions(+), 2 deletions(-) create mode 100644 examples/js/SpecGlossMultiUVInstanceExample.js create mode 100644 examples/webgl_materials_modified2.html diff --git a/examples/files.js b/examples/files.js index a84dc6bae96e69..e35f16db166bce 100644 --- a/examples/files.js +++ b/examples/files.js @@ -298,6 +298,7 @@ var files = { "webgl_custom_attributes_points2", "webgl_custom_attributes_points3", "webgl_materials_modified", + "webgl_materials_modified2", "webgl_raymarching_reflect", "webgl_shadowmap_pcss", "webgl_simple_gi", diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js new file mode 100644 index 00000000000000..28271a9615a967 --- /dev/null +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -0,0 +1,220 @@ +// some utils + +function addOrMergeProp( material, propName, data ) { + + if ( material[ propName ] ) { + + Object.assign( material[ propName ], data ); + + } else { + + material[ propName ] = data; + + } + +} + +// from three's texture transform api, to be applied to a uniform matrix +function setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { + + var c = Math.cos( rotation ); + var s = Math.sin( rotation ); + + this.set( + sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, + - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, + 0, 0, 0 + ); + +} + +//spec gloss stuff --------------------------------------------------------- + +//this extends the shader to use specular gloss PBR model instead of rough/metal + +var specularMapFragmentChunk = [ + 'vec3 specularFactor = specular;', + '#ifdef USE_SPECULARMAP', + ' vec4 texelSpecular = texture2D( specularMap, vUv );', + ' texelSpecular = sRGBToLinear( texelSpecular );', + ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' specularFactor *= texelSpecular.rgb;', + '#endif', + // 'gl_FragColor = vec4(vec3(specularFactor),1.);', + // 'return;', +].join( '\n' ); + +var glossinessMapFragmentChunk = [ + 'float glossinessFactor = glossiness;', + '#ifdef USE_GLOSSINESSMAP', + ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', + ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' glossinessFactor *= texelGlossiness.r;', + // 'gl_FragColor = vec4(vec3(glossinessFactor),1.);', + // 'return;', + '#endif', +].join( '\n' ); + +var lightPhysicalFragmentChunk = [ + 'PhysicalMaterial material;', + 'material.diffuseColor = diffuseColor.rgb;', + 'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );', + 'material.specularColor = specularFactor.rgb;', +].join( '\n' ); + +var SHADER_INCLUDES_SPEC_GLOSS = { + roughnessmap_fragment: specularMapFragmentChunk, + metalnessmap_fragment: glossinessMapFragmentChunk, + lights_physical_fragment: lightPhysicalFragmentChunk, +}; + +function decorateMaterialWithSpecGloss( material ) { + + if ( material.isSpecGlossExtended ) return material; + + material.isSpecGlossExtended = true; + + var shaderUniforms = { + specular: { value: new THREE.Color().setHex( 0xffffff ), type: 'vec3', stage: 'fragment' }, //fragment can be ommitted (defaults to it) but for sake of clarity + glossiness: { value: 1, type: 'float', stage: 'fragment' }, + glossinessMap: { value: null, type: 'sampler2D', stage: 'fragment' }, + specularMap: { value: null, type: 'sampler2D', stage: 'fragment' }, + }; + + var defines = {USE_GLOSSINESSMAP: ''} + + //conflicts could be resolved here + addOrMergeProp( material, 'shaderUniforms', shaderUniforms ); + addOrMergeProp( material, 'shaderIncludes', SHADER_INCLUDES_SPEC_GLOSS ); + addOrMergeProp( material, 'defines', defines ); + + console.log(material.shaderUniforms) + console.log(material.shaderIncludes) + //expose uniforms as props for a cleaner interface (but shaderUniforms is also available so this can be omitted) + for ( let propName in shaderUniforms ) { + + Object.defineProperty( material, propName, { + get: ()=> shaderUniforms[ propName ].value, + set: ( v )=> (shaderUniforms[ propName ].value = v), + } ); + + } + +} + +// multi uv stuff --------------------------------------------------------- + +// this moves the transform from textures to the material, textures become just data + +//list of maps to be extended, these are easy +var DEFAULT_MAP_LIST = [ + 'alphaMap', + 'specularMap', + 'map', + 'emissiveMap', + 'metalnessMap', + 'roughnessMap', + 'glossinessMap' //this one is from the other example, but if its there it should work, this can be solved to work together somehow +]; + +//this can be programatic +var PROP_TO_CHUNK_MAP = { + 'alphaMap': 'alphamap_fragment', + 'specularMap': 'specularmap_fragment', + 'map': 'map_fragment', + 'emissiveMap': 'emissivemap_fragment', + 'metalnessMap': 'metalnessmap_fragment', + 'roughnessMap': 'roughnessmap_fragment', + 'glossinessMap': 'metalnessmap_fragment', //this one cant be programatic because it belongs to another override, could be a specific check somewhere else + 'specularMapGloss': 'roughnessmap_fragment', +}; + +//some utils + +var mapRegex = /texture2D\( (.*Map|map), vUv \)/gm //look for this + +function getReplaceString(mapName){ + return `texture2D( $1, ( ${getUniformNameFromProp(mapName)} * vec3( vUv, 1. ) ).xy )` +} + + +function getUniformNameFromProp(prop){ + return `u_${prop}Transform` +} + +function addMapTransformPropsToMaterial( material, mapName ){ + + let _mapName = mapName + material[`${mapName}Repeat`] = new THREE.Vector2(1,1) + material[`${mapName}Offset`] = new THREE.Vector2() + material[`${mapName}Center`] = new THREE.Vector2() + material[`${mapName}Rotation`] = 0 + material[`${mapName}UpdateMatrix`] = function(){ + this.shaderUniforms[getUniformNameFromProp(_mapName)].value + .setUvTransform( + this[`${_mapName}Offset`].x, + this[`${_mapName}Offset`].y, + this[`${_mapName}Repeat`].x, + this[`${_mapName}Repeat`].y, + this[`${_mapName}Rotation`], + this[`${_mapName}Center`].x, + this[`${_mapName}Center`].y, + ) + }.bind(material) +} + + +function decorateMaterialWithPerMapTransforms( material, mapList ) { + + if ( material.isPerMapTransformExtended ) return material; + + material.isPerMapTransformExtended = true; + + delete material.metalnessMap + delete material.roughnessMap + + mapList = mapList || DEFAULT_MAP_LIST; + + var shaderUniforms = {} + var shaderIncludes = {} + + for ( var i = 0; i < mapList.length; i ++ ) { + + var mapName = mapList[ i ]; + + addMapTransformPropsToMaterial(material, mapName) + + if ( material[ mapName ] !== undefined ) { + + var uniform = { value: new THREE.Matrix3(), type:'mat3', stage: 'fragment' }; + uniform.value.setUvTransform = setUvTransform.bind( uniform.value ); + + shaderUniforms[getUniformNameFromProp(mapName)] = uniform + + var lookup = mapName + if( material.isSpecGlossExtended && mapName === 'specularMap'){ + lookup = 'specularMapGloss' + } + + var chunkName = PROP_TO_CHUNK_MAP[lookup] + + console.log('chunkName',chunkName) + + console.log('ownChunk?',(material.shaderIncludes && material.shaderIncludes[chunkName])) + + console.log(mapName) + + var shaderChunk = (material.shaderIncludes && material.shaderIncludes[chunkName]) || THREE.ShaderChunk[chunkName] + + shaderChunk = shaderChunk.replace( mapRegex , getReplaceString(mapName) ) + + shaderIncludes[ chunkName ] = shaderChunk + + } + + } + + addOrMergeProp( material, 'shaderUniforms', shaderUniforms ); + addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + +} diff --git a/examples/webgl_materials_modified.html b/examples/webgl_materials_modified.html index 8f34c8ca8e772e..99194ff9e3e82c 100644 --- a/examples/webgl_materials_modified.html +++ b/examples/webgl_materials_modified.html @@ -88,7 +88,7 @@ material.shaderIncludes = { begin_vertex: my_begin_vertex }; - material.shaderUniforms = { time: { value: 0, type: 'float' } }; + material.shaderUniforms = { time: { value: 0, type: 'float', stage: 'vertex' } }; var loader = new THREE.JSONLoader(); loader.load( 'models/json/leeperrysmith/LeePerrySmith.json', function( geometry ) { diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html new file mode 100644 index 00000000000000..6ffa35229bd711 --- /dev/null +++ b/examples/webgl_materials_modified2.html @@ -0,0 +1,187 @@ + + + + three.js webgl - materials - modified + + + + + + +
+ three.js wegbl - modified material. + Lee Perry-Smith head. + Author @pailhead. +
+ + + + + + + + + + + + diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index dda001d8b9555c..ec525d66ed2b96 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1489,7 +1489,7 @@ function WebGLRenderer( parameters ) { if ( type ) { - if ( stage === 'vertex' ) { + if ( stage === 'vertex' ) { //dunno what to do here, maybe if not provided should inject into both shaderUniformsGLSLVert += 'uniform ' + type + ' ' + uniformName + ';\n'; From 64930c5790253fd1526a1e4cf16a368f72f76fa7 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 20:16:03 -0700 Subject: [PATCH 03/27] add instance example --- .../js/SpecGlossMultiUVInstanceExample.js | 39 ++++++++++++++++--- examples/webgl_materials_modified2.html | 31 ++++++++++++++- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 28271a9615a967..dc6c6dc709bde2 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -198,12 +198,6 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { var chunkName = PROP_TO_CHUNK_MAP[lookup] - console.log('chunkName',chunkName) - - console.log('ownChunk?',(material.shaderIncludes && material.shaderIncludes[chunkName])) - - console.log(mapName) - var shaderChunk = (material.shaderIncludes && material.shaderIncludes[chunkName]) || THREE.ShaderChunk[chunkName] shaderChunk = shaderChunk.replace( mapRegex , getReplaceString(mapName) ) @@ -218,3 +212,36 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); } + + + +// simple instance stuff from lambert example --------------------------------------------------------- + +var after_vertex_transform_chunk = ` + transformed *= instanceScale; //the value present in transformed is in model space, + transformed = transformed + instanceOffset; +` + +function decorateMaterialWithSimpleInstancing( material ) { + if( material.isSimpleInstanceExtended ) return material + material.isSimpleInstanceExtended = true + + var shaderIncludes = { + begin_vertex:` + ${THREE.ShaderChunk.begin_vertex} + ${after_vertex_transform_chunk} + ` + } + + //no good global chunk, but could be uv_pars, heres how to make it work with onbeforecompile + material.onBeforeCompile = shader => { + shader.vertexShader = ` + attribute vec3 instanceOffset; + attribute float instanceScale; + ${shader.vertexShader} + ` + } + + addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + +} \ No newline at end of file diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 6ffa35229bd711..affd87aa643b3e 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -48,6 +48,8 @@ + + @@ -115,7 +117,7 @@ var material = new THREE.MeshStandardMaterial({ color: 0xffb54a, }) - mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(60), material) + mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(10), material) scene.add(mesh) decorateMaterialWithSpecGloss(material) @@ -129,6 +131,33 @@ gui.add( material.glossinessMapOffset,'x',0,1).onChange(material.glossinessMapUpdateMatrix) gui.add( material, 'glossinessMapRotation',0,1).onChange(material.glossinessMapUpdateMatrix) + //instancing + const INSTANCES = 256; + var knot = new THREE.Curves.TorusKnot( 60 ); + var positions = knot.getSpacedPoints( INSTANCES ); + + var offsets = new Float32Array( INSTANCES * 3 ); // xyz + var scales = new Float32Array( INSTANCES * 1 ); // s + for ( var i = 0, l = INSTANCES; i < l; i ++ ) { + + var index = 3 * i; + + // per-instance position offset + offsets[ index ] = positions[ i ].x; + offsets[ index + 1 ] = positions[ i ].y; + offsets[ index + 2 ] = positions[ i ].z; + + // per-instance scale variation + scales[ i ] = 1 + 0.5 * Math.sin( 32 * Math.PI * i / INSTANCES ); + + } + mesh.geometry = new THREE.InstancedBufferGeometry().copy(mesh.geometry) + mesh.geometry.maxInstancedCount = INSTANCES + console.log(mesh.geometry) + mesh.geometry.addAttribute( 'instanceOffset', new THREE.InstancedBufferAttribute( offsets, 3 ) ); + mesh.geometry.addAttribute( 'instanceScale', new THREE.InstancedBufferAttribute( scales, 1 ) ); + + decorateMaterialWithSimpleInstancing(material) } From f79639d84f77294fecb6dbd57a5c0b1c46d556b7 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 20:19:16 -0700 Subject: [PATCH 04/27] add envmap add env map and deferedd update? --- examples/webgl_materials_modified2.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index affd87aa643b3e..c9fccb7bb67c62 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -89,11 +89,6 @@ scene.add(light) - var light = new THREE.DirectionalLight( 0xffffff, 0.4 ); - light.position.set( -50, 40, 40 ); - scene.add(light) - - renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); @@ -114,9 +109,19 @@ var texture = new THREE.TextureLoader().load( `textures/roughness_map.jpg` ) texture.wrapS = texture.wrapT = THREE.RepeatWrapping + var envMap = new THREE.TextureLoader().load( `textures/metal.jpg`, function ( texture ) { + + texture.mapping = THREE.SphericalReflectionMapping; + texture.encoding = THREE.sRGBEncoding; + if ( mesh ) mesh.material.needsUpdate = true; + + } ); + var material = new THREE.MeshStandardMaterial({ color: 0xffb54a, + envMap: envMap, }) + mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(10), material) scene.add(mesh) From f295e49321ae01bbe09be2b43db5a4ba28f56fa1 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 20:43:47 -0700 Subject: [PATCH 05/27] add shadow stuff --- .../js/SpecGlossMultiUVInstanceExample.js | 7 +++- examples/webgl_materials_modified2.html | 34 +++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index dc6c6dc709bde2..0a7ec2708c099f 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -99,6 +99,8 @@ function decorateMaterialWithSpecGloss( material ) { } ); } + + return material } @@ -211,6 +213,7 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { addOrMergeProp( material, 'shaderUniforms', shaderUniforms ); addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + return material } @@ -241,7 +244,9 @@ function decorateMaterialWithSimpleInstancing( material ) { ${shader.vertexShader} ` } - + addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + return material + } \ No newline at end of file diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index c9fccb7bb67c62..c68d57d2807d07 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -82,18 +82,43 @@ scene = new THREE.Scene(); - material = new THREE.MeshNormalMaterial(); //no need to create a uniform at some obscure compile time, it's available now (obsucure because its both onBeforeParse and onBeforeCompile`) - var light = new THREE.DirectionalLight( 0xffffff, 0.4 ); - light.position.set( 50, 40, 40 ); + light.position.set( 100, 260, 160 ); + light.castShadow = true; + light.shadow.camera.left = - 240; + light.shadow.camera.right = 240; + light.shadow.camera.top = 240; + light.shadow.camera.bottom = - 240; + light.shadow.camera.near = 10; + light.shadow.camera.far = 1500; + + light.shadow.bias = - 0.001; + light.shadow.mapSize.width = 512; + light.shadow.mapSize.height = 512; scene.add(light) + + // light shadow camera helper + light.shadowCameraHelper = new THREE.CameraHelper( light.shadow.camera ); + scene.add( light.shadowCameraHelper ); + scene.add( new THREE.AmbientLight( 0xffffff, 0.17 ) ); + + var ground = new THREE.Mesh( + new THREE.PlaneBufferGeometry( 800, 800 ).rotateX( - Math.PI / 2 ), + new THREE.MeshPhongMaterial( { color: 0x888888 } ) + ); + ground.position.set( 0, - 200, 0 ); + ground.receiveShadow = true; + + scene.add( ground ); + renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); + renderer.shadowMap.enabled = true; // stats = new Stats(); @@ -124,6 +149,8 @@ mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(10), material) scene.add(mesh) + mesh.castShadow = true + mesh.receiveShadow = true decorateMaterialWithSpecGloss(material) material.glossinessMap = texture @@ -162,6 +189,7 @@ mesh.geometry.addAttribute( 'instanceOffset', new THREE.InstancedBufferAttribute( offsets, 3 ) ); mesh.geometry.addAttribute( 'instanceScale', new THREE.InstancedBufferAttribute( scales, 1 ) ); + mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing(new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })) decorateMaterialWithSimpleInstancing(material) } From cb68da76f2c4c2584f9cb7a8aa48e0e11364ff00 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sat, 2 Jun 2018 20:46:08 -0700 Subject: [PATCH 06/27] lint webglPrograms --- src/renderers/webgl/WebGLPrograms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index f1f13c68d5f238..3d3825f788ab8a 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -243,7 +243,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) { array.push( renderer.gammaOutput ); - // if there is this dictionary present + // if there is this dictionary present if ( material.shaderIncludes !== undefined ) { for ( var include in material.shaderIncludes ) { From 9c20d69595b4d995042bed8d09e521005a140e1c Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:07:42 -0700 Subject: [PATCH 07/27] comment everything --- .../js/SpecGlossMultiUVInstanceExample.js | 69 ++++++++++++++++--- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 0a7ec2708c099f..5539b7097fb275 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -74,6 +74,8 @@ function decorateMaterialWithSpecGloss( material ) { material.isSpecGlossExtended = true; + // these are the extra uniforms, but instead of being stored in .userData, or some such place + // a designated prop could be used var shaderUniforms = { specular: { value: new THREE.Color().setHex( 0xffffff ), type: 'vec3', stage: 'fragment' }, //fragment can be ommitted (defaults to it) but for sake of clarity glossiness: { value: 1, type: 'float', stage: 'fragment' }, @@ -88,9 +90,8 @@ function decorateMaterialWithSpecGloss( material ) { addOrMergeProp( material, 'shaderIncludes', SHADER_INCLUDES_SPEC_GLOSS ); addOrMergeProp( material, 'defines', defines ); - console.log(material.shaderUniforms) - console.log(material.shaderIncludes) //expose uniforms as props for a cleaner interface (but shaderUniforms is also available so this can be omitted) + //it just leads to a cleaner more familiar interface (PhongMaterial has specularMap, so this now has it too) for ( let propName in shaderUniforms ) { Object.defineProperty( material, propName, { @@ -99,7 +100,7 @@ function decorateMaterialWithSpecGloss( material ) { } ); } - + return material } @@ -120,6 +121,9 @@ var DEFAULT_MAP_LIST = [ ]; //this can be programatic +//it tells the extension where to look for certain maps +//these follow the /texture2D( $mapname, vUv )/ pattern +//normal map is a bit more complex and would require a non programatic chunk var PROP_TO_CHUNK_MAP = { 'alphaMap': 'alphamap_fragment', 'specularMap': 'specularmap_fragment', @@ -133,17 +137,22 @@ var PROP_TO_CHUNK_MAP = { //some utils -var mapRegex = /texture2D\( (.*Map|map), vUv \)/gm //look for this +var mapRegex = /texture2D\( (.*Map|map), vUv \)/gm //look for the pattern /texture2D( $someMap, vUv )/ +//because the other extension changes roughnessMap to specularMap we need the $1 to replace the name, otherwise it could be `mapName` function getReplaceString(mapName){ return `texture2D( $1, ( ${getUniformNameFromProp(mapName)} * vec3( vUv, 1. ) ).xy )` } - +//in order to keep the uniform name obvious that it belongs to the GLSL context, and to make it as private sounding as possible function getUniformNameFromProp(prop){ return `u_${prop}Transform` } +//a utility to add the necessary transform properties to a material based on an arbitrary map name +//so if specularMap is provided it will create these Vector2, a float, and an updateMatrix method +//this is very similar to the Texture transform interface the only difference being that the props are prefixed +//myTexture.repeat vs myMaterial.specularMapRepeat function addMapTransformPropsToMaterial( material, mapName ){ let _mapName = mapName @@ -172,9 +181,14 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { material.isPerMapTransformExtended = true; - delete material.metalnessMap - delete material.roughnessMap + //this could be more generic, say, check if the chunks belonging to these maps have been altered + //but also knowing about the other extension, makes for an easy check + if( material.isSpecGlossExtended){ + delete material.metalnessMap //remove the unused map names so the loop below doesnt account for them (conflict) + delete material.roughnessMap + } + //one can provide a subset from outside mapList = mapList || DEFAULT_MAP_LIST; var shaderUniforms = {} @@ -184,32 +198,42 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { var mapName = mapList[ i ]; - addMapTransformPropsToMaterial(material, mapName) if ( material[ mapName ] !== undefined ) { + addMapTransformPropsToMaterial(material, mapName) + var uniform = { value: new THREE.Matrix3(), type:'mat3', stage: 'fragment' }; uniform.value.setUvTransform = setUvTransform.bind( uniform.value ); shaderUniforms[getUniformNameFromProp(mapName)] = uniform + //this is for resolving the conflict, its not the most elegant solution but it works + //i believe that this would be solved by refactoring the shader templates var lookup = mapName if( material.isSpecGlossExtended && mapName === 'specularMap'){ lookup = 'specularMapGloss' } + //based on the map name ie. specularMap or even an extended glossinessMap pick a chunk var chunkName = PROP_TO_CHUNK_MAP[lookup] + //if there already is a chunk from some extension, pick that, otherwise copy the default chunk var shaderChunk = (material.shaderIncludes && material.shaderIncludes[chunkName]) || THREE.ShaderChunk[chunkName] + //apply the string transformation, this contains the copy of whatever chunk was provided (default or custom) shaderChunk = shaderChunk.replace( mapRegex , getReplaceString(mapName) ) + //provide this copy as the include chunk, this shader wont look up THREE.ShaderChunk + //and doesnt have to wait for onBeforeCompile to do the transformation + //final transformed chunk is already stored here in this context sync shaderIncludes[ chunkName ] = shaderChunk } } + //combine with other chunks addOrMergeProp( material, 'shaderUniforms', shaderUniforms ); addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); @@ -220,15 +244,20 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { // simple instance stuff from lambert example --------------------------------------------------------- +//this is a stage after begin_vertex, this would be more elegant with hooks and template refactor var after_vertex_transform_chunk = ` transformed *= instanceScale; //the value present in transformed is in model space, transformed = transformed + instanceOffset; ` function decorateMaterialWithSimpleInstancing( material ) { + if( material.isSimpleInstanceExtended ) return material + material.isSimpleInstanceExtended = true + //make a custom chunk that includes a copy of the default chunk from THREE.ShaderChunk + //followed by a custom chunk, that is simply appended to the copy var shaderIncludes = { begin_vertex:` ${THREE.ShaderChunk.begin_vertex} @@ -237,14 +266,34 @@ function decorateMaterialWithSimpleInstancing( material ) { } //no good global chunk, but could be uv_pars, heres how to make it work with onbeforecompile - material.onBeforeCompile = shader => { - shader.vertexShader = ` + //because this is somewhat of a set and forget thing, onBeforeCompile (or onBeforeParse) is + //perfectly valid to use here + //"here are some attribute names, whenver you get around to assemblying the shader on WebGL level use them" + //A uniform (over an attribute) would be better if it were available in this scope + + var attributeInjection = ` attribute vec3 instanceOffset; attribute float instanceScale; + ` + + material.onBeforeCompile = shader => { + shader.vertexShader = ` + ${attributeInjection} ${shader.vertexShader} ` } + //alternatively one can use `uv_pars_vertex` + //since displacement map is used in almost all of the shaders, this chunk is present + //depth for example, has this chunk, so whatever attribute is added to StandardMaterial + //is also going to be added to DepthMaterial + /*shaderIncludes = { + uv_pars_vertex: ` + ${attributeInjection} + ${THREE.ShaderChunk.uv_pars_vertex} + ` + }*/ + addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); return material From 748ebb78e1b47aaf2f10d0fc608edafdc900b5ec Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:23:50 -0700 Subject: [PATCH 08/27] something is off with the spec gloss map? --- examples/js/loaders/GLTFLoader.js | 52 +++------------------- examples/webgl_loader_gltf_extensions.html | 1 + 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index ea907316859455..b72a5266139e43 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -565,8 +565,6 @@ THREE.GLTFLoader = ( function () { getMaterialType: function () { - // return THREE.ShaderMaterial; - // return THREE.MeshStandardMaterial return 'SPEC_GLOSS'; }, @@ -575,45 +573,6 @@ THREE.GLTFLoader = ( function () { var pbrSpecularGlossiness = material.extensions[ this.name ]; - var specularMapFragmentChunk = [ - 'vec3 specularFactor = specular;', - '#ifdef USE_SPECULARMAP', - ' vec4 texelSpecular = texture2D( specularMap, vUv );', - ' texelSpecular = sRGBToLinear( texelSpecular );', - ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' specularFactor *= texelSpecular.rgb;', - '#endif' - ].join( '\n' ); - - var glossinessMapFragmentChunk = [ - 'float glossinessFactor = glossiness;', - '#ifdef USE_GLOSSINESSMAP', - ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', - ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' glossinessFactor *= texelGlossiness.a;', - '#endif' - ].join( '\n' ); - - var lightPhysicalFragmentChunk = [ - 'PhysicalMaterial material;', - 'material.diffuseColor = diffuseColor.rgb;', - 'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );', - 'material.specularColor = specularFactor.rgb;', - ].join( '\n' ); - - params.shaderUniforms = { - specular: { value: new THREE.Color().setHex( 0x111111 ), type: 'vec3' }, //atm these end up in both vert and frag :/ - glossiness: { value: 0.5, type: 'float' }, - glossinessMap: { value: null, type: 'sampler2D' }, - specularMap: { value: null, type: 'sampler2D' }, - }; - - params.shaderIncludes = { - roughnessmap_fragment: specularMapFragmentChunk, - metalnessmap_fragment: glossinessMapFragmentChunk, - lights_physical_fragment: lightPhysicalFragmentChunk, - }; - params.color = new THREE.Color( 1.0, 1.0, 1.0 ); params.opacity = 1.0; @@ -666,8 +625,7 @@ THREE.GLTFLoader = ( function () { console.log( material ); - material.shaderIncludes = params.shaderIncludes; - material.shaderUniforms = params.shaderUniforms; + decorateMaterialWithSpecGloss(material) material.isGLTFSpecularGlossinessMaterial = true; @@ -697,21 +655,21 @@ THREE.GLTFLoader = ( function () { if ( params.specularMap ) { - material.shaderUniforms.specularMap.value = params.glossinessMap; + material.specularMap = params.specularMap; material.defines.USE_SPECULARMAP = ''; } - material.shaderUniforms.specular.value = params.specular; + material.specular = params.specular; if ( params.glossinessMap ) { - material.shaderUniforms.glossinessMap.value = params.glossinessMap; + material.glossinessMap = params.glossinessMap; material.defines.USE_GLOSSINESSMAP = ''; } - material.shaderUniforms.glossiness.value = params.glossiness; + material.glossiness = params.glossiness; material.alphaMap = null; diff --git a/examples/webgl_loader_gltf_extensions.html b/examples/webgl_loader_gltf_extensions.html index 7eb1fcef031808..d23919b72f951f 100644 --- a/examples/webgl_loader_gltf_extensions.html +++ b/examples/webgl_loader_gltf_extensions.html @@ -52,6 +52,7 @@ + From 38a5d9204d7745fa5a141fa6e6fb16847a06a6d9 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:24:36 -0700 Subject: [PATCH 09/27] was looking at wrong channel --- examples/js/SpecGlossMultiUVInstanceExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 5539b7097fb275..4b7406b4f612df 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -49,7 +49,7 @@ var glossinessMapFragmentChunk = [ '#ifdef USE_GLOSSINESSMAP', ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', - ' glossinessFactor *= texelGlossiness.r;', + ' glossinessFactor *= texelGlossiness.a;', // 'gl_FragColor = vec4(vec3(glossinessFactor),1.);', // 'return;', '#endif', From 7a7e072b2eba4040f95882153b15eefb7a131ba8 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:28:04 -0700 Subject: [PATCH 10/27] add some comments to example --- examples/webgl_materials_modified2.html | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index c68d57d2807d07..4d8de1ac1b2eec 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -152,11 +152,17 @@ mesh.castShadow = true mesh.receiveShadow = true + //decorate with spec gloss decorateMaterialWithSpecGloss(material) + + //results in these maps being immidiately available material.glossinessMap = texture material.specularMap = texture + + //decorate with map transforms decorateMaterialWithPerMapTransforms(material) + //results in thse Vector2 and primitev properties being immidiately available gui.add( material.glossinessMapRepeat,'x',0,10).onChange(material.glossinessMapUpdateMatrix) gui.add( material.glossinessMapRepeat,'y',0,10).onChange(material.glossinessMapUpdateMatrix) gui.add( material.glossinessMapOffset,'x',0,1).onChange(material.glossinessMapUpdateMatrix) @@ -164,6 +170,8 @@ gui.add( material, 'glossinessMapRotation',0,1).onChange(material.glossinessMapUpdateMatrix) //instancing + + //create geometry attributes const INSTANCES = 256; var knot = new THREE.Curves.TorusKnot( 60 ); var positions = knot.getSpacedPoints( INSTANCES ); @@ -185,12 +193,18 @@ } mesh.geometry = new THREE.InstancedBufferGeometry().copy(mesh.geometry) mesh.geometry.maxInstancedCount = INSTANCES - console.log(mesh.geometry) + + //end custom geometry creation + + + //material decorator exposes instanceOffset and instanceScale, + //provide these to geometry mesh.geometry.addAttribute( 'instanceOffset', new THREE.InstancedBufferAttribute( offsets, 3 ) ); mesh.geometry.addAttribute( 'instanceScale', new THREE.InstancedBufferAttribute( scales, 1 ) ); - mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing(new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })) decorateMaterialWithSimpleInstancing(material) + //same for depth material + mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing(new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })) } From 346c03abe5aec2e60b262b10ed09e89101ba1293 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:33:29 -0700 Subject: [PATCH 11/27] remove gloss from gui cause it did nothing it looks up .a which the map didnt have, specular is more illustrative --- examples/webgl_materials_modified2.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 4d8de1ac1b2eec..fa7e28b6d8b122 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -163,11 +163,11 @@ decorateMaterialWithPerMapTransforms(material) //results in thse Vector2 and primitev properties being immidiately available - gui.add( material.glossinessMapRepeat,'x',0,10).onChange(material.glossinessMapUpdateMatrix) - gui.add( material.glossinessMapRepeat,'y',0,10).onChange(material.glossinessMapUpdateMatrix) - gui.add( material.glossinessMapOffset,'x',0,1).onChange(material.glossinessMapUpdateMatrix) - gui.add( material.glossinessMapOffset,'x',0,1).onChange(material.glossinessMapUpdateMatrix) - gui.add( material, 'glossinessMapRotation',0,1).onChange(material.glossinessMapUpdateMatrix) + gui.add( material.specularMapRepeat,'x',0,10).onChange(material.specularMapUpdateMatrix) + gui.add( material.specularMapRepeat,'y',0,10).onChange(material.specularMapUpdateMatrix) + gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) + gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) + gui.add( material, 'specularMapRotation',0,1).onChange(material.specularMapUpdateMatrix) //instancing From 9a410ccda41a5b9efa6a7bf7cc1f434942ee1b46 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:34:32 -0700 Subject: [PATCH 12/27] add glossiness gui float --- examples/webgl_materials_modified2.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index fa7e28b6d8b122..42118149963fbd 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -168,6 +168,7 @@ gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) gui.add( material, 'specularMapRotation',0,1).onChange(material.specularMapUpdateMatrix) + gui.add( material, 'glossiness',0,1) //instancing From 5680d396884c6232ed9afc7668c6744de330c4f2 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:35:55 -0700 Subject: [PATCH 13/27] put texture into map slot too to illustrate that its decoupled --- examples/webgl_materials_modified2.html | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 42118149963fbd..54ec72dc56193f 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -145,6 +145,7 @@ var material = new THREE.MeshStandardMaterial({ color: 0xffb54a, envMap: envMap, + map: texture, }) mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(10), material) From d0bda3ff19942a1a77fdfaa9d1e2a1fdeaa303d2 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 03:58:01 -0700 Subject: [PATCH 14/27] add an inline example on how to override the override say that the three features are provided from an npm module or something, an example how to further "inline" extend it --- examples/webgl_materials_modified2.html | 57 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 54ec72dc56193f..4b7a580015fbd4 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -57,7 +57,7 @@ if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); - var camera, scene, renderer, stats; + var camera, scene, renderer, stats, clock; var mesh, material; @@ -70,13 +70,22 @@ var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; - var gui = new dat.GUI() + var _gui = new dat.GUI() + + var gui = _gui.addFolder('gui') + gui.open() + + var guiData = { speed: 1 } + + gui.add( guiData, 'speed', 0, 5 ) init(); animate(); function init() { + clock = new THREE.Clock(); + camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.z = 1200; @@ -207,6 +216,47 @@ decorateMaterialWithSimpleInstancing(material) //same for depth material mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing(new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })) + + + + //4. add a final custom animation effect on top of the instancing effect + var indecis = new Float32Array( INSTANCES * 1 ); + + for ( var i = 0, l = INSTANCES; i < l; i ++ ) { + indecis[i] = i / INSTANCES + } + //add this new attribute + mesh.geometry.addAttribute('aIndex', new THREE.InstancedBufferAttribute( indecis, 1 ) ) + + //remove the old attibute (we could have overloaded it though) + delete mesh.geometry.attributes.instanceScale + + var frequency = 32 + //knowing we decorated with simpleInstancing we have a parsed/included "compiled" chunk to work with + material.shaderIncludes.begin_vertex = material.shaderIncludes.begin_vertex.replace( + 'transformed *= instanceScale;', //we know how simpleInstancing works + `float _ind = aIndex + uTime; + transformed *= 1. + 0.5 * sin(${frequency}.0 * ${Math.PI} * _ind );` //we override a part of that extension with our custom logic + ) + + //we need a custom time uniform for the effect + material.shaderUniforms.uTime = { value: 0, type: 'float', stage: 'vertex' } + + //we expose it as a primitive + Object.defineProperty(material, 'time', { + get:()=>material.shaderUniforms.uTime.value, + set:v=>material.shaderUniforms.uTime.value = v + }) + + //because there is already an onBeforeCompile, it's tricky to add another one to append + //the new attribute ( and remove the old one ), fortunately, we can use the uv_pars_vertex + + material.shaderIncludes.uv_pars_vertex = ` + ${THREE.ShaderChunk.uv_pars_vertex} + attribute float aIndex; + ` + + } @@ -229,7 +279,6 @@ mouseX = ( event.clientX - windowHalfX ); mouseY = ( event.clientY - windowHalfY ); - console.log } @@ -253,6 +302,7 @@ mesh.rotation.y += 0.05 * ( targetX - mesh.rotation.y ); mesh.rotation.x += 0.05 * ( targetY - mesh.rotation.x ); + mesh.material.time += clock.getDelta() * 0.01 * guiData.speed } renderer.render( scene, camera ); @@ -260,6 +310,5 @@ } - From d3b39fa921781504746ff5d008d2d61222aff1d6 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 04:06:37 -0700 Subject: [PATCH 15/27] add more comments --- examples/webgl_materials_modified2.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 4b7a580015fbd4..da5766b355e6a3 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -250,7 +250,15 @@ //because there is already an onBeforeCompile, it's tricky to add another one to append //the new attribute ( and remove the old one ), fortunately, we can use the uv_pars_vertex - + //ideally there should be a chunk called global_vertex_pars or something like that where + //one could inject uniforms functions varyings and attributes + //with this api, in this stage, at least one would have the unrolled raw glsl to work with + //available in this scope at this time + //aka + //material.shaderIncludes.some_chunk = my_some_chunk || THREE.ShaderChunk.some_chunk + //^ either way, shaderIncludes.some_chunk contains the GLSL, with onBeforeCompile this is blackboxed + // we could then do: + // global_vertex.replace( 'attribute float instanceOffset', 'attribute float aIndex' ) material.shaderIncludes.uv_pars_vertex = ` ${THREE.ShaderChunk.uv_pars_vertex} attribute float aIndex; From f1f1d3ee2c78242482524eba20a39ad42ed77383 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 04:08:42 -0700 Subject: [PATCH 16/27] add test for needs update --- examples/webgl_materials_modified2.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index da5766b355e6a3..2bd7e9cd9197de 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -75,7 +75,7 @@ var gui = _gui.addFolder('gui') gui.open() - var guiData = { speed: 1 } + var guiData = { speed: 1 , map: true} gui.add( guiData, 'speed', 0, 5 ) @@ -265,6 +265,11 @@ ` + //test needs update after all of this + gui.add(guiData, 'map').onChange(function(val){ + material.map = val ? texture : null + material.needsUpdate = true + }) } From 3345acd84c07192ef2a0c907970f7293a5aff7ec Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 3 Jun 2018 04:13:17 -0700 Subject: [PATCH 17/27] hook up shadow to effect --- examples/webgl_materials_modified2.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index 2bd7e9cd9197de..ea4f29912f8205 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -264,6 +264,10 @@ attribute float aIndex; ` + //to make it work with shadows, + mesh.customDepthMaterial.shaderIncludes.uv_pars_vertex = material.shaderIncludes.uv_pars_vertex //copy these + mesh.customDepthMaterial.shaderIncludes.begin_vertex = material.shaderIncludes.begin_vertex //copy these + mesh.customDepthMaterial.shaderUniforms = { uTime: material.shaderUniforms.uTime }//wire this by reference, whenever prop updates material uniform this material updates too by referencing the same uniform //test needs update after all of this gui.add(guiData, 'map').onChange(function(val){ From 8cf4ae6f2a25f7284fb9b5da59043feb0bbaed03 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Mon, 4 Jun 2018 19:33:24 -0700 Subject: [PATCH 18/27] try to serialize --- .../js/SpecGlossMultiUVInstanceExample.js | 64 +++++++++++++++++++ examples/webgl_materials_modified2.html | 7 +- src/materials/Material.js | 4 +- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 4b7406b4f612df..67648b969534da 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -14,6 +14,11 @@ function addOrMergeProp( material, propName, data ) { } +//serialize +function toJSON(){ + return THREE.Material.prototype.toJSON.call(this, undefined, this._serializationManager.serialize.bind(this._serializationManager)) +} + // from three's texture transform api, to be applied to a uniform matrix function setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { @@ -90,6 +95,7 @@ function decorateMaterialWithSpecGloss( material ) { addOrMergeProp( material, 'shaderIncludes', SHADER_INCLUDES_SPEC_GLOSS ); addOrMergeProp( material, 'defines', defines ); + //expose uniforms as props for a cleaner interface (but shaderUniforms is also available so this can be omitted) //it just leads to a cleaner more familiar interface (PhongMaterial has specularMap, so this now has it too) for ( let propName in shaderUniforms ) { @@ -101,6 +107,19 @@ function decorateMaterialWithSpecGloss( material ) { } + if(!material._serializationManager) material._serializationManager = new SerializationManager() + var f = function(data,meta){ + if( !data.metadata.extensions ) data.metadata.extensions = {} + data.metadata.extensions.isSpecGlossExtended = true + data.glossiness = this.glossiness + data.specular = this.specular.getHex() + if(this.glossinessMap && this.glossinessMap.isTexture) data.glossinessMap = this.glossinessMap.toJSON( meta ) + }.bind(material) + + material._serializationManager.addFunction(f) + + material.toJSON = toJSON.bind(material) + return material } @@ -193,6 +212,7 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { var shaderUniforms = {} var shaderIncludes = {} + var serialize = [] for ( var i = 0; i < mapList.length; i ++ ) { @@ -214,6 +234,7 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { if( material.isSpecGlossExtended && mapName === 'specularMap'){ lookup = 'specularMapGloss' } + serialize.push(mapName) //based on the map name ie. specularMap or even an extended glossinessMap pick a chunk var chunkName = PROP_TO_CHUNK_MAP[lookup] @@ -237,6 +258,25 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { addOrMergeProp( material, 'shaderUniforms', shaderUniforms ); addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + if(!material._serializationManager) material._serializationManager = new SerializationManager() + + material._serializationManager.addFunction(((data,meta)=>{ + if( !data.metadata.extensions ) data.metadata.extensions = {} + data.metadata.extensions.isPerMapTransformExtended = true + + serialize.forEach(mapName=>{ + data[`${mapName}Repeat`] = material[`${mapName}Repeat`].toArray() + data[`${mapName}Offset`] = material[`${mapName}Offset`].toArray() + data[`${mapName}Center`] = material[`${mapName}Center`].toArray() + data[`${mapName}Rotation`] = material[`${mapName}Rotation`] + }) + + return data + + }).bind(material)) + + material.toJSON = toJSON.bind(material) + return material } @@ -296,6 +336,30 @@ function decorateMaterialWithSimpleInstancing( material ) { addOrMergeProp( material, 'shaderIncludes', shaderIncludes ); + if(!material._serializationManager) material._serializationManager = new SerializationManager() + + material._serializationManager.addFunction((data)=>{ + if( !data.metadata.extensions ) data.metadata.extensions = {} + data.metadata.extensions.isSimpleInstanceExtended = true + }) + + material.toJSON = toJSON.bind(material) + return material +} + + +function SerializationManager(){ + this.processFunctions = [] +} + +SerializationManager.prototype = { + addFunction: function( func ){ + this.processFunctions.push(func) + }, + serialize(data, meta){ + this.processFunctions.forEach(f=>f(data)) + return data + } } \ No newline at end of file diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index ea4f29912f8205..23bb6f41876d69 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -54,7 +54,7 @@ - - + + + - - - + + + + + + @@ -59,7 +62,8 @@ var camera, scene, renderer, stats, clock; - var mesh, material; + var mesh, material, meshGLTF, materialGLTF; + var texture, envMap; var mouseX = 0; var mouseY = 0; @@ -70,19 +74,90 @@ var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; - var _gui = new dat.GUI() + var meshOptions = ['sphere','gltf'] + var guiData = { + speed: 1, + map: true, + currentMesh: meshOptions[0] + } + var _gui = new dat.GUI() //fix css later + var guiArray = [] - var gui = _gui.addFolder('gui') + var gui = _gui.addFolder('global') gui.open() - - var guiData = { speed: 1 , map: true} - gui.add( guiData, 'speed', 0, 5 ) - - init(); + gui.add( guiData, 'currentMesh', meshOptions ).onChange(function(value){ + mesh.visible = value === 'sphere' + if(meshGLTF) meshGLTF.visible = value === 'gltf' + onChangeGuiMaterial(value==='gltf'?materialGLTF:material) + }) + + // var guiMaterial = _gui.addFolder('material') + // guiMaterial.open() + + // var guiTexture = _gui.addFolder('specular map') + // guiTexture.open() + + const INSTANCES = 256; + var frequency = 32 + var instanceOffsetAttribute, instanceScaleAttribute + + initScene(); + initInstanceAttributes(); + initTexture(); + initBall(); + onChangeGuiMaterial(material); + loadGLTF(); animate(); - function init() { + var _gltfTextureMap + + function onChangeGuiMaterial(material){ + while(guiArray.length){ + gui.remove(guiArray.pop()) + } + guiArray.push( + gui.add( material.specularMapRepeat,'x',0,10) + .onChange(material.specularMapUpdateMatrix) + .name('repeat.x') + ) + guiArray.push( + gui.add( material.specularMapRepeat,'y',0,10) + .onChange(material.specularMapUpdateMatrix) + .name('repeat.y') + ) + guiArray.push( + gui.add( material.specularMapOffset,'x',0,1) + .onChange(material.specularMapUpdateMatrix) + .name('offset.x') + ) + guiArray.push( + gui.add( material.specularMapOffset,'x',0,1) + .onChange(material.specularMapUpdateMatrix) + .name('offset.y') + ) + guiArray.push( + gui.add( material, 'specularMapRotation',0,1) + .onChange(material.specularMapUpdateMatrix) + .name('rotation') + ) + guiArray.push(gui.add( material, 'glossiness',0,1)) + guiArray.push( + gui.add(guiData, 'map').onChange(function(val){ + if(!_gltfTextureMap && meshGLTF ) _gltfTextureMap = meshGLTF.material.map + + mesh.material.map = val ? texture : null + mesh.material.needsUpdate = true + + if(meshGLTF){ + meshGLTF.material.map = val ? _gltfTextureMap : null + meshGLTF.material.needsUpdate = true + } + }) + ) + } + + function initScene() { clock = new THREE.Clock(); @@ -107,11 +182,8 @@ light.shadow.mapSize.height = 512; scene.add(light) - - // light shadow camera helper - light.shadowCameraHelper = new THREE.CameraHelper( light.shadow.camera ); - scene.add( light.shadowCameraHelper ); - scene.add( new THREE.AmbientLight( 0xffffff, 0.17 ) ); + var ambient = new THREE.AmbientLight( 0x222222 ); + scene.add( ambient ); var ground = new THREE.Mesh( new THREE.PlaneBufferGeometry( 800, 800 ).rotateX( - Math.PI / 2 ), @@ -126,6 +198,8 @@ renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); + renderer.gammaOutput = true; + renderer.physicallyCorrectLights = true; renderer.shadowMap.enabled = true; // @@ -137,56 +211,110 @@ document.addEventListener( 'mousemove', onDocumentMouseMove, false ); window.addEventListener( 'resize', onWindowResize, false ); + } + + function loadGLTF(){ + + loader = new THREE.GLTFLoader(); + + THREE.DRACOLoader.setDecoderPath( 'js/libs/draco/gltf/' ); + loader.setDRACOLoader( new THREE.DRACOLoader() ); + + var loadStartTime = performance.now(); + loader.load( './models/gltf/BoomBox/glTF-pbrSpecularGlossiness/BoomBox.gltf', function( data ) { + + gltf = data; + + var object = gltf.scene; + + console.info( 'Load time: ' + ( performance.now() - loadStartTime ).toFixed( 2 ) + ' ms.' ); + + object.traverse( function( node ) { + + if ( node.material && ( node.material.isMeshStandardMaterial || + ( node.material.isShaderMaterial && node.material.envMap !== undefined ) ) ) { + + node.material.envMap = envMap; + node.material.needsUpdate = true; + } + + } ); + + object.traverse( function ( node ) { + + if ( node.isMesh || node.isLight ) node.castShadow = true; + + } ); + + scene.add( object ); + object.rotation.y -= Math.PI; + + var scale = 2000 + meshGLTF = object.children[0] + meshGLTF.frustumCulled = false + meshGLTF.visible = guiData.currentMesh === 'gltf' + meshGLTF.geometry.scale(scale,scale,scale) + + materialGLTF = meshGLTF.material + decorateMaterialWithPerMapTransforms(materialGLTF) + applyInstancingToMesh(meshGLTF) + applyIndecisToInstancedMesh(meshGLTF) + + }, undefined, function ( error ) { + console.error( error ); + } ); + + } - var texture = new THREE.TextureLoader().load( `textures/roughness_map.jpg` ) + function initTexture(){ + + texture = new THREE.TextureLoader().load( `textures/roughness_map.jpg` ) texture.wrapS = texture.wrapT = THREE.RepeatWrapping texture.name = "texture" - var envMap = new THREE.TextureLoader().load( `textures/metal.jpg`, function ( texture ) { + envMap = new THREE.TextureLoader().load( `textures/metal.jpg`, function ( texture ) { texture.mapping = THREE.SphericalReflectionMapping; texture.encoding = THREE.sRGBEncoding; - if ( mesh ) mesh.material.needsUpdate = true; + if ( mesh ) material.needsUpdate = true; + if ( meshGLTF ) materialGLTF.needsUpdate = true; } ); envMap.name = "envMap" + } - var material = new THREE.MeshStandardMaterial({ - color: 0xffb54a, - envMap: envMap, - map: texture, - }) + function initBall(){ + + material = decorateMaterialWithSpecGloss( + new THREE.MeshStandardMaterial({ + color: 0xffb54a, + envMap: envMap, + map: texture, + }) + ) + decorateMaterialWithPerMapTransforms(material) mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(10), material) + scene.add(mesh) + mesh.castShadow = true mesh.receiveShadow = true - //decorate with spec gloss - decorateMaterialWithSpecGloss(material) - - //results in these maps being immidiately available - material.glossinessMap = texture + material.glossinessMap = texture //needs .a so doesnt work with this texture material.specularMap = texture - //decorate with map transforms - decorateMaterialWithPerMapTransforms(material) + applyInstancingToMesh(mesh) + applyIndecisToInstancedMesh(mesh) - //results in thse Vector2 and primitev properties being immidiately available - gui.add( material.specularMapRepeat,'x',0,10).onChange(material.specularMapUpdateMatrix) - gui.add( material.specularMapRepeat,'y',0,10).onChange(material.specularMapUpdateMatrix) - gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) - gui.add( material.specularMapOffset,'x',0,1).onChange(material.specularMapUpdateMatrix) - gui.add( material, 'specularMapRotation',0,1).onChange(material.specularMapUpdateMatrix) - gui.add( material, 'glossiness',0,1) + } - //instancing - + //instancing + function initInstanceAttributes(){ //create geometry attributes - const INSTANCES = 256; var knot = new THREE.Curves.TorusKnot( 60 ); var positions = knot.getSpacedPoints( INSTANCES ); @@ -202,83 +330,73 @@ offsets[ index + 2 ] = positions[ i ].z; // per-instance scale variation - scales[ i ] = 1 + 0.5 * Math.sin( 32 * Math.PI * i / INSTANCES ); + scales[ i ] = 1 + 0.5 * Math.sin( frequency * Math.PI * i / INSTANCES ); } - mesh.geometry = new THREE.InstancedBufferGeometry().copy(mesh.geometry) - mesh.geometry.maxInstancedCount = INSTANCES - //end custom geometry creation - + instanceOffsetAttribute = new THREE.InstancedBufferAttribute( offsets, 3 ) + instanceScaleAttribute = new THREE.InstancedBufferAttribute( scales, 1 ) + } - //material decorator exposes instanceOffset and instanceScale, - //provide these to geometry - mesh.geometry.addAttribute( 'instanceOffset', new THREE.InstancedBufferAttribute( offsets, 3 ) ); - mesh.geometry.addAttribute( 'instanceScale', new THREE.InstancedBufferAttribute( scales, 1 ) ); + function applyInstancingToMesh(mesh){ - decorateMaterialWithSimpleInstancing(material) - //same for depth material - mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing(new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })) + decorateMaterialWithSimpleInstancing(mesh.material) + mesh.customDepthMaterial = decorateMaterialWithSimpleInstancing( + new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking }) + ) + mesh.geometry = new THREE.InstancedBufferGeometry().copy(mesh.geometry) + mesh.geometry.maxInstancedCount = INSTANCES - //4. add a final custom animation effect on top of the instancing effect - var indecis = new Float32Array( INSTANCES * 1 ); + mesh.geometry.addAttribute( 'instanceOffset', instanceOffsetAttribute ); + mesh.geometry.addAttribute( 'instanceScale', instanceScaleAttribute ); + + } + + function applyIndecisToInstancedMesh(mesh){ + console.log(mesh) + var indecis = new Float32Array( INSTANCES ); for ( var i = 0, l = INSTANCES; i < l; i ++ ) { indecis[i] = i / INSTANCES } - //add this new attribute + mesh.geometry.addAttribute('aIndex', new THREE.InstancedBufferAttribute( indecis, 1 ) ) //remove the old attibute (we could have overloaded it though) delete mesh.geometry.attributes.instanceScale - var frequency = 32 //knowing we decorated with simpleInstancing we have a parsed/included "compiled" chunk to work with - material.shaderIncludes.begin_vertex = material.shaderIncludes.begin_vertex.replace( + mesh.material.shaderIncludes.begin_vertex = mesh.material.shaderIncludes.begin_vertex.replace( 'transformed *= instanceScale;', //we know how simpleInstancing works `float _ind = aIndex + uTime; transformed *= 1. + 0.5 * sin(${frequency}.0 * ${Math.PI} * _ind );` //we override a part of that extension with our custom logic ) //we need a custom time uniform for the effect - material.shaderUniforms.uTime = { value: 0, type: 'float', stage: 'vertex' } + var uTime = { value: 0, type: 'float', stage: 'vertex' } + mesh.material.shaderUniforms.uTime = uTime //we expose it as a primitive - Object.defineProperty(material, 'time', { - get:()=>material.shaderUniforms.uTime.value, - set:v=>material.shaderUniforms.uTime.value = v + Object.defineProperty(mesh.material, 'time', { + get:()=>uTime.value, + set:v=>uTime.value = v }) - - //because there is already an onBeforeCompile, it's tricky to add another one to append - //the new attribute ( and remove the old one ), fortunately, we can use the uv_pars_vertex - //ideally there should be a chunk called global_vertex_pars or something like that where - //one could inject uniforms functions varyings and attributes - //with this api, in this stage, at least one would have the unrolled raw glsl to work with - //available in this scope at this time - //aka - //material.shaderIncludes.some_chunk = my_some_chunk || THREE.ShaderChunk.some_chunk - //^ either way, shaderIncludes.some_chunk contains the GLSL, with onBeforeCompile this is blackboxed - // we could then do: - // global_vertex.replace( 'attribute float instanceOffset', 'attribute float aIndex' ) - material.shaderIncludes.uv_pars_vertex = ` + + mesh.material.shaderIncludes.uv_pars_vertex = ` ${THREE.ShaderChunk.uv_pars_vertex} attribute float aIndex; ` //to make it work with shadows, - mesh.customDepthMaterial.shaderIncludes.uv_pars_vertex = material.shaderIncludes.uv_pars_vertex //copy these - mesh.customDepthMaterial.shaderIncludes.begin_vertex = material.shaderIncludes.begin_vertex //copy these - mesh.customDepthMaterial.shaderUniforms = { uTime: material.shaderUniforms.uTime }//wire this by reference, whenever prop updates material uniform this material updates too by referencing the same uniform - - //test needs update after all of this - gui.add(guiData, 'map').onChange(function(val){ - material.map = val ? texture : null - material.needsUpdate = true - }) + mesh.customDepthMaterial.shaderIncludes.uv_pars_vertex = mesh.material.shaderIncludes.uv_pars_vertex //copy these + mesh.customDepthMaterial.shaderIncludes.begin_vertex = mesh.material.shaderIncludes.begin_vertex //copy these + mesh.customDepthMaterial.shaderUniforms = { uTime: mesh.material.shaderUniforms.uTime }//wire this by reference, whenever prop updates material uniform this material updates too by referencing the same uniform - console.log(material.toJSON()) + console.log(mesh) + + console.log(mesh.material.toJSON()) } @@ -298,7 +416,6 @@ } function onDocumentMouseMove( event ) { - mouseX = ( event.clientX - windowHalfX ); mouseY = ( event.clientY - windowHalfY ); } @@ -319,12 +436,21 @@ targetX = mouseX * .001; targetY = mouseY * .001; + var delta = clock.getDelta() * 0.01 * guiData.speed if ( mesh ) { mesh.rotation.y += 0.05 * ( targetX - mesh.rotation.y ); mesh.rotation.x += 0.05 * ( targetY - mesh.rotation.x ); - mesh.material.time += clock.getDelta() * 0.01 * guiData.speed + mesh.material.time += delta + } + + if ( meshGLTF ) { + + meshGLTF.rotation.y += 0.05 * ( targetX - meshGLTF.rotation.y ); + meshGLTF.rotation.x += 0.05 * ( targetY - meshGLTF.rotation.x ); + + meshGLTF.material.time += delta } renderer.render( scene, camera ); From 63b248d6b41aafb95f82367b5134655106e592ab Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Fri, 8 Jun 2018 18:22:00 -0700 Subject: [PATCH 21/27] rename --- examples/webgl_materials_modified2.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index db17ede31ea15b..e1498f42d86a37 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -39,8 +39,7 @@
- three.js wegbl - modified material. - Lee Perry-Smith head. + three.js wegbl - modified MeshStandardMaterial with specular/glossines lighting model, per map transforms and simple instancing. Author @pailhead.
@@ -80,7 +79,7 @@ map: true, currentMesh: meshOptions[0] } - var _gui = new dat.GUI() //fix css later + var _gui = new dat.GUI({width: 300}) //fix css later var guiArray = [] var gui = _gui.addFolder('global') @@ -119,27 +118,27 @@ guiArray.push( gui.add( material.specularMapRepeat,'x',0,10) .onChange(material.specularMapUpdateMatrix) - .name('repeat.x') + .name('spec map repeat.x') ) guiArray.push( gui.add( material.specularMapRepeat,'y',0,10) .onChange(material.specularMapUpdateMatrix) - .name('repeat.y') + .name('spec map repeat.y') ) guiArray.push( gui.add( material.specularMapOffset,'x',0,1) .onChange(material.specularMapUpdateMatrix) - .name('offset.x') + .name('spec map offset.x') ) guiArray.push( gui.add( material.specularMapOffset,'x',0,1) .onChange(material.specularMapUpdateMatrix) - .name('offset.y') + .name('spec map offset.y') ) guiArray.push( gui.add( material, 'specularMapRotation',0,1) .onChange(material.specularMapUpdateMatrix) - .name('rotation') + .name('spec map rotation') ) guiArray.push(gui.add( material, 'glossiness',0,1)) guiArray.push( @@ -154,6 +153,7 @@ meshGLTF.material.needsUpdate = true } }) + .name('albedo map on/off') ) } From e83b31b0e2fb134153283bf89c3611e4ca9a099d Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 12:28:35 -0700 Subject: [PATCH 22/27] broke it --- examples/js/SpecGlossMultiUVInstanceExample.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 4affbc5879b70c..aea2f7ff2e3140 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -16,7 +16,13 @@ function addOrMergeProp( material, propName, data ) { //serialize function toJSON(){ - return THREE.Material.prototype.toJSON.call(this, undefined, this._serializationManager.serialize.bind(this._serializationManager)) + var res = THREE.Material.prototype.toJSON.call( + this, + undefined, + this._serializationManager.serialize.bind(this._serializationManager) + ) + this._serializationManager.afterSerialize.call(this._serializationManager,res) + return res } // from three's texture transform api, to be applied to a uniform matrix @@ -349,6 +355,7 @@ function decorateMaterialWithSimpleInstancing( material ) { function SerializationManager(){ this.processFunctions = [] + this.afterFunctions = [] } SerializationManager.prototype = { @@ -358,5 +365,11 @@ SerializationManager.prototype = { serialize(data, meta){ this.processFunctions.forEach(f=>f(data)) return data + }, + afterSerialize(data){ + this.afterFunctions.forEach(f=>f(data)) + }, + addAfterFunction: function( func ){ + this.afterFunctions.push(func) } } \ No newline at end of file From 25494ad58db6256fbd12991cba2517cb6676516e Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 12:51:20 -0700 Subject: [PATCH 23/27] update serialization --- .../js/SpecGlossMultiUVInstanceExample.js | 12 ++++++++++-- examples/js/loaders/GLTFLoader.js | 2 -- examples/webgl_materials_modified2.html | 19 ++++++++++++++----- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index aea2f7ff2e3140..0781a5357d7f36 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -277,14 +277,22 @@ function decorateMaterialWithPerMapTransforms( material, mapList ) { return data }).bind(material)) + + + material._serializationManager.addAfterFunction( + function( data ){ + delete data.roughnessMap + delete data.roughness + delete data.metalnessMap + delete data.metalness + } + ) material.toJSON = toJSON.bind(material) return material } - - // simple instance stuff from lambert example --------------------------------------------------------- //this is a stage after begin_vertex, this would be more elegant with hooks and template refactor diff --git a/examples/js/loaders/GLTFLoader.js b/examples/js/loaders/GLTFLoader.js index b8619db2d86b9d..f24927773a21f3 100644 --- a/examples/js/loaders/GLTFLoader.js +++ b/examples/js/loaders/GLTFLoader.js @@ -623,8 +623,6 @@ THREE.GLTFLoader = ( function () { transparent: params.transparent } ); - console.log( material ); - decorateMaterialWithSpecGloss( material ); material.isGLTFSpecularGlossinessMaterial = true; diff --git a/examples/webgl_materials_modified2.html b/examples/webgl_materials_modified2.html index e1498f42d86a37..53446010b33e96 100644 --- a/examples/webgl_materials_modified2.html +++ b/examples/webgl_materials_modified2.html @@ -73,11 +73,17 @@ var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; + var currentMesh var meshOptions = ['sphere','gltf'] var guiData = { speed: 1, map: true, - currentMesh: meshOptions[0] + currentMesh: meshOptions[0], + serialize: function(){ + console.log( + JSON.stringify( currentMesh.material.toJSON()) + ) + } } var _gui = new dat.GUI({width: 300}) //fix css later var guiArray = [] @@ -86,6 +92,7 @@ gui.open() gui.add( guiData, 'speed', 0, 5 ) gui.add( guiData, 'currentMesh', meshOptions ).onChange(function(value){ + currentMesh = value === 'sphere' ? mesh : meshGLTF mesh.visible = value === 'sphere' if(meshGLTF) meshGLTF.visible = value === 'gltf' onChangeGuiMaterial(value==='gltf'?materialGLTF:material) @@ -155,6 +162,9 @@ }) .name('albedo map on/off') ) + guiArray.push( + gui.add(guiData, 'serialize') + ) } function initScene() { @@ -310,6 +320,8 @@ applyInstancingToMesh(mesh) applyIndecisToInstancedMesh(mesh) + currentMesh = mesh + } //instancing @@ -355,7 +367,7 @@ } function applyIndecisToInstancedMesh(mesh){ - console.log(mesh) + var indecis = new Float32Array( INSTANCES ); for ( var i = 0, l = INSTANCES; i < l; i ++ ) { @@ -394,9 +406,6 @@ mesh.customDepthMaterial.shaderIncludes.begin_vertex = mesh.material.shaderIncludes.begin_vertex //copy these mesh.customDepthMaterial.shaderUniforms = { uTime: mesh.material.shaderUniforms.uTime }//wire this by reference, whenever prop updates material uniform this material updates too by referencing the same uniform - console.log(mesh) - - console.log(mesh.material.toJSON()) } From ddab6f0a74dd6d78827fb6f7ff4467589ad3ae7f Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 12:54:25 -0700 Subject: [PATCH 24/27] add serialization result --- examples/serializedResult.json | 190 +++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 examples/serializedResult.json diff --git a/examples/serializedResult.json b/examples/serializedResult.json new file mode 100644 index 00000000000000..b1b00ac2cf14bd --- /dev/null +++ b/examples/serializedResult.json @@ -0,0 +1,190 @@ +{ + "alphaMapCenter": [ + 0, + 0 + ], + "alphaMapOffset": [ + 0, + 0 + ], + "alphaMapRepeat": [ + 1, + 1 + ], + "alphaMapRotation": 0, + "color": 16758090, + "depthFunc": 3, + "depthTest": true, + "depthWrite": true, + "emissive": 0, + "emissiveMapCenter": [ + 0, + 0 + ], + "emissiveMapOffset": [ + 0, + 0 + ], + "emissiveMapRepeat": [ + 1, + 1 + ], + "emissiveMapRotation": 0, + "envMap": "A78E1632-2AD0-438A-9571-D983C8491B1B", + "glossiness": 1, + "glossinessMap": { + "anisotropy": 1, + "center": [ + 0, + 0 + ], + "flipY": true, + "format": 1022, + "image": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957", + "magFilter": 1006, + "mapping": 300, + "metadata": { + "generator": "Texture.toJSON", + "type": "Texture", + "version": 4.5 + }, + "minFilter": 1008, + "name": "texture", + "offset": [ + 0, + 0 + ], + "repeat": [ + 1, + 1 + ], + "rotation": 0, + "uuid": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", + "wrap": [ + 1000, + 1000 + ] + }, + "glossinessMapCenter": [ + 0, + 0 + ], + "glossinessMapOffset": [ + 0, + 0 + ], + "glossinessMapRepeat": [ + 1, + 1 + ], + "glossinessMapRotation": 0, + "images": [ + { + "url": "...", + "uuid": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957" + }, + { + "url": "...", + "uuid": "414A29DF-CA45-4364-902F-B2369E673083" + } + ], + "map": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", + "mapCenter": [ + 0, + 0 + ], + "mapOffset": [ + 0, + 0 + ], + "mapRepeat": [ + 1, + 1 + ], + "mapRotation": 0, + "metadata": { + "extensions": { + "isPerMapTransformExtended": true, + "isSimpleInstanceExtended": true, + "isSpecGlossExtended": true + }, + "generator": "Material.toJSON", + "type": "Material", + "version": 4.5 + }, + "specular": 16777215, + "specularMap": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", + "specularMapCenter": [ + 0, + 0 + ], + "specularMapOffset": [ + 0, + 0 + ], + "specularMapRepeat": [ + 1, + 1 + ], + "specularMapRotation": 0, + "textures": [ + { + "anisotropy": 1, + "center": [ + 0, + 0 + ], + "flipY": true, + "format": 1022, + "image": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957", + "magFilter": 1006, + "mapping": 300, + "minFilter": 1008, + "name": "texture", + "offset": [ + 0, + 0 + ], + "repeat": [ + 1, + 1 + ], + "rotation": 0, + "uuid": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", + "wrap": [ + 1000, + 1000 + ] + }, + { + "anisotropy": 1, + "center": [ + 0, + 0 + ], + "flipY": true, + "format": 1022, + "image": "414A29DF-CA45-4364-902F-B2369E673083", + "magFilter": 1006, + "mapping": 305, + "minFilter": 1008, + "name": "envMap", + "offset": [ + 0, + 0 + ], + "repeat": [ + 1, + 1 + ], + "rotation": 0, + "uuid": "A78E1632-2AD0-438A-9571-D983C8491B1B", + "wrap": [ + 1001, + 1001 + ] + } + ], + "type": "MeshStandardMaterial", + "uuid": "AC55A38A-DAD4-4BD7-861A-87ADB212871F" +} \ No newline at end of file From c207aca767fe1b73d4c8b05ee078305e69559a53 Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 13:14:38 -0700 Subject: [PATCH 25/27] fix serialization --- .../js/SpecGlossMultiUVInstanceExample.js | 2 +- examples/serializedResult.json | 208 +++++------------- 2 files changed, 52 insertions(+), 158 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index 0781a5357d7f36..d14b324529963f 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -123,7 +123,7 @@ function decorateMaterialWithSpecGloss( material ) { data.metadata.extensions.isSpecGlossExtended = true data.glossiness = this.glossiness data.specular = this.specular.getHex() - if(this.glossinessMap && this.glossinessMap.isTexture) data.glossinessMap = this.glossinessMap.toJSON( meta ) + if(this.glossinessMap && this.glossinessMap.isTexture) data.glossinessMap = this.glossinessMap.toJSON( meta ).uuid }.bind(material) material._serializationManager.addFunction(f) diff --git a/examples/serializedResult.json b/examples/serializedResult.json index b1b00ac2cf14bd..499454ea581a32 100644 --- a/examples/serializedResult.json +++ b/examples/serializedResult.json @@ -1,190 +1,84 @@ { - "alphaMapCenter": [ - 0, - 0 - ], - "alphaMapOffset": [ - 0, - 0 - ], - "alphaMapRepeat": [ - 1, - 1 - ], - "alphaMapRotation": 0, - "color": 16758090, - "depthFunc": 3, - "depthTest": true, - "depthWrite": true, - "emissive": 0, - "emissiveMapCenter": [ - 0, - 0 - ], - "emissiveMapOffset": [ - 0, - 0 - ], - "emissiveMapRepeat": [ - 1, - 1 - ], - "emissiveMapRotation": 0, - "envMap": "A78E1632-2AD0-438A-9571-D983C8491B1B", - "glossiness": 1, - "glossinessMap": { - "anisotropy": 1, - "center": [ - 0, - 0 - ], - "flipY": true, - "format": 1022, - "image": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957", - "magFilter": 1006, - "mapping": 300, - "metadata": { - "generator": "Texture.toJSON", - "type": "Texture", - "version": 4.5 - }, - "minFilter": 1008, - "name": "texture", - "offset": [ - 0, - 0 - ], - "repeat": [ - 1, - 1 - ], - "rotation": 0, - "uuid": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", - "wrap": [ - 1000, - 1000 - ] - }, - "glossinessMapCenter": [ - 0, - 0 - ], - "glossinessMapOffset": [ - 0, - 0 - ], - "glossinessMapRepeat": [ - 1, - 1 - ], - "glossinessMapRotation": 0, - "images": [ - { - "url": "...", - "uuid": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957" - }, - { - "url": "...", - "uuid": "414A29DF-CA45-4364-902F-B2369E673083" - } - ], - "map": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", - "mapCenter": [ - 0, - 0 - ], - "mapOffset": [ - 0, - 0 - ], - "mapRepeat": [ - 1, - 1 - ], - "mapRotation": 0, "metadata": { - "extensions": { - "isPerMapTransformExtended": true, - "isSimpleInstanceExtended": true, - "isSpecGlossExtended": true - }, - "generator": "Material.toJSON", + "version": 4.5, "type": "Material", - "version": 4.5 + "generator": "Material.toJSON" }, + "uuid": "61C0257B-17C3-45C6-AEB9-F603A1CA19E7", + "type": "MeshStandardMaterial", + "color": 16758090, + "emissive": 0, "specular": 16777215, - "specularMap": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", - "specularMapCenter": [ - 0, - 0 - ], - "specularMapOffset": [ - 0, - 0 - ], - "specularMapRepeat": [ - 1, - 1 - ], - "specularMapRotation": 0, + "map": "F0B81796-573E-40F8-B7DA-02245A073DF9", + "specularMap": "F0B81796-573E-40F8-B7DA-02245A073DF9", + "envMap": "1E99684C-AE4B-40EF-83CC-83A50FFD6A30", + "depthFunc": 3, + "depthTest": true, + "depthWrite": true, "textures": [ { - "anisotropy": 1, - "center": [ - 0, - 0 - ], - "flipY": true, - "format": 1022, - "image": "D440D3C6-6D2A-44C3-ACE4-BC97CE407957", - "magFilter": 1006, - "mapping": 300, - "minFilter": 1008, + "uuid": "F0B81796-573E-40F8-B7DA-02245A073DF9", "name": "texture", + "mapping": 300, + "repeat": [ + 1, + 1 + ], "offset": [ 0, 0 ], - "repeat": [ - 1, - 1 + "center": [ + 0, + 0 ], "rotation": 0, - "uuid": "0E08FCFE-5FC4-4343-8137-97B8781A33B9", "wrap": [ 1000, 1000 - ] - }, - { - "anisotropy": 1, - "center": [ - 0, - 0 ], - "flipY": true, "format": 1022, - "image": "414A29DF-CA45-4364-902F-B2369E673083", - "magFilter": 1006, - "mapping": 305, "minFilter": 1008, + "magFilter": 1006, + "anisotropy": 1, + "flipY": true, + "image": "87D4C31C-6983-48D4-961A-FACDA45DB7AC" + }, + { + "uuid": "1E99684C-AE4B-40EF-83CC-83A50FFD6A30", "name": "envMap", + "mapping": 305, + "repeat": [ + 1, + 1 + ], "offset": [ 0, 0 ], - "repeat": [ - 1, - 1 + "center": [ + 0, + 0 ], "rotation": 0, - "uuid": "A78E1632-2AD0-438A-9571-D983C8491B1B", "wrap": [ 1001, 1001 - ] + ], + "format": 1022, + "minFilter": 1008, + "magFilter": 1006, + "anisotropy": 1, + "flipY": true, + "image": "678F6BAE-A377-49D5-A59E-A9BCDE5AE472" } ], - "type": "MeshStandardMaterial", - "uuid": "AC55A38A-DAD4-4BD7-861A-87ADB212871F" + "images": [ + { + "uuid": "87D4C31C-6983-48D4-961A-FACDA45DB7AC", + }, + { + "uuid": "678F6BAE-A377-49D5-A59E-A9BCDE5AE472", + } + ] } \ No newline at end of file From 9b507151c286393ce4935fbddcabf11c0cb6558c Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 13:16:33 -0700 Subject: [PATCH 26/27] fix serialization --- examples/serializedResult.json | 98 +++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/examples/serializedResult.json b/examples/serializedResult.json index 499454ea581a32..bc7c321f240dbf 100644 --- a/examples/serializedResult.json +++ b/examples/serializedResult.json @@ -2,22 +2,94 @@ "metadata": { "version": 4.5, "type": "Material", - "generator": "Material.toJSON" + "generator": "Material.toJSON", + "extensions": { + "isSpecGlossExtended": true, + "isPerMapTransformExtended": true, + "isSimpleInstanceExtended": true + } }, - "uuid": "61C0257B-17C3-45C6-AEB9-F603A1CA19E7", + "glossiness": 1, + "specular": 16777215, + "glossinessMap": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", + "alphaMapRepeat": [ + 1, + 1 + ], + "alphaMapOffset": [ + 0, + 0 + ], + "alphaMapCenter": [ + 0, + 0 + ], + "alphaMapRotation": 0, + "specularMapRepeat": [ + 1, + 1 + ], + "specularMapOffset": [ + 0, + 0 + ], + "specularMapCenter": [ + 0, + 0 + ], + "specularMapRotation": 0, + "mapRepeat": [ + 1, + 1 + ], + "mapOffset": [ + 0, + 0 + ], + "mapCenter": [ + 0, + 0 + ], + "mapRotation": 0, + "emissiveMapRepeat": [ + 1, + 1 + ], + "emissiveMapOffset": [ + 0, + 0 + ], + "emissiveMapCenter": [ + 0, + 0 + ], + "emissiveMapRotation": 0, + "glossinessMapRepeat": [ + 1, + 1 + ], + "glossinessMapOffset": [ + 0, + 0 + ], + "glossinessMapCenter": [ + 0, + 0 + ], + "glossinessMapRotation": 0, + "uuid": "55437FF3-5A86-463E-8C5E-9E8F5290F92F", "type": "MeshStandardMaterial", "color": 16758090, "emissive": 0, - "specular": 16777215, - "map": "F0B81796-573E-40F8-B7DA-02245A073DF9", - "specularMap": "F0B81796-573E-40F8-B7DA-02245A073DF9", - "envMap": "1E99684C-AE4B-40EF-83CC-83A50FFD6A30", + "map": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", + "specularMap": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", + "envMap": "32AA12E2-017E-42CA-90C4-483B95D456A5", "depthFunc": 3, "depthTest": true, "depthWrite": true, "textures": [ { - "uuid": "F0B81796-573E-40F8-B7DA-02245A073DF9", + "uuid": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", "name": "texture", "mapping": 300, "repeat": [ @@ -42,10 +114,10 @@ "magFilter": 1006, "anisotropy": 1, "flipY": true, - "image": "87D4C31C-6983-48D4-961A-FACDA45DB7AC" + "image": "FB5A325A-5CAA-47E7-921D-2A56C672CFCE" }, { - "uuid": "1E99684C-AE4B-40EF-83CC-83A50FFD6A30", + "uuid": "32AA12E2-017E-42CA-90C4-483B95D456A5", "name": "envMap", "mapping": 305, "repeat": [ @@ -70,15 +142,15 @@ "magFilter": 1006, "anisotropy": 1, "flipY": true, - "image": "678F6BAE-A377-49D5-A59E-A9BCDE5AE472" + "image": "F9CB0870-83F8-4762-961E-191FF7685340" } ], "images": [ { - "uuid": "87D4C31C-6983-48D4-961A-FACDA45DB7AC", - }, + "uuid": "FB5A325A-5CAA-47E7-921D-2A56C672CFCE", + }, { - "uuid": "678F6BAE-A377-49D5-A59E-A9BCDE5AE472", + "uuid": "F9CB0870-83F8-4762-961E-191FF7685340", } ] } \ No newline at end of file From 1d7ee68cebbe252564976c82824f2200f9b72bed Mon Sep 17 00:00:00 2001 From: Dusan Bosnjak Date: Sun, 10 Jun 2018 13:24:55 -0700 Subject: [PATCH 27/27] fix serialization --- .../js/SpecGlossMultiUVInstanceExample.js | 2 +- examples/serializedResult.json | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/js/SpecGlossMultiUVInstanceExample.js b/examples/js/SpecGlossMultiUVInstanceExample.js index d14b324529963f..e74061ed3b3e00 100644 --- a/examples/js/SpecGlossMultiUVInstanceExample.js +++ b/examples/js/SpecGlossMultiUVInstanceExample.js @@ -371,7 +371,7 @@ SerializationManager.prototype = { this.processFunctions.push(func) }, serialize(data, meta){ - this.processFunctions.forEach(f=>f(data)) + this.processFunctions.forEach(f=>f(data,meta)) return data }, afterSerialize(data){ diff --git a/examples/serializedResult.json b/examples/serializedResult.json index bc7c321f240dbf..e88b4dd6b9e15c 100644 --- a/examples/serializedResult.json +++ b/examples/serializedResult.json @@ -11,7 +11,7 @@ }, "glossiness": 1, "specular": 16777215, - "glossinessMap": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", + "glossinessMap": "2B8CE6E5-7846-4D84-B4BE-3D4211AE2BBA", "alphaMapRepeat": [ 1, 1 @@ -77,19 +77,19 @@ 0 ], "glossinessMapRotation": 0, - "uuid": "55437FF3-5A86-463E-8C5E-9E8F5290F92F", + "uuid": "B1168031-2FEB-4362-BFF5-04D2B366BA17", "type": "MeshStandardMaterial", "color": 16758090, "emissive": 0, - "map": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", - "specularMap": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", - "envMap": "32AA12E2-017E-42CA-90C4-483B95D456A5", + "map": "2B8CE6E5-7846-4D84-B4BE-3D4211AE2BBA", + "specularMap": "2B8CE6E5-7846-4D84-B4BE-3D4211AE2BBA", + "envMap": "58FDD3E2-882B-4F66-B4E2-BAE2C367595C", "depthFunc": 3, "depthTest": true, "depthWrite": true, "textures": [ { - "uuid": "4CBD81D6-6DEC-4B13-8B9A-3109D205B518", + "uuid": "2B8CE6E5-7846-4D84-B4BE-3D4211AE2BBA", "name": "texture", "mapping": 300, "repeat": [ @@ -114,10 +114,10 @@ "magFilter": 1006, "anisotropy": 1, "flipY": true, - "image": "FB5A325A-5CAA-47E7-921D-2A56C672CFCE" + "image": "B440D9F5-D47E-40D1-B912-DBFF0AE719AE" }, { - "uuid": "32AA12E2-017E-42CA-90C4-483B95D456A5", + "uuid": "58FDD3E2-882B-4F66-B4E2-BAE2C367595C", "name": "envMap", "mapping": 305, "repeat": [ @@ -142,15 +142,15 @@ "magFilter": 1006, "anisotropy": 1, "flipY": true, - "image": "F9CB0870-83F8-4762-961E-191FF7685340" + "image": "14DDC238-F4C1-4D89-AED5-597BD2927B84" } ], "images": [ { - "uuid": "FB5A325A-5CAA-47E7-921D-2A56C672CFCE", + "uuid": "B440D9F5-D47E-40D1-B912-DBFF0AE719AE", }, { - "uuid": "F9CB0870-83F8-4762-961E-191FF7685340", + "uuid": "14DDC238-F4C1-4D89-AED5-597BD2927B84", } ] } \ No newline at end of file