我正在寻找一种通过在Android上围绕Y轴旋转样条来创建3D对象的方法。结果应该是碗状/玻璃状物体:
http://www.3d-resources.com/cinema_4d_tutorials/realistic_glass_tutorial.html
表单的形状应该是动态的,用户应该能够在应用程序中调整样条曲线的半径和控制点。
基本上我正在寻找实现这一目标的最直接的方法。有人能指出我正确的方向吗? (框架,示例性实施,......)
这种建模技术有一个众所周知的名称吗? (在电影院4d,它被称为"车床nurbs")
-----编辑-----
我的输入是一系列2D控制点(贝塞尔路径)以及旋转轴和样条曲线之间的半径。 我的输出应该是对象的实时3D渲染,通过围绕轴旋转样条来创建。
答案 0 :(得分:1)
有关buzier curve和surface rotation的信息。
您可以从github获取代码 我几年前写过这篇文章,当时我是Java新手,因此代码质量可能有点差......
输出:
主要课程:
贝兹曲线:
package kpi.ua.shapes;
import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;
public class BezierCurve {
private List<Point> allPoints;
public BezierCurve(List<Point> allPoints) {
this.allPoints = allPoints;
}
public Point getValue(double t) {
Point result = new Point();
int i = 0;
Double x=new Double(0);
Double y=new Double(0);
for (Point p : allPoints) {
x+=p.getX() * b(i, allPoints.size()-1, t);
y+=p.getY() * b(i, allPoints.size()-1, t);
i++;
}
result.setX(x);
result.setY(y);
return result;
}
private Double b(int i, int n, double t) {
return fact(n)* Math.pow(t, i) * Math.pow(1 - t, n - i) / (fact(i) * fact(n - i));
}
private int fact(int num) {
return (num == 0) ? 1 : num * fact(num - 1);
}
public void drawCarcass(Graphics2D gr) {
Double[] x=new Double[allPoints.size()];
Double[] y=new Double[allPoints.size()];
int i=0;
for(Point p:allPoints){
x[i]=p.getX();
y[i]=p.getY();
i++;
}
// gr.drawPolygon(x, y, i);
}
public List<Line> getCurve(){
LinkedList<Line> curve=new LinkedList<Line>();
Double t=0.0;
Point prev = getValue(t);
Point next;
while (t <= 1) {
next =getValue(t);
curve.add(new Line(prev,next));
// gr.drawLine(prev.getX(), prev.getY(), next.getX(), next.getY());
prev = next;
t += 0.001;
}
next = getValue(t);
curve.add(new Line(prev,next));
return curve;
//gr.drawLine(prev.getX(), prev.getY(), next.getX(), next.getY());
}
public void drawCurve(Graphics2D gr){
// Double t=0.0;
// Point prev = getValue(t);
// Point next;
// gr.setColor(Color.yellow);
// gr.setStroke(new BasicStroke(2.5f));
// while (t <= 1) {
// next =getValue(t);
// // gr.drawLine(prev.getX(), prev.getY(), next.getX(), next.getY());
// prev = next;
// t += 0.001;
// }
// next = getValue(t);
// gr.drawLine(prev.getX(), prev.getY(), next.getX(), next.getY());
}
}
复合物:
package kpi.ua.shapes;
public class Complex extends Point {
private Double re;
private Double im;
public Complex(Double im, Double re) {
this.im = im;
this.re = re;
Double r = Math.sqrt(im * im + re * re);
Double fi = Math.atan(im / re);
this.x=r * Math.cos(fi);
this.y=r * Math.sin(fi);
}
public Double getRe() {
return re;
}
public void setRe(Double re) {
this.re = re;
}
public Double getIm() {
return im;
}
public void setIm(Double im) {
this.im = im;
}
}
锥形:
package kpi.ua.shapes;
public class Cone {
private Double a;
private Double b;
private Double c;
private Double fi;
public Cone() {
super();
}
public Cone(Double a, Double b, Double c) {
super();
this.a = a;
this.b = b;
this.c = c;
}
public Double getA() {
return a;
}
public void setA(Double a) {
this.a = a;
}
public Double getB() {
return b;
}
public void setB(Double b) {
this.b = b;
}
public Double getC() {
return c;
}
public void setC(Double c) {
this.c = c;
}
public Double getFi() {
return fi;
}
public void setFi(Double fi) {
this.fi = fi;
}
public Point3D getPoint(Double fi,Double r){
Double x=this.a*r*Math.cos(fi);
Double y=this.b*r*Math.sin(fi);
Double z=this.c*r;
return new Point3D(x, y, z);
}
}
ConeSurface:
package kpi.ua.shapes;
import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;
import kpi.ua.util.ControlUtil;
import kpi.ua.util.GraphicUtil;
public class ConeSurface {
private List<Point3D> conePoints;
public List<Point3D> getConePoints() {
return conePoints;
}
public void setConePoints(List<Point3D> conePoints) {
this.conePoints = conePoints;
}
public void calcConePoints(){
Cone cone = new Cone(ControlUtil.CONE_PARAMETR_A, ControlUtil.CONE_PARAMETR_B, ControlUtil.CONE_PARAMETR_C);
Double r = ControlUtil.CONE_START_RADIOUS;
conePoints=new LinkedList<Point3D>();
while (r >= 0) {
for (double fi = 0; fi < 2 * Math.PI; fi += ControlUtil.STEP_BY_FI) {
conePoints.add(cone.getPoint(fi, r));
conePoints.add(cone.getPoint(fi+ControlUtil.STEP_BY_FI, r));
if(r!=0){
conePoints.add(cone.getPoint(fi, r-1));
}
}
r--;
}
}
public void drawCone(Graphics2D gr){
if(conePoints==null)
calcConePoints();
GraphicUtil.drawTriangulation(gr, conePoints);
}
}
行:
package kpi.ua.shapes;
public class Line {
private Point from;
private Point to;
public Line(Point from, Point to) {
super();
this.from = from;
this.to = to;
}
public Point getFrom() {
return from;
}
public void setFrom(Point from) {
this.from = from;
}
public Point getTo() {
return to;
}
public void setTo(Point to) {
this.to = to;
}
}
Line3D:
package kpi.ua.shapes;
public class Line3D {
private Point3D from;
private Point3D to;
public Line3D() {
super();
}
public Line3D(Point3D from, Point3D to) {
super();
this.from = from;
this.to = to;
}
public Point3D getFrom() {
return from;
}
public void setFrom(Point3D from) {
this.from = from;
}
public Point3D getTo() {
return to;
}
public void setTo(Point3D to) {
this.to = to;
}
public Line get2DVision() {
return new Line(from.get2DVision(), to.get2DVision());
}
}
点:
package kpi.ua.shapes;
public class Point {
protected Double x;
protected Double y;
public Point() {
}
public Point(Double x, Double y) {
this.x = x;
this.y = y;
}
public Double getX() {
return x;
}
public void setX(Double x) {
this.x = x;
}
public Double getY() {
return y;
}
public void setY(Double y) {
this.y = y;
}
}
三维点:
package kpi.ua.shapes;
public class Point3D extends Point {
private Double z;
public Point3D(Double x, Double y, Double z) {
super(x, y);
this.z = z;
}
public Double getZ() {
return z;
}
public void setZ(Double z) {
this.z = z;
}
/**Èçîìåòðèÿ
* @return
*/
public Point get2DVision() {
Double cx=(1.0/Math.sqrt(6))*(Math.sqrt(3)*this.x-Math.sqrt(3)*this.z);
Double cy=(1.0/Math.sqrt(6))*(Math.sqrt(2)*this.x-Math.sqrt(2)*this.y+Math.sqrt(2)*this.z);
return new Point(cx, cy);
}
@Override
public String toString() {
return "Point3D [z=" + z + ", x=" + x + ", y=" + y + "]";
}
}
SurfaceBasedOnBuzierCurve:
package kpi.ua.shapes;
import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;
import kpi.ua.util.ControlUtil;
import kpi.ua.util.GraphicUtil;
public class SurfaceBasedOnBuzierCurve {
private final static Double DEFAULT_STEP_BY_T = 0.05;
private final static Double DEFAULT_Q = 1.0;
private final static Double DEFAULT_STEP_BY_FI = 0.15;
private BezierCurve movingCurve;
private List<Point3D> buzierPoints;
public SurfaceBasedOnBuzierCurve() {
refreshBuzierCurve();
}
public List<Point3D> getBuzierPoints() {
return buzierPoints;
}
public void setConePoints(List<Point3D> buzierPoints) {
this.buzierPoints = buzierPoints;
}
public void calcBuzierPoints() {
this.buzierPoints = new LinkedList<Point3D>();
Double q = DEFAULT_Q;
Point movingPoint;
for(double fi=0.0;fi<Math.PI*2;fi+=DEFAULT_STEP_BY_FI){
for(double t=0.0;t<=1.0;t+=DEFAULT_STEP_BY_T){
movingPoint=this.movingCurve.getValue(t);
Point3D firstPoint =getSurfacePoint(movingPoint, movingPoint, q, fi);
if(t+DEFAULT_STEP_BY_T<=1){
movingPoint=this.movingCurve.getValue(t+DEFAULT_STEP_BY_T);
Point3D secondPoint =getSurfacePoint(movingPoint, movingPoint, q, fi);
Point3D thirdPoint=getSurfacePoint(movingPoint, movingPoint, q, fi+DEFAULT_STEP_BY_FI);
buzierPoints.add(firstPoint);
buzierPoints.add(thirdPoint);
buzierPoints.add(secondPoint);
}
}
}
}
/**
* Gets 3DPoint on surface via roating line
*
* @param from
* @param to
* @param q
* @param fi
* @return
*/
public Point3D getSurfacePoint(Point from, Point to, Double q, Double fi) {
Double x = from.getX() + (to.getX() - from.getX()) * q;
Double y = (from.getY() + (to.getY() - from.getY()) * q) * Math.cos(fi);
Double z = (from.getY() + (to.getY() - from.getY()) * q) * Math.sin(fi);
return new Point3D(x, y, z);
}
public void drawBuzierSurface(Graphics2D gr) {
if (buzierPoints == null)
calcBuzierPoints();
GraphicUtil.drawTriangulation(gr, buzierPoints);
}
public void refreshBuzierCurve(){
LinkedList<Point> allPoints = new LinkedList<>();
allPoints.add(new Point(ControlUtil.BUZIER_FIRST_X, ControlUtil.BUZIER_FIRST_Y));
allPoints.add(new Point(ControlUtil.BUZIER_SECOND_X, ControlUtil.BUZIER_SECOND_Y));
allPoints.add(new Point(ControlUtil.BUZIER_THIRD_X, ControlUtil.BUZIER_THIRD_Y));
allPoints.add(new Point(ControlUtil.BUZIER_FOURTH_X, ControlUtil.BUZIER_FOURTH_X));
allPoints.add(new Point(ControlUtil.BUZIER_FIFTH_X, ControlUtil.BUZIER_FIFTH_X));
this.movingCurve = new BezierCurve(allPoints);
}
}
ControlUtil:
package kpi.ua.util;
import kpi.ua.shapes.Point;
import kpi.ua.shapes.Point3D;
public class ControlUtil {
public static Double scaleX=1.0;
public static Double scaleY=1.0;
public static Double scaleZ=1.0;
public static long serialVersionUID = 45L;
public static Double AXIS_LENGTH = 200.0;
public static Point CENTER_AXISES = new Point(300.0, 200.0);
public static Point3D AXIS_X;
public static Point3D AXIS_Y;
public static Point3D AXIS_Z;
public static Double CONE_PARAMETR_A=4.0;
public static Double CONE_PARAMETR_B=6.0;
public static Double CONE_PARAMETR_C=5.0;
public static Double CONE_START_RADIOUS=25.0;
public static Double STEP_BY_FI=0.2;
public static Boolean isDrawCone=false;
// allPoints.add(new Point(30.0, 10.0));
// allPoints.add(new Point(300.0, 210.0));
// allPoints.add(new Point(100.0, 200.0));
// allPoints.add(new Complex((double) 55.0, (double) 251.0));
// allPoints.add(new Complex((double) 155.0, (double) 300.0));
public static Double BUZIER_FIRST_X=30.0;
public static Double BUZIER_FIRST_Y=10.0;
public static Double BUZIER_SECOND_X=-150.0;
public static Double BUZIER_SECOND_Y=110.0;
public static Double BUZIER_THIRD_X=100.0;
public static Double BUZIER_THIRD_Y=200.0;
public static Double BUZIER_FOURTH_X=55.0;
public static Double BUZIER_FOURTH_Y=251.0;
public static Double BUZIER_FIFTH_X=155.0;
public static Double BUZIER_FIFTH_Y=300.0;
static{
AXIS_X=new Point3D(AXIS_LENGTH, 0.0 ,0.0);
AXIS_Y=new Point3D(0.0,AXIS_LENGTH, 0.0);
AXIS_Z=new Point3D(0.0, 0.0, AXIS_LENGTH);
}
}
GraphicUtil:
package kpi.ua.util;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.util.Iterator;
import java.util.List;
import kpi.ua.shapes.Line;
import kpi.ua.shapes.Line3D;
import kpi.ua.shapes.Point3D;
public class GraphicUtil{
public static void drawAxis(Graphics2D gr){
gr.setColor(Color.RED);
drawLine(gr,new Line3D(new Point3D(0.0,0.0,0.0),ControlUtil.AXIS_X));
gr.setColor(Color.WHITE);
gr.drawString("x", ControlUtil.CENTER_AXISES.getX().intValue()+ControlUtil.AXIS_X.get2DVision().getX().intValue()+5,
ControlUtil.CENTER_AXISES.getY().intValue()-ControlUtil.AXIS_X.get2DVision().getY().intValue());
gr.setColor(Color.RED);
drawLine(gr,new Line3D(new Point3D(0.0,0.0,0.0),ControlUtil.AXIS_Y));
gr.setColor(Color.WHITE);
gr.drawString("y", ControlUtil.CENTER_AXISES.getX().intValue()+ControlUtil.AXIS_Y.get2DVision().getX().intValue()+5,
ControlUtil.CENTER_AXISES.getY().intValue()-ControlUtil.AXIS_Y.get2DVision().getY().intValue());
gr.setColor(Color.RED);
drawLine(gr,new Line3D(new Point3D(0.0,0.0,0.0),ControlUtil.AXIS_Z));
gr.setColor(Color.WHITE);
gr.drawString("z", ControlUtil.CENTER_AXISES.getX().intValue()+ControlUtil.AXIS_Z.get2DVision().getX().intValue()+5,
ControlUtil.CENTER_AXISES.getY().intValue()-ControlUtil.AXIS_Z.get2DVision().getY().intValue());
}
public static void moveAroundZ(Double fi,List<Point3D> shape){
Double x;
Double y;
if(shape!=null){
for(Point3D point:shape){
x=point.getX()*Math.cos(fi)+point.getY()*Math.sin(fi);
y=point.getX()*Math.sin(fi)-point.getY()*Math.cos(fi);
point.setX(x);
point.setY(y);
}
}
}
public static void moveAroundX(Double fi,List<Point3D> shape){
Double y;
Double z;
if(shape!=null){
for(Point3D point:shape){
y=-point.getY()*Math.cos(fi)-point.getZ()*Math.sin(fi);
z=-point.getY()*Math.sin(fi)+point.getZ()*Math.cos(fi);
point.setY(y);
point.setZ(z);
}
}
}
public static void moveAroundY(Double fi,List<Point3D> shape){
Double x;
Double z;
if(shape!=null){
for(Point3D point:shape){
x=point.getX()*Math.cos(fi)+point.getZ()*Math.sin(fi);
z=-point.getX()*Math.sin(fi)+point.getZ()*Math.cos(fi);
point.setX(x);
point.setZ(z);
}
}
}
public static void drawLine(Graphics2D gr,Line3D line3D){
line3D.getFrom().setX(ControlUtil.scaleX*line3D.getFrom().getX());
line3D.getFrom().setY(ControlUtil.scaleY*line3D.getFrom().getY());
line3D.getFrom().setZ(ControlUtil.scaleZ*line3D.getFrom().getZ());
line3D.getTo().setX(ControlUtil.scaleX*line3D.getTo().getX());
line3D.getTo().setY(ControlUtil.scaleY*line3D.getTo().getY());
line3D.getTo().setZ(ControlUtil.scaleZ*line3D.getTo().getZ());
Line line=line3D.get2DVision();
gr.drawLine((int)Math.round(ControlUtil.CENTER_AXISES.getX()+line.getFrom().getX()), (int)Math.round(ControlUtil.CENTER_AXISES.getY()-line.getFrom().getY()), (int)Math.round(ControlUtil.CENTER_AXISES.getX()+line.getTo().getX()),(int) Math.round(ControlUtil.CENTER_AXISES.getY()-line.getTo().getY()));
}
public static void drawTriangulation(Graphics2D gr,List<Point3D> shape){
if(shape==null)
return;
Iterator<Point3D> iter=shape.iterator();
Point3D from=null;
Point3D to=null;
while(iter.hasNext()){
from=iter.next();
if(iter.hasNext()){
to=iter.next();
GraphicUtil.drawLine(gr, new Line3D(from,to));
if(iter.hasNext()){
from=iter.next();
GraphicUtil.drawLine(gr, new Line3D(from,to));
}
}
}
}
}