手绘与码绘————趣味交互式绘画系统的实现

本文介绍了一个利用向量变化和玫瑰曲线实现的趣味交互式绘画系统,结合Processing编程,创建动态图形。系统包括展览模式和绘画模式,允许用户通过参数调整创造丰富多变的艺术效果。设计思路注重互动性和动态展示,挑战传统绘画的材料和表现形式。代码结构清晰,使用了controlP5库设计GUI,提供不同的形态选择和参数调节。该系统展示了数学美学,适用于教育和娱乐场景。
摘要由CSDN通过智能技术生成

简介

上一篇博文我主要写了用向量来实现笛卡尔之心的形态变化。这一次我们以此为基础,把这种向量变化作为“颜料”来制作一个非常有趣的交互式绘画系统。
另外,这次我还使用了一种新的充满艺术美感的数学图案——玫瑰曲线。这种曲线是如此适合用于图形变换,以至于能创造出我意想不到的艺术效果。
综上,本文将详细介绍这个系统的设计思路、代码结构设计以及从多个角度进行的总结。

设计思路

嗯,多说无益,先看看最终效果图吧!
展览模式
此模式用于欣赏(或者说观察)各种参数对图形变化的影响,这些参数将在代码章节具体介绍。
展览模式
绘画模式
调整各种参数绘制动态画面
拖动绘画
绘画(拖拽)
点击绘画
绘画(点击)
GUI界面
GUI界面
这里是设计思路
一般来讲,绘画有四种要素:材料、作画者、交互方式和作品。
传统的绘画是艺术家使用笔、颜料、画笔等材料,在画布上直接画出图案。
更加宽泛的来讲,只要满足绘画的四要素,创作出可以表达情感的作品,都可以被称之为绘画。比如用延时摄影的技术画“灯影”,在白纸上用裁纸刀“画”线等。

本文的绘画系统即是对“绘画”概念的扩展:
1.在材料上,本系统和传统绘画有很大的不同。传统绘画的颜料是静止的,画完怎么样就是怎么样;本文系统的颜料是向量组成的图形,能够动态周期性变化。
2.在作画者角度上,两者相似。
3.在交互方式上,抽象的来看,鼠标和屏幕,或者数位板和屏幕与传统绘画的画笔与画布没有本质性的不同。打个比方,我用数位板控制机械手在画布上画画和用数位板在屏幕上画画在交互方式上有任何不同吗,这只有“感觉”上的不同。
4.在作品上,传统绘画是静止的,本文的系统是运动的,为的是表现出一种充满活力的动感还有酷炫的变化效果。
总的来讲,就是在材料和展现效果上的对传统绘画进行扩展。

以下是新花样——玫瑰曲线的介绍。
在上一篇博文中我实现了笛卡尔之心的变换,而这一次我找到了另一个有趣的玩意——玫瑰曲线(Rose Curve)。这是一种可以生成类似花瓣样图形的函数。

其极坐标方程如下:
在这里插入图片描述

其参数方程如下:
在这里插入图片描述
k这个参数决定了玫瑰图案的花瓣数:
花瓣数为2k如果k是偶数
花瓣数为k如果k是奇数

以下是不同参数下的玫瑰图案。这张图中的玫瑰曲线是由极坐标方程定义的,参数k=n/d。
仔细看,里面有笛卡尔之心的样子。遗憾的是,在系统中的参数k只能取整数,所以看不到那个熟悉的身影。
在这里插入图片描述

关于玫瑰曲线的资料和图片均来自维基百科。
维基百科——玫瑰曲线介绍

代码

和上次一样,本次的开发平台依然是好用的Processing(3.4版本)。开发语言是java。

封装的类

通过封装核心代码,实现简化代码编写的目的。同时,这种方法也增强了程序的可扩展性和可读性。以下是实现核心功能的两个类:Morph_Color和Morph_Brush
Morph_Color
这个类是用于初始化图形的向量位置的,跟上一次相比新增了一个初始化玫瑰曲线的方法。我已经在上一篇博文中详细介绍了用向量构建图形的原理,这里就不赘述了。

// this class is used to initiative the graph's Vectors
class Morph_Color{
   
  
  // save the vectors of a morph profile
  ArrayList<PVector> morphList;
  
  Morph_Color()
  {
   
    morphList = new ArrayList<PVector>();
  }
  
  // init rect
  void addPolygonVectors(int vectorNum, int pWidth, float part)
  {
   
    // Top of square
    for (int x = -pWidth/2; x < pWidth/2; x += pWidth/(vectorNum/4)) {
   
      morphList.add(new PVector(x, -(int)pWidth*part));
    }
    // Right side
    for (int y = -pWidth/2; y < pWidth/2; y += pWidth/(vectorNum/4)) {
   
      morphList.add(new PVector((int)pWidth*part, y));
    }
    // Bottom
    for (int x = pWidth/2; x > -pWidth/2; x -= pWidth/(vectorNum/4)) {
   
      morphList.add(new PVector(x, (int)pWidth*part));
    }
    // Left side
    for (int y = pWidth/2; y > -pWidth/2; y -= pWidth/(vectorNum/4)) {
   
      morphList.add(new PVector(-(int)pWidth*part, y));
    }
  }
  
  // init heart
  void addHeartVectors(int vectorNum, int r)
  {
   
    float x,y,a;
    float crossOver;
    crossOver = 1.6;
    x=y=0;a=r;
    pushMatrix();
    translate(width/2,height/2);
    int count = 0;
    for(float t = -PI;t < PI;t += 2*PI/vectorNum){
   
      if(count == vectorNum)
      {
   
        break;
      }
      x = a*(crossOver*cos(t)-cos(2*t));
      y = a*(crossOver*sin(t)-sin(2*t));
      morphList.add(new PVector(x,y));
      count++;
    }
   print("heart"+count);
    popMatrix();
  }
  
  // init circle
  void addCircleVectors(int vectorNum, int radius)
  {
   
    float angleSector = 2*PI/vectorNum;
    int count = 0;
    for (float angle = -PI; angle < PI; angle += angleSector) {
   
      if(count == vectorNum)
      {
   
        break;
      }
      PVector v = PVector.fromAngle(angle);
      v.mult(radius);
      morphList.add(v);
      count++;
    }
  }
  
  // init rose curve
  void addRoseCurveVectors(int vectorNum, int a, int k)
  {
   
    float x,y;
    x=y=0;
    pushMatrix();
    translate(width/2,height/2);
    int count = 0;
    for(float t = -PI;t < PI;t += 2*PI/vectorNum){
   
      if(count == vectorNum)
      {
   
        break;
      }
      x = a*sin(k*t)*cos(t);
      y = a*sin(k*t)*sin(t);
      morphList.add(new PVector(x,y));
      count++;
    }
    popMatrix();
  }
  
}

Morph_Brush
这个类是用于实现形态切换的。切换是靠向量的线性插值实现的。原理详见上篇博文,链接在参考文献中。

// this class is used to draw the process of the 
// graph's morph change
class Morph_Brush{
   
  
  // the two state of one graph
  ArrayList<PVector> morphList1;
  ArrayList<PVector> morphList2;
  boolean state = false;
  boolean state2 = true;
  int delayValue = 0;
  ArrayList<PVector> morph = new ArrayList<PVector>();
  
  Morph_Brush(ArrayList<PVector> ml1)
  {
   
    morphList1 = ml1;
    for (int i = 0; i < morphList1.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值