I am using example https://threejs.org/examples/#webgl_materials_standard for my purposes but can't get the code to read both metal and rough maps when using promise (Cerberus_RM metalness is in channel B roughness is in channel G):
Promise.all([
new Promise((resolve, reject) => basisLoader.load(
"Photog_Glace1/Cerberus_A.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load(
"Photog_Glace1/Cerberus_N.basis", resolve, undefined, reject ) ),
**new Promise((resolve, reject) => basisLoader.load(
"Photog_Glace1/Cerberus_RM.basis", resolve, undefined, reject ) ),**
** new Promise((resolve, reject) => basisLoader.load(
"Photog_Glace1/Cerberus_RM.basis", resolve, undefined, reject ) ),**
** ]).then(([albedoM, normalMap, metalMap, roughMap]) => {**
Yields error:
BasisTextureLoader.js:152 Uncaught (in promise) DOMException: Failed to execute 'postMessage' on 'Worker': ArrayBuffer at index 0 is already neutered.
at examples/jsm/loaders/BasisTextureLoader.js:152:13
at new Promise (<anonymous>)
at examples/jsm/loaders/BasisTextureLoader.js:146:12
I tried this code but I only get a full metal textured object without roughness (both roughness and metalness settings=1). Can I please get some guidance how to build this with Promise
Promise.all([
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/Cerberus_A.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/Cerberus_N.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load(Photog_Glace1/Cerberus_RM.basis", resolve, undefined, reject ) ),
]).then(([albedoM, normalMap, metalMap, roughMap]) => {
albedoM.encoding = THREE.sRGBEncoding;
albedoM.wrapS = THREE.RepeatWrapping;
albedoM.wrapT = THREE.RepeatWrapping;
albedoM.repeat.x = 1;
albedoM.repeat.y = 1;
normalMap.wrapS = THREE.RepeatWrapping;
normalMap.wrapT = THREE.RepeatWrapping;
normalMap.repeat.x = 1;
normalMap.repeat.y = 1;
metalMap.wrapS = THREE.RepeatWrapping;
metalMap.wrapT = THREE.RepeatWrapping;
metalMap.repeat.x = 1;
metalMap.repeat.y = 1;
roughMap=metalMap;
vaseMeshMaterial = new THREE.MeshStandardMaterial({
roughnessMap: roughMap,
metalnessMap: metalMap,
map: albedoM,
normalMap: normalMap,
roughness: settings.roughness,
metalness: settings.metalness,
side: THREE.DoubleSide
});
roughMap.wrapS = THREE.RepeatWrapping;
roughMap.wrapT = THREE.RepeatWrapping;
roughMap.repeat.x = 1;
roughMap.repeat.y = 1;
in case three.js forum would become unavailable solution was:
Promise.all([
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/albedo.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/normal.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/cavity.basis", resolve, undefined, reject ) ),
new Promise((resolve, reject) => basisLoader.load( "Photog_Glace1/rough_metal_Map.basis", resolve, undefined, reject ) ),
]).then(([albedoM, normalMap, aoMap, metalRoughMap]) => {
albedoM.encoding = THREE.sRGBEncoding;
vaseMeshMaterial = new THREE.MeshStandardMaterial({
roughnessMap: metalRoughMap,
metalnessMap: metalRoughMap,
map: albedoM,
normalMap: normalMap,
roughness: settings.roughness,
metalness: settings.metalness,
aoMap: aoMap,
aoMapIntensity: 1,
flatShading: false,
side: THREE.DoubleSide
});
console.log("Materials Finished Loading");
myObjectLoader.load( "Photog_Glace1/Glace1_Model.obj", function ( group ) {
var geometry = group.children[ 0 ].geometry;
geometry.attributes.uv2 = geometry.attributes.uv;
geometry.center();
vaseMesh = new THREE.Mesh( geometry, vaseMeshMaterial );
vaseMeshMaterial.normalScale.x = -1;
vaseMesh.castShadow = true;
vaseMesh.receiveShadow = true;
vaseMesh.position.set(28,0,0);
} , onProgress,onError);
});
The problem was basis loader won't read the same file more than once, e.g. metallic in B channel and rough in G channel. I couldn't get the right code using Promise. Thanks to #Mugen87 and #donmccurdy who helped solved the issue, full thread on Three.js forum https://discourse.threejs.org/t/how-part-rough-part-specular/9985/8
Related
The custom implementation below of Promise.race is working correctly when I pass a Promise object to it. However, if I pass Promise.reject it sort of dismisses it and just resolves to the Promise.resolve value.
function race(promises) {
return new Promise((resolve, reject) => {
function resolveCB(value) {
resolve(value);
}
function rejectCB(value) {
reject(value);
}
promises.forEach((p) => {
p.then(resolveCB).catch(rejectCB);
});
});
}
const p1 = Promise.reject(1)
const p2 = Promise.reject(5)
const p3 = Promise.resolve(2)
race([p1, p2, p3]).then(result => console.log(result)).catch(err => console.log(err));
The above code logs 2. I would expect it to log 1.
const p1 = new Promise((resolve, reject) => {
setTimeout(() => reject(1), 1500);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve(6), 1000);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => reject(8), 500);
});
This logs 8 as expected, so the issue is not in the function race it seems but in the misunderstanding of Promise.reject I guess?
If you switch the order of then and catch in your forEach, you can see the results you're expecting. The then takes up the space in the microtask queue even though the Promise rejection and lack of a catch handler means it doesn't actually transform the promise.
promises.forEach((p) => {
// This demonstrates how the results are sensitive to the order, but
// creates the opposite ordering: rejected promises are favored
// over resolved ones.
p.catch(rejectCB).then(resolveCB);
});
function race(promises) {
return new Promise((resolve, reject) => {
function resolveCB(value) {
resolve(value);
}
function rejectCB(value) {
reject(value);
}
promises.forEach((p) => {
p.catch(rejectCB).then(resolveCB);
});
});
}
const p1 = Promise.reject(1)
const p2 = Promise.reject(5)
const p3 = Promise.resolve(2)
race([p1, p2, p3]).then(result => console.log(result)).catch(err => console.log(err));
It'd be better, though, just to use the normal two-arg behavior of then so both of those outcomes happen at the same time:
promises.forEach((p) => {
p.then(resolveCB, rejectCB);
});
function race(promises) {
return new Promise((resolve, reject) => {
function resolveCB(value) {
resolve(value);
}
function rejectCB(value) {
reject(value);
}
promises.forEach((p) => {
p.then(resolveCB, rejectCB);
});
});
}
const p1 = Promise.reject(1)
const p2 = Promise.reject(5)
const p3 = Promise.resolve(2)
race([p1, p2, p3]).then(result => console.log(result)).catch(err => console.log(err));
(Outside of a toy or homework problem, you should be using the built-in race or a common polyfill. FWIW, the core-js polyfill uses the two-arg then.)
When importing a .gltf file into threejs (in expo), I get the following error:
Error: Event {
"isTrusted": false,
}
I am using the GLTFLoader from three(/examples/jsm/loaders/GLTFLoader.js) in an expo react native project with the following code:
loader.load(
"../body.gltf",
(gltf) => {
console.log("Object: ", gltf);
scene.add(gltf.scene);
},
(progress) => console.log("Progress: ", progress),
(err) => console.log("Error: ", err)
);
Is there something in my permissions I am not aware of, is it something in expo or something else?
Loading assets:
useEffect(() => {
(async () => {
const assets = [
Asset.fromModule(require("./assets/abductors.gltf")),
Asset.fromModule(require("./assets/abs.gltf")),
Asset.fromModule(require("./assets/adductors.gltf")),
Asset.fromModule(require("./assets/biceps.gltf")),
Asset.fromModule(require("./assets/bracheoradialis.gltf")),
Asset.fromModule(require("./assets/calves.gltf")),
Asset.fromModule(require("./assets/chest.gltf")),
Asset.fromModule(require("./assets/feet.gltf")),
Asset.fromModule(require("./assets/flexors.gltf")),
Asset.fromModule(require("./assets/forearms.gltf")),
Asset.fromModule(require("./assets/glutes.gltf")),
Asset.fromModule(require("./assets/hamstrings.gltf")),
Asset.fromModule(require("./assets/hands.gltf")),
Asset.fromModule(require("./assets/head.gltf")),
Asset.fromModule(require("./assets/lats.gltf")),
Asset.fromModule(require("./assets/obliques.gltf")),
Asset.fromModule(require("./assets/pelvic.gltf")),
Asset.fromModule(require("./assets/quads.gltf")),
Asset.fromModule(require("./assets/rotators.gltf")),
Asset.fromModule(require("./assets/serratus.gltf")),
Asset.fromModule(require("./assets/shoulders.gltf")),
Asset.fromModule(require("./assets/tibalis.gltf")),
Asset.fromModule(require("./assets/transverse.gltf")),
Asset.fromModule(require("./assets/traps.gltf")),
Asset.fromModule(require("./assets/triceps.gltf"))
];
let body = new THREE.Scene();
for (let i = 0; i < assets.length; i++) {
await assets[i].downloadAsync();
const loader = new GLTFLoader();
loader.load(
assets[i].uri || "",
(gltf) => {
assets[i] = gltf.scene;
body.add(gltf.scene);
},
(xhr) => {
console.log(`${(xhr.loaded / xhr.total) * 100}% loaded`);
},
(error) => {
console.error("An error happened", error);
}
);
}
setBody(body);
})();
}, []);
Showing them:
const _onContextCreate = async (gl) => {
const { drawingBufferWidth: width, drawingBufferHeight: height } = gl;
let renderer = new ExpoTHREE.Renderer({ gl });
renderer.setSize(width, height);
renderer.setClearColor(0xffffff);
let camera = new THREE.PerspectiveCamera(80, width / height, 0.01, 1000);
camera.position.z = 5;
let scene = new THREE.Scene();
const light = new THREE.PointLight(0xffffff, 1, 500);
light.position.set(5, 10, 10);
scene.add(light);
scene.add(body);
body.position.set(0, -2, -5);
body.scale.set(1.2, 1.2, 1.2);
body.rotation.set(0, 0, 0);
[...]
};
return (
<Model
_onContextCreate={_onContextCreate}
body={body}
setActiveMuscles={setActiveMuscles}
onChangeStroke={onChangeStroke}
/>
);
I'm trying to get my websocket code to automatically attempt a reconnect (indefinitely) until successful. By sending a "ping" message every x seconds, I can detect when a pipe is broken, and the closeObserver is called.
However, I'm not sure how to get a reconnect sequence to initiate.
const notificationConnectionEpic: Epic<ActionTypes, any, RootState> = (
action$,
state$
) =>
action$.pipe(
filter(isActionOf(actions.connectNotificationPipeline.request)),
switchMap(async action => {
const resp = await requireValidToken(action$, state$, params =>
AdminHubs.getHubNotificationsToken({
...params,
id: action.payload.hubId
})
);
return resp.pipe(
switchMap(v => {
if (isAction(v)) {
return of(v);
}
if (!v.ok) {
return of(
actions.connectNotificationPipeline.failure({
hubId: action.payload.hubId,
error: v.error
})
);
}
const webSocketOpen$ = new Subject();
const webSocketClose$ = new Subject();
const webSocket$ = webSocket<AdminHubs.HubNotification>({
url: v.value,
openObserver: webSocketOpen$,
closeObserver: webSocketClose$
});
const message$ = webSocket$.pipe(
map(message => actions.receiveNotification({ message })),
takeUntil(action$.ofType(HubActionConsts.NOTIFICATION_PIPE_CLOSED))
);
const ping$ = interval(1000).pipe(
map(_ => webSocket$.next("ping" as any)),
ignoreElements()
);
const open$ = webSocketOpen$.pipe(
take(1),
map(_ =>
actions.connectNotificationPipeline.success({
hubId: action.payload.hubId
})
)
);
const close$ = webSocketClose$.pipe(
// called when a network drop happens. handle reconnect?
); // also happens on net error
return merge(message$, open$, ping$, close$);
})
);
}),
mergeMap(v => v)
);
When the WebSocket connection closes, just dispatch actions.connectNotificationPipeline.request again. That will re-run this code and create a new WebSocket connection.
In this code why subject.onNext(3) is printing first as I set subject.sample(500) but setTimeout(200)?
const Rx = require('rx');
const subject = new Rx.Subject();
const sampleObservable = subject.sample(500);
sampleObservable.subscribe(
data => console.log(data),
error => console.log(error),
() => console.log('FINISHED')
);
subject.onNext(0);
subject.onNext(1);
setTimeout(() => {
subject.onNext(2);
subject.onNext(3);
subject.onCompleted();
}, 200);
I'm trying to build a bit complex workflow in gulp 4, essentially I would like to run 5 tasks one after another every time I run the "default" gulp task (see tasks list below); but I have experienced some bugs, if I run them one by one manually, all works good, but if I run the "default" task, it seems gulp going crazy and didn't end all the tasks, it stop at task 4, but the result has no concat inside, and miss completely the task 5, even if in the bash said "finished". I think the problem is the time execution.
Tasks list:
1. Task 1: pull vendors from "node_modules/vendor folder" into "src/vendors/pending" (I know isn't necessary pull out vendors, but I have my reasons)
2. Task 2: concat and compressing all js inside "src/vendors/pending" and push into "src/vendors/ready"; concat name result: "vendors.min.js"
3. Task 3: compiling and compressing my es6 script and push into "src/requests/pending"; compiling name result: "main.min.js"
4. Task 4: concat "vendors.min.js" and "main.min.js" and push into "src/request/ready" compiling name result: "frontend.min.js"
5. Task 5: create map and push "frontend.min.js" into "assets/js" folder
default task:
gulp.task('default', gulp.series('task1', 'task2', 'task3, 'task4', 'task5' ));
Is there a way to make a task dependent on another and start next task only if the previous task has ended?
I tried wrapping all tasks with a "setTimeout function", and seems to work, but I don't like it very much, I'm looking for something that can run step by step.
Here the gulp file:
var gulp = require( 'gulp' );
const { src, dest, task, watch, series, parallel } = require('gulp');
// JS related plugins
var concat = require( 'gulp-concat' );
var uglify = require( 'gulp-uglify' );
var babelify = require( 'babelify' );
var browserify = require( 'browserify' );
var source = require( 'vinyl-source-stream' );
var buffer = require( 'vinyl-buffer' );
var stripDebug = require( 'gulp-strip-debug' );
// Utility plugins
var rename = require( 'gulp-rename' );
var sourcemaps = require( 'gulp-sourcemaps' );
var notify = require( 'gulp-notify' );
var plumber = require( 'gulp-plumber' );
var options = require( 'gulp-options' );
var gulpif = require( 'gulp-if' );
// Browers related plugins
var browserSync = require( 'browser-sync' ).create();
// js
var jsFront = 'main.js';
var jsFiles = [ jsFront ];
// Tasks
function browser_sync() {
browserSync.init({
server: {
baseDir: './assets/'
}
});
}
function reload(done) {
browserSync.reload();
done();
}
function vendorsFront(done) {
gulp.src([
'./node_modules/jquery/dist/jquery.js',
'./node_modules/animejs/lib/anime.min.js',
])
.pipe(gulp.dest( './src/vendors/pending/frontend' ));
console.log(0);
done();
};
function vendorsFrontReady(done) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
gulp.src([
'./src/vendors/pending/frontend/**/*.js'
])
.pipe(concat('vendors.js'))
.pipe( rename( {
extname: '.min.js'
} ) )
.pipe( uglify() )
.pipe(gulp.dest( './src/vendors/ready/frontend' ));
console.log(1);
done();
}, 1000)
resolve();
});
};
function js(done) {
jsFiles.map( function( entry ) {
return browserify({
entries: ['./src/scripts/' + entry]
})
.transform( babelify, { presets: [ '#babel/preset-env' ] } )
.bundle()
.pipe( source( entry ) )
.pipe( rename( {
extname: '.min.js'
} ) )
.pipe( buffer() )
.pipe( gulpif( options.has( 'production' ), stripDebug() ) )
.pipe( uglify() )
.pipe( dest( './src/requests/pending' ) )
.pipe( browserSync.stream() );
});
console.log(2);
done();
};
function concatVendorScripts(done) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
return gulp.src([ './src/vendors/ready/frontend/**/*.js', './src/requests/pending/main.min.js' ])
.pipe( buffer() )
.pipe(concat('frontend.js'))
.pipe( rename( {
extname: '.min.js'
} ) )
.pipe( gulpif( options.has( 'production' ), stripDebug() ) )
.pipe( dest( './src/requests/ready' ) )
console.log(3);
done();
}, 4000)
resolve();
});
};
function moveJs(done) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
return gulp.src('./src/requests/ready/*')
.pipe(sourcemaps.init({loadMaps: true}))
.pipe( sourcemaps.write( '.' ) )
.pipe(gulp.dest('./assets/js/' ));
console.log(4);
done();
}, 5000)
resolve();
});
};
function triggerPlumber( src_file, dest_file ) {
return src( src_file )
.pipe( plumber() )
.pipe( dest( dest_file ) );
}
task("vendorsFront", vendorsFront);
task("vendorsFrontReady", vendorsFrontReady);
task("concatVendorScripts", concatVendorScripts);
task("moveJs", moveJs);
gulp.task('default', gulp.series('vendorsFront', 'js','vendorsFrontReady', 'concatVendorScripts', 'moveJs'));
you may use Gulp 4 series, please refer below link:
https://fettblog.eu/gulp-4-parallel-and-series/
The best way to achieve this was using Promise, create one task and use promise as below
gulp.task('compile-code', gulp.series(function () {
return Promise.all([
new Promise(function (resolve, reject) {
gulp.src([
'./src/services/*.js',
'./src/directives/directive.js'])
.pipe(concat('bundle.js'))
.on('error', reject)
.pipe(gulp.dest('./'))
.on('end', resolve);
}),
new Promise(function (resolve, reject) {
gulp.src(['./src/assets/css/*.css'])
.pipe(concat('style.css'))
.pipe(gulp.dest('assets/css'))
.on('error', reject)
.pipe(gulp.dest('./'))
.on('end', resolve);
}),
new Promise(function (resolve, reject) {
gulp.src(['./src/assets/img/*'])
.on('error', reject)
.pipe(gulp.dest('assets/img'))
.on('end', resolve);
}),
new Promise(function (resolve, reject) {
gulp.src(['./src/views/*.html'])
.on('error', reject)
.pipe(gulp.dest('views/'))
.on('end', resolve);
}),
new Promise(function (resolve, reject) {
gulp.src(['./src/robots.txt'])
.on('error', reject)
.pipe(gulp.dest('./'))
.on('end', resolve);
})
]).then(function () {
gulp.src('/index.html')
.pipe(browserSync.reload({
stream: true
}))
.pipe(gulp.dest('./'));
});
}));