Bre*_*ron 4 javascript node.js express three.js reactjs
我想使用 Three.js 显示用户上传的 STL 文件。
\n\n我的文件通过 GET 请求发送到前端:res.sendFile(path)
。问题是,如果不编辑 Three.js 的加载器,我就无法使用该原始数据来加载文件!
有人可以帮我编辑STLLoader以接受结果res.sendFile(path)
而不是路径(URL)吗?
经过一周的绞尽脑汁,我还是没有运气!
\n\n这是 STLLoader.js 的代码:
\n\nimport {\n BufferAttribute,\n BufferGeometry,\n DefaultLoadingManager,\n FileLoader,\n Float32BufferAttribute,\n LoaderUtils,\n Vector3\n} from "three/build/three.module.js";\n\n\nvar STLLoader = function ( manager ) {\n\n this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n};\n\nSTLLoader.prototype = {\n\n constructor: STLLoader,\n\n load: function ( url, onLoad, onProgress, onError ) {\n\n var scope = this;\n\n var loader = new FileLoader( scope.manager );\n loader.setPath( scope.path );\n loader.setResponseType( \'arraybuffer\' );\n loader.load( url, function ( text ) {\n\n try {\n\n onLoad( scope.parse( text ) );\n\n } catch ( exception ) {\n\n if ( onError ) {\n\n onError( exception );\n\n }\n\n }\n\n }, onProgress, onError );\n\n },\n\n setPath: function ( value ) {\n\n this.path = value;\n return this;\n\n },\n\n parse: function ( data ) {\n\n function isBinary( data ) {\n\n var expect, face_size, n_faces, reader;\n reader = new DataView( data );\n face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 );\n n_faces = reader.getUint32( 80, true );\n expect = 80 + ( 32 / 8 ) + ( n_faces * face_size );\n\n if ( expect === reader.byteLength ) {\n\n return true;\n\n }\n\n // An ASCII STL data must begin with \'solid \' as the first six bytes.\n // However, ASCII STLs lacking the SPACE after the \'d\' are known to be\n // plentiful. So, check the first 5 bytes for \'solid\'.\n\n // Several encodings, such as UTF-8, precede the text with up to 5 bytes:\n // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding\n // Search for "solid" to start anywhere after those prefixes.\n\n // US-ASCII ordinal values for \'s\', \'o\', \'l\', \'i\', \'d\'\n\n var solid = [ 115, 111, 108, 105, 100 ];\n\n for ( var off = 0; off < 5; off ++ ) {\n\n // If "solid" text is matched to the current offset, declare it to be an ASCII STL.\n\n if ( matchDataViewAt( solid, reader, off ) ) return false;\n\n }\n\n // Couldn\'t find "solid" text at the beginning; it is binary STL.\n\n return true;\n\n }\n\n function matchDataViewAt( query, reader, offset ) {\n\n // Check if each byte in query matches the corresponding byte from the current offset\n\n for ( var i = 0, il = query.length; i < il; i ++ ) {\n\n if ( query[ i ] !== reader.getUint8( offset + i, false ) ) return false;\n\n }\n\n return true;\n\n }\n\n function parseBinary( data ) {\n\n var reader = new DataView( data );\n var faces = reader.getUint32( 80, true );\n\n var r, g, b, hasColors = false, colors;\n var defaultR, defaultG, defaultB, alpha;\n\n // process STL header\n // check for default color in header ("COLOR=rgba" sequence).\n\n for ( var index = 0; index < 80 - 10; index ++ ) {\n\n if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) &&\n ( reader.getUint8( index + 4 ) == 0x52 /*\'R\'*/ ) &&\n ( reader.getUint8( index + 5 ) == 0x3D /*\'=\'*/ ) ) {\n\n hasColors = true;\n colors = new Float32Array( faces * 3 * 3 );\n\n defaultR = reader.getUint8( index + 6 ) / 255;\n defaultG = reader.getUint8( index + 7 ) / 255;\n defaultB = reader.getUint8( index + 8 ) / 255;\n alpha = reader.getUint8( index + 9 ) / 255;\n\n }\n\n }\n\n var dataOffset = 84;\n var faceLength = 12 * 4 + 2;\n\n var geometry = new BufferGeometry();\n\n var vertices = new Float32Array( faces * 3 * 3 );\n var normals = new Float32Array( faces * 3 * 3 );\n\n for ( var face = 0; face < faces; face ++ ) {\n\n var start = dataOffset + face * faceLength;\n var normalX = reader.getFloat32( start, true );\n var normalY = reader.getFloat32( start + 4, true );\n var normalZ = reader.getFloat32( start + 8, true );\n\n if ( hasColors ) {\n\n var packedColor = reader.getUint16( start + 48, true );\n\n if ( ( packedColor & 0x8000 ) === 0 ) {\n\n // facet has its own unique color\n\n r = ( packedColor & 0x1F ) / 31;\n g = ( ( packedColor >> 5 ) & 0x1F ) / 31;\n b = ( ( packedColor >> 10 ) & 0x1F ) / 31;\n\n } else {\n\n r = defaultR;\n g = defaultG;\n b = defaultB;\n\n }\n\n }\n\n for ( var i = 1; i <= 3; i ++ ) {\n\n var vertexstart = start + i * 12;\n var componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 );\n\n vertices[ componentIdx ] = reader.getFloat32( vertexstart, true );\n vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true );\n vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true );\n\n normals[ componentIdx ] = normalX;\n normals[ componentIdx + 1 ] = normalY;\n normals[ componentIdx + 2 ] = normalZ;\n\n if ( hasColors ) {\n\n colors[ componentIdx ] = r;\n colors[ componentIdx + 1 ] = g;\n colors[ componentIdx + 2 ] = b;\n\n }\n\n }\n\n }\n\n geometry.addAttribute( \'position\', new BufferAttribute( vertices, 3 ) );\n geometry.addAttribute( \'normal\', new BufferAttribute( normals, 3 ) );\n\n if ( hasColors ) {\n\n geometry.addAttribute( \'color\', new BufferAttribute( colors, 3 ) );\n geometry.hasColors = true;\n geometry.alpha = alpha;\n\n }\n\n return geometry;\n\n }\n\n function parseASCII( data ) {\n\n var geometry = new BufferGeometry();\n var patternSolid = /solid([\\s\\S]*?)endsolid/g;\n var patternFace = /facet([\\s\\S]*?)endfacet/g;\n var faceCounter = 0;\n\n var patternFloat = /[\\s]+([+-]?(?:\\d*)(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)/.source;\n var patternVertex = new RegExp( \'vertex\' + patternFloat + patternFloat + patternFloat, \'g\' );\n var patternNormal = new RegExp( \'normal\' + patternFloat + patternFloat + patternFloat, \'g\' );\n\n var vertices = [];\n var normals = [];\n\n var normal = new Vector3();\n\n var result;\n\n var groupVertexes = [];\n var groupCount = 0;\n var startVertex = 0;\n var endVertex = 0;\n\n while ( ( result = patternSolid.exec( data ) ) !== null ) {\n\n startVertex = endVertex;\n\n var solid = result[ 0 ];\n\n while ( ( result = patternFace.exec( solid ) ) !== null ) {\n\n var vertexCountPerFace = 0;\n var normalCountPerFace = 0;\n\n var text = result[ 0 ];\n\n while ( ( result = patternNormal.exec( text ) ) !== null ) {\n\n normal.x = parseFloat( result[ 1 ] );\n normal.y = parseFloat( result[ 2 ] );\n normal.z = parseFloat( result[ 3 ] );\n normalCountPerFace ++;\n\n }\n\n while ( ( result = patternVertex.exec( text ) ) !== null ) {\n\n vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) );\n normals.push( normal.x, normal.y, normal.z );\n vertexCountPerFace ++;\n endVertex ++;\n\n }\n\n // every face have to own ONE valid normal\n\n if ( normalCountPerFace !== 1 ) {\n\n console.error( \'THREE.STLLoader: Something isn\\\'t right with the normal of face number \' + faceCounter );\n\n }\n\n // each face have to own THREE valid vertices\n\n if ( vertexCountPerFace !== 3 ) {\n\n console.error( \'THREE.STLLoader: Something isn\\\'t right with the vertices of face number \' + faceCounter );\n\n }\n\n faceCounter ++;\n\n }\n\n groupVertexes.push( { startVertex: startVertex, endVertex: endVertex } );\n groupCount ++;\n\n }\n\n geometry.addAttribute( \'position\', new Float32BufferAttribute( vertices, 3 ) );\n geometry.addAttribute( \'normal\', new Float32BufferAttribute( normals, 3 ) );\n\n if ( groupCount > 0 ) {\n\n for ( var i = 0; i < groupVertexes.length; i ++ ) {\n\n geometry.addGroup( groupVertexes[ i ].startVertex, groupVertexes[ i ].endVertex, i );\n\n }\n\n }\n\n return geometry;\n\n }\n\n function ensureString( buffer ) {\n\n if ( typeof buffer !== \'string\' ) {\n\n return LoaderUtils.decodeText( new Uint8Array( buffer ) );\n\n }\n\n return buffer;\n\n }\n\n function ensureBinary( buffer ) {\n\n if ( typeof buffer === \'string\' ) {\n\n var array_buffer = new Uint8Array( buffer.length );\n for ( var i = 0; i < buffer.length; i ++ ) {\n\n array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian\n\n }\n\n return array_buffer.buffer || array_buffer;\n\n } else {\n\n return buffer;\n\n }\n\n }\n\n // start\n\n var binData = ensureBinary( data );\n\n return isBinary( binData ) ? parseBinary( binData ) : parseASCII( ensureString( data ) );\n\n }\n\n};\n\nexport { STLLoader };\n
Run Code Online (Sandbox Code Playgroud)\n\n一些额外的信息:
\n\n当我的前端收到文件数据时,它看起来像这样:\xef\xbf\xbdu#\xcd\xbe\xef\xbf\xbdO_?\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdW\xef\xbf\xbdBt\xef\xbf\xbd\xef\xbf\xbdB\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdA\xef\xbf\xbd\xef\xbf\xbdB\xe5\x87\xaaB\xef\xbf\xbdF\xef\xbf\xbdA\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbdBJJ\xef\xbf\xbdB\xc8\xa7A\xef\xbf\xbd\xdb\xa2>#(q>\xef\xbf\xbdk?\xef\xbf\xbd\xef\xbf\xbdB
我一直在尝试将其编码为ArrayBuffer
使用:
var enc = new TextEncoder();\n var arrayBuffer = enc.encode(fileString).buffer;\n
Run Code Online (Sandbox Code Playgroud)\n
读取客户端上拖放的文件。然后更改 THREE.DefaultLoadingManager.resolveURL 方法以转换请求的文件名,以将编码的文件内容作为 Blob 返回。然后,如果您需要服务器上传,此时,您可以启动它并让它在后台运行。
归档时间: |
|
查看次数: |
1977 次 |
最近记录: |