Source: extern/geometry.js

  1. import register from "../util/register.js";
  2. import m_batch_fact from "../intern/batch.js";
  3. import m_geom_fact from "../intern/geometry.js";
  4. import m_print_fact from "../intern/print.js";
  5. import m_render_fact from "../intern/renderer.js";
  6. import * as m_tbn from "../intern/tbn.js";
  7. /**
  8. * Low-level geometry API.
  9. * Enable the "Dynamic geometry" checkbox for the objects to allow geometry modification.
  10. * @module geometry
  11. */
  12. function Geometry(ns, exports) {
  13. var m_batch = m_batch_fact(ns);
  14. var m_geom = m_geom_fact(ns);
  15. var m_print = m_print_fact(ns);
  16. var m_render = m_render_fact(ns);
  17. /**
  18. * Extract the vertex array from the object.
  19. * @method module:geometry.extract_vertex_array
  20. * @param {Object3D} obj Object 3D
  21. * @param {string} mat_name Material name
  22. * @param {string} attrib_name Attribute name (a_position, a_tbn, a_normal)
  23. * @returns {Float32Array} Vertex array
  24. */
  25. exports.extract_vertex_array = function(obj, mat_name, attrib_name) {
  26. if (!m_geom.has_dyn_geom(obj)) {
  27. m_print.error("Wrong object:", obj.name);
  28. return null;
  29. }
  30. var batch = m_batch.find_batch_material(obj, mat_name, "MAIN");
  31. if (batch) {
  32. var bufs_data = batch.bufs_data;
  33. if (bufs_data && bufs_data.pointers &&
  34. (attrib_name == "a_normal" && bufs_data.pointers["a_tbn"] ||
  35. bufs_data.pointers[attrib_name])) {
  36. return m_geom.extract_array_float(bufs_data, attrib_name);
  37. } else {
  38. m_print.error("Attribute not found:" + attrib_name);
  39. return null;
  40. }
  41. } else {
  42. m_print.error("Wrong material:", mat_name);
  43. return null;
  44. }
  45. }
  46. /**
  47. * Extract the array of triangulated face indices from the given object.
  48. * @method module:geometry.extract_index_array
  49. * @param {Object3D} obj Object 3D
  50. * @param {string} mat_name Material name
  51. * @returns {Uint16Array|Uint32Array} Array of triangle indices
  52. */
  53. exports.extract_index_array = function(obj, mat_name) {
  54. if (!m_geom.has_dyn_geom(obj)) {
  55. m_print.error("Wrong object:", obj.name);
  56. return null;
  57. }
  58. var batch = m_batch.find_batch_material(obj, mat_name, "MAIN");
  59. if (batch) {
  60. var bufs_data = batch.bufs_data;
  61. if (bufs_data && bufs_data.pointers) {
  62. return bufs_data.ibo_array;
  63. } else {
  64. m_print.error("Buffer data not found");
  65. return null;
  66. }
  67. } else {
  68. m_print.error("Wrong material:", mat_name);
  69. return null;
  70. }
  71. }
  72. /**
  73. * Update the vertex array for the given object.
  74. * @method module:geometry.update_vertex_array
  75. * @param {Object3D} obj Object 3D
  76. * @param {string} mat_name Material name
  77. * @param {string} attrib_name Attribute name (a_position, a_tbn, a_normal)
  78. * @param {Float32Array} array The new array
  79. */
  80. exports.update_vertex_array = function(obj, mat_name, attrib_name, array) {
  81. if (!m_geom.has_dyn_geom(obj)) {
  82. m_print.error("Wrong object:", obj.name);
  83. return;
  84. }
  85. var types = ["MAIN", "SHADOW", "COLOR_ID"];
  86. for (var i = 0; i < types.length; i++) {
  87. var type = types[i];
  88. var batch = m_batch.find_batch_material(obj, mat_name, type);
  89. if (batch) {
  90. var bufs_data = batch.bufs_data;
  91. if (bufs_data && bufs_data.pointers &&
  92. (attrib_name == "a_normal" && bufs_data.pointers["a_tbn"] ||
  93. bufs_data.pointers[attrib_name]))
  94. m_geom.update_bufs_data_array(bufs_data, attrib_name, 0, array);
  95. }
  96. }
  97. }
  98. /**
  99. * Override geometry for the given object.
  100. * @method module:geometry.override_geometry
  101. * @param {Object3D} obj Object 3D
  102. * @param {string} mat_name Material name
  103. * @param {Uint16Array|Uint32Array} ibo_array Array of triangle indices
  104. * @param {Float32Array} positions_array New vertex positions array
  105. * @param {boolean} smooth_normals Enable normals smoothing
  106. */
  107. exports.override_geometry = function(obj, mat_name, ibo_array,
  108. positions_array, smooth_normals) {
  109. if (!m_geom.has_dyn_geom(obj)) {
  110. m_print.error("Wrong object:", obj.name);
  111. return;
  112. }
  113. if (!(ibo_array instanceof Uint16Array) &&
  114. !(ibo_array instanceof Uint32Array)) {
  115. m_print.error("Wrong ibo_array type");
  116. return;
  117. }
  118. if (!(positions_array instanceof Float32Array)) {
  119. m_print.error("Wrong positions_array type");
  120. return;
  121. }
  122. var types = ["MAIN", "SHADOW", "COLOR_ID"];
  123. for (var i = 0; i < types.length; i++) {
  124. var batch_type = types[i];
  125. var batch = m_batch.find_batch_material(obj, mat_name, batch_type);
  126. if (batch) {
  127. var bufs_data = batch.bufs_data;
  128. if (bufs_data) {
  129. m_geom.update_bufs_data_index_array(bufs_data, batch.draw_mode,
  130. ibo_array);
  131. var lengths = {};
  132. for (var attr in bufs_data.pointers) {
  133. var pointer = bufs_data.pointers[attr];
  134. var len = positions_array.length / 3 * pointer.num_comp;
  135. var type = m_geom.get_vbo_type_by_attr_name(attr);
  136. if (!lengths[type])
  137. lengths[type] = 0;
  138. lengths[type] += len;
  139. }
  140. var vbo_source_data = m_geom.init_vbo_source_data(lengths);
  141. bufs_data.vbo_source_data = vbo_source_data;
  142. var offsets = {}
  143. for (var attr in bufs_data.pointers) {
  144. var pointer = bufs_data.pointers[attr];
  145. var type = m_geom.get_vbo_type_by_attr_name(attr);
  146. if (!offsets[type])
  147. offsets[type] = 0;
  148. switch (attr) {
  149. case "a_position":
  150. m_geom.vbo_source_data_set_attr(bufs_data.vbo_source_data,
  151. "a_position", positions_array, offsets[type]);
  152. pointer.offset = offsets[type];
  153. pointer.length = positions_array.length;
  154. offsets[type] += pointer.length;
  155. break;
  156. case "a_tbn":
  157. var shared_indices;
  158. if (smooth_normals)
  159. shared_indices = m_geom.calc_shared_indices(
  160. ibo_array, positions_array, positions_array);
  161. var normals = m_geom.calc_normals(ibo_array,
  162. positions_array, shared_indices);
  163. pointer.length = positions_array.length / 3 * pointer.num_comp;
  164. var tangents = new Float32Array(pointer.length);
  165. for (var j = 0; j < tangents.length; j +=4) {
  166. tangents[j] = 1;
  167. tangents[j + 3] = 1;
  168. }
  169. var a_tbn = m_tbn.from_norm_tan(normals, tangents);
  170. m_geom.vbo_source_data_set_attr(bufs_data.vbo_source_data,
  171. "a_tbn", a_tbn, offsets[type]);
  172. pointer.offset = offsets[type];
  173. offsets[type] += pointer.length;
  174. break;
  175. default:
  176. pointer.offset = offsets[type];
  177. pointer.length = positions_array.length / 3 * pointer.num_comp;
  178. var constructor = m_geom.get_constructor_by_type(type);
  179. var new_array = new constructor(pointer.length);
  180. m_geom.vbo_source_data_set_attr(bufs_data.vbo_source_data,
  181. attr, new_array, offsets[type]);
  182. offsets[type] += pointer.length;
  183. break;
  184. }
  185. }
  186. m_geom.update_gl_buffers(bufs_data);
  187. m_render.assign_attribute_setters(batch);
  188. // NOTE: process child batches if bufs_data was copied not by link
  189. var child_batch = m_batch.find_batch_material_forked(obj, batch);
  190. if (child_batch && child_batch.bufs_data)
  191. child_batch.bufs_data = bufs_data;
  192. }
  193. }
  194. }
  195. }
  196. /**
  197. * Apply shape key to the object. If the object is supposed to be available for
  198. * selecting (for example, via the {@link module:scenes.pick_object|pick_object}
  199. * method) call the {@link module:objects.update_boundings|update_boundings} method
  200. * after applying a shape key or override object bounding volumes in Blender
  201. * beforehand so that the boundings can contain the object in its largest shape.
  202. * @method module:geometry.set_shape_key_value
  203. * @param {Object3D} obj Object 3D
  204. * @param {string} key_name Shape key name
  205. * @param {number} value Shape key value
  206. * @example var m_geom = require("geometry");
  207. * var m_scenes = require("scenes");
  208. *
  209. * var cube = m_scenes.get_object_by_name("Cube");
  210. * m_geom.set_shape_key_value(cube, "Key 1", 0.5);
  211. */
  212. exports.set_shape_key_value = function(obj, key_name, value) {
  213. if (!m_geom.check_shape_keys(obj)) {
  214. m_print.error("Wrong object:", obj.name);
  215. return;
  216. }
  217. if (!m_geom.has_shape_key(obj, key_name)) {
  218. m_print.error("Wrong key name:", key_name);
  219. return;
  220. }
  221. var float_value = parseFloat(value);
  222. m_geom.apply_shape_key(obj, key_name, float_value);
  223. }
  224. /**
  225. * Check if object has got shape keys.
  226. * @method module:geometry.check_shape_keys
  227. * @param {Object3D} obj Object 3D
  228. * @returns {boolean} Checking result.
  229. */
  230. exports.check_shape_keys = function(obj) {
  231. return m_geom.check_shape_keys(obj);
  232. }
  233. /**
  234. * Return all available shape keys names.
  235. * @method module:geometry.get_shape_keys_names
  236. * @param {Object3D} obj Object 3D
  237. * @returns {string[]} Array of animation names
  238. */
  239. exports.get_shape_keys_names = function(obj) {
  240. if (!m_geom.check_shape_keys(obj)) {
  241. m_print.error("Wrong object:", obj.name);
  242. return [];
  243. }
  244. return m_geom.get_shape_keys_names(obj);
  245. }
  246. /**
  247. * Return shape key current value.
  248. * @method module:geometry.get_shape_key_value
  249. * @param {Object3D} obj Object 3D
  250. * @param {string} key_name Shape key name
  251. * @returns {number} value Shape key value
  252. */
  253. exports.get_shape_key_value = function(obj, key_name) {
  254. if (!m_geom.check_shape_keys(obj)) {
  255. m_print.error("Wrong object:", obj.name);
  256. return 0;
  257. }
  258. if (!m_geom.has_shape_key(obj, key_name)) {
  259. m_print.error("Wrong key name:", key_name);
  260. return 0;
  261. }
  262. return m_geom.get_shape_key_value(obj, key_name);
  263. }
  264. /**
  265. * Draw a line.
  266. * @method module:geometry.draw_line
  267. * @param {Object3D} obj Line object
  268. * @param {Float32Array} positions Line points [X0,Y0,Z0,X1,Y1,Z1...] in the
  269. * local space of the given line object.
  270. * @param {boolean} [is_split=false] True - draw a split line
  271. * (points specified in pairs), false - draw continuous line
  272. * @example
  273. * var m_geom = require("geometry");
  274. * var m_scenes = require("scenes");
  275. *
  276. * var empty = m_scenes.get_object_by_name("Empty");
  277. * var points = new Float32Array([0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0]); // draw a triangle
  278. * m_geom.draw_line(empty, points);
  279. */
  280. exports.draw_line = function(obj, positions, is_split) {
  281. is_split = is_split || false;
  282. if (!(positions instanceof Float32Array)) {
  283. m_print.error("Wrong positions type");
  284. return;
  285. }
  286. var batch = m_batch.get_first_batch(obj);
  287. if (batch) {
  288. m_geom.draw_line(batch, positions, is_split);
  289. m_render.assign_attribute_setters(batch);
  290. }
  291. }
  292. }
  293. var geometry_factory = register("geometry", Geometry);
  294. export default geometry_factory;