Custom Mesh Shapes

自定义网格形状

Use the Mesh class to create custom shapes that go beyond Quad, Box, Cylinder, and Sphere, even procedural shapes are possible. Thank you to KayTrance for providing the sample code!

In this tutorial, we (re)create a very simple rectangular mesh, and we have a look at different ways of coloring it. A flat rectangle may not look useful because it's exactly the same as a com.jme3.scene.shape.Quad. We choose this simple example in order to show you how to build any shape out of triangles – without the distractions of more complex shapes.

使用 Mesh 类来创建自定义形状,他超出了方形 、盒子、圆筒和球体等形状的,甚至来制作程序的形状也是可能的。在这里谢谢提供样品密码的 KayTrance, 谢谢你!

在这个指导中,我们 (关于)创建非常简单的矩形网格,而且我们用不同方法给它涂颜色。因为它完全和 same as a com.jme3.scene.shape.Quad 相同,所以一个平坦的长方形可能没有什么用。我们选择这个简单的例子主要为了要教你该如何从三角形建立任何想要的形状-没有比较复杂形状更有用处。

  • Full code sample: TestCustomMesh.java
  • 完整的代码请看: TestCustomMesh.java

Polygon Meshes 多边形网格

Polygon meshes are made up of triangles. The corners of the triangles are vertices. So, when ever you create a new shape, you break it down into triangles.

多边形网格是由三角形组成的。三角形的角是顶点所以无论何时只要你创建新的形状,你都必须把它们拆散为三角形。

Let's look at a cube. A cube is made up of 6 rectangles. Each rectangle can be broken down into two triangles. This means you need 12 triangles to create a cube mesh. You also need to know the 8 corner coordinates (vertices). The trick is that you have to specify the vertices in a certain order: Each triangle separately, counter-clockwise.

我们先来分析一下立方体,一个立方体由 6 矩形构成,每一个矩形都可以分解为两个三角形。这一就是说你需要 12 个三角形来组成一个立方体网格。这时你就需要 8 个角的坐标(顶点)。所以你不得不按照一定顺序指定顶点。

Sounds worse than it is – here is an example:

实际比这还要糟糕(复杂)请看线面这个例子:

Creating a Quad Mesh 创建一个四边形网格

Okay, we want to create a Quad. A quad has four vertices, and is made up of two triangles.

好下面我们创建一个四边形。一个四边形包含四个顶点,由两个三角组成。

The base class for creating meshes is com.jme3.scene.Mesh.

基础的创建四边形的类是 com.jme3.scene.Mesh 。使用方法如下:

Mesh m = new Mesh();

Vertices 顶点

To define your own shape, determine its vertex positions in space. Store them in an array using com.jme3.math.Vector3f. For a Quad, we need four vertices: Bottom left, bottom right, top left, top right. We name the array vertices[].

确定你自己的形状,确定它所有的顶点在空间中的位置,用 com.jme3.math.Vector3f 这个类型的数组来储存它们。我们需要四个顶点,左下、右下、左上、右上,(这个顺序很重要)我们以 vertices[] 来命名这个数组。

Vector3f [] vertices = new Vector3f[4];

vertices[0] = new Vector3f(0,0,0);

vertices[1] = new Vector3f(3,0,0);

vertices[2] = new Vector3f(0,3,0);

vertices[3] = new Vector3f(3,3,0);

Texture Coordinates 纹理坐标

Next, define the Quad's 2D texture coordinates for each vertex, in the same order: Bottom left, bottom right, top left, top right. We name this array texCoord[]

下面,定义四边形每个顶点的 2D 纹理坐标,用和上面类似的方法:左下、右下、左上、右上。给这个数组起名字叫: texCoord[]

Vector2f[] texCoord = new Vector2f[4];

texCoord[0] = new Vector2f(0,0);

texCoord[1] = new Vector2f(1,0);

texCoord[2] = new Vector2f(0,1);

texCoord[3] = new Vector2f(1,1);

Connecting the Dots 链接这些点

Next we turn the unrelated coordinates into triangles – We define the order in which the mesh is constructed. Think of these indexes as coming in groups of three. Each group of indexes describes one triangle. Note that the vertices are giving counter-clockwise!

下面我们转换这些无关的坐标为一个三角形,我们定义创建哪些三角形的命令。想想这些索引会有三组, 每一个索引组描述一个三角。注意顶点是逆时针旋转的。

int [] indexes = { 2,0,1, 1,3,2 };

  • The 2,0,1 triangle starts at top left, continues bottom left, and ends at bottom right.
  • The 1,3,2 triangle start at bottom right, continues top right, and ends at top left.
  • 索引顺序 2,0,1 起始于左上角,经过左下角,最后在右下角结束。
  • 索引顺序 2,0,1 起始于右下角,经过右上角,在左上角结束。

2\ 2-3

|   \    |         Counter-clockwise 逆时针旋转。

|     \   |

0–1\1

Setting the Mesh Buffer 设置网格缓冲器

The Mesh data is stored in a buffer. 网格数据被存储在一个缓冲器中。

  1. Using com.jme3.util.BufferUtils, we create three buffers for the three types of information we have:

使用 com.jme3.util.BufferUtils ,我们创建三个缓冲器对应我们三种不同类型的信息:

    • vertex positions,
    • texture coordinates,
    • indices.
    • 顶点坐标
    • 纹理坐标
    • 索引顺序
  1. We assign the data to the appropriate type of buffer inside the mesh object. The three buffer types are taken from an enum in com.jme3.scene.VertexBuffer.Type.

在网格对象中我们分配这些数据到合适类型的缓冲器。这三个缓冲器类型来自于枚举类型类 com.jme3.scene.VertexBuffer.Type 。

  1. The third parameter describes the number of components of the values. Vertex postions are 3 float values, texture coordinates are 2 float values, and the indices are single ints.

这三个参数描述组成不同部分的值。顶点坐标是 3 float 值,纹理坐标是 2 float 值,索引是 int 类型。

m.setBuffer(Type.Position , 3, BufferUtils.createFloatBuffer(vertices));

m.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(texCoord));

m.setBuffer(Type.Index,    1, BufferUtils.createIntBuffer(indexes));

Our Mesh is ready! Now we want to see it. 这时网格已经做好了,我们来看看它。

Using the Mesh in a Scene 在场景里使用网格

We create a com.jme3.scene.Geometry, apply a simple color material to it, and attach it to the rootNode to make it appear in the scene.

我们创建一个 com.jme3.scene.Geometry 对象,给它使用一个简单的材质,在把它绑定到 rootNode 节点上让它出现在场景中。

Geometry geom = new Geometry("OurMesh", m);

Material mat = new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

mat.setColor("m_Color", ColorRGBA.Blue);

geom.setMaterial(mat);

rootNode.attachChild(geom);

Ta-daa!

Optional: Vertex Colors 可选的:顶点颜色

Vertex coloring is a simple way of coloring meshes. Instead of just assigning one solid color, each vertex (corner) has a color assigned. The faces between the vertices are then colored with a gradient.

顶点颜色是一个给网格着色简单的方法。代替刚刚的单一颜色,每个顶点都给分配一种不同的颜色。这个面上的颜色就会有从一个顶点到另一个顶点颜色的过渡。

We will use the same mesh m as defined above, but with a special VertexColor material.

我们将使用相同的网格对象 m 但是使用特殊的顶点着色材质。

Geometry coloredMesh = new Geometry ("ColoredMesh", m);

Material matVC = new Material(assetManager, "Common/MatDefs/Misc/VertexColor.j3md");

We create a float array color buffer.

我们创建一个浮点型数组颜色缓冲器。

  • We assign 4 color values, RGBA, to each vertex.

    • To loop over the 4 color values, we use a color index
  • 我们先指定四个颜色值, RGBA, 给每一个顶点。
    • 在四个颜色值构成一个循环,我们使用颜色索引。

int colorIndex = 0;

  • The color buffer contains four color values for each vertex.

    • The Quad in this example has 4 vertices.
  • 颜色索引包含四个颜色值对应每个顶点
    • 四边形有四个顶点。

float[] colorArray = new float[4*4];

  • Tip: If your mesh has a different number of vertices, you would write:
  • 提示:如果你的网格有不同的顶点数,你应该写成:

float[] colorArray = new float[yourVertexCount * 4]

We loop over the colorArray buffer to quickly set some RGBA value for each vertex. As usual, RGBA color values range from 0.0f to 1.0f. The values we use here are quite arbitrary, we are just trying to give every vertex a different RGBA value (a purplish gray, purple, a greenish gray, green, in the screenshot), without writing too much code. For your own mesh, you'd choose the values the color buffer depending on which color you want the mesh to have.

我们循环这个颜色数组缓冲来快速设置 RGBA 的值给每一个顶点通常, RGBA 的值取于 0.0 到 1.0 之间,这里我们随意取几个数值,我们仅仅来给每一个顶点一个不同颜色的实验。(暗紫色、紫色、暗绿色、绿色)这些都没有太多的代码。对于我们的网格,需要选择你像个网格用的颜色值来替换掉颜色缓冲器中的颜色值。

for(int i = 0; i < 4; i++){

// Red value (is increased by .2 on each next vertex here)

colorArray[colorIndex++]= 0.1f+(.2f*i);

// Green value (is reduced by .2 on each next vertex)

colorArray[colorIndex++]= 0.9f-(0.2f*i);

// Blue value (remains the same in our case)

colorArray[colorIndex++]= 0.5f;

// Alpha value (no transparency set here)

colorArray[colorIndex++]= 1.0f;

}

Next, set the color buffer. An RGBA color value contains four float components, thus the parameter 4.

下面设置颜色缓冲器。一个 RGBA 颜色值包含了 4 个部分的值,所以这里参数用四。

m.setBuffer(Type.Color , 4, colorArray);

coloredMesh.setMaterial(matVC);

Now you see a gradient color extending from each vertex.

现在你可以看到渐变颜色从每一个顶点发射出来。

Optional: Point Mode 可选的:点模型

Alternatively, you can show the vertices as colored points instead of coloring the faces.

作为选择,你可以使用着色的点显示顶点,而不像上面一样显示面。

Geometry coloredMesh = new Geometry ("ColoredMesh", cMesh);

...

m.setMode(Mesh.Mode.Points);

m.setPointSize(10f);

m.updateBound();

m.setStatic();

Geometry points = new Geometry("Points", m);

points.setMaterial(mat);

rootNode.attachChild(points);

rootNode.attachChild(coloredMesh);

This will result in a 10 px dot being rendered for each of the four vertices. The dot has the vertex color you specified above. The Quad's faces are not rendered at all. This can be used for a special debugging or editing mode.

这种设置将使用十个像素点来渲染每一个顶点。这些点会精确地显示你指定的颜色。四边形的面不会被渲染,这种方式常被用在专用的测试或者编辑模型中。

Front and Back Faces 前后面

By default, jME3 optimizes a scene by culling all backfaces. It determines which side the front or backface of a mesh is by the order of the vertices. The frontface is the one where the vertices are specified counter-clockwise.

对于默认的情况, JME3 会使用剔除所有的背面的方式来优化场景。这就必须指出模型中哪些面是正面哪些面是反面,这个规定就是有顶点的顺序来得到的。正面是顶点链接顺序为逆时针方向的一面。

This means you mesh, as created above, is invisible when seen from “behind”. This may not be a problem and is often even intended. If you use the custom meshes to form a polyhedron, or flat wallpaper-like object, rendering the backfaces (the inside of the polyhedron) would indeed be a waste of resources.

这就是说刚才创建的网格从后面看是什么也看不到的。这可能不会出问题并且通常都会这么做。如果你使用自定义网格制作一个多面体,或者做一张壁纸,这时去渲染他的背面是很浪费资源的。

In case that your use case requires the backfaces to be visible, you have two options:

有时你需要同时显示正反两面时,你可以使用两种方式

  • If you have a very simple scene, you can just deactivate backface culling for this one mesh's material.
  • 如果你有一个简单的场景,你可以将该材质的剔除背面设置为无效。

mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off));

  • The recommended solution is to specify each triangle twice, the second time with the opposite order of vertices. The second, reversed triangle makes up the backface.
  • 一般的做法是在指定顶点链接索引时,每个三角面都指定两次,第二次指定时和第一次方向相反。正好就是第二次指定颠倒了第一次的顺序。
    int[] indexes = { 2,0,1, 1,3,2, 2,3,1, 1,0,2 };

我的代码

/**

*

* @author zbp

*/

public class MeshTer extends SimpleApplication{

@Override

public void simpleInitApp() {

Mesh m=new Mesh();

Quad qq=new Quad(5,2);

// 顶点坐标

Vector3f[] v=new Vector3f[5];

v[0]= new Vector3f(0,0,0);

v[1]=new Vector3f(0,2,0);

v[2]=new Vector3f(1,2,0);

v[3]=new Vector3f(1,0,0);

v[4]=new Vector3f(2,1,0);

// 纹理坐标

Vector2f[] texCoord=new Vector2f[5];

texCoord[0] = new Vector2f(0,0);

texCoord[1] = new Vector2f(0,1);

texCoord[2] = new Vector2f((float) 0.5,1);

texCoord[3] = new Vector2f((float) 0.5,0);

texCoord[4] = new Vector2f(1,1);

// 连接索引

int index[]={4,3,2,3,0,1,3,1,2};//

//int index[]={0,3,1,1,3,2,2,3,4};// 只按照逆时针方向的规则来连接点,面可以全部显示 , 网格显示时有的边没有闭合

//int index[]={0,1,3,1,3,2,2,3,4};// 第 1 个三角面顺时针转 ,面可以全部显示 , 网格显示时有的边没有闭合

//int index[]={0,3,1, 1,2,3, 3,4,2};// 第 2 个三角面顺时针转,面可以全部显示 , 网格显示时有的边没有闭合

//int index[]={0,3,1, 1,3,2, 2,4,3};// 第 3 个三角面顺时针转,面可以全部显示 , 网格显示时有的边没有闭合

//int index[]={1,3,0, 1,2,3, 2,4,3};// 所有三角面顺时针转,面可以全部显示 , 网格显示时有的边没有闭合

//int index[]={0,3,1,2,1,3,2,3,4};// 下一个三角面起点不是上一个的重点,面可以全部显示 , 网格显示时有的边没有闭合

m.setBuffer(Type.Position,3, BufferUtils.createFloatBuffer(v));

m.setBuffer(Type.TexCoord,2, BufferUtils.createFloatBuffer(texCoord));

m.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(index));

/* 以线框模式显示网格 */

m.setMode(Mesh.Mode.LineLoop);//

m.updateBound();

m.setStatic();

/* 结束 */

Geometry g=new Geometry("myMesha",m);

Material mm=new Material(assetManager, "Common/MatDefs/Misc/SolidColor.j3md");

mm.setColor("m_Color", ColorRGBA.Blue);

g.setMaterial(mm);

this.rootNode.attachChild(g);

}

public static void main(String[] args) {

MeshTer mt=new MeshTer();

mt.start();

}

}

 

通过我的实验,这个 index 是很重要。通过 index 中指定的顺序连接各个点,但是如果用线框模式显示时,就会有不闭合的边,很难看,但是现在还不知道是否影响程序。默认情况下绘制连接线时也是用的是 index 中的这个顺序,唯一不同的是顺序中的第一个点和最后一个点要单独再连接一次。

上图这种情况 031023 这个顺序也行,可能这个说明不太合适,有高手请给予指教。

 

JME3 官方教程翻译 - 自定义网格形状相关推荐

  1. Unity3D Shader官方教程翻译(三)

    Unity3D Shader官方教程翻译(三) 1.Shader语法:Pass 1个Pass块可以使一个几何物体被一次渲染. Pass { [Name and Tags] [RenderSetup] ...

  2. Dapper官方教程翻译8:Dapper方法之QueryMultiple(转)

    Dapper官方教程翻译8:Dapper方法之QueryMultiple 2019年02月28日 10:42:22 Day_and_Night_2017 阅读数:120 QueryMultiple方法 ...

  3. Caffe官方教程翻译(10):Editing model parameters

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  4. 2D Toolkit官方教程翻译

    系统综述 2D Toolkit分为两个系统:运行时组件(runtime components)和脚本编辑器.脚本编辑器在Assets目录下产生资源,运行时脚本在场景中产生objects. 两者关系如下 ...

  5. Caffe官方教程翻译(9):Multilabel Classification with Python Data Layer

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  6. Caffe官方教程翻译(8):Brewing Logistic Regression then Going Deeper

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  7. Caffe官方教程翻译(7):Fine-tuning for Style Recognition

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  8. Caffe官方教程翻译(6):Learning LeNet

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  9. Caffe官方教程翻译(5):Classification: Instant Recognition with Caffe

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

最新文章

  1. 科研与爱情选谁?中科院教授教你平衡!
  2. 每个程序员都必须知道的 8 种数据结构
  3. 卧槽!火爆github!超越YOLOv5,1.3M超轻量,高效易用,这个目标检测开源项目太香了!...
  4. JMeter性能测试,完整入门篇(自己做测试了)
  5. 没有理智的欲望会走向毁灭,没有欲望的理智会永守清贫
  6. Qt5.7 win10环境 调试器未设置问题解决
  7. SQL递归查询知多少
  8. 【教程分享】大数据视频教程
  9. java snap7_Snap7 referance manual PDF 下载
  10. 高等数学(第七版)同济大学 总习题二 个人解答
  11. wowza 技术交流群/ wowza 流媒体软件交流群
  12. uchome登陆机制分析(一)
  13. 2020计算机一级必背知识点,2020高考理综必背知识点
  14. NOI2014起床困难综合症
  15. 最迷你的瑞典大学,如何建立起了影响全球的游戏发展体系
  16. 基于控制主题的对话生成 相关论文总结
  17. 热修复系列之一----Android 热修复原理篇及几大方案比较
  18. win10电脑连接投影仪怎样设置,有相关教程吗
  19. uva 1471 Defense Lines
  20. U盘识别不出来——解决办法

热门文章

  1. 中科大科学岛计算机复试,2020年中国科学技术大学研究生院科学岛分院复试办法及复试内容...
  2. LUR 算法 原理(附带自己实现源码)
  3. Reactor模式:反应器模式
  4. Android 几个ApplicationInfo Info系列类的总结
  5. github监控平台hawkeye搭建
  6. 通过串口给ESP8266发送AT指令连接wifi的注意事项
  7. 【XSY2733】Disembrangle DP
  8. 本质安全设备标准(IEC60079-11)的理解(一)
  9. 黏菌算法(Slime Mould Algorithm,SMA)
  10. 宿舍管理系统的设计与实现/学生宿舍管理系统