Skip to content

Commit

Permalink
Xeltalliv/simple3D: fix bugs with transform direction block, model im…
Browse files Browse the repository at this point in the history
…porting, invalid mesh drawing (#1480)

- If `transform direction from to` has to directly use 1 existing matrix
instead of creating a new one, it ends up zero-ing out 13th-15th
(12th-14th) elements of it which are responsible for offset. This block
wasn't meant to have any side-effects on the input data.
[Example](https://turbowarp.org/editor?project_url=https://xeltalliv.github.io/simple3d-extension-examples/projects/manualTransforms/controllerSimple.sb3)
b1af7db
- Mesh without vertex positions is considered valid for drawing and
trying to draw it throws an error.
[Example](https://turbowarp.org/editor?project_url=https://xeltalliv.github.io/simple3d-extension-examples/projects/meshMistakes/mistakeNoPositions.sb3)
a4c328f
- In OBJ importer, material colors do not work, because extension is
looking for `Ka` (ambient) tags instead of `Kd` (diffuse) tags.
[Example](https://turbowarp.org/editor?project_url=https://xeltalliv.github.io/simple3d-extension-examples/projects/import/import4.sb3)
b130924
- In OFF importer, default value for red was missing.
b130924
- In OFF importer, colors are not parsed correctly. They can be provided
as integers 0 to 255 or as floats 0.0 to 1.0, but currently everything
is treated as floats. That is why OFF [example from the
Wikipedia](https://en.wikipedia.org/wiki/OFF_(file_format)#Example)
doesn't work. Can be tested in
[this](https://turbowarp.org/editor?project_url=https://xeltalliv.github.io/simple3d-extension-examples/projects/import/import4.sb3).
8343bd0
- import from file transform is incorrect, because it doesn't copy
values before modifying them, so ends up using already processed values
mid-computation for the remaining ones. In the past I had a reduced copy
of m4 library in the WebWorker, so it worked correctly, but then I
incorrectly simplified it and only tested scaling which still worked
correctly.
[Example](https://turbowarp.org/editor?project_url=https://xeltalliv.github.io/simple3d-extension-examples/projects/import/importTransform.sb3)
d008f02

The example projects weren't made for this PR and are the part of the
new documentation.
  • Loading branch information
Xeltalliv authored May 20, 2024
1 parent 6a18c3e commit 07ba291
Showing 1 changed file with 28 additions and 12 deletions.
40 changes: 28 additions & 12 deletions extensions/Xeltalliv/simple3D.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Description: Make GPU accelerated 3D projects easily.
// By: Vadik1 <https://scratch.mit.edu/users/Vadik1/>
// License: MPL-2.0 AND BSD-3-Clause
// Version: 1.0.1
// Version: 1.0.2

(function (Scratch) {
"use strict";
Expand Down Expand Up @@ -634,6 +634,7 @@
}
checkIfValid() {
if (currentRenderTarget.getMesh() == this) return false;
if (!this.buffers.position) return false;
let length = -1;
let lengthIns = -1;
for (const name in this.buffers) {
Expand Down Expand Up @@ -717,12 +718,12 @@
const workerSrc = `
class OffModelImporter {
constructor(dataRaw) {
const dataStr = dataRaw.map(str => str.replaceAll("\t", " ").trim()).filter(str => str.length && str[0] !== "#");
const dataArr = dataStr.map(str => str.split(" ").filter(e => e).map(e => +e));
const dataStr = dataRaw.map(str => str.split("#")[0].replaceAll("\t", " ").trim()).filter(str => str.length);
const dataArr = dataStr.map(str => str.split(" ").filter(e => e));
let i = 0;
if (dataStr[i] == "OFF") i++;
if (dataStr[i].endsWith("OFF")) i++;
if (dataArr[i].length !== 3) return false;
const [vertexCount, faceCount, edgeCount] = dataArr[i]; i++;
const [vertexCount, faceCount, edgeCount] = dataArr[i].map(n => +n); i++;
const vertices = dataArr.slice(i, i+vertexCount); i += vertexCount;
const faces = dataArr.slice(i, i+faceCount); i += faceCount;
this.vertices = vertices;
Expand All @@ -731,7 +732,8 @@
rgba: []
}
for(const face of faces) {
this.addPoly(face.slice(1, 1+face[0]), face.slice(1+face[0]));
const nVerts = +face[0];
this.addPoly(face.slice(1, 1+nVerts), face.slice(1+nVerts));
}
let hasColor = false;
const rgba = this.output.rgba;
Expand All @@ -744,6 +746,7 @@
if (!hasColor) delete this.output.rgba;
}
addPoly(vs, fallback) {
fallback = fallback.map(this.parseColor);
if (fallback.length == 3) fallback.push(1);
for(let i=2; i<vs.length; i++) {
this.addVertex(vs[ 0], fallback);
Expand All @@ -753,8 +756,14 @@
}
addVertex(idx, fallback) {
const v = this.vertices[idx];
this.output.xyz.push(v[0], v[1], v[2]);
this.output.rgba.push(v[3] ?? fallback[0], v[4] ?? fallback[1] ?? 1, v[5] ?? fallback[2] ?? 1, v[6] ?? fallback[3] ?? 1);
this.output.xyz.push(+v[0], +v[1], +v[2]);
this.output.rgba.push(this.parseColor(v[3]) ?? fallback[0] ?? 1, this.parseColor(v[4]) ?? fallback[1] ?? 1, this.parseColor(v[5]) ?? fallback[2] ?? 1, this.parseColor(v[6]) ?? fallback[3] ?? 1);
}
parseColor(string) {
const number = +string;
if (!Number.isFinite(number)) return undefined;
if (string.indexOf(".") == -1) return number / 255;
return number;
}
}
class ObjModelImporter {
Expand Down Expand Up @@ -789,7 +798,7 @@
materialLast = arr[1];
materials[materialLast] = [1,1,1,1];
}
if (arr[0] == "Ka") {
if (arr[0] == "Kd") {
const color = materials[materialLast];
color[0] = +arr[1];
color[1] = +arr[2];
Expand Down Expand Up @@ -845,9 +854,12 @@
const a = importMatrix;
if (needsScaling) {
for(let i=0; i<xyz.length; i+=3) {
xyz[i ] = xyz[i] * a[0] + xyz[i+1] * a[4] + xyz[i+2] * a[8] + a[12];
xyz[i+1] = xyz[i] * a[1] + xyz[i+1] * a[5] + xyz[i+2] * a[9] + a[13];
xyz[i+2] = xyz[i] * a[2] + xyz[i+1] * a[6] + xyz[i+2] * a[10] + a[14];
const x = xyz[i];
const y = xyz[i+1];
const z = xyz[i+2];
xyz[i ] = x * a[0] + y * a[4] + z * a[8] + a[12];
xyz[i+1] = x * a[1] + y * a[5] + z * a[9] + a[13];
xyz[i+2] = x * a[2] + y * a[6] + z * a[10] + a[14];
}
}
}
Expand Down Expand Up @@ -2642,6 +2654,7 @@ void main() {
if (!mesh) return;
if (!currentRenderTarget.checkIfValid()) return;
if (currentRenderTarget.getMesh() == mesh) return;
if (!mesh.buffers.position) return;

// TODO: only recompute this after one or more buffers were changed
let length = -1;
Expand Down Expand Up @@ -3830,6 +3843,9 @@ void main() {
for (let i = from + 1; i < to; i++) {
totalMat = m4.multiply(lookup2[i], totalMat);
}
if (from + 1 == to) {
totalMat = totalMat.slice();
}
totalMat[12] = totalMat[13] = totalMat[14] = 0;
if (swapped) totalMat = m4.inverse(totalMat);
transformed = m4.multiplyVec(totalMat, vec);
Expand Down

0 comments on commit 07ba291

Please sign in to comment.