未验证 提交 b35bbd5b 编写于 作者: M Michael Herzog 提交者: GitHub

WebGLRenderer: Add support for morphing colors. (#23523)

* WebGLRenderer: Add support for morphing colors.

* WebGLMorphtargets: Simplify code.

* WebGLRenderer: Make morph color check more safe.
上级 ad4612c2
......@@ -2051,6 +2051,7 @@ function addMorphTargets( geometry, targets, parser ) {
let hasMorphPosition = false;
let hasMorphNormal = false;
let hasMorphColor = false;
for ( let i = 0, il = targets.length; i < il; i ++ ) {
......@@ -2058,15 +2059,17 @@ function addMorphTargets( geometry, targets, parser ) {
if ( target.POSITION !== undefined ) hasMorphPosition = true;
if ( target.NORMAL !== undefined ) hasMorphNormal = true;
if ( target.COLOR_0 !== undefined ) hasMorphColor = true;
if ( hasMorphPosition && hasMorphNormal ) break;
if ( hasMorphPosition && hasMorphNormal && hasMorphColor ) break;
}
if ( ! hasMorphPosition && ! hasMorphNormal ) return Promise.resolve( geometry );
if ( ! hasMorphPosition && ! hasMorphNormal && ! hasMorphColor ) return Promise.resolve( geometry );
const pendingPositionAccessors = [];
const pendingNormalAccessors = [];
const pendingColorAccessors = [];
for ( let i = 0, il = targets.length; i < il; i ++ ) {
......@@ -2092,18 +2095,31 @@ function addMorphTargets( geometry, targets, parser ) {
}
if ( hasMorphColor ) {
const pendingAccessor = target.COLOR_0 !== undefined
? parser.getDependency( 'accessor', target.COLOR_0 )
: geometry.attributes.color;
pendingColorAccessors.push( pendingAccessor );
}
}
return Promise.all( [
Promise.all( pendingPositionAccessors ),
Promise.all( pendingNormalAccessors )
Promise.all( pendingNormalAccessors ),
Promise.all( pendingColorAccessors )
] ).then( function ( accessors ) {
const morphPositions = accessors[ 0 ];
const morphNormals = accessors[ 1 ];
const morphColors = accessors[ 2 ];
if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
if ( hasMorphColor ) geometry.morphAttributes.color = morphColors;
geometry.morphTargetsRelative = true;
return geometry;
......
......@@ -1419,6 +1419,7 @@ function WebGLRenderer( parameters = {} ) {
materialProperties.skinning = parameters.skinning;
materialProperties.morphTargets = parameters.morphTargets;
materialProperties.morphNormals = parameters.morphNormals;
materialProperties.morphColors = parameters.morphColors;
materialProperties.morphTargetsCount = parameters.morphTargetsCount;
materialProperties.numClippingPlanes = parameters.numClippingPlanes;
materialProperties.numIntersection = parameters.numClipIntersection;
......@@ -1442,9 +1443,12 @@ function WebGLRenderer( parameters = {} ) {
const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent;
const morphTargets = !! geometry.morphAttributes.position;
const morphNormals = !! geometry.morphAttributes.normal;
const morphTargetsCount = !! geometry.morphAttributes.position ? geometry.morphAttributes.position.length : 0;
const morphColors = !! geometry.morphAttributes.color;
const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping;
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
const materialProperties = properties.get( material );
const lights = currentRenderState.state.lights;
......@@ -1525,6 +1529,10 @@ function WebGLRenderer( parameters = {} ) {
needsProgramChange = true;
} else if ( materialProperties.morphColors !== morphColors ) {
needsProgramChange = true;
} else if ( materialProperties.toneMapping !== toneMapping ) {
needsProgramChange = true;
......@@ -1675,7 +1683,9 @@ function WebGLRenderer( parameters = {} ) {
}
if ( geometry.morphAttributes.position !== undefined || geometry.morphAttributes.normal !== undefined ) {
const morphAttributes = geometry.morphAttributes;
if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
morphtargets.update( object, geometry, material, program );
......
......@@ -59,6 +59,7 @@ import map_particle_fragment from './ShaderChunk/map_particle_fragment.glsl.js';
import map_particle_pars_fragment from './ShaderChunk/map_particle_pars_fragment.glsl.js';
import metalnessmap_fragment from './ShaderChunk/metalnessmap_fragment.glsl.js';
import metalnessmap_pars_fragment from './ShaderChunk/metalnessmap_pars_fragment.glsl.js';
import morphcolor_vertex from './ShaderChunk/morphcolor_vertex.glsl.js';
import morphnormal_vertex from './ShaderChunk/morphnormal_vertex.glsl.js';
import morphtarget_pars_vertex from './ShaderChunk/morphtarget_pars_vertex.glsl.js';
import morphtarget_vertex from './ShaderChunk/morphtarget_vertex.glsl.js';
......@@ -180,6 +181,7 @@ export const ShaderChunk = {
map_particle_pars_fragment: map_particle_pars_fragment,
metalnessmap_fragment: metalnessmap_fragment,
metalnessmap_pars_fragment: metalnessmap_pars_fragment,
morphcolor_vertex: morphcolor_vertex,
morphnormal_vertex: morphnormal_vertex,
morphtarget_pars_vertex: morphtarget_pars_vertex,
morphtarget_vertex: morphtarget_vertex,
......
export default /* glsl */`
#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )
// morphTargetBaseInfluence is set based on BufferGeometry.morphTargetsRelative value:
// When morphTargetsRelative is false, this is set to 1 - sum(influences); this results in normal = sum((target - base) * influence)
// When morphTargetsRelative is true, this is set to 1; as a result, all morph targets are simply added to the base after weighting
vColor *= morphTargetBaseInfluence;
for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {
#if defined( USE_COLOR_ALPHA )
if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];
#elif defined( USE_COLOR )
if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]
#endif
}
#endif
`;
......@@ -10,7 +10,7 @@ export default /* glsl */`
for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {
if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1, 2 ) * morphTargetInfluences[ i ];
if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];
}
......
......@@ -9,14 +9,14 @@ export default /* glsl */`
uniform sampler2DArray morphTargetsTexture;
uniform vec2 morphTargetsTextureSize;
vec3 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset, const in int stride ) {
vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {
float texelIndex = float( vertexIndex * stride + offset );
float texelIndex = float( vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset );
float y = floor( texelIndex / morphTargetsTextureSize.x );
float x = texelIndex - y * morphTargetsTextureSize.x;
vec3 morphUV = vec3( ( x + 0.5 ) / morphTargetsTextureSize.x, y / morphTargetsTextureSize.y, morphTargetIndex );
return texture( morphTargetsTexture, morphUV ).xyz;
return texture( morphTargetsTexture, morphUV );
}
......
......@@ -10,15 +10,7 @@ export default /* glsl */`
for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {
#ifndef USE_MORPHNORMALS
if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 1 ) * morphTargetInfluences[ i ];
#else
if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0, 2 ) * morphTargetInfluences[ i ];
#endif
if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];
}
......
......@@ -16,6 +16,7 @@ void main() {
vLineDistance = scale * lineDistance;
#include <color_vertex>
#include <morphcolor_vertex>
#include <begin_vertex>
#include <morphtarget_vertex>
#include <project_vertex>
......
......@@ -15,6 +15,7 @@ void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )
......
......@@ -28,6 +28,7 @@ void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
......
......@@ -19,6 +19,7 @@ void main() {
#include <uv_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
......
......@@ -22,6 +22,7 @@ void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
......
......@@ -27,6 +27,7 @@ void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
......
......@@ -21,6 +21,7 @@ void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#include <beginnormal_vertex>
#include <morphnormal_vertex>
......
......@@ -12,6 +12,7 @@ uniform float scale;
void main() {
#include <color_vertex>
#include <morphcolor_vertex>
#include <begin_vertex>
#include <morphtarget_vertex>
#include <project_vertex>
......
import { FloatType, RGBAFormat } from '../../constants.js';
import { DataArrayTexture } from '../../textures/DataArrayTexture.js';
import { Vector3 } from '../../math/Vector3.js';
import { Vector4 } from '../../math/Vector4.js';
import { Vector2 } from '../../math/Vector2.js';
function numericalSort( a, b ) {
......@@ -34,7 +34,7 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
const influencesList = {};
const morphInfluences = new Float32Array( 8 );
const morphTextures = new WeakMap();
const morph = new Vector3();
const morph = new Vector4();
const workInfluences = [];
......@@ -53,23 +53,30 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
// instead of using attributes, the WebGL 2 code path encodes morph targets
// into an array of data textures. Each layer represents a single morph target.
const numberOfMorphTargets = geometry.morphAttributes.position.length;
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
let entry = morphTextures.get( geometry );
if ( entry === undefined || entry.count !== numberOfMorphTargets ) {
if ( entry === undefined || entry.count !== morphTargetsCount ) {
if ( entry !== undefined ) entry.texture.dispose();
const hasMorphPosition = geometry.morphAttributes.position !== undefined;
const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
const hasMorphColors = geometry.morphAttributes.color !== undefined;
const morphTargets = geometry.morphAttributes.position;
const morphTargets = geometry.morphAttributes.position || [];
const morphNormals = geometry.morphAttributes.normal || [];
const morphColors = geometry.morphAttributes.color || [];
const numberOfVertices = geometry.attributes.position.count;
const numberOfVertexData = ( hasMorphNormals === true ) ? 2 : 1; // (v,n) vs. (v)
let vertexDataCount = 0;
let width = numberOfVertices * numberOfVertexData;
if ( hasMorphPosition === true ) vertexDataCount = 1;
if ( hasMorphNormals === true ) vertexDataCount = 2;
if ( hasMorphColors === true ) vertexDataCount = 3;
let width = geometry.attributes.position.count * vertexDataCount;
let height = 1;
if ( width > capabilities.maxTextureSize ) {
......@@ -79,36 +86,41 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
}
const buffer = new Float32Array( width * height * 4 * numberOfMorphTargets );
const buffer = new Float32Array( width * height * 4 * morphTargetsCount );
const texture = new DataArrayTexture( buffer, width, height, numberOfMorphTargets );
const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
texture.format = RGBAFormat; // using RGBA since RGB might be emulated (and is thus slower)
texture.type = FloatType;
texture.needsUpdate = true;
// fill buffer
const vertexDataStride = numberOfVertexData * 4;
const vertexDataStride = vertexDataCount * 4;
for ( let i = 0; i < numberOfMorphTargets; i ++ ) {
for ( let i = 0; i < morphTargetsCount; i ++ ) {
const morphTarget = morphTargets[ i ];
const morphNormal = morphNormals[ i ];
const morphColor = morphColors[ i ];
const offset = width * height * 4 * i;
for ( let j = 0; j < morphTarget.count; j ++ ) {
morph.fromBufferAttribute( morphTarget, j );
const stride = j * vertexDataStride;
if ( morphTarget.normalized === true ) denormalize( morph, morphTarget );
if ( hasMorphPosition === true ) {
const stride = j * vertexDataStride;
morph.fromBufferAttribute( morphTarget, j );
buffer[ offset + stride + 0 ] = morph.x;
buffer[ offset + stride + 1 ] = morph.y;
buffer[ offset + stride + 2 ] = morph.z;
buffer[ offset + stride + 3 ] = 0;
if ( morphTarget.normalized === true ) denormalize( morph, morphTarget );
buffer[ offset + stride + 0 ] = morph.x;
buffer[ offset + stride + 1 ] = morph.y;
buffer[ offset + stride + 2 ] = morph.z;
buffer[ offset + stride + 3 ] = 0;
}
if ( hasMorphNormals === true ) {
......@@ -123,12 +135,25 @@ function WebGLMorphtargets( gl, capabilities, textures ) {
}
if ( hasMorphColors === true ) {
morph.fromBufferAttribute( morphColor, j );
if ( morphColor.normalized === true ) denormalize( morph, morphNormal );
buffer[ offset + stride + 8 ] = morph.x;
buffer[ offset + stride + 9 ] = morph.y;
buffer[ offset + stride + 10 ] = morph.z;
buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;
}
}
}
entry = {
count: numberOfMorphTargets,
count: morphTargetsCount,
texture: texture,
size: new Vector2( width, height )
};
......
......@@ -497,8 +497,10 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
( parameters.morphTargets && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
( parameters.morphTargets && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '',
( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
parameters.flipSided ? '#define FLIP_SIDED' : '',
......
......@@ -75,6 +75,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
function getParameters( material, lights, shadows, scene, object ) {
const fog = scene.fog;
const geometry = object.geometry;
const environment = material.isMeshStandardMaterial ? scene.environment : null;
const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
......@@ -99,6 +100,19 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
}
//
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
let morphTextureStride = 0;
if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;
//
let vertexShader, fragmentShader;
let customVertexShaderID, customFragmentShaderID;
......@@ -194,9 +208,9 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
combine: material.combine,
vertexTangents: ( !! material.normalMap && !! object.geometry && !! object.geometry.attributes.tangent ),
vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ),
vertexColors: material.vertexColors,
vertexAlphas: material.vertexColors === true && !! object.geometry && !! object.geometry.attributes.color && object.geometry.attributes.color.itemSize === 4,
vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,
vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap,
uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap,
......@@ -213,9 +227,11 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
maxBones: maxBones,
useVertexTexture: floatVertexTextures,
morphTargets: !! object.geometry && !! object.geometry.morphAttributes.position,
morphNormals: !! object.geometry && !! object.geometry.morphAttributes.normal,
morphTargetsCount: ( !! object.geometry && !! object.geometry.morphAttributes.position ) ? object.geometry.morphAttributes.position.length : 0,
morphTargets: geometry.morphAttributes.position !== undefined,
morphNormals: geometry.morphAttributes.normal !== undefined,
morphColors: geometry.morphAttributes.color !== undefined,
morphTargetsCount: morphTargetsCount,
morphTextureStride: morphTextureStride,
numDirLights: lights.directional.length,
numPointLights: lights.point.length,
......@@ -316,6 +332,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
array.push( parameters.sizeAttenuation );
array.push( parameters.maxBones );
array.push( parameters.morphTargetsCount );
array.push( parameters.morphAttributeCount );
array.push( parameters.numDirLights );
array.push( parameters.numPointLights );
array.push( parameters.numSpotLights );
......@@ -415,40 +432,42 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
_programLayers.enable( 5 );
if ( parameters.morphNormals )
_programLayers.enable( 6 );
if ( parameters.premultipliedAlpha )
if ( parameters.morphColors )
_programLayers.enable( 7 );
if ( parameters.shadowMapEnabled )
if ( parameters.premultipliedAlpha )
_programLayers.enable( 8 );
if ( parameters.physicallyCorrectLights )
if ( parameters.shadowMapEnabled )
_programLayers.enable( 9 );
if ( parameters.doubleSided )
if ( parameters.physicallyCorrectLights )
_programLayers.enable( 10 );
if ( parameters.flipSided )
if ( parameters.doubleSided )
_programLayers.enable( 11 );
if ( parameters.depthPacking )
if ( parameters.flipSided )
_programLayers.enable( 12 );
if ( parameters.dithering )
if ( parameters.depthPacking )
_programLayers.enable( 13 );
if ( parameters.specularIntensityMap )
if ( parameters.dithering )
_programLayers.enable( 14 );
if ( parameters.specularColorMap )
if ( parameters.specularIntensityMap )
_programLayers.enable( 15 );
if ( parameters.transmission )
if ( parameters.specularColorMap )
_programLayers.enable( 16 );
if ( parameters.transmissionMap )
if ( parameters.transmission )
_programLayers.enable( 17 );
if ( parameters.thicknessMap )
if ( parameters.transmissionMap )
_programLayers.enable( 18 );
if ( parameters.sheen )
if ( parameters.thicknessMap )
_programLayers.enable( 19 );
if ( parameters.sheenColorMap )
if ( parameters.sheen )
_programLayers.enable( 20 );
if ( parameters.sheenRoughnessMap )
if ( parameters.sheenColorMap )
_programLayers.enable( 21 );
if ( parameters.decodeVideoTexture )
if ( parameters.sheenRoughnessMap )
_programLayers.enable( 22 );
if ( parameters.opaque )
if ( parameters.decodeVideoTexture )
_programLayers.enable( 23 );
if ( parameters.opaque )
_programLayers.enable( 24 );
array.push( _programLayers.mask );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册