接上

我们趁热打铁,紧接上一回的棋盘格绘制,来挖掘一些不同绘制思路,使用pixel()函数来绘画。这是一个以每个像素点作为对象来绘制的思路,而不是以图形的方式来填充。这就改变了绘画思路。实际上,Processing有这样的现成函数,使用x、y坐标来定义视口内某个像素点的颜色值,即set(x,y),反之获取某个像素点的颜色值get(x,y),你可以进传送门get() set() 看一下官方给的解释。而pixel()是指定图片的像素序列中某个点的颜色值,意味着不能随心所欲能将其颜色改变成你要的,需要通过读取操作loadPixels()和刷新操作updatePixels()才能正确操作。前者将当前的PGraphics一张图的所有像素点对象存入容器pixels[]之中,方可进行操作,后者是将pixels[]容器的数值对当前的PGraphics图像像素作一更新。当然也和屏幕像素密度属性pixelDensity()有关,具体参见pixels()

第一步

因此,我们不妨先在空pde中做些测试。如下:

  1. void setup() {
  2. size(400, 400);
  3. loadPixels();
  4. pixels[0] = color(0);
  5. updatePixels();
  6. }

试着运行,发现并没有报错,说明pixels[]这个数组容器是存在的,而且取到了index索引0的这个pixel变量。有没有问题?有!真有,如果写多了面向对象的程序,就会很敏感的想到问题,那就是这个pixels[]是谁的属性?这者说针对的对象是谁?是在访问哪张图的像素集合?带着疑问,去官网找答案。。。(我是没有见到相关说明,当然不排除自己的疏忽,按道理这是需要给开发者说明白的,有读者细心找到的话告知一声,感激不尽!)并没有找到很理想的说明,但是在Processing开发文档http://processing.github.io/processing-javadocs/core/中我找到了答案。发现PApplet类中有:



之后又查阅了Processing源码。也就是说,Processing帮我们默认创建了一个PGraphics,所有的PApplet类中的诸多绘制方法都在调取内部这个“g”的相应方法进行绘制或是其他操作,然后在draw()函数调用之后将g图像显示在窗口上!上述测试代码应该这样补全:

  1. void setup() {
  2. size(400, 400); //定义的该PApplet对于surface视口大小,
  3. //并且也创建了一个内置PGraphics,命名为g,大小是(width,height),并做了初识化
  4. g.loadPixels();
  5. g.pixels[0] = color(0);
  6. g.updatePixels();
  7. }

如果是DIY的PGraphics,那会是下面的代码形式:

  1. PGraphics mygraphics;
  2. void setup() {
  3. size(400, 400); //定义的该PApplet对于surface视口大小
  4. mygraphics = createGraphics(width,height);//创建graphics,大小为width,height,画布大小
  5. mygraphics.beginDraw(); //这两行实则在做PGraphics的pixels[]等属性的初始化,
  6. mygraphics.endDraw(); //如果不加,下面的pixels就获取不到,会抛空指针异常
  7. mygraphics.loadPixels();
  8. mygraphics.pixels[0] = color(0);
  9. mygraphics.updatePixels();
  10. }

这样的话,大家对PGraphics和其pixels[]应该有新的认识了。

言归正传

回过头,想想究竟如何使用一个像素数组来控制这个画布的图形图像呢,比如pixels[30]和pixels[120],还有pixels[600],到底分别代表画布上哪个像素点的颜色呢?初学者首先要做的当然是找官网,官方的文档是最好的教辅材料https://processing.org/tutorials/pixels/,这个链接是tutorials栏目中对pixels以及image的详细讲解。嗯,这些内容不是针对processing的,而是所有数字图像处理所有软硬件的,值得细细研读。

我们会得出这样的结论,使用pixels[]数组操控画布上的颜色值来绘制图形图像的方法有诸多,有一种方式比较通用和方便,参考文档中的图示:

可转换成代码表示,即:

  1. for (int x = 0; x < width; x++) {
  2. for (int y = 0; y < height; y++) {
  3. int loc = x + y * width; //这是一个公式,以横纵两轴向进行遍历,一位数组带被映射到二维数组中的某个值,即图中的某个像素点,可用loc = x + y *width来表示
  4. pixels[loc] = color(0); //那么loc 这个索引号 代表的是 (x,y) 这一个像素点
  5. }
  6. }

可以总结出规律,可用loc = x + y *width来表示 坐标(x,y)上的点正是pixels[loc]所对应的点,前提是以横纵两轴向坐标点(像素点数量)进行遍历,一位数组带被映射到二维数组中的某个值。有了这个算法,那接下来的工作就能顺利展开。

按照上篇的逻辑,要计算出循环变量的增幅,来控制方块大小,在这个环境中就转变成单位时间端需要运算多少次pixels[] = ?这一语句。因为像素偏移我们不用管了, for循环中x,y变量就已经在偏移。首先确定步长,每轴向多少步长?当然是increW,increH:

  1. increW = width/WCOUNT;
  2. increH = height/HCOUNT;

有了步长限制,pixels[] = ?语句没有定义呢。上文说到有画rect的颜色区分,这里同样道理,也有定义像素点的颜色区分,绘制方式来回切换,即:

  1. int k= 0;
  2. void draw()
  3. {
  4. k ++;
  5. if(k % 2 == 0)
  6. pixels[x + y * width] = color(0);
  7. if(k % 2 != 0)
  8. pixels[x + y * width] = color(255);
  9. }

上文使用k开关变量(切换状态)去做累加,判断其奇偶性来达到切换语句执行的效果,这里沿用。那什么时候是到了切换状态的时间点呢,对,上述的步长就能派上用场,每走increW或increH个步长,就要切换状态,以increH为例,其逻辑用代码表示:

  1. indexH ++ ; //这个东东是什么?又来了个增幅?还是开关变量?其实它才是真正控制步长的变量。
  2. if (indexH % increH == 0)//注意表达式,同样做求余运算,判断是否取到0,如果是,则刚好index加了一个步长
  3. {
  4. indexH = 0; //当到了一个步长,那步长计数要归零,重新计数(其实这里可以省略,因为求余算法可以弥补,但是为了设计算法方便,可以保留)
  5. k ++;
  6. }

因为是套在循环体里的,indexH的创建,就为了让其循环体中循环次数达到increH次数之后执行if()语句,indexH作为计数器!同样,在另外一个for中也得套一层计数,加if(),即:

  1. increW = width/WCOUNT;
  2. increH = height/HCOUNT;
  3. int k = 0;
  4. int indexH = 0;
  5. int indexW = 0;
  6. for (int x = 0; x < width; x ++)
  7. {
  8. for (int y = 0; y < height; y ++)
  9. {
  10. if (k % 2 == 0)
  11. {
  12. pixels[x + y * width] = color(0);
  13. } else
  14. {
  15. pixels[x + y * width] = color(255);
  16. }
  17. ///////第一层逻辑控制,控制纵向绘制时每走步长数换一次K//////////
  18. indexH ++ ;
  19. if (indexH % increH == 0)
  20. {
  21. indexH = 0;
  22. k ++;
  23. }
  24. ///////第一层逻辑控制//////////
  25. }
  26. ///////第二层逻辑控制,控制横向绘制时每走步长数换一次K//////////
  27. indexW ++ ;
  28. if (indexW % increW == 0)
  29. {
  30. indexW = 0;
  31. k ++;
  32. }
  33. ///////第二层逻辑控制//////////
  34. }

这样,两层逻辑控制k的变化走向,才能控制好对于像素点的颜色。完整代码如下:

  1. int increW;
  2. int increH;
  3. int WCOUNT = 10;
  4. int HCOUNT = 10;
  5. void settings() {
  6. size(800, 800);
  7. }
  8. void setup() {
  9. loadPixels();
  10. increW = width/WCOUNT;
  11. increH = height/HCOUNT;
  12. int k = 0;
  13. int indexH = 0;
  14. int indexW = 0;
  15. for (int x = 0; x < width; x ++)
  16. {
  17. for (int y = 0; y < height; y ++)
  18. {
  19. if (k % 2 == 0)
  20. {
  21. pixels[x + y * width] = color(0);
  22. } else
  23. {
  24. pixels[x + y * width] = color(255);
  25. }
  26. indexH ++ ;
  27. if (indexH % increH == 0)
  28. {
  29. indexH = 0;
  30. k ++;
  31. }
  32. }
  33. indexW ++ ;
  34. if (indexW % increW == 0)
  35. {
  36. indexW = 0;
  37. k ++;
  38. }
  39. }
  40. updatePixels();
  41. }
  42. void draw() {
  43. }

言外

做个思考题,如果是用set()直接定义像素点值呢。如果能融会贯通,那这个题目就很好解了,因为例子本身就以像素点的形式在两层for()循环中遍历,因此,直接替换就可,同时对上述代码做些优化,如下:

  1. int increW;
  2. int increH;
  3. int WCOUNT = 10;
  4. int HCOUNT = 10;
  5. void settings() {
  6. size(800, 800);
  7. }
  8. void setup() {
  9. //loadPixels();
  10. increW = width/WCOUNT;
  11. increH = height/HCOUNT;
  12. int k = 0;
  13. int indexH = 0;
  14. int indexW = 0;
  15. for (int x = 0; x < width; x ++)
  16. {
  17. for (int y = 0; y < height; y ++)
  18. {
  19. if (k % 2 == 0)
  20. {
  21. set(x, y, color(0));
  22. } else
  23. {
  24. set(x, y, color(255));
  25. }
  26. indexH ++ ;
  27. if (indexH % increH == 0)
  28. k ++;
  29. }
  30. indexW ++ ;
  31. if (indexW % increH == 0)
  32. k ++;
  33. }
  34. //updatePixels();
  35. }
  36. void draw() {
  37. }

注意,不再使用pixels[],则无需使用loadPixels()updatePixels(),直接定义(x,y)坐标像素点上的颜色值(set()最后一个参数即为color类型数值)。至于性能上的比较,我们回头再谈,这回就结束了,再见!

结果

Processing 网格纹理制作(棋盘格)使用pixel() set()像素点绘制方式的更多相关文章

  1. Processing 网格纹理制作(棋盘格)

    写在前面的话 很久没有写博文了.最近在整理Processing有关文档,看到之前做的一些例子,想着分享在互联网上,当然和以前一样,目前也仅为了给初学者有个学习参考,笔者能力有限.废话不多说,干就完事了 ...

  2. Processing 网格(棋盘格)无限偏移纹理动画

    过火 再度出击!这次我们要玩得更火一点---把静帧变动画.没错,将棋盘格动起来!看一下效果: 这是一个经典的无限偏移动画,在很多2d横版射击游戏中都会采用的技术.如何在Processing中实现,有两 ...

  3. Html5+Css3制作下拉菜单的三种方式

    一.渐变式改变ol的高度 1.外部为ul标签,在每个li里嵌套一个ol列表2.设置外部li左浮动,内部ol标签绝对定位,外部li标签相对定位3.设置ol的高为0,溢出隐藏4.外部li标签:hover ...

  4. 使用D3制作图表(1)--画布绘制

    使用D3绘制图表可以使数据更加直观. 使用D3前要先加载D3库,这里有两种方式,一种是在线加载<script type="text/javascript" src=" ...

  5. java制作二维码的两种方式

    原博:http://www.importnew.com/15028.html Zebra Crossing(ZXing)是一个很棒的,几乎可以在所有平台(Android.JavaSE.iPhone.R ...

  6. Unity Shader 学习之旅

    Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...

  7. OpenGL ES2.0基础入门

    1.OpenGL ES 1.x渲染管线(又称为渲染流水线) (1).基本处理: 基本处理主要是设定3D空间中物体的顶点坐标.顶点对应的颜色.顶点的纹理坐标等属性,并且指定绘制方式. 常见的绘制方式有: ...

  8. 第27章 LTDC/DMA2D—液晶显示

    本章参考资料:<STM32F76xxx参考手册2>.<STM32F7xx规格书>.库帮助文档<STM32F779xx_User_Manual.chm>. 关于开发板 ...

  9. 第27章 LTDC/DMA2D—液晶显示—零死角玩转STM32-F429系列

    第27章     LTDC/DMA2D—液晶显示 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

随机推荐

  1. 第6篇 Scrum 冲刺博客

    1.站立会议 照骗 进度 成员 昨日完成任务 今日计划任务 遇到的困难 钟智锋 重构游戏逻辑代码 改写部分客户端代码,制作单机版 庄诗楷 进行了相关的装饰改进 与其他部分合成完成游戏 合成遇到bug, ...

  2. Json解析方式汇总 excel vba

    一. 这种方式比较复杂,因为office版本的原因,所以要加其它函数 Private Function parseScript(strJson As String) Dim objJson As Ob ...

  3. LR与LR?

    目录 逻辑回归与线性回归 逻辑回归 1.建立目标函数 2. 梯度求解 3. 实现 线性回归 1. 建立目标函数 2. 求解 3. 实现 逻辑回归与交叉熵 逻辑回归与线性回归 逻辑回归 线性回归 目标函 ...

  4. 如何解决 iframe 无法触发 clickOutside

    注:(1)非原创,来自https://blog.csdn.net/weixin_33985679/article/details/89699215.https://zhuanlan.zhihu.com ...

  5. 让这个Java语言的开源商城系统火起来

    Java是一门非常优秀的面向对象编程语言,功能强大且简单易用,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,凭借其简单性.面向对象.分布式.健壮性.安全性.平台独立与可 ...

  6. vue实现pdf文件的在线预览

    我是通过 <iframe> 标签就可以满足我工作的 pdf预览需求 如果<iframe> 无法满足需求 , 可以使用pdf.js这个插件,功能强大. <iframe :s ...

  7. webpack打包初始入门教程

    Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 从图中我们可以看出,Webpack 可以将多种静态资源 js.css ...

  8. 【web系统UI自动化】关于UI自动化的总结

    实施过了web系统的UI自动化,回顾梳理下,想到什么写什么,随时补充. 首先,自动化测试不是手动测试的替代品,是比较好的补充,而且不是占大比重的补充. 70%的测试工作集中在底层接口测试和单元测试,2 ...

  9. C# 发送邮件通知

    web.config <!-- 配置发邮件:邮件访问登录地址--> <add key="HttpsUrl" value="http://localhos ...

  10. 02_套接字编程(socket抽象层)

    1.套接字概述 1.套接概述: 套接是进行网络通信的一种手段(socket) 2.套接字分类:         流式套接字(SOCK_STREAM): 传输层基于tcp协议进行通信         数 ...