I want to improve the quality of the 3d object's material - three.js

First of all, please understand that I am not good at English.
I'm using react three fiber so hard. I uploaded the obj file using OBJLoader.
In this way, image A was rendered. But the quality is very, very bad...
I want to increase the quality like image B
I don't know if I matched the map of the material incorrectly
What should I do??
Thanks for sharing your wisdom
Image A:
Image B:
const canvasRef = useRef(null);
const cameraControls = useRef<CameraControlsType | null>(null);
const [aoMap, map, normalMap, roughnessMap] = useLoader(THREE.TextureLoader, [
`${process.env.PUBLIC_URL}/NT_NO061/Textures/T_NT_NO061_AO.png`,
`${process.env.PUBLIC_URL}/NT_NO061/Textures/T_NT_NO061_D.png`,
`${process.env.PUBLIC_URL}/NT_NO061/Textures/T_NT_NO061_N.png`,
`${process.env.PUBLIC_URL}/NT_NO061/Textures/T_NT_NO061_R.png`
])
const scene = useLoader(OBJLoader, `${process.env.PUBLIC_URL}/NT_NO061/NT_NO061.obj`);
const {nodes, materials} = useGraph(scene);
const object3d = nodes[Object.keys(nodes)[0]];
const material = materials[Object.keys(materials)[0]];
material.aoMap = aoMap;
material.map = map;
material.normalMap = normalMap;
material.displacementMap = roughnessMap;
material.displacementScale = 0.1;
useEffect(() => {
console.log('canvasRef', canvasRef)
}, [canvasRef])
const playVideo = () => {
cameraControls.current?.reset(true);
setTimeout(() => {
cameraControls.current?.rotate(Math.PI, 0, true)
}, 1000)
setTimeout(() => {
cameraControls.current?.rotate(Math.PI, 0, true)
}, 2000)
}
return (
<Wrapper>
<Canvas
ref={canvasRef}
camera={{position: [3, 3, 3]}}
onCreated={state => state.gl.setClearColor('black')}
>
<CameraControls ref={cameraControls} />
<OrbitControls/>
<pointLight
color={'white'}
intensisty={1}
position={[10, 10, 10]}
/>
<mesh
position={[0, -2, 0]}
geometry={object3d.geometry}
material={material}
/>
</Canvas>
<div style={{ position: 'absolute', top: '0' }}>
<button type={'button'} onClick={() => cameraControls.current?.rotate(Math.PI / 4, 0, true)}>
rotate theta 45deg
</button>
<button type={'button'} onClick={() => cameraControls.current?.reset(true)}>
reset
</button>
<button type={'button'} onClick={playVideo}>
play video
</button>
</div>
</Wrapper>
);
}

Let's find the differences between these 2 images first.
Image A:
Image B:
The first difference I see here is that Image B is smooth, while Image A is composed of triangular faces. You can open this up in Blender and apply a Smooth modifier, or just manually increase the vertice count.
The next thing I see is that Image B is shiny, with a mild reflection, while Image A is obsolete. You can use the roughness and metalness properties of three.js to change the way light reflects off of your mesh.
That should do it~

Related

How to make smooth camera transition in react three fiber

Till now I have managed to achieve camera shifting from one place to another but it goes all of a sudden i want a animation or a smooth effect in between current and final camera point
function Rig({ children }) {
const outer = useRef(null)
const inner = useRef(null)
const [pos, setPos] = useState({
x: -12,
y: 20,
z: 34
})
const [type, setType] = useState('initial')
setTimeout(() => {
setType('third')
}, 5000)
useEffect(() => {}, [pos])
useFrame(({ camera, clock }) => {
if (type === 'initial') {
outer.current.position.y = THREE.MathUtils.lerp(outer.current.position.y, 0, 0.05)
inner.current.rotation.y = Math.sin(clock.getElapsedTime() / 8) * Math.PI
inner.current.position.z = 5 + -Math.sin(clock.getElapsedTime() / 2) * 10
inner.current.position.y = -5 + Math.sin(clock.getElapsedTime() / 2) * 2
}
if (type === 'final') {
camera.position.set(0, 20, 34)
}
})
return (
<group position={[0, -100, 0]} ref={outer}>
<group ref={inner}>{children}</group>
</group>
)
}
I read in the documentation this could be achieve through react spring or tween camera but i couldn't implement any of those
I use CameraControls npm i camera-controls, but don't know how to change transition speed
Example https://codesandbox.io/s/react-three-fiber-camera-controls-4jjor?file=/src/App.tsx

Remove perspective warping in react three fiber

I'm trying to make a sphere that follows my cursor. Most of it is done, however, the sphere severely warps on the edges of my screen.
Middle of screen:
Edge of screen:
I have the default camera (fov changed) setup but I feel like it's the wrong one
Canvas:
const Canvas: NextPage<CanvasProps> = ({ children }) => {
const camera = { fov: 60, near: 0.1, far: 1000, position: [0, 0, 5] }
return (
<ThreeCanvas className="bg-gray-900" camera={camera}>
{children}
<Mouse />
</ThreeCanvas>
)
}
Mouse.tsx:
const Mouse: NextPage<MouseProps> = ({}) => {
const [active, setActive] = useState(false)
const { viewport } = useThree()
const { scale } = useSpring({ scale: active ? 0.7 : 1 })
useEffect(() => {
if (active) {
setTimeout(() => setActive(false), 200)
}
}, [active])
const ref = useRef()
useFrame(({ mouse }) => {
const x = (mouse.x * viewport.width) / 2
const y = (mouse.y * viewport.height) / 2
if (typeof ref !== undefined) {
// #ts-ignore
ref!.current.position.set(x, y, 0)
// #ts-ignore
ref!.current.rotation.set(-y, x, 0)
}
})
return (
<>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<animated.mesh scale={scale} onClick={() => setActive(!active)} ref={ref}>
<sphereGeometry args={[0.15, 32, 32]} />
<meshStandardMaterial color="beige" transparent />
</animated.mesh>
</>
)
}

React native state change transitions

What is the best pattern, in react native, to animate components on state change?
For example I have a list of elements and tapping on one I want it to disappear and the ones below him to 'get up' filling the missing space
How can I make the transition smooth?
React-natives own animated API works really well.
Basically you have a value in state, which you connect with a style props, and change that value over time. (for examples follow link)
For smooth animations use usenativedriver (not always possible) and also, make sure you don't have debugger runnning in emulated/real device
EDIT: 2018-05-31
This is an example of how I've used it. Probably exist other ways of doing it
import { Animated, Text} from 'react-native';
class ShowCaseAnimation extends Component {
state = {
animations: {
height: new Animated.Value(0),
fade: new Animated.Value(0),
}
}
componentDidMount() {
const { height, fade } = this.state.animations;
if (this.props.animate) {
doneAnimation({ height, fade }).start(() => {
// Do stuff after animations
});
}
}
render() {
const { animations } = this.state;
return (
<Animated.View
style={{
height: animate? animations.height : 300,
opacity: animate? animations.fade: 1,
// other styling
}}
>
<Text> All your base are belong to us </Text>
</Animated.View>
);
}
}
*doneAnimation: *
import { Animated, Easing } from 'react-native';
export const doneAnimation = ({ height, fade }) => Animated.parallel([
Animated.timing(height, {
toValue: 300,
easing: Easing.elastic(),
duration: 500,
delay: 1500,
}),
Animated.timing(fade, {
toValue: 1,
easing: Easing.ease,
duration: 1000,
delay: 1500,
}),
]);
export default doneAnimation;
doneAnimation will change the state and perform the described animations.
This is how you can trigger an animation on state change in a functional component.
Say you have a Button that changes state with onPress:
<Button title="toggle" onPress={() => setValue(!Value)} />
then you can trigger the animation inside a useEffect with the Value
that changes in the dependency array:
const [Value, setValue] = useState(true);
useEffect(() => {
// Input your animation here
// ...
}, [Value]);

React navigation transition animations with useNativeDriver only run first time

I am using react-navigation Transitioner to create a custom StackNavigator. When using useNativeDriver: true in my transition configuration, the animation for the transition only runs the first time. When set to false, it works as expected.
Note: Whilst setting it to false does fix my problem, I get choppy performance on Android without it, even in production mode.
Below snippet is my navigation view
render() {
return (
<Transitioner
configureTransition={this._configureTransition}
navigation={this.props.navigation}
render={this._render}
/>
);
}
_configureTransition = () => {
return { useNativeDriver: true };
}
_render = (transitionProps) => {
return transitionProps.scenes.map(scene => this._renderScene(transitionProps, scene));
}
_renderScene = (transitionProps, scene) => {
const { layout, position } = transitionProps;
const { index } = scene;
const translateX = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [layout.initWidth, 0, 0],
});
const animationStyle = {
position: 'absolute',
width: '100%',
height: '100%',
backgroundColor: '#FFF',
transform: [{ translateX }],
};
const Scene = this.props.router.getComponentForRouteName(scene.route.routeName);
return (
<Animated.View key={scene.key} style={animationStyle}>
<Scene />
</Animated.View>
);
}
Below is a screen cap of the problem. Note how the first transition is animated, whilst future ones are not (the 'back' navigation should be animated too)

d3 zoom behavior in React Native

In React Native I draw my charts with d3 and ART libraries.
export default class DevTest extends React.Component {
static defaultProps = {
width: 300,
height: 150,
}
mainScaleX = d3Scale.scaleTime()
.domain(d3Array.extent(chartDataTo, data => data.date))
.range([0, this.props.width])
mainScaleY = d3Scale.scaleLinear()
.domain(d3Array.extent(chartDataTo, data => data.value))
.range([this.props.height, 0])
rawChartValue = d3Shape.line()
.x(data => this.mainScaleX(data.date))
.y(data => this.mainScaleY(data.value))
render(){
return (
<View>
<Surface width = {this.props.width} height = {this.props.height}>
<Group x = {0} y = {0}>
<Shape
d = {this.rawChartValue(chartData)}
stroke = "#000"
strokeWidth = {1}
/>
</Group>
</Surface>
</View>
)
}
}
Is there any way to implement d3 svg-like zoom behavior, but without DOM mutation. For example, using some d3 pure functions with just x and y values as input to rescale mainScaleX and mainScaleY?
You can use PanResponder from react-native and zoomIdentity from d3-zoom for that purpose.
Code example looks sometihng like this
componentWillMount() {
this._panResponder = PanResponder.create({
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderMove: (event, { dx, dy }) => {
const zoomIdentity = d3Zoom.zoomIdentity.translate(dx, dy)
this._onDrag(zoomIdentity)
},
});
}
_onDrag(zoomIdentity){
this.setState({
rescaledX: zoomIdentity.rescaleX(this.state.mainScaleX),
rescaledY: zoomIdentity.rescaleY(this.state.mainScaleY)
})
}
And you pass your rescaled{X, Y} to a chart component
render(){
return (
<View {...this._panResponder.panHandlers}>
<Component
{...this.props}
scaleX = {this.state.rescaledX}
scaleY = {this.state.rescaledY}
/>
</View>
)
}

Resources