@damienmortini/three 0.1.181 → 0.1.183

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1225,6 +1225,112 @@ function mergeGroups( geometry ) {
1225
1225
 
1226
1226
  }
1227
1227
 
1228
+
1229
+ // Creates a new, non-indexed geometry with smooth normals everywhere except faces that meet at
1230
+ // an angle greater than the crease angle.
1231
+ function toCreasedNormals( geometry, creaseAngle = Math.PI / 3 /* 60 degrees */ ) {
1232
+
1233
+ const creaseDot = Math.cos( creaseAngle );
1234
+ const hashMultiplier = ( 1 + 1e-10 ) * 1e2;
1235
+
1236
+ // reusable vertors
1237
+ const verts = [ new Vector3(), new Vector3(), new Vector3() ];
1238
+ const tempVec1 = new Vector3();
1239
+ const tempVec2 = new Vector3();
1240
+ const tempNorm = new Vector3();
1241
+ const tempNorm2 = new Vector3();
1242
+
1243
+ // hashes a vector
1244
+ function hashVertex( v ) {
1245
+
1246
+ const x = ~ ~ ( v.x * hashMultiplier );
1247
+ const y = ~ ~ ( v.y * hashMultiplier );
1248
+ const z = ~ ~ ( v.z * hashMultiplier );
1249
+ return `${x},${y},${z}`;
1250
+
1251
+ }
1252
+
1253
+ const resultGeometry = geometry.toNonIndexed();
1254
+ const posAttr = resultGeometry.attributes.position;
1255
+ const vertexMap = {};
1256
+
1257
+ // find all the normals shared by commonly located vertices
1258
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
1259
+
1260
+ const i3 = 3 * i;
1261
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
1262
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
1263
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
1264
+
1265
+ tempVec1.subVectors( c, b );
1266
+ tempVec2.subVectors( a, b );
1267
+
1268
+ // add the normal to the map for all vertices
1269
+ const normal = new Vector3().crossVectors( tempVec1, tempVec2 ).normalize();
1270
+ for ( let n = 0; n < 3; n ++ ) {
1271
+
1272
+ const vert = verts[ n ];
1273
+ const hash = hashVertex( vert );
1274
+ if ( ! ( hash in vertexMap ) ) {
1275
+
1276
+ vertexMap[ hash ] = [];
1277
+
1278
+ }
1279
+
1280
+ vertexMap[ hash ].push( normal );
1281
+
1282
+ }
1283
+
1284
+ }
1285
+
1286
+ // average normals from all vertices that share a common location if they are within the
1287
+ // provided crease threshold
1288
+ const normalArray = new Float32Array( posAttr.count * 3 );
1289
+ const normAttr = new BufferAttribute( normalArray, 3, false );
1290
+ for ( let i = 0, l = posAttr.count / 3; i < l; i ++ ) {
1291
+
1292
+ // get the face normal for this vertex
1293
+ const i3 = 3 * i;
1294
+ const a = verts[ 0 ].fromBufferAttribute( posAttr, i3 + 0 );
1295
+ const b = verts[ 1 ].fromBufferAttribute( posAttr, i3 + 1 );
1296
+ const c = verts[ 2 ].fromBufferAttribute( posAttr, i3 + 2 );
1297
+
1298
+ tempVec1.subVectors( c, b );
1299
+ tempVec2.subVectors( a, b );
1300
+
1301
+ tempNorm.crossVectors( tempVec1, tempVec2 ).normalize();
1302
+
1303
+ // average all normals that meet the threshold and set the normal value
1304
+ for ( let n = 0; n < 3; n ++ ) {
1305
+
1306
+ const vert = verts[ n ];
1307
+ const hash = hashVertex( vert );
1308
+ const otherNormals = vertexMap[ hash ];
1309
+ tempNorm2.set( 0, 0, 0 );
1310
+
1311
+ for ( let k = 0, lk = otherNormals.length; k < lk; k ++ ) {
1312
+
1313
+ const otherNorm = otherNormals[ k ];
1314
+ if ( tempNorm.dot( otherNorm ) > creaseDot ) {
1315
+
1316
+ tempNorm2.add( otherNorm );
1317
+
1318
+ }
1319
+
1320
+ }
1321
+
1322
+ tempNorm2.normalize();
1323
+ normAttr.setXYZ( i3 + n, tempNorm2.x, tempNorm2.y, tempNorm2.z );
1324
+
1325
+ }
1326
+
1327
+ }
1328
+
1329
+ resultGeometry.setAttribute( 'normal', normAttr );
1330
+ return resultGeometry;
1331
+
1332
+ }
1333
+
1228
1334
  export {
1229
1335
  computeTangents,
1230
1336
  computeMikkTSpaceTangents,
@@ -1235,5 +1341,6 @@ export {
1235
1341
  mergeVertices,
1236
1342
  toTrianglesDrawMode,
1237
1343
  computeMorphedAttributes,
1238
- mergeGroups
1344
+ mergeGroups,
1345
+ toCreasedNormals
1239
1346
  };
@@ -1,175 +1,175 @@
1
- import { Mesh, OrthographicCamera, PlaneBufferGeometry, DataTexture, RGBAFormat, FloatType, WebGLRenderer, WebGLRenderTarget, Scene, NearestFilter, RGBFormat, HalfFloatType, MathUtils } from '../../../three/src/Three.js'
2
-
3
- import THREEShaderMaterial from '../material/THREEShaderMaterial.js'
4
- import DatatextureShader from '@damienmortini/core/shader/DataTextureShader.js'
5
- import Float16 from '@damienmortini/core/math/Float16.js'
6
-
7
- let DEBUG_RENDERER
8
-
9
- export default class THREEGPGPUSystem {
10
- constructor({
11
- data,
12
- renderer,
13
- uniforms = {},
14
- stride = 1,
15
- fragmentChunks = [],
16
- format = RGBAFormat,
17
- debug = false,
18
- }) {
19
- this._renderer = renderer
20
- this._stride = stride
21
-
22
- const channels = format === RGBFormat ? 3 : 4
23
- const dataSize = data.length / channels / stride
24
- const width = MathUtils.ceilPowerOfTwo(Math.sqrt(dataSize))
25
- this._dataTextureWidth = width * stride
26
- this._dataTextureHeight = MathUtils.ceilPowerOfTwo(dataSize / width)
27
-
28
- this.debug = debug
29
-
30
- const finalData = new Float32Array(this._dataTextureWidth * this._dataTextureHeight * channels)
31
- finalData.set(data)
32
- let dataTexture
33
- // if (renderer.capabilities.isWebGL2) {
34
- dataTexture = new DataTexture(finalData, this._dataTextureWidth, this._dataTextureHeight, format, FloatType)
35
- // } else {
36
- // dataTexture = new DataTexture(Float16.fromFloat32Array(finalData), this._dataTextureWidth, this._dataTextureHeight, format, HalfFloatType);
37
- // }
38
- dataTexture.needsUpdate = true
39
-
40
- this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
41
- this.scene = new Scene()
42
-
43
- this._webglRenderTargetIn = new WebGLRenderTarget(this._dataTextureWidth, this._dataTextureHeight, {
44
- minFilter: NearestFilter,
45
- magFilter: NearestFilter,
46
- format,
47
- stencilBuffer: false,
48
- depthBuffer: false,
49
- type: renderer.capabilities.isWebGL2 ? FloatType : HalfFloatType, // Half float for iOS
50
- })
51
- this._webglRenderTargetIn.texture.generateMipmaps = false
52
- this._webglRenderTargetOut = this._webglRenderTargetIn.clone()
53
-
54
- this._quad = new Mesh(new PlaneBufferGeometry(2, 2), new THREEShaderMaterial({
55
- uniforms: {
56
- dataTexture,
57
- ...uniforms,
58
- },
59
- fragment: `
60
- void main() {
61
- gl_FragColor = vec4(0.);
62
- }
63
- `,
64
- vertexChunks: [
65
- ['start',
66
- 'out vec2 vUV;',
67
- ],
68
- ['main',
69
- 'vUV = uv;',
70
- ],
71
- ],
72
- fragmentChunks: [
73
- ...fragmentChunks,
74
- ['start', `
75
- #define DATA_TEXTURE_WIDTH ${this.dataTextureWidth.toFixed(1)}
76
- #define DATA_TEXTURE_HEIGHT ${this.dataTextureHeight.toFixed(1)}
77
-
78
- uniform highp sampler2D dataTexture;
79
-
80
- in vec2 vUV;
81
-
82
- ${DatatextureShader.getTextureDataChunkFromUV()}
83
-
84
- vec4 getDataChunk(int chunkIndex) {
85
- return getTextureDataChunkFromUV(dataTexture, vUV, chunkIndex, ${stride}, vec2(DATA_TEXTURE_WIDTH, DATA_TEXTURE_HEIGHT));
86
- }
87
-
88
- int getDataIndex() {
89
- vec2 dataPosition = floor(vUV * vec2(DATA_TEXTURE_WIDTH / float(${stride}), DATA_TEXTURE_HEIGHT));
90
- return int(dataPosition.x + dataPosition.y * DATA_TEXTURE_WIDTH / float(${stride}));
91
- }
92
-
93
- int getChunkIndex() {
94
- return int(mod(vUV * DATA_TEXTURE_WIDTH, float(${stride})));
95
- }
96
- `],
97
- ],
98
- }))
99
- this.scene.add(this._quad)
100
- }
101
-
102
- get onBeforeRender() {
103
- return this._quad.onBeforeRender
104
- }
105
-
106
- set onBeforeRender(value) {
107
- this._quad.onBeforeRender = value
108
- }
109
-
110
- get material() {
111
- return this._quad.material
112
- }
113
-
114
- get dataTextureWidth() {
115
- return this._dataTextureWidth
116
- }
117
-
118
- get dataTextureHeight() {
119
- return this._dataTextureHeight
120
- }
121
-
122
- get dataTextureSize() {
123
- return [this._dataTextureWidth, this._dataTextureHeight]
124
- }
125
-
126
- get dataTexture() {
127
- return this._quad.material.dataTexture
128
- }
129
-
130
- get stride() {
131
- return this._stride
132
- }
133
-
134
- get debug() {
135
- return this._debug
136
- }
137
-
138
- set debug(value) {
139
- this._debug = value
140
- if (this._debug && !DEBUG_RENDERER) {
141
- DEBUG_RENDERER = new WebGLRenderer()
142
- document.body.appendChild(DEBUG_RENDERER.domElement)
143
- DEBUG_RENDERER.setSize(this._dataTextureWidth, this._dataTextureHeight, false)
144
- DEBUG_RENDERER.domElement.style.position = 'absolute'
145
- DEBUG_RENDERER.domElement.style.bottom = '0'
146
- DEBUG_RENDERER.domElement.style.left = '0'
147
- DEBUG_RENDERER.domElement.style.width = '100%'
148
- DEBUG_RENDERER.domElement.style.height = '25%'
149
- DEBUG_RENDERER.domElement.style.imageRendering = 'pixelated'
150
- }
151
- if (DEBUG_RENDERER) {
152
- DEBUG_RENDERER.domElement.hidden = !this._debug
153
- }
154
- }
155
-
156
- update() {
157
- const savedRendertarget = this._renderer.getRenderTarget()
158
-
159
- this._renderer.setRenderTarget(this._webglRenderTargetOut)
160
- this._renderer.render(this.scene, this.camera)
161
-
162
- if (this.debug) {
163
- DEBUG_RENDERER.setRenderTarget(this._webglRenderTargetOut)
164
- DEBUG_RENDERER.render(this.scene, this.camera)
165
- DEBUG_RENDERER.setRenderTarget(null)
166
- DEBUG_RENDERER.render(this.scene, this.camera)
167
- }
168
-
169
- [this._webglRenderTargetIn, this._webglRenderTargetOut] = [this._webglRenderTargetOut, this._webglRenderTargetIn]
170
-
171
- this._quad.material.dataTexture = this._webglRenderTargetIn.texture
172
-
173
- this._renderer.setRenderTarget(savedRendertarget)
174
- }
175
- }
1
+ import { Mesh, OrthographicCamera, PlaneBufferGeometry, DataTexture, RGBAFormat, FloatType, WebGLRenderer, WebGLRenderTarget, Scene, NearestFilter, RGBFormat, HalfFloatType, MathUtils } from '../../../three/src/Three.js'
2
+
3
+ import THREEShaderMaterial from '../material/THREEShaderMaterial.js'
4
+ import DatatextureShader from '@damienmortini/core/shader/DataTextureShader.js'
5
+ import Float16 from '@damienmortini/core/math/Float16.js'
6
+
7
+ let DEBUG_RENDERER
8
+
9
+ export default class THREEGPGPUSystem {
10
+ constructor({
11
+ data,
12
+ renderer,
13
+ uniforms = {},
14
+ stride = 1,
15
+ fragmentChunks = [],
16
+ format = RGBAFormat,
17
+ debug = false,
18
+ }) {
19
+ this._renderer = renderer
20
+ this._stride = stride
21
+
22
+ const channels = format === RGBFormat ? 3 : 4
23
+ const dataSize = data.length / channels / stride
24
+ const width = MathUtils.ceilPowerOfTwo(Math.sqrt(dataSize))
25
+ this._dataTextureWidth = width * stride
26
+ this._dataTextureHeight = MathUtils.ceilPowerOfTwo(dataSize / width)
27
+
28
+ this.debug = debug
29
+
30
+ const finalData = new Float32Array(this._dataTextureWidth * this._dataTextureHeight * channels)
31
+ finalData.set(data)
32
+ let dataTexture
33
+ // if (renderer.capabilities.isWebGL2) {
34
+ dataTexture = new DataTexture(finalData, this._dataTextureWidth, this._dataTextureHeight, format, FloatType)
35
+ // } else {
36
+ // dataTexture = new DataTexture(Float16.fromFloat32Array(finalData), this._dataTextureWidth, this._dataTextureHeight, format, HalfFloatType);
37
+ // }
38
+ dataTexture.needsUpdate = true
39
+
40
+ this.camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1)
41
+ this.scene = new Scene()
42
+
43
+ this._webglRenderTargetIn = new WebGLRenderTarget(this._dataTextureWidth, this._dataTextureHeight, {
44
+ minFilter: NearestFilter,
45
+ magFilter: NearestFilter,
46
+ format,
47
+ stencilBuffer: false,
48
+ depthBuffer: false,
49
+ type: renderer.capabilities.isWebGL2 ? FloatType : HalfFloatType, // Half float for iOS
50
+ })
51
+ this._webglRenderTargetIn.texture.generateMipmaps = false
52
+ this._webglRenderTargetOut = this._webglRenderTargetIn.clone()
53
+
54
+ this._quad = new Mesh(new PlaneBufferGeometry(2, 2), new THREEShaderMaterial({
55
+ uniforms: {
56
+ dataTexture,
57
+ ...uniforms,
58
+ },
59
+ fragment: `
60
+ void main() {
61
+ gl_FragColor = vec4(0.);
62
+ }
63
+ `,
64
+ vertexChunks: [
65
+ ['start',
66
+ 'out vec2 vUV;',
67
+ ],
68
+ ['main',
69
+ 'vUV = uv;',
70
+ ],
71
+ ],
72
+ fragmentChunks: [
73
+ ...fragmentChunks,
74
+ ['start', `
75
+ #define DATA_TEXTURE_WIDTH ${this.dataTextureWidth.toFixed(1)}
76
+ #define DATA_TEXTURE_HEIGHT ${this.dataTextureHeight.toFixed(1)}
77
+
78
+ uniform highp sampler2D dataTexture;
79
+
80
+ in vec2 vUV;
81
+
82
+ ${DatatextureShader.getTextureDataChunkFromUV()}
83
+
84
+ vec4 getDataChunk(int chunkIndex) {
85
+ return getTextureDataChunkFromUV(dataTexture, vUV, chunkIndex, ${stride}, vec2(DATA_TEXTURE_WIDTH, DATA_TEXTURE_HEIGHT));
86
+ }
87
+
88
+ int getDataIndex() {
89
+ vec2 dataPosition = floor(vUV * vec2(DATA_TEXTURE_WIDTH / float(${stride}), DATA_TEXTURE_HEIGHT));
90
+ return int(dataPosition.x + dataPosition.y * DATA_TEXTURE_WIDTH / float(${stride}));
91
+ }
92
+
93
+ int getChunkIndex() {
94
+ return int(mod(vUV * DATA_TEXTURE_WIDTH, float(${stride})));
95
+ }
96
+ `],
97
+ ],
98
+ }))
99
+ this.scene.add(this._quad)
100
+ }
101
+
102
+ get onBeforeRender() {
103
+ return this._quad.onBeforeRender
104
+ }
105
+
106
+ set onBeforeRender(value) {
107
+ this._quad.onBeforeRender = value
108
+ }
109
+
110
+ get material() {
111
+ return this._quad.material
112
+ }
113
+
114
+ get dataTextureWidth() {
115
+ return this._dataTextureWidth
116
+ }
117
+
118
+ get dataTextureHeight() {
119
+ return this._dataTextureHeight
120
+ }
121
+
122
+ get dataTextureSize() {
123
+ return [this._dataTextureWidth, this._dataTextureHeight]
124
+ }
125
+
126
+ get dataTexture() {
127
+ return this._quad.material.dataTexture
128
+ }
129
+
130
+ get stride() {
131
+ return this._stride
132
+ }
133
+
134
+ get debug() {
135
+ return this._debug
136
+ }
137
+
138
+ set debug(value) {
139
+ this._debug = value
140
+ if (this._debug && !DEBUG_RENDERER) {
141
+ DEBUG_RENDERER = new WebGLRenderer()
142
+ document.body.appendChild(DEBUG_RENDERER.domElement)
143
+ DEBUG_RENDERER.setSize(this._dataTextureWidth, this._dataTextureHeight, false)
144
+ DEBUG_RENDERER.domElement.style.position = 'absolute'
145
+ DEBUG_RENDERER.domElement.style.bottom = '0'
146
+ DEBUG_RENDERER.domElement.style.left = '0'
147
+ DEBUG_RENDERER.domElement.style.width = '100%'
148
+ DEBUG_RENDERER.domElement.style.height = '25%'
149
+ DEBUG_RENDERER.domElement.style.imageRendering = 'pixelated'
150
+ }
151
+ if (DEBUG_RENDERER) {
152
+ DEBUG_RENDERER.domElement.hidden = !this._debug
153
+ }
154
+ }
155
+
156
+ update() {
157
+ const savedRendertarget = this._renderer.getRenderTarget()
158
+
159
+ this._renderer.setRenderTarget(this._webglRenderTargetOut)
160
+ this._renderer.render(this.scene, this.camera)
161
+
162
+ if (this.debug) {
163
+ DEBUG_RENDERER.setRenderTarget(this._webglRenderTargetOut)
164
+ DEBUG_RENDERER.render(this.scene, this.camera)
165
+ DEBUG_RENDERER.setRenderTarget(null)
166
+ DEBUG_RENDERER.render(this.scene, this.camera)
167
+ }
168
+
169
+ [this._webglRenderTargetIn, this._webglRenderTargetOut] = [this._webglRenderTargetOut, this._webglRenderTargetIn]
170
+
171
+ this._quad.material.dataTexture = this._webglRenderTargetIn.texture
172
+
173
+ this._renderer.setRenderTarget(savedRendertarget)
174
+ }
175
+ }