Processing项目实践——水雾成像(1)
实现
- Box2D物理库的boundary设置轮廓
- Particle System 模拟流体质感
- 群集算法做流体的运动特效
Part One;Box2D物理引擎
关于Box2D物理库
box2D对像素是屏蔽的,在processing中将像素转换为box2D的实体
基本要素
world:Box2D的运行环境。在setup里构建。world是经典的笛卡尔坐标系,角度而这恰好相反,
**body:**相当于p5中的图形,自带location,velocity,accelerate等物理特性,无形状特征。(inner attribution)
shape:几何属性,形状可以自绘制,原理和processing中的beginShape类似,
shape的作用不单单是外表呈现,也是碰撞检测的计算关键
这里一个实践技巧是逆时针将vertex存在数组中。(outside attribution)
**fixture:**固定器,用来将shape适配于相对的body
**joint:**关节,用用来构建body之间的连接关系,常用于骨骼系统的构建(attraction,repel等),其joint方式有三种:
同样的,利用joint的特性,可以拼凑形状, 也可以物理特性(如弹簧,旋转)
**vec2:**相当于PVector,用法一样,个别语法不同,多用于像素世界和物理世界的标定和追踪
1)语法区别:
Vec2 a=new PVector(1,2);
Vec2 b=new PVector(2,3);
//1.static add
a.add(b);
//2.dynamic add
a.addLocal(b); //⚠️
//3 mag==>length
//4 mult==>multLocal
2) coorPixelsToWorld(x,y) 函数来标定坐标
代码框架
import shiffman.box2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
import org.jbox2d.dynamics.joints.*;
import org.jbox2d.dynamics.contacts.*;
// A declaration to box2d world
Box2DProcessing box2d;
// A list we'll use to track fixed objects
ArrayList<Boundary> boundaries;
ArrayList<Box> boxes;//particle basket
void setup() {
....
//创建世界
box2d = new Box2DProcessing(this);
box2d.createWorld();
box2d.setGravity(0, -20);//设置重力库,不设置有默认,-20是重力的映射值垂直向下,因此水平为0,垂直为-;
// Create ArrayLists
boxes = new ArrayList<Box>();
boundaries = new ArrayList<Boundary>();
// Add a bunch of fixed boundaries
boundaries.add(new Boundary(width/4,height-5,width/2-50,10));//
...
}
void draw() {
...
box2d.step();//step is very very important!!
...
}
Implementation
1)不同环境的坐标转换–》World changes!!
格式:What-Who-To-Who
What:coord 坐标
scalar尺寸
Who:Pixels:画图的时候专程pixels坐标,在draw中转
World:在物理仿真的时候转world ,在setup中转
eg:
void setup(){
....
Vec worldloc=box2d.coorPixelsToWorld(mouseX,mouseY);
....
}
在setup中正常创建像素对象和变量,并将位置长度等信息转换为world坐标
在draw中,要将物理坐标再转成像素坐标再去画图
- create an entity in box2D
在Box2D中,entity=body (fixture[+])shape ,其实质是先创建元素,再组合作用
- 每个元素的创建流程是相同的
-
定义whatDef()
-
配置定义体的参数Whatname.attribute.set();
-
设置类型
-
创建 createWhat(),注意创建的时候是Body 对象
-
对象的初始化,可以设置对象的一些基本参数如速度,等objectName.setAttribution();
其中第一部分是对定义体的定义,相当于对家族的定义
第4部分是对具体对象的创建,和各个对象的参数设置,这个机制使得一个家族可以创建多个对象,注意其参数配置的语法区别;
BodyDef bd=new BodyDef();//Def和create是两个声明
bd.type=BodyType.DYNNAMIC;
bd.position.set(center);//center 必须是经过坐标系转换的一个向量
Body body=box2d.createBody(bd);
body.setLinearVelocity(new Vec2(2,3));
Body issues
- 属性的设置包括:
position:position.set
rotation: fixedRotation
damping阻尼:linearDamping/ angularDamping
bullut=true ; //子弹效果适用于快速运动的物体,设置bullet保证物体之间的碰撞检测,而不是直接穿过
-
body类型:
- STATIC:固定的,一般用于设置场景和Boundary
- DYNAMIC:运动和碰撞,用的比较多
- KINEMATIC:适合手动控制的对象,只能碰撞动态物体
-
body属性的获取
-
坐标获取: box2d.getBodyPixelCoord(body);
-
角度的获取:body.getAngel();
一般获取完坐标后我门直接放进matrix里,以body的坐标为中心进行变化
-
pushMatrix();
translate(pos.x,pos.y);
rotate(-a);//角度相反;
...//正常画图
popMatrix();//matrix保证了物体的旋转和运动不冲突
- body的清楚
- box2D.destroyBody(body);
Shape issues
形状的设置和body略有不同
PolygonShape ps=new PolygonShape();//形状类有很多
ps.setAsBox(boxw,boxh);//注意boxw和boxh要通过scalarPixelsToWorld转换
shape class
- PolygonShape,参数为w和h,用setAsBox传
- CircleShape,参数是半径 ,cs.m_radians(box2d.scalearPixelsToWorld®;
- ChainShape,chain可以画曲线
- chain和beginShape类似,可以用vertex数组构造
- chainshape只能画Convex,如果还concave,用convex拼接
chain.createChain(vertexs,vertexs.length);//vertexs是顶点的逆时针存储数组,注意这里的顶点坐标要求是转化过的物理坐标
- 多个图形拼接,要设置偏移量否则都会以body的center为中心,offset的函数是m_p.set(offset.x,offset.y);
fixture issues
- 定义
- 绑定 (形状)
- 属性设置(这里的属性都是针对的物理身体,可以不设置)
- 通过body对象创建固定器(createFixture(ps,1),ps,1是密度值)
FixtureDef fd=new FixtureDef();
fd.shape =ps;// 绑定物理身体
body.createFixture(fd);//body.createFixture(ps,1)
固定器的属性包括:
摩擦系数friction
弹性 restitution
密度 density
joints issues
一般是物体间的运动绑定,绑定的连接点是body的中心,也就是锚点,因此在绑定对象的时候保证在类内创建了body
根据绑定指标,分为三种joints:
-
distance joints:
- frequencyHz (频率设置的范围是1-5,表示震荡频率)
- dampingRatio(阻尼的范围是0-1)
-
revolute joints:
- enablemoter是自动旋转,/boolean
- motorSpeed= float
- setMotorTorque= float
- rjd.enableLimit = true;
- rjd.lowerAngle = -PI/8;
- rjd.upperAngle = PI/8;
最简单的revolute joints 可以联想风车
-
mouse joints
mousejoints比较简单,将转换后的鼠标坐标设置为target即可
MouseJoint.setTarget(box2d.coordPixelsToWorld(mouseX,mouseY));
先定义=》在创建=〉在配置
DistanceJointDef djd = new DistanceJointDef(); //定义
djd.bodyA = p1.body;
djd.bodyB = p2.body; //保证p1和p2这两个实例所对应的对象类内有body构建,.body自动锁定锚点
djd.length = box2d.scalarPixelsToWorld(len); //
djd.frequencyHz = 0;
//创建joints对象
DistanceJoint dj = (DistanceJoint) box2d.world.createJoint(djd); //这里类型转化符号内参数可换,其他类型的Joints操作相同
Joints不一定需要画出来
Conclude all the steps
- Define a body using a BodyDef object (set any properties, such as location). 2. Create the Body object from the body definition.
- Define a Shape object using PolygonShape, CircleShape, or any other shape class.
- Define a fixture using FixtureDef and assign the fixture a shape (set any properties, such as friction, density, and restitution).
- Attach the shape to the body. BodyDef
Box2D和Particle System结合要点
1)在setup中引库和定义
2)在Particle的类的构造函数中进行实体的创建部分
3)类体的display函数转坐标并画图