本文的范围将涵盖对 Three.js 库和 Animated API 的探索。 您应该具备 JavaScript 和 React Native 的基本知识才能继续学习; 要了解更多关于可以在 React Native 中完成的所有美妙事情, 的React Native 档案是一个很好的学习场所。 LogRocket 博客上

我们将这篇文章一分为二。 在第一部分,我们探索在 React Native 中创建高级 3D 动画。 我们将依赖 Three.js 库,它是一个跨平台 JavaScript 3D 库,用于在 Web 环境中创建 3D 内容,例如图形和动画。 Three.js 结合了 WebGL 增强行为以在 Web 上渲染 3D 模型和 TweenMax 以增强动画质量。

本文的第二部分将探索 Animated API ,它使我们的动画变得流畅。

跳跃前进:

  • 安装和先决条件

  • 如何使用 Three.js 渲染 3D 模型

  • 使用 3D 立方体创建场景

  • 探索动画 API

  • 使用 Animated API 创建 3D 效果

    • 添加背景

安装和先决条件

首先,我们需要创建我们的 React Native 应用程序。 安装 Expo CLI 为我们的项目服务; 它与 Expo GO 库协同工作,这是一个移动客户端应用程序,我们将使用它在 iOS 或 Android 平台上打开我们的项目。

安装 Expo CLI 后,继续在终端中运行以下命令。 此应用程序将使用 TypeScript 模板。

expo init reactNative3D
cd reactNative3D
yarn start

在继续之前,我们需要安装一些核心依赖项。 打开终端窗口,运行以下命令。

yarn add three expo-three expo-gl
yarn add --dev @types/three

让我们回顾一下这些依赖项:

  • expo-gl :这提供了一个 View充当 OpenGL ES 渲染目标,这对于渲染 2D 和 3D 图形非常有用。 挂载后,会创建一个 OpenGL 上下文,该上下文接受 onContextCreate prop,它有一个 WebGL RenderingContext 接口

  • expo-three : 作为 Three.js 和 ExpoGL 之间的桥梁; 它还为 React Native 中的原生 OpenGL-ES 提供了一个 WebGL 接口,这有助于将 DOM 从 Three.js 中抽象出来

  • 三 :用于在网页上创建 3D 内容的 3D 库

如何使用 Three.js 渲染 3D 模型

当使用 Three.js 渲染 3D 模型时,我们首先创建一个场景作为模型渲染的集合。下图说明了 Three.js 应用程序的基本结构,其中需要创建对象并将它们连接起来一起。

来源: Three.js

让我们探索一下上面的图表。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →


  • 关键部分是 renderer, Three.js 的主要对象。 我们创建的 scene和 camera被传递给渲染器,渲染器渲染(绘制)3D场景的一部分

  • 这 scene是一个定义根的对象 scenegraph并包含一些属性,例如背景颜色

  • Mesh是表示特定绘图的对象 Geometry具有特定的 Material班级

  • 一块的顶点数据 Geometry(球体,立方体)由 Geometry目的。 Three.js 提供了内置的几何原语

  • 用于绘制几何图形的表面属性由 Material目的。 它接受诸如 color和 texture

  • Texture对象表示从图像文件加载的图像

在以下部分中,我们将使用这些结构中的每一个来创建 3D 动画。

使用 3D 立方体创建场景

在里面 App.tsx在我们项目目录的根目录下,我们将创建一个基本的 React Native 组件。 将需要的包导入到 App.tsx零件。

code App.tsx
import React from 'react';
import { View } from 'react-native';
import Expo from 'expo';
import {Scene, Mesh, MeshBasicMaterial, PerspectiveCamera} from 'three';
import ExpoTHREE, {Renderer} from 'expo-three';
import { ExpoWebGLRenderingContext, GLView } from 'expo-gl';

继续创建场景, GLView exported from expo-gl provides a view that acts as an OpenGL ES render target. This is very useful for rendering the 3D objects we’re creating.

在里面 App.tsx组件,创建一个功能组件。

const App = () => {const onContextCreate = async (gl: Object) => {}return (<View><GLViewonContextCreate={onContextCreate}/></View>)
}
​
export default App;

我们的应用程序的基本骨架已经完成。 这 onContextCreate道具被传递到 GLView用一个论点, gl,它有一个 WebGL RenderingContext 接口。

转移我们的注意力,让我们创造 onContextCreate功能。

  const onContextCreate = async (gl: any) => {// three.js implementation.const scene = new Scene();const camera = new PerspectiveCamera(75,gl.drawingBufferWidth / gl.drawingBufferHeight,0.1,1000);gl.canvas = {width: gl.drawingBufferWidth,height: gl.drawingBufferHeight,};
​// set camera position away from cubecamera.position.z = 2;
​const renderer = new Renderer({ gl });// set size of buffer to be equal to drawing buffer widthrenderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
​// create cube// define geometryconst geometry = new BoxBufferGeometry(1, 1, 1);const material = new MeshBasicMaterial({color: "cyan",});
​const cube = new Mesh(geometry, material);
​// add cube to scenescene.add(cube);
​// create render functionconst render = () => {requestAnimationFrame(render);// create rotate functionality// rotate around x axiscube.rotation.x += 0.01;
​// rotate around y axiscube.rotation.y += 0.01;
​renderer.render(scene, camera);gl.endFrameEXP();};
​// call renderrender();};

With the completion of the onContextCreate function, our 3D cube is complete.

Your App.tsx file should look like this:

import React from "react";
import { View } from "react-native";
import Expo from "expo";
import {Scene,Mesh,MeshBasicMaterial,PerspectiveCamera,BoxBufferGeometry,
} from "three";
import ExpoTHREE, { Renderer } from "expo-three";
import { ExpoWebGLRenderingContext, GLView } from "expo-gl";
import { StatusBar } from "expo-status-bar";
​
const App = () => {
​const onContextCreate = async (gl: any) => {// three.js implementation.const scene = new Scene();const camera = new PerspectiveCamera(75,gl.drawingBufferWidth / gl.drawingBufferHeight,0.1,1000);gl.canvas = {width: gl.drawingBufferWidth,height: gl.drawingBufferHeight,};
​// set camera position away from cubecamera.position.z = 2;
​const renderer = new Renderer({ gl });// set size of buffer to be equal to drawing buffer widthrenderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);
​// create cube// define geometryconst geometry = new BoxBufferGeometry(1, 1, 1);const material = new MeshBasicMaterial({color: "cyan",});
​const cube = new Mesh(geometry, material);
​// add cube to scenescene.add(cube);
​// create render functionconst render = () => {requestAnimationFrame(render);// create rotate functionality// rotate around x axiscube.rotation.x += 0.01;
​// rotate around y axiscube.rotation.y += 0.01;
​renderer.render(scene, camera);gl.endFrameEXP();};
​// call renderrender();};
​return (<View><GLViewonContextCreate={onContextCreate}// set height and width of GLViewstyle={{ width: 400, height: 400 }}/></View>);
};
​
export default App;

停止 Metro 服务器以确保已添加所有新文件并重新启动它。


来自 LogRocket 的更多精彩文章:

  • 不要错过 The Replay 来自 LogRocket 的精选时事通讯

  • 了解 LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题

  • 使用 React 的 useEffect 优化应用程序的性能

  • 之间切换 在多个 Node 版本

  • 了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画

  • 探索 Tauri ,一个用于构建二进制文件的新框架

  • 比较 NestJS 与 Express.js


ctrl c
yarn start

使用 Expo 应用程序打开应用程序。

我要查题软件,学习查题必备神器,完全免费哪里不会查哪里!

Exploring the Animated API

In this section, we’ll create a 3D carousel using a FlatList and the Animated API. Let’s first create the carousel without the 3D effect.

In the App.tsx, comment out the previous code and start the new implementation from scratch. We begin by installing the dependencies we’ll need in the project.

安装 react-native-uuid 库和 @expo/vector-icons 。

yarn add react-native-uuid @expo/vector-icons

现在,将所需的库导入到组件中。

import * as React from "react";
import {FlatList,Image,Text,View,Dimensions,TouchableOpacity,StyleSheet,Animated,
} from "react-native";
import { SafeAreaView } from "react-native";
import { AntDesign } from "@expo/vector-icons";
import uuid from "react-native-uuid";
import { StatusBar } from "expo-status-bar";
const { width, height } = Dimensions.get("screen");

创建图像轮播时,指定 width和 height轮播中图像的属性可以提供更好的视图。 这 Spacing变量支持跨不同样式需求的可重用性。

const IMAGE_WIDTH = width * 0.65;
const IMAGE_HEIGHT = height * 0.7;
const SPACING = 20;

使用 Pexels Images API ,我们可以生成一组图像来填充我们的应用程序。

const images = ["https://images.pexels.com/photos/1799912/pexels-photo-1799912.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1769524/pexels-photo-1769524.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1758101/pexels-photo-1758101.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1738434/pexels-photo-1738434.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1698394/pexels-photo-1698394.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1684429/pexels-photo-1684429.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1690351/pexels-photo-1690351.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1668211/pexels-photo-1668211.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1647372/pexels-photo-1647372.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1616164/pexels-photo-1616164.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1799901/pexels-photo-1799901.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1789968/pexels-photo-1789968.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1774301/pexels-photo-1774301.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1734364/pexels-photo-1734364.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500","https://images.pexels.com/photos/1724888/pexels-photo-1724888.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
];

我们将使用 react-native-uuid 库 将随机数据播种到应用程序中。

const DATA = [...Array(images.length).keys()].map((_, i) => {return {key: uuid.v4(),image: images[i],};
});

现在是时候实现我们的轮播视图了。

export default () => {return (<View style={{ backgroundColor: "#A5F1FA", flex: 1 }}><StatusBar hidden /><SafeAreaView style={{ marginTop: SPACING * 1 }}><View style={{ height: IMAGE_HEIGHT * 2.1 }}><FlatListdata={DATA}keyExtractor={(item) => item.key}horizontalpagingEnabledbounces={false}style={{ flexGrow: 0, zIndex: 9999 }}contentContainerStyle={{height: IMAGE_HEIGHT + SPACING * 2,paddingHorizontal: SPACING * 4,}}showsHorizontalScrollIndicator={false}renderItem={({ item, index }) => {return (<Viewstyle={{width,paddingVertical: SPACING,}}><Imagesource={{ uri: item.image }}style={{width: IMAGE_WIDTH,height: IMAGE_HEIGHT,resizeMode: "cover",}}/></View>);}}/></View></SafeAreaView></View>);
};

图像轮播已成功创建。

使用 Animated API 创建 3D 效果

下一步是使用 Animated API 创建 3D 效果。 为了使用动画 API,我们需要改变我们的 FlatList对一个 Animated.FlatList并添加一个 onScroll事件,我们将在其中传递一个 NativeEvent.

一个变量 scrollX将被定义为我们的 x 轴的值。 我们将传入一个 useRef()Hook 使 React 能够跟踪动画。 这坚持了 scrollX即使重新渲染后的价值。

export default () => {const scrollX = React.useRef(new Animated.Value(0)).current;return (<View style={{ backgroundColor: "#A5F1FA", flex: 1 }}><StatusBar hidden /><SafeAreaView style={{ marginTop: SPACING * 1 }}><View style={{ height: IMAGE_HEIGHT * 2.1 }}><Animated.FlatListdata={DATA}keyExtractor={(item) => item.key}horizontalpagingEnabledonScroll={Animated.event([{nativeEvent: { contentOffset: { x: scrollX } },},],{useNativeDriver: true,})}

现在我们可以在依赖的同时插入值 scrollX创建动画。 在里面 renderItem我们的 FlatList, 创建一个 inputRange. 我们将使用输入范围数字进行插值。 然后,创建一个 opacity变量内 renderItem.

           renderItem={({ item, index }) => {const inputRange = [(index - 1) * width, // next slideindex * width, // current slide(index + 1) * width, // previous slide];const opacity = scrollX.interpolate({inputRange,outputRange: [0, 1, 0],});const translateY = scrollX.interpolate({inputRange,outputRange: [50, 0, 20] // create a wave})

继续前进,我们已将项目中的视图转换为 Animated.View, 和 opacity我们之前创建的变量将作为样式传入。

             return (<Animated.Viewstyle={{width,paddingVertical: SPACING,opacity,transform: [{ translateY }]}}><Imagesource={{ uri: item.image }}style={{width: IMAGE_WIDTH,height: IMAGE_HEIGHT,resizeMode: "cover",}}/></Animated.View>);

现在在滑动时,根据输入范围应用不透明度。

添加背景

让我们在滑动图像时添加一个白色背景以突出 3D 动画。

在下面 View,粘贴下面的代码块。

 <Viewstyle={{width: IMAGE_WIDTH + SPACING * 4,height: 450,position: "absolute",backgroundColor: "white",backfaceVisibility: true,zIndex: -1,top: SPACING * 1,left: SPACING * 1.7,bottom: 0,shadowColor: "#000",shadowOpacity: 0.2,shadowRadius: 24,shadowOffset: {width: 0,height: 0,},}}/></View>

下一步是为白色背景设置动画,使其在 3D 视图中旋转。 但在我们这样做之前,让我们想办法查看 inputRange之间 0和 1.

在我们的顶部 Carousel组件,使用方法创建一个进度变量 divide()和 modulo()来自 Animated API,它让我们修改并获取之间的值 0和 1. 这 progress变量使我们能够将我们的值限制在 0和 1.

export default () => {const scrollX = React.useRef(new Animated.Value(0)).current;const progress = Animated.modulo(Animated.divide(scrollX, width), width);

我们现在准备开始修改 View持有我们的白色背景的组件。 正如我们之前所做的那样,将 View组件成 Animated.View.

一个 transform输入被传递到 Animated.View零件; 这 transform收到一个 perspective和一个 rotateY.

          <Animated.Viewstyle={{width: IMAGE_WIDTH + SPACING * 4,height: 450,position: "absolute",backgroundColor: "white",backfaceVisibility: true,zIndex: -1,top: SPACING * 1,left: SPACING * 1.7,bottom: 0,shadowColor: "#000",shadowOpacity: 0.2,shadowRadius: 24,shadowOffset: {width: 0,height: 0,},transform: [{perspective: IMAGE_WIDTH * 4,},{rotateY: progress.interpolate({inputRange: [0, 0.5, 1],outputRange: ["0deg", "90deg", "180deg"],}),},],}}/>

这个项目的 repo 可以 在 GitHub 上找到。

结论

在本文中,我们探索了使用 Three.js 在 React Native 中创建 3D 内容。 Three.js 支持在 React Native 环境中渲染 3D 模型。 当与 Animated API 结合使用时,这些工具可以为我们提供额外的灵活性,使我们能够为我们的用户构建更流畅、更有吸引力的视图。 这只是对可以使用 Animated API 执行的惊人动画的一种体验。

希望这篇文章可以作为未来开发人员创建出色用户体验的探索性指南。

LogRocket 主动显示和诊断 React Native 应用程序中最重要的问题

成千上万的工程和产品团队使用 LogRocket 来减少了解其 React Native 应用程序中技术和可用性问题的根本原因所需的时间。 使用 LogRocket,您将减少与客户来回对话的时间,并消除无休止的故障排除过程。 LogRocket 让您可以花更多时间构建新事物,而减少修复错误的时间。

在 React Native 中实现 3D 动画相关推荐

  1. 如何在React Native中创建精美的动画加载器

    by Vikrant Negi 通过Vikrant Negi 如何在React Native中创建精美的动画加载器 (How to create a beautifully animated load ...

  2. 如何在React Native中使用react-navigation 5处理导航

    React-navigation is the navigation library that comes to my mind when we talk about navigation in Re ...

  3. android 倒计时封装,react native中的聊天气泡及timer封装成的发送验证码倒计时

    其实,今天我想把我近期遇到的坑都总结一下: 1.goBack的跨页面跳转,又两种方法,一可以像兔哥那样修改navigation源码,二可以用navigationActions 2.父子组件的传值,一可 ...

  4. 理解 React Native 中的 AJAX 请求

    曾经,大多数 Web 应用程序通过用户操作刷新整个网页以与 Web 服务器通信. 后来,AJAX(异步 JavaScript 和 XML)概念通过提供一种在后台与 Web 服务器通信的方式使 Web ...

  5. React Native每日Apple App动画第二部分:打开图像

    在这篇文章中,我们将继续从当天React Native苹果应用程序的最后一部分继续. 在本教程的第一部分中,我们成功实现了React Native Shared元素过渡并设置了UI部分. 在这里,我们 ...

  6. 我在React Native中构建时获得的经验教训

    by Amanda Bullington 通过阿曼达·布林顿(Amanda Bullington) 我在React Native中构建时获得的经验教训 (Lessons I learned while ...

  7. 如何在React Native中写一个自定义模块

    前言 在 React Native 项目中可以看到 node_modules 文件夹,这是存放 node 模块的地方,Node.js 的包管理器 npm 是全球最大的开源库生态系统.提到npm,一般指 ...

  8. 如何在React Native中记录日志?

    本文翻译自:How to do logging in React Native? 如何为Web开发时在React Native中记录变量,例如使用console.log ? #1楼 参考:https: ...

  9. react native中一次错误排查 Error:Error: Duplicate resources

    最近一直在使用react native中,遇到了很多的坑,同时也学习到了一些移动端的开发经验. 今天在做一个打包的测试时,遇到了一个问题,打包过程中报错"Error:Error: Dupli ...

最新文章

  1. es6学习笔记2-—symbol、变量与作用域
  2. R语言使用caret包的preProcess函数进行数据预处理:对所有的数据列进行YeoJohnson变换(将非正态分布数据列转换为正态分布数据、可以处理负数)、设置参数为YeoJohnson
  3. httpd启动不能加载模块
  4. springBoot静态资源处理
  5. Java——集合(输入5个学生的信息按总分高低排序)
  6. 海量运维、运营规划之道
  7. WebSocket和WebRtc的一些心得
  8. dz论坛非应用商店的插件如何安装教程
  9. 终端上网_家里wifi上网很慢怎么办?通过这4招,让网速快到飞起来
  10. 10bit视频编码——特性及全面播放方法介绍
  11. echart 折线图设置y轴单位_Echarts自定义Y轴
  12. ChatGPT突遭大面积封号!网友应急出解封教程
  13. 以读博为目标的硕士研究生阶段规划(仅供参考)
  14. 【方便的Opencv】实现图片合成视频+附带图片生成gif
  15. 段间转移、长调用、短调用
  16. chatbot聊天机器人技术路线
  17. 量化投资入门指南:风险模型和交易成本模型
  18. 管理者和企业如何做好员工管理?
  19. Semantic Segmentation--SegNet:A Deep Convolutional Encoder-Decoder Architecture..论文解读
  20. Ubuntu 20.04 live server版安装(详细版)

热门文章

  1. UWP部署,DEP0001 : 意外错误: -1988945903
  2. Flink Checkpoint 详解
  3. 【愚公系列】用友系列之YonBuilder低代码平台概论和基本使用
  4. 小觅相机的相机标定全家桶(相机IMU,相机内参,相机外参)
  5. Google 拉起「红色警戒线」,应对 ChatGPT 的巨大威胁!
  6. 怎样通过历史数据预测未来?
  7. 程序员提加薪被领导点名批评,领导:技术不提高就想着加薪?
  8. 电子计算机课文五年级上册,小学五年级上册语文《鲸》课文原文
  9. html怎么在链接中加链接,怎么给div加链接 在div中可以加整体的链接
  10. 华为副总裁徐家骏离职:年薪千万工作感悟十二条