Processing 网格纹理制作(棋盘格)使用pixel() set()像素点绘制方式
接上
我们趁热打铁,紧接上一回的棋盘格绘制,来挖掘一些不同绘制思路,使用pixel()
函数来绘画。这是一个以每个像素点作为对象来绘制的思路,而不是以图形的方式来填充。这就改变了绘画思路。实际上,Processing有这样的现成函数,使用x、y坐标来定义视口内某个像素点的颜色值,即set(x,y)
,反之获取某个像素点的颜色值get(x,y)
,你可以进传送门get() set() 看一下官方给的解释。而pixel()
是指定图片的像素序列中某个点的颜色值,意味着不能随心所欲能将其颜色改变成你要的,需要通过读取操作loadPixels()
和刷新操作updatePixels()
才能正确操作。前者将当前的PGraphics一张图的所有像素点对象存入容器pixels[]之中,方可进行操作,后者是将pixels[]容器的数值对当前的PGraphics图像像素作一更新。当然也和屏幕像素密度属性pixelDensity()
有关,具体参见pixels()。
第一步
因此,我们不妨先在空pde中做些测试。如下:
void setup() {
size(400, 400);
loadPixels();
pixels[0] = color(0);
updatePixels();
}
试着运行,发现并没有报错,说明pixels[]这个数组容器是存在的,而且取到了index索引0的这个pixel变量。有没有问题?有!真有,如果写多了面向对象的程序,就会很敏感的想到问题,那就是这个pixels[]是谁的属性?这者说针对的对象是谁?是在访问哪张图的像素集合?带着疑问,去官网找答案。。。(我是没有见到相关说明,当然不排除自己的疏忽,按道理这是需要给开发者说明白的,有读者细心找到的话告知一声,感激不尽!)并没有找到很理想的说明,但是在Processing开发文档http://processing.github.io/processing-javadocs/core/中我找到了答案。发现PApplet类中有:
之后又查阅了Processing源码。也就是说,Processing帮我们默认创建了一个PGraphics,所有的PApplet类中的诸多绘制方法都在调取内部这个“g”的相应方法进行绘制或是其他操作,然后在draw()
函数调用之后将g图像显示在窗口上!上述测试代码应该这样补全:
void setup() {
size(400, 400); //定义的该PApplet对于surface视口大小,
//并且也创建了一个内置PGraphics,命名为g,大小是(width,height),并做了初识化
g.loadPixels();
g.pixels[0] = color(0);
g.updatePixels();
}
如果是DIY的PGraphics,那会是下面的代码形式:
PGraphics mygraphics;
void setup() {
size(400, 400); //定义的该PApplet对于surface视口大小
mygraphics = createGraphics(width,height);//创建graphics,大小为width,height,画布大小
mygraphics.beginDraw(); //这两行实则在做PGraphics的pixels[]等属性的初始化,
mygraphics.endDraw(); //如果不加,下面的pixels就获取不到,会抛空指针异常
mygraphics.loadPixels();
mygraphics.pixels[0] = color(0);
mygraphics.updatePixels();
}
这样的话,大家对PGraphics
和其pixels[]
应该有新的认识了。
言归正传
回过头,想想究竟如何使用一个像素数组来控制这个画布的图形图像呢,比如pixels[30]和pixels[120],还有pixels[600],到底分别代表画布上哪个像素点的颜色呢?初学者首先要做的当然是找官网,官方的文档是最好的教辅材料https://processing.org/tutorials/pixels/,这个链接是tutorials栏目中对pixels以及image的详细讲解。嗯,这些内容不是针对processing的,而是所有数字图像处理所有软硬件的,值得细细研读。
我们会得出这样的结论,使用pixels[]数组操控画布上的颜色值来绘制图形图像的方法有诸多,有一种方式比较通用和方便,参考文档中的图示:
可转换成代码表示,即:
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int loc = x + y * width; //这是一个公式,以横纵两轴向进行遍历,一位数组带被映射到二维数组中的某个值,即图中的某个像素点,可用loc = x + y *width来表示
pixels[loc] = color(0); //那么loc 这个索引号 代表的是 (x,y) 这一个像素点
}
}
可以总结出规律,可用loc = x + y *width
来表示 坐标(x,y)
上的点正是pixels[loc]
所对应的点,前提是以横纵两轴向坐标点(像素点数量)进行遍历,一位数组带被映射到二维数组中的某个值。有了这个算法,那接下来的工作就能顺利展开。
按照上篇的逻辑,要计算出循环变量的增幅,来控制方块大小,在这个环境中就转变成单位时间端需要运算多少次pixels[] = ?
这一语句。因为像素偏移我们不用管了, for循环中x,y变量就已经在偏移。首先确定步长,每轴向多少步长?当然是increW,increH:
increW = width/WCOUNT;
increH = height/HCOUNT;
有了步长限制,pixels[] = ?
语句没有定义呢。上文说到有画rect的颜色区分,这里同样道理,也有定义像素点的颜色区分,绘制方式来回切换,即:
int k= 0;
void draw()
{
k ++;
if(k % 2 == 0)
pixels[x + y * width] = color(0);
if(k % 2 != 0)
pixels[x + y * width] = color(255);
}
上文使用k开关变量(切换状态)去做累加,判断其奇偶性来达到切换语句执行的效果,这里沿用。那什么时候是到了切换状态的时间点呢,对,上述的步长就能派上用场,每走increW或increH个步长,就要切换状态,以increH为例,其逻辑用代码表示:
indexH ++ ; //这个东东是什么?又来了个增幅?还是开关变量?其实它才是真正控制步长的变量。
if (indexH % increH == 0)//注意表达式,同样做求余运算,判断是否取到0,如果是,则刚好index加了一个步长
{
indexH = 0; //当到了一个步长,那步长计数要归零,重新计数(其实这里可以省略,因为求余算法可以弥补,但是为了设计算法方便,可以保留)
k ++;
}
因为是套在循环体里的,indexH的创建,就为了让其循环体中循环次数达到increH次数之后执行if()
语句,indexH作为计数器!同样,在另外一个for中也得套一层计数,加if()
,即:
increW = width/WCOUNT;
increH = height/HCOUNT;
int k = 0;
int indexH = 0;
int indexW = 0;
for (int x = 0; x < width; x ++)
{
for (int y = 0; y < height; y ++)
{
if (k % 2 == 0)
{
pixels[x + y * width] = color(0);
} else
{
pixels[x + y * width] = color(255);
}
///////第一层逻辑控制,控制纵向绘制时每走步长数换一次K//////////
indexH ++ ;
if (indexH % increH == 0)
{
indexH = 0;
k ++;
}
///////第一层逻辑控制//////////
}
///////第二层逻辑控制,控制横向绘制时每走步长数换一次K//////////
indexW ++ ;
if (indexW % increW == 0)
{
indexW = 0;
k ++;
}
///////第二层逻辑控制//////////
}
这样,两层逻辑控制k的变化走向,才能控制好对于像素点的颜色。完整代码如下:
int increW;
int increH;
int WCOUNT = 10;
int HCOUNT = 10;
void settings() {
size(800, 800);
}
void setup() {
loadPixels();
increW = width/WCOUNT;
increH = height/HCOUNT;
int k = 0;
int indexH = 0;
int indexW = 0;
for (int x = 0; x < width; x ++)
{
for (int y = 0; y < height; y ++)
{
if (k % 2 == 0)
{
pixels[x + y * width] = color(0);
} else
{
pixels[x + y * width] = color(255);
}
indexH ++ ;
if (indexH % increH == 0)
{
indexH = 0;
k ++;
}
}
indexW ++ ;
if (indexW % increW == 0)
{
indexW = 0;
k ++;
}
}
updatePixels();
}
void draw() {
}
言外
做个思考题,如果是用set()
直接定义像素点值呢。如果能融会贯通,那这个题目就很好解了,因为例子本身就以像素点的形式在两层for()循环中遍历,因此,直接替换就可,同时对上述代码做些优化,如下:
int increW;
int increH;
int WCOUNT = 10;
int HCOUNT = 10;
void settings() {
size(800, 800);
}
void setup() {
//loadPixels();
increW = width/WCOUNT;
increH = height/HCOUNT;
int k = 0;
int indexH = 0;
int indexW = 0;
for (int x = 0; x < width; x ++)
{
for (int y = 0; y < height; y ++)
{
if (k % 2 == 0)
{
set(x, y, color(0));
} else
{
set(x, y, color(255));
}
indexH ++ ;
if (indexH % increH == 0)
k ++;
}
indexW ++ ;
if (indexW % increH == 0)
k ++;
}
//updatePixels();
}
void draw() {
}
注意,不再使用pixels[]
,则无需使用loadPixels()
和updatePixels()
,直接定义(x,y)
坐标像素点上的颜色值(set()
最后一个参数即为color类型数值)。至于性能上的比较,我们回头再谈,这回就结束了,再见!
结果
Processing 网格纹理制作(棋盘格)使用pixel() set()像素点绘制方式的更多相关文章
- Processing 网格纹理制作(棋盘格)
写在前面的话 很久没有写博文了.最近在整理Processing有关文档,看到之前做的一些例子,想着分享在互联网上,当然和以前一样,目前也仅为了给初学者有个学习参考,笔者能力有限.废话不多说,干就完事了 ...
- Processing 网格(棋盘格)无限偏移纹理动画
过火 再度出击!这次我们要玩得更火一点---把静帧变动画.没错,将棋盘格动起来!看一下效果: 这是一个经典的无限偏移动画,在很多2d横版射击游戏中都会采用的技术.如何在Processing中实现,有两 ...
- Html5+Css3制作下拉菜单的三种方式
一.渐变式改变ol的高度 1.外部为ul标签,在每个li里嵌套一个ol列表2.设置外部li左浮动,内部ol标签绝对定位,外部li标签相对定位3.设置ol的高为0,溢出隐藏4.外部li标签:hover ...
- 使用D3制作图表(1)--画布绘制
使用D3绘制图表可以使数据更加直观. 使用D3前要先加载D3库,这里有两种方式,一种是在线加载<script type="text/javascript" src=" ...
- java制作二维码的两种方式
原博:http://www.importnew.com/15028.html Zebra Crossing(ZXing)是一个很棒的,几乎可以在所有平台(Android.JavaSE.iPhone.R ...
- Unity Shader 学习之旅
Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...
- OpenGL ES2.0基础入门
1.OpenGL ES 1.x渲染管线(又称为渲染流水线) (1).基本处理: 基本处理主要是设定3D空间中物体的顶点坐标.顶点对应的颜色.顶点的纹理坐标等属性,并且指定绘制方式. 常见的绘制方式有: ...
- 第27章 LTDC/DMA2D—液晶显示
本章参考资料:<STM32F76xxx参考手册2>.<STM32F7xx规格书>.库帮助文档<STM32F779xx_User_Manual.chm>. 关于开发板 ...
- 第27章 LTDC/DMA2D—液晶显示—零死角玩转STM32-F429系列
第27章 LTDC/DMA2D—液晶显示 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...
随机推荐
- 第6篇 Scrum 冲刺博客
1.站立会议 照骗 进度 成员 昨日完成任务 今日计划任务 遇到的困难 钟智锋 重构游戏逻辑代码 改写部分客户端代码,制作单机版 庄诗楷 进行了相关的装饰改进 与其他部分合成完成游戏 合成遇到bug, ...
- Json解析方式汇总 excel vba
一. 这种方式比较复杂,因为office版本的原因,所以要加其它函数 Private Function parseScript(strJson As String) Dim objJson As Ob ...
- LR与LR?
目录 逻辑回归与线性回归 逻辑回归 1.建立目标函数 2. 梯度求解 3. 实现 线性回归 1. 建立目标函数 2. 求解 3. 实现 逻辑回归与交叉熵 逻辑回归与线性回归 逻辑回归 线性回归 目标函 ...
- 如何解决 iframe 无法触发 clickOutside
注:(1)非原创,来自https://blog.csdn.net/weixin_33985679/article/details/89699215.https://zhuanlan.zhihu.com ...
- 让这个Java语言的开源商城系统火起来
Java是一门非常优秀的面向对象编程语言,功能强大且简单易用,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,凭借其简单性.面向对象.分布式.健壮性.安全性.平台独立与可 ...
- vue实现pdf文件的在线预览
我是通过 <iframe> 标签就可以满足我工作的 pdf预览需求 如果<iframe> 无法满足需求 , 可以使用pdf.js这个插件,功能强大. <iframe :s ...
- webpack打包初始入门教程
Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 从图中我们可以看出,Webpack 可以将多种静态资源 js.css ...
- 【web系统UI自动化】关于UI自动化的总结
实施过了web系统的UI自动化,回顾梳理下,想到什么写什么,随时补充. 首先,自动化测试不是手动测试的替代品,是比较好的补充,而且不是占大比重的补充. 70%的测试工作集中在底层接口测试和单元测试,2 ...
- C# 发送邮件通知
web.config <!-- 配置发邮件:邮件访问登录地址--> <add key="HttpsUrl" value="http://localhos ...
- 02_套接字编程(socket抽象层)
1.套接字概述 1.套接概述: 套接是进行网络通信的一种手段(socket) 2.套接字分类: 流式套接字(SOCK_STREAM): 传输层基于tcp协议进行通信 数 ...