I am currently trying to load a 3D model I made into my react app. The 3D model exported as a folder which had a model.obj and a model.mtl file. After surfing the web for a bit I figured I could use Three-JS for this. My website is currently not displaying anything on the page I have this on.
import React from "react";
import { Canvas } from "#react-three/fiber";
import { ObjectLoader } from "three";
import { useLoader } from "#react-three/fiber";
import { MaterialLoader } from "three";
const ThreeDFloorPlan = () => {
const materials = useLoader(MaterialLoader, "../models/floorplan.mtl")
const object = useLoader(ObjectLoader, "../models/floorplan.obj", loader => {
materials.preload()
loader.setMaterials(materials)
})
return (
<Canvas>
<primitive object={object} />
</Canvas>
)
}
export default ThreeDFloorPlan;
import React from 'react';
import Button from '#mui/material/Button';
import { NavLink } from 'react-router-dom';
import ThreeDFloorPlan from '../components/ThreeDFloorPlan';
const Entry = () => {
return (
<div>
<ThreeDFloorPlan />
</div>
);
};
export default Entry;
Would love some feedback or help on this matter!
I have tried various different ThreeJS walk throughs, scoured the internet, and pulled out a bit of hair.
Related
I am currently building an office 365 add-in on outlook and upon first load the add in is showing an empty html content like so before the whole add in render correctly after couple of seconds
<html>
<head></head>
<body></body>
</html>
First I thought it is from the office.then function shown below and I tried to add a spinner before the .then is called but the loader didn't show, and I couldn't find the reason behind this.
Note that the add-in is developed with react and the following is the index.js page
Also note that the blank page is only showing on outlook for windows installed on a window 10 machine
import "office-ui-fabric-react/dist/css/fabric.min.css";
import App from "./components/App";
import { AppContainer } from "react-hot-loader";
import { initializeIcons } from "#fluentui/react/lib/Icons";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "../../store/store";
import 'react-app-polyfill/ie11';
import Spinner from '#atlaskit/spinner';
/* global AppCpntainer, Component, document, Office, module, React, require */
initializeIcons();
let isOfficeInitialized = false;
const title = "test";
const render = Component => {
ReactDOM.render(
<Provider store={store}>
<AppContainer>
<Component title={title} isOfficeInitialized={isOfficeInitialized} />
</AppContainer>
</Provider>,
document.getElementById("container")
);
};
Office.onReady().then(function () {
isOfficeInitialized = true;
render(App);
});
render(App);
if (module.hot) {
module.hot.accept("./components/App", () => {
const NextApp = require("./components/App").default;
render(NextApp);
});
}
I am using the following Component with Meteor
https://github.com/CaptainN/npdev-react-loadable
import { Loadable } from 'meteor/npdev:react-loadable';
I create my Loadable component as follows
const HomePageBlog = Loadable({
loading: () => <FullPageLoader />,
loader: () => import('./HomePageBlog'),
});
I have gone through the SSR setup in the docs and it looks something like this
Server index.js
import React from 'react';
import { renderToString, renderToNodeStream } from 'react-dom/server';
import { onPageLoad } from 'meteor/server-render';
import { StaticRouter } from 'react-router';
import { Helmet } from 'react-helmet';
import Loadable from 'react-loadable';
import { ServerStyleSheet } from 'styled-components';
import {
LoadableCaptureProvider,
preloadAllLoadables,
} from 'meteor/npdev:react-loadable';
preloadAllLoadables().then(() => {
onPageLoad(async (sink) => {
const context = {};
const sheet = new ServerStyleSheet();
const loadableHandle = {};
const routes = (await import('../both/routes.js')).default;
const App = (props) => (
<StaticRouter location={props.location} context={context}>
{routes}
</StaticRouter>
);
const modules = [];
// const html = renderToNodeStream((
const html = renderToString(
<LoadableCaptureProvider handle={loadableHandle}>
<App location={sink.request.url} />
</LoadableCaptureProvider>,
);
// we have a list of modules here, hopefully Meteor will allow to add them to bundle
// console.log(modules);
sink.renderIntoElementById('app', html);
sink.appendToBody(loadableHandle.toScriptTag());
const helmet = Helmet.renderStatic();
// console.log(helmet);
sink.appendToHead(helmet.meta.toString());
sink.appendToHead(helmet.title.toString());
sink.appendToHead(helmet.link.toString());
sink.appendToHead(sheet.getStyleTags());
});
});
client index.js
import { Meteor } from 'meteor/meteor';
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, withRouter } from 'react-router-dom';
import { onPageLoad } from 'meteor/server-render';
import { createBrowserHistory } from 'history';
import { preloadLoadables } from 'meteor/npdev:react-loadable';
console.log('hi');
const history = createBrowserHistory();
/**
* If browser back button was used, flush cache
* This ensures that user will always see an accurate, up-to-date view based on their state
* https://stackoverflow.com/questions/8788802/prevent-safari-loading-from-cache-when-back-button-is-clicked
*/
(function () {
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
})();
onPageLoad(async () => {
const routes = (await import('../both/routes.js')).default;
const App = () => (
<>
<Router history={history}>
<div>{routes}</div>
</Router>
</>
);
preloadLoadables().then(() => {
ReactDOM.hydrate(<App />, document.getElementById('app'));
});
});
What I am trying to determine is what exactly react loadable does. I am wanting to separate my bundle so I can only load code via SSR when it is needed. Right now I have quite a low score on lighthouse for page speed.
The code that I have here works.
But what I expected to happen was have a separate request to grab more js for the loadable component when it is requested. So it's not in the initial bundle. Is this not how this package works.
Could someone one help me me understand this better.
Thanks for any help ahead of time
I'm trying to render an .obj file into my react project using the OBJLoader and useLoader() hook from React Three Fiber, but I'm unable to do so. My file path is correct and I'm wrapping the Model in Suspense tags, so why is this occurring?
import React, { Suspense } from "react";
import * as THREE from "three";
import { Canvas, useLoader } from "#react-three/fiber";
import { OrbitControls } from "#react-three/drei";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
function Model() {
const model = useLoader(
OBJLoader,
"../assets/Model.obj"
);
return <primitive object={model} scale={0.4} />;
}
function App() {
return (
<div className="App">
<Canvas>
<OrbitControls
enablePan={true}
enableZoom={true}
enableRotate={true}
addEventListener={undefined}
hasEventListener={undefined}
removeEventListener={undefined}
dispatchEvent={undefined}
/>
<Lights />
<Suspense fallback={null}>
<Model />
</Suspense>
</Canvas>
</div>
);
}
export default App;
You have to put your 3D files inside the public folder.
Then your path will be "./Model.obj"
Also you can make make folders inside public folder and put 3D models inside them.
ex- "./folder1/Model.obj" like this
on my freshly installed app i try to import my components like this:
import {Cards , Chart , CountryPicker} from '../components'
and i made an index.js directory:
export {default as Cards} from './Cards/Cards'
export {default as Chart} from './Chart/Chart'
export {default as CountryPicker} from './CountryPicker/CountryPicker'
but it return error :Uncaught SyntaxError: Unexpected token 'export'.
i am doing this trying to copy a tutorial and it looks like it works for the tutor but not me!
This is the basic format for Reactjs.
for more you can Basic example here
//Card
import React from 'react';
const Card = (props) => {
return (
// JSX code
)
}
export default Card;
//Chart
import React from 'react';
const Chart = (props) => {
return (
// JSX code
)
}
export default Chart;
//CountryPicker
import React from 'react';
const CountryPicker = (props) => {
return (
// JSX code
)
}
export default CountryPicker;
//index.JSX
import {Card} from './component/Card';
import {Chart} from './component/Chart';
import {CountryPicker} from './component/CountryPicker';
I think you should first define the components individually and each component should be exported at the bottom of the definition page like so...
import React from "react"
const Cards = () => {
//Helper functions here
return (
//Jsx here
)
}
export default Cards
And then you can now import this component in your App.js component based on the relative path like so...
import Cards from "./components/Cards/Cards";
This is assuming Cards is 2 folders deep from your home directory.
the problem was that i have not put my component folder inside the src folder. hence webpack did nothing about it and it was interpreted as a raw js file which resulted in the error. moving it to the src folder did the trick!
WARNING This is not a copy of three.js OBJLoader not loading in react. react-three-renderer is deprecated and I use functional components here.
I need to load an .obj file but two problems appear. First, it throws TypeError: instance is undefined by react-three-fiber. Second, it loads .obj as HTML: Error: THREE.OBJLoader: Unexpected line: "<!DOCTYPE html>".
Are these issues related to Parcel, THREE or react-three-fiber?
Here's the code that doesn't work:
App.js
import React from 'react'
import { render } from 'react-dom'
import { Canvas } from 'react-three-fiber'
import Model from '/Model'
import Controls from '/Controls'
import '/style.css'
const App = () => {
return (
<main>
<Canvas>
<Model url="demo.obj" />
<Controls />
</Canvas>
</main>
)
}
render(<App />, document.getElementById('app'))
Controls.js
import React, { useRef } from 'react'
import { useThree, useRender, extend } from 'react-three-fiber'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
extend({ OrbitControls })
const Controls = props => {
const { camera } = useThree()
const controls = useRef()
useRender(({ camera }) => {
controls.current && controls.current.update()
camera.updateMatrixWorld()
})
return <orbitControls ref={controls} args={[camera]} {...props} />
}
export default Controls
Model.js
import React, { useRef, useMemo } from 'react'
import { Math as THREEMath } from 'three'
import { useRender } from 'react-three-fiber'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
const Model = ({ url }) => {
const model = useRef()
let rot = 0
const obj = useMemo(() => new OBJLoader().load(url), [url])
useRender(() => {
const rad = 5 * Math.sin(THREEMath.degToRad(rot += 0.3))
model.current.rotation.set(rad, rad, 0)
})
return <primitive object={obj} ref={model} />
}
export default Model
OBJ File here
wrong path. the doctype stuff is the 404 page it pulls. as of r3f 3 you can use the useLoader hook, it makes error handling easier since it's based on react suspense, so you could wrap it into error boundaries and fallbacks.