mirror of
https://github.com/godotengine/godot.git
synced 2026-01-05 06:11:29 +03:00
Octahedral Normal/Tangent Compression
Implement Octahedral Compression for normal/tangent vectors *Oct32 for uncompressed vectors *Oct16 for compressed vectors Reduces vertex size for each attribute by *Uncompressed: 12 bytes, vec4<float32> -> vec2<unorm16> *Compressed: 2 bytes, vec4<unorm8> -> vec2<unorm8> Binormal sign is encoded in the y coordinate of the encoded tangent Added conversion functions to go from octahedral mapping to cartesian for normal and tangent vectors sprite_3d and soft_body meshes write to their vertex buffer memory directly and need to convert their normals and tangents to the new oct format before writing Created a new mesh flag to specify whether a mesh is using octahedral compression or not Updated documentation to discuss new flag/defaults Created shader flags to specify whether octahedral or cartesian vectors are being used Updated importers to use octahedral representation as the default format for importing meshes Updated ShaderGLES2 to support 64 bit version codes as we hit the limit of the 32-bit integer that was previously used as a bitset to store enabled/disabled flags
This commit is contained in:
@@ -329,6 +329,59 @@ RID VisualServer::get_white_texture() {
|
||||
#define SMALL_VEC2 Vector2(0.00001, 0.00001)
|
||||
#define SMALL_VEC3 Vector3(0.00001, 0.00001, 0.00001)
|
||||
|
||||
// Maps normalized vector to an octohedron projected onto the cartesian plane
|
||||
// Resulting 2D vector in range [-1, 1]
|
||||
// See http://jcgt.org/published/0003/02/01/ for details
|
||||
Vector2 VisualServer::norm_to_oct(const Vector3 v) {
|
||||
const float invL1Norm = (1.0f) / (Math::absf(v.x) + Math::absf(v.y) + Math::absf(v.z));
|
||||
|
||||
Vector2 res;
|
||||
|
||||
if (v.z < 0.0f) {
|
||||
res.x = (1.0f - Math::absf(v.y * invL1Norm)) * SGN(v.x);
|
||||
res.y = (1.0f - Math::absf(v.x * invL1Norm)) * SGN(v.y);
|
||||
} else {
|
||||
res.x = v.x * invL1Norm;
|
||||
res.y = v.y * invL1Norm;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Maps normalized tangent vector to an octahedron projected onto the cartesian plane
|
||||
// Encodes the tangent vector sign in the second componenet of the returned Vector2 for use in shaders
|
||||
// high_precision specifies whether the encoding will be 32 bit (true) or 16 bit (false)
|
||||
// Resulting 2D vector in range [-1, 1]
|
||||
// See http://jcgt.org/published/0003/02/01/ for details
|
||||
Vector2 VisualServer::tangent_to_oct(const Vector3 v, const float sign, const bool high_precision) {
|
||||
float bias = high_precision ? 1.0f / 32767 : 1.0f / 127;
|
||||
Vector2 res = norm_to_oct(v);
|
||||
res.y = res.y * 0.5f + 0.5f;
|
||||
res.y = MAX(res.y, bias) * SGN(sign);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Convert Octohedron-mapped normalized vector back to Cartesian
|
||||
// Assumes normalized format (elements of v within range [-1, 1])
|
||||
Vector3 VisualServer::oct_to_norm(const Vector2 v) {
|
||||
Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
|
||||
float t = MAX(-res.z, 0.0f);
|
||||
res.x += t * -SGN(res.x);
|
||||
res.y += t * -SGN(res.y);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Convert Octohedron-mapped normalized tangent vector back to Cartesian
|
||||
// out_sign provides the direction for the original cartesian tangent
|
||||
// Assumes normalized format (elements of v within range [-1, 1])
|
||||
Vector3 VisualServer::oct_to_tangent(const Vector2 v, float *out_sign) {
|
||||
Vector2 v_decompressed = v;
|
||||
v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
|
||||
Vector3 res = oct_to_norm(v_decompressed);
|
||||
*out_sign = SGN(v[1]);
|
||||
return res;
|
||||
}
|
||||
|
||||
Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t *p_stride, PoolVector<uint8_t> &r_vertex_array, int p_vertex_array_len, PoolVector<uint8_t> &r_index_array, int p_index_array_len, AABB &r_aabb, Vector<AABB> &r_bone_aabb) {
|
||||
PoolVector<uint8_t>::Write vw = r_vertex_array.write();
|
||||
|
||||
@@ -437,22 +490,47 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_
|
||||
|
||||
// setting vertices means regenerating the AABB
|
||||
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
int8_t vector[4] = {
|
||||
(int8_t)CLAMP(src[i].x * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i].y * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i].z * 127, -128, 127),
|
||||
0,
|
||||
};
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
Vector2 res = norm_to_oct(src[i]);
|
||||
int8_t vector[2] = {
|
||||
(int8_t)CLAMP(res.x * 127, -128, 127),
|
||||
(int8_t)CLAMP(res.y * 127, -128, 127),
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 2);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
Vector2 res = norm_to_oct(src[i]);
|
||||
int16_t vector[2] = {
|
||||
(int16_t)CLAMP(res.x * 32767, -32768, 32767),
|
||||
(int16_t)CLAMP(res.y * 32767, -32768, 32767),
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
float vector[3] = { src[i].x, src[i].y, src[i].z };
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 3 * 4);
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
int8_t vector[4] = {
|
||||
(int8_t)CLAMP(src[i].x * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i].y * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i].z * 127, -128, 127),
|
||||
0,
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
float vector[3] = { src[i].x, src[i].y, src[i].z };
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 3 * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,28 +546,57 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_
|
||||
PoolVector<real_t>::Read read = array.read();
|
||||
const real_t *src = read.ptr();
|
||||
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
int8_t xyzw[4] = {
|
||||
(int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
|
||||
};
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
Vector3 source(src[i * 4 + 0], src[i * 4 + 1], src[i * 4 + 2]);
|
||||
Vector2 res = tangent_to_oct(source, src[i * 4 + 3], false);
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4);
|
||||
int8_t vector[2] = {
|
||||
(int8_t)CLAMP(res.x * 127, -128, 127),
|
||||
(int8_t)CLAMP(res.y * 127, -128, 127)
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 2);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
Vector3 source(src[i * 4 + 0], src[i * 4 + 1], src[i * 4 + 2]);
|
||||
Vector2 res = tangent_to_oct(source, src[i * 4 + 3], true);
|
||||
|
||||
int16_t vector[2] = {
|
||||
(int16_t)CLAMP(res.x * 32767, -32768, 32767),
|
||||
(int16_t)CLAMP(res.y * 32767, -32768, 32767)
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], vector, 4);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
float xyzw[4] = {
|
||||
src[i * 4 + 0],
|
||||
src[i * 4 + 1],
|
||||
src[i * 4 + 2],
|
||||
src[i * 4 + 3]
|
||||
};
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
int8_t xyzw[4] = {
|
||||
(int8_t)CLAMP(src[i * 4 + 0] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 1] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 2] * 127, -128, 127),
|
||||
(int8_t)CLAMP(src[i * 4 + 3] * 127, -128, 127)
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4 * 4);
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 0; i < p_vertex_array_len; i++) {
|
||||
float xyzw[4] = {
|
||||
src[i * 4 + 0],
|
||||
src[i * 4 + 1],
|
||||
src[i * 4 + 2],
|
||||
src[i * 4 + 3]
|
||||
};
|
||||
|
||||
memcpy(&vw[p_offsets[ai] + i * p_stride[ai]], xyzw, 4 * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,19 +877,35 @@ uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format,
|
||||
|
||||
} break;
|
||||
case VS::ARRAY_NORMAL: {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case VS::ARRAY_TANGENT: {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
@@ -959,10 +1082,18 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
|
||||
|
||||
} break;
|
||||
case VS::ARRAY_NORMAL: {
|
||||
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
if (p_compress_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
}
|
||||
}
|
||||
offsets[i] = attributes_base_offset + attributes_stride;
|
||||
attributes_stride += elem_size;
|
||||
@@ -970,10 +1101,18 @@ void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_prim
|
||||
} break;
|
||||
|
||||
case VS::ARRAY_TANGENT: {
|
||||
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_compress_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
if (p_compress_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
}
|
||||
}
|
||||
offsets[i] = attributes_base_offset + attributes_stride;
|
||||
attributes_stride += elem_size;
|
||||
@@ -1146,19 +1285,35 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
|
||||
|
||||
} break;
|
||||
case VS::ARRAY_NORMAL: {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case VS::ARRAY_TANGENT: {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint8_t) * 2;
|
||||
} else {
|
||||
elem_size = sizeof(uint16_t) * 2;
|
||||
}
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
elem_size = sizeof(uint32_t);
|
||||
} else {
|
||||
elem_size = sizeof(float) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
@@ -1287,20 +1442,42 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
|
||||
PoolVector<Vector3> arr;
|
||||
arr.resize(p_vertex_len);
|
||||
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
const float multiplier = 1.f / 127.f;
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *n = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
Vector2 enc(n[0] / 127.0f, n[1] / 127.0f);
|
||||
|
||||
w[j] = oct_to_norm(enc);
|
||||
}
|
||||
} else {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int16_t *n = (const int16_t *)&r[j * total_elem_size + offsets[i]];
|
||||
Vector2 enc(n[0] / 32767.0f, n[1] / 32767.0f);
|
||||
|
||||
w[j] = oct_to_norm(enc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
if (p_format & ARRAY_COMPRESS_NORMAL) {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
const float multiplier = 1.f / 127.f;
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
|
||||
w[j] = Vector3(v[0], v[1], v[2]);
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
w[j] = Vector3(float(v[0]) * multiplier, float(v[1]) * multiplier, float(v[2]) * multiplier);
|
||||
}
|
||||
} else {
|
||||
PoolVector<Vector3>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
|
||||
w[j] = Vector3(v[0], v[1], v[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,22 +1488,51 @@ Array VisualServer::_get_array_from_surface(uint32_t p_format, PoolVector<uint8_
|
||||
case VS::ARRAY_TANGENT: {
|
||||
PoolVector<float> arr;
|
||||
arr.resize(p_vertex_len * 4);
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
w[j * 4 + k] = float(v[k] / 127.0);
|
||||
if (p_format & ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *t = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
Vector2 enc(t[0] / 127.0f, t[1] / 127.0f);
|
||||
Vector3 dec = oct_to_tangent(enc, &w[j * 3 + 2]);
|
||||
|
||||
w[j * 3 + 0] = dec.x;
|
||||
w[j * 3 + 1] = dec.y;
|
||||
w[j * 3 + 2] = dec.z;
|
||||
}
|
||||
} else {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int16_t *t = (const int16_t *)&r[j * total_elem_size + offsets[i]];
|
||||
Vector2 enc(t[0] / 32767.0f, t[1] / 32767.0f);
|
||||
Vector3 dec = oct_to_tangent(enc, &w[j * 3 + 2]);
|
||||
|
||||
w[j * 3 + 0] = dec.x;
|
||||
w[j * 3 + 1] = dec.y;
|
||||
w[j * 3 + 2] = dec.z;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
if (p_format & ARRAY_COMPRESS_TANGENT) {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
w[j * 4 + k] = v[k];
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const int8_t *v = (const int8_t *)&r[j * total_elem_size + offsets[i]];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
w[j * 4 + k] = float(v[k] / 127.0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PoolVector<float>::Write w = arr.write();
|
||||
|
||||
for (int j = 0; j < p_vertex_len; j++) {
|
||||
const float *v = (const float *)&r[j * total_elem_size + offsets[i]];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
w[j * 4 + k] = v[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2019,6 +2225,7 @@ void VisualServer::_bind_methods() {
|
||||
BIND_ENUM_CONSTANT(ARRAY_COMPRESS_INDEX);
|
||||
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES);
|
||||
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_16_BIT_BONES);
|
||||
BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION);
|
||||
BIND_ENUM_CONSTANT(ARRAY_COMPRESS_DEFAULT);
|
||||
|
||||
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
|
||||
|
||||
Reference in New Issue
Block a user