@jscad/regl-renderer 2.6.7 → 3.0.0-alpha.0
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.
- package/CHANGELOG.md +5 -189
- package/README.md +21 -11
- package/demo-cli.js +20 -16
- package/demo-web.js +6 -4
- package/demo.es.html +236 -0
- package/demo.html +21 -15
- package/dist/jscad-regl-renderer.es.js +13 -0
- package/dist/jscad-regl-renderer.min.js +13 -335
- package/package.json +41 -16
- package/rollup.config.js +27 -0
- package/src/bound-utils/boundingBox.js +1 -2
- package/src/bound-utils/boundingSphere.js +4 -5
- package/src/bound-utils/computeBounds.js +4 -6
- package/src/bound-utils/computeBounds.test.js +2 -2
- package/src/cameras/camera.js +15 -19
- package/src/cameras/index.js +8 -4
- package/src/cameras/orthographicCamera.js +4 -6
- package/src/cameras/perspectiveCamera.js +7 -9
- package/src/controls/index.js +6 -0
- package/src/controls/orbitControls.js +18 -27
- package/src/{geometry-utils-V2 → geometry-utils-V3}/entitiesFromSolids.js +7 -9
- package/src/{geometry-utils-V2 → geometry-utils-V3}/entitiesFromSolids.test.js +4 -4
- package/src/geometry-utils-V3/geom2ToGeometries.js +57 -0
- package/src/{geometry-utils-V2 → geometry-utils-V3}/geom2ToGeometries.test.js +16 -12
- package/src/{geometry-utils-V2 → geometry-utils-V3}/geom3ToGeometries.js +3 -5
- package/src/{geometry-utils-V2 → geometry-utils-V3}/geom3ToGeometries.test.js +2 -2
- package/src/{geometry-utils-V2 → geometry-utils-V3}/path2ToGeometries.js +4 -5
- package/src/{geometry-utils-V2 → geometry-utils-V3}/path2ToGeometries.test.js +2 -2
- package/src/index.js +5 -20
- package/src/rendering/commands/drawAxis/index.js +2 -4
- package/src/rendering/commands/drawExps/drawConnector/arcGeo.js +1 -3
- package/src/rendering/commands/drawExps/drawConnector/index.js +5 -7
- package/src/rendering/commands/drawExps/drawMesh.js +2 -4
- package/src/rendering/commands/drawExps/drawMeshNoNormals.js +2 -4
- package/src/rendering/commands/drawExps/drawNormals.js +2 -4
- package/src/rendering/commands/drawExps/drawNormals2.js +2 -4
- package/src/rendering/commands/drawGrid/{index.js → makeDrawGrid.js} +2 -4
- package/src/rendering/commands/drawGrid/{multi.js → makeDrawMultiGrid.js} +5 -5
- package/src/rendering/commands/drawLines/colorOnlyShaders.js +2 -2
- package/src/rendering/commands/drawLines/index.js +9 -7
- package/src/rendering/commands/drawLines/meshShaders.js +3 -3
- package/src/rendering/commands/drawLines/vColorShaders.js +3 -3
- package/src/rendering/commands/drawMesh/colorOnlyShaders.js +2 -2
- package/src/rendering/commands/drawMesh/index.js +8 -7
- package/src/rendering/commands/drawMesh/meshShaders.js +3 -3
- package/src/rendering/commands/drawMesh/vColorShaders.js +3 -3
- package/src/rendering/commands/index.js +11 -0
- package/src/rendering/render.js +10 -10
- package/src/rendering/renderContext.js +2 -4
- package/src/rendering/renderDefaults.js +9 -11
- package/src/utils.js +3 -6
- package/src/geometry-utils-V1/cagToGeometries.js +0 -52
- package/src/geometry-utils-V1/csgToGeometries.js +0 -220
- package/src/geometry-utils-V1/entitiesFromSolids.js +0 -75
- package/src/geometry-utils-V2/geom2ToGeometries.js +0 -66
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
const vec3 = require('gl-vec3')
|
|
2
|
-
|
|
3
|
-
const { toArray } = require('@jscad/array-utils')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* convert a CSG from csg.js to an array of geometries with positions, normals, colors & indices
|
|
7
|
-
* typically used for example to display the csg data in a webgl wiever
|
|
8
|
-
* @param {Array} csgs single or an array of CSG object
|
|
9
|
-
* @param {Object} options options hash
|
|
10
|
-
* @param {Boolean} options.smoothLighting=false set to true if we want to use interpolated vertex normals
|
|
11
|
-
* this creates nice round spheres but does not represent the shape of the actual model
|
|
12
|
-
* @param {Float} options.normalThreshold=0.349066 threshold beyond which to split normals // 20 deg
|
|
13
|
-
* @param {String} options.faceColor='#FF000' hex color
|
|
14
|
-
* @returns {Object} {indices, positions, normals, colors}
|
|
15
|
-
*/
|
|
16
|
-
const csgToGeometries = (csgs, options) => {
|
|
17
|
-
const defaults = {
|
|
18
|
-
smoothLighting: false, // set to true if we want to use interpolated vertex normals this creates nice round spheres but does not represent the shape of the actual model
|
|
19
|
-
normalThreshold: 0.349066, // 20 deg
|
|
20
|
-
faceColor: [1, 0.4, 0, 1]// default color
|
|
21
|
-
}
|
|
22
|
-
const { smoothLighting, normalThreshold, faceColor } = Object.assign({}, defaults, options)
|
|
23
|
-
const faceColorRgb = faceColor === undefined ? undefined : normalizedColor(faceColor) // TODO : detect if hex or rgba
|
|
24
|
-
|
|
25
|
-
const convert = (csg) => {
|
|
26
|
-
const geometries = []
|
|
27
|
-
|
|
28
|
-
const positions = []
|
|
29
|
-
const colors = []
|
|
30
|
-
const normals = []
|
|
31
|
-
const indices = []
|
|
32
|
-
|
|
33
|
-
// flag for transparency
|
|
34
|
-
let isTransparent = false
|
|
35
|
-
|
|
36
|
-
const polygons = csg.canonicalized().toPolygons()
|
|
37
|
-
|
|
38
|
-
/* let positions = new Float32Array(faces * 3 * 3)
|
|
39
|
-
let normals = new Float32Array(faces * 3 * 3) */
|
|
40
|
-
|
|
41
|
-
let normalPositionLookup = []
|
|
42
|
-
normalPositionLookup = {}
|
|
43
|
-
let tupplesIndex = 0
|
|
44
|
-
|
|
45
|
-
for (let i = 0; i < polygons.length; i++) {
|
|
46
|
-
const polygon = polygons[i]
|
|
47
|
-
|
|
48
|
-
const color = polygonColor(polygon, faceColorRgb)
|
|
49
|
-
const rawNormal = polygon.plane.normal
|
|
50
|
-
const normal = [rawNormal.x, rawNormal.y, rawNormal.z]
|
|
51
|
-
|
|
52
|
-
if (color[3] !== 1) {
|
|
53
|
-
isTransparent = true
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const polygonIndices = []
|
|
57
|
-
// we need unique tupples of normal + position , that gives us a specific index (indices)
|
|
58
|
-
// if the angle between a given normal and another normal is less than X they are considered the same
|
|
59
|
-
for (let j = 0; j < polygon.vertices.length; j++) {
|
|
60
|
-
let index
|
|
61
|
-
|
|
62
|
-
const vertex = polygon.vertices[j]
|
|
63
|
-
const position = [vertex.pos.x, vertex.pos.y, vertex.pos.z]
|
|
64
|
-
|
|
65
|
-
if (smoothLighting) {
|
|
66
|
-
const candidateTupple = { normal, position }
|
|
67
|
-
const existingTupple = fuzyNormalAndPositionLookup(normalPositionLookup, candidateTupple, normalThreshold)
|
|
68
|
-
if (!existingTupple) {
|
|
69
|
-
const existingPositing = normalPositionLookup[candidateTupple.position]
|
|
70
|
-
const itemToAdd = [{ normal: candidateTupple.normal, index: tupplesIndex }]
|
|
71
|
-
if (!existingPositing) {
|
|
72
|
-
normalPositionLookup[candidateTupple.position] = itemToAdd
|
|
73
|
-
} else {
|
|
74
|
-
normalPositionLookup[candidateTupple.position] = normalPositionLookup[candidateTupple.position]
|
|
75
|
-
.concat(itemToAdd)
|
|
76
|
-
}
|
|
77
|
-
index = tupplesIndex
|
|
78
|
-
// normalPositionLookup.push(candidateTupple)
|
|
79
|
-
// index = normalPositionLookup.length - 1
|
|
80
|
-
if (faceColor !== undefined) {
|
|
81
|
-
colors.push(color)
|
|
82
|
-
}
|
|
83
|
-
normals.push(normal)
|
|
84
|
-
positions.push(position)
|
|
85
|
-
tupplesIndex += 1
|
|
86
|
-
} else {
|
|
87
|
-
index = existingTupple.index
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
if (faceColor !== undefined) {
|
|
91
|
-
colors.push(color)
|
|
92
|
-
}
|
|
93
|
-
normals.push(normal)
|
|
94
|
-
positions.push(position)
|
|
95
|
-
index = positions.length - 1
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// let prevcolor = colors[index]
|
|
99
|
-
polygonIndices.push(index)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
for (let j = 2; j < polygonIndices.length; j++) {
|
|
103
|
-
indices.push([polygonIndices[0], polygonIndices[j - 1], polygonIndices[j]])
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// if too many vertices or we are at the end, start a new geometry
|
|
107
|
-
if (positions.length > 65000 || i === polygons.length - 1) {
|
|
108
|
-
// special case to deal with face color SPECICIALLY SET TO UNDEFINED
|
|
109
|
-
if (faceColor === undefined) {
|
|
110
|
-
geometries.push({
|
|
111
|
-
indices,
|
|
112
|
-
positions,
|
|
113
|
-
normals,
|
|
114
|
-
isTransparent
|
|
115
|
-
})
|
|
116
|
-
} else {
|
|
117
|
-
geometries.push({
|
|
118
|
-
indices,
|
|
119
|
-
positions,
|
|
120
|
-
normals,
|
|
121
|
-
colors,
|
|
122
|
-
isTransparent
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return geometries
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
csgs = toArray(csgs)
|
|
131
|
-
const geometriesPerCsg = csgs.map(convert)
|
|
132
|
-
|
|
133
|
-
return geometriesPerCsg
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** determine if input is a hex (color) or not
|
|
137
|
-
* @param {Object} object a string, array, object , whatever
|
|
138
|
-
* @returns {Boolean} wether the input is a hex string or not
|
|
139
|
-
*/
|
|
140
|
-
const isHexColor = (object) => {
|
|
141
|
-
if (typeof sNum !== 'string') {
|
|
142
|
-
return false
|
|
143
|
-
}
|
|
144
|
-
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(object)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// modified from https://stackoverflow.com/questions/21646738/convert-hex-to-rgba
|
|
148
|
-
const hexToRgbNormalized = (hex, alpha) => {
|
|
149
|
-
hex = hex.replace('#', '')
|
|
150
|
-
const r = parseInt(hex.length === 3 ? hex.slice(0, 1).repeat(2) : hex.slice(0, 2), 16)
|
|
151
|
-
const g = parseInt(hex.length === 3 ? hex.slice(1, 2).repeat(2) : hex.slice(2, 4), 16)
|
|
152
|
-
const b = parseInt(hex.length === 3 ? hex.slice(2, 3).repeat(2) : hex.slice(4, 6), 16)
|
|
153
|
-
return (alpha ? [r, g, b, alpha] : [r, g, b, 255]).map((x) => x / 255)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** outputs a normalized [0...1] range, 4 component array color
|
|
157
|
-
* @param {} input
|
|
158
|
-
*/
|
|
159
|
-
const normalizedColor = (input) => {
|
|
160
|
-
if (isHexColor(input)) {
|
|
161
|
-
return hexToRgbNormalized(input)
|
|
162
|
-
} else if (Array.isArray(input) && input.length >= 3) {
|
|
163
|
-
input = input.length < 4 ? [input[0], input[1], input[2], 1] : input.slice(0, 4)
|
|
164
|
-
if (input[0] > 1 || input[1] > 1 || input[2] > 1) {
|
|
165
|
-
return input.map((x) => x / 255)
|
|
166
|
-
}
|
|
167
|
-
return input
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* return the color information of a polygon
|
|
173
|
-
* @param {Object} polygon a csg.js polygon
|
|
174
|
-
* @param {Object} faceColor a hex color value to default to
|
|
175
|
-
* @returns {Array} `[r, g, b, a]`
|
|
176
|
-
*/
|
|
177
|
-
const polygonColor = (polygon, faceColor) => {
|
|
178
|
-
let color = faceColor
|
|
179
|
-
|
|
180
|
-
if (polygon.shared && polygon.shared.color) {
|
|
181
|
-
color = polygon.shared.color
|
|
182
|
-
} else if (polygon.color) {
|
|
183
|
-
color = polygon.color
|
|
184
|
-
}
|
|
185
|
-
// opaque is default
|
|
186
|
-
if (color !== undefined && color.length < 4) {
|
|
187
|
-
color.push(1.0)
|
|
188
|
-
}
|
|
189
|
-
return color
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* determine if the two given normals are 'similar' ie if the distance/angle between the
|
|
194
|
-
* two is less than the given threshold
|
|
195
|
-
* @param {Array} normal a 3 component array normal
|
|
196
|
-
* @param {Array} otherNormal another 3 component array normal
|
|
197
|
-
* @returns {Boolean} true if the two normals are similar
|
|
198
|
-
*/
|
|
199
|
-
const areNormalsSimilar = (normal, otherNormal, threshold) => vec3.distance(normal, otherNormal) <= threshold
|
|
200
|
-
// angle computation is too slow but actually precise
|
|
201
|
-
// return vec3.angle(normal, otherNormal) <= threshold
|
|
202
|
-
|
|
203
|
-
const fuzyNormalAndPositionLookup = (normalPositionLookup, toCompare, normalThreshold = 0.349066) => {
|
|
204
|
-
const normalsCandidates = normalPositionLookup[toCompare.position]
|
|
205
|
-
if (normalsCandidates) {
|
|
206
|
-
// normalPositionLookup[toCompare.position] = normalPositionLookup[toCompare.position].concat([toCompare.normal])
|
|
207
|
-
// get array of normals with same position
|
|
208
|
-
for (let i = 0; i < normalsCandidates.length; i++) {
|
|
209
|
-
const normal = normalsCandidates[i].normal
|
|
210
|
-
const similarNormal = areNormalsSimilar(normal, toCompare.normal, normalThreshold)
|
|
211
|
-
const similar = similarNormal
|
|
212
|
-
if (similar) {
|
|
213
|
-
return { tupple: { position: toCompare.position, normal }, index: normalsCandidates[i].index }
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return undefined
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
module.exports = csgToGeometries
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
const mat4 = require('gl-mat4')
|
|
2
|
-
const { flatten, toArray } = require('@jscad/array-utils')
|
|
3
|
-
const csgToGeometries = require('./csgToGeometries')
|
|
4
|
-
const cagToGeometries = require('./cagToGeometries')
|
|
5
|
-
const computeBounds = require('../bound-utils/computeBounds')
|
|
6
|
-
|
|
7
|
-
const entitiesFromSolids = (params, solids) => {
|
|
8
|
-
const defaults = {
|
|
9
|
-
meshColor: [0, 0.6, 1, 1],
|
|
10
|
-
smoothNormals: true
|
|
11
|
-
}
|
|
12
|
-
const { meshColor, smoothNormals } = defaults
|
|
13
|
-
// const defaultColor = params.rendering.meshColor
|
|
14
|
-
solids = toArray(solids)
|
|
15
|
-
// warning !!! fixTJunctions alters the csg and can result in visual issues ??
|
|
16
|
-
// .fixTJunctions()
|
|
17
|
-
// cachedSolids = solids
|
|
18
|
-
// const start = performance.now()
|
|
19
|
-
const entities = solids.map((solid) => {
|
|
20
|
-
let geometry
|
|
21
|
-
let type
|
|
22
|
-
if ('sides' in solid) {
|
|
23
|
-
type = '2d'
|
|
24
|
-
geometry = cagToGeometries(solid, { color: meshColor })
|
|
25
|
-
} else if ('polygons' in solid) {
|
|
26
|
-
type = '3d'
|
|
27
|
-
geometry = csgToGeometries(solid, {
|
|
28
|
-
smoothLighting: smoothNormals,
|
|
29
|
-
normalThreshold: 0.3,
|
|
30
|
-
faceColor: meshColor
|
|
31
|
-
})//, normalThreshold: 0})
|
|
32
|
-
}
|
|
33
|
-
// geometry = flatten(geometries)// FXIME : ACTUALLY deal with arrays since a single csg can
|
|
34
|
-
// generate multiple geometries if positions count is >65535
|
|
35
|
-
geometry = flatten(geometry)[0]
|
|
36
|
-
|
|
37
|
-
// bounds
|
|
38
|
-
const bounds = computeBounds({ geometry })// FXIME : ACTUALLY deal with arrays as inputs see above
|
|
39
|
-
|
|
40
|
-
// transforms: for now not used, since all transformed are stored in the geometry
|
|
41
|
-
// FIXME : for V2 we will be able to use the transfors provided by the solids directly
|
|
42
|
-
const matrix = mat4.identity([])
|
|
43
|
-
|
|
44
|
-
const transforms = {
|
|
45
|
-
matrix
|
|
46
|
-
/* const modelViewMatrix = mat4.multiply(mat4.create(), model, props.camera.view)
|
|
47
|
-
const normalMatrix = mat4.create()
|
|
48
|
-
mat4.invert(normalMatrix, modelViewMatrix)
|
|
49
|
-
mat4.transpose(normalMatrix, normalMatrix)
|
|
50
|
-
return normalMatrix */
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const visuals = {
|
|
54
|
-
drawCmd: 'drawMesh',
|
|
55
|
-
show: true,
|
|
56
|
-
color: meshColor,
|
|
57
|
-
transparent: geometry.isTransparent, // not sure
|
|
58
|
-
useVertexColors: true
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const entity = {
|
|
62
|
-
type,
|
|
63
|
-
geometry,
|
|
64
|
-
transforms,
|
|
65
|
-
bounds,
|
|
66
|
-
visuals,
|
|
67
|
-
isTransparent: geometry.isTransparent
|
|
68
|
-
}
|
|
69
|
-
return entity
|
|
70
|
-
})
|
|
71
|
-
// }
|
|
72
|
-
return entities
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports = entitiesFromSolids
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
const mat4 = require('gl-mat4')
|
|
2
|
-
|
|
3
|
-
const maxIndex = Math.floor(65535 / 2) // two vertices per segment
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
* Convert the given solid into one or more geometries for rendering.
|
|
7
|
-
* @param {Object} options - options for conversion
|
|
8
|
-
* @param {Array} options.color - RGBA of solid
|
|
9
|
-
* @param {geom2} solid - the solid to convert
|
|
10
|
-
* @return {Array} list of new geometries
|
|
11
|
-
*/
|
|
12
|
-
const geom2ToGeometries = (options, solid) => {
|
|
13
|
-
let { color } = options
|
|
14
|
-
|
|
15
|
-
const sides = solid.sides
|
|
16
|
-
if (sides.length === 0) return []
|
|
17
|
-
|
|
18
|
-
if ('color' in solid) color = solid.color
|
|
19
|
-
const isTransparent = (color[3] < 1.0)
|
|
20
|
-
const colors = []
|
|
21
|
-
const numgeometries = Math.floor(sides.length / (maxIndex)) + 1
|
|
22
|
-
|
|
23
|
-
const addColor = (startColor, endColor) => {
|
|
24
|
-
// each line needs 2 colors: startColor and endColor
|
|
25
|
-
// endColor is optional
|
|
26
|
-
colors.push(startColor, endColor || startColor)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const geometries = []
|
|
30
|
-
for (let g = 0; g < numgeometries; g++) {
|
|
31
|
-
const offset = g * maxIndex
|
|
32
|
-
const endset = Math.min(offset + maxIndex, sides.length)
|
|
33
|
-
const positions = []
|
|
34
|
-
|
|
35
|
-
for (let i = offset; i < endset; i++) {
|
|
36
|
-
const side = sides[i]
|
|
37
|
-
if (side.color) {
|
|
38
|
-
// backfill colors, so colors array is not used unless at least one side has color defined
|
|
39
|
-
if (colors.length === 0 && positions.length > 0) {
|
|
40
|
-
const toFill = positions.length
|
|
41
|
-
for (let j = 0; j < toFill; j++) {
|
|
42
|
-
colors.push(color) // push default color
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
// shader actually allows for gradient on the lines by design
|
|
46
|
-
addColor(side.color, side.endColor)
|
|
47
|
-
} else if (colors.length) {
|
|
48
|
-
addColor(color)
|
|
49
|
-
}
|
|
50
|
-
positions.push([side[0][0], side[0][1], 0])
|
|
51
|
-
positions.push([side[1][0], side[1][1], 0])
|
|
52
|
-
}
|
|
53
|
-
// assemble the geometry
|
|
54
|
-
const normals = positions.map((x) => [0, 0, -1])
|
|
55
|
-
const indices = positions.map((x, i) => i)
|
|
56
|
-
const transforms = solid.transforms ? mat4.clone(solid.transforms) : mat4.create()
|
|
57
|
-
|
|
58
|
-
// FIXME positions should be Float32Array buffers to eliminate another conversion
|
|
59
|
-
// FIXME normals should be Float32Array buffers to eliminate another conversion
|
|
60
|
-
// FIXME indices should be Uint16Array buffers to eliminate another conversion
|
|
61
|
-
geometries.push({ type: '2d', positions, normals, indices, transforms, color, colors, isTransparent })
|
|
62
|
-
}
|
|
63
|
-
return geometries
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
module.exports = geom2ToGeometries
|