zoukankan      html  css  js  c++  java
  • 『openframeworks』shader制作三角形马赛克效果

    不久前做了六边形马赛克的效果,很有意思,乘热打铁,弄了个三角形马赛克。

    首先肯定是等边三角形,这样才能真正的无缝拼接。观察发现,三角形可以拼接成之前做个的六边形。

    如下图:


    我们可以发现6个三角形正好组成了一个六边形。

    我们要判断一个点属于哪个三角形,必须先判断它属于那个六边形,这个在之前的博文中已经提到了。

    OK,我们知道在那个六边形了,也就是我们知道了上面O点的坐标。我们开始想怎么判断它在哪个三角形。

    嗯,我想大家都能想到,根据点与中心点O的夹角判断在那个三角形,调用atan就OK了:

    float a = atan((x-O.x)/(y-O.y));//夹角

    然后根据各自的角度就能判断是属于哪一个三角形的了,这里注意一下atan算出的范围是-180至180度,对应的数值是-PI至PI。

    然后算出6个三角形的中心点坐标,属于哪一个三角形就去哪一个坐标点的像素值。

    碎片着色器frag shader如下:

    #version 400
    #extension GL_ARB_texture_rectangle : enable
    
    uniform float len;
    uniform sampler2DRect colorTex0;
    void main (void){
    	float TR = 0.866025f;
    	float PI6 = 0.523599f; //PI/6
    	float x = gl_TexCoord[0].x;
    	float y = gl_TexCoord[0].y;
    	int wx = int(x/1.5f/len);
    	int wy = int(y/TR/len);
    	vec2 v1, v2, vn;
    	if(wx/2 * 2 == wx) {
    		if(wy/2 * 2 == wy) {
    				v1 = vec2(len*1.5f*wx, len*TR*wy);
    				v2 = vec2(len*1.5f*(wx+1), len*TR*(wy+1));
    			} else {
    				v1 = vec2(len*1.5f*wx, len*TR*(wy+1));
    				v2 = vec2(len*1.5f*(wx+1), len*TR*wy);
    			}
    		} else {
    		if(wy/2 * 2 == wy) {
    			v1 = vec2(len*1.5f*wx, len*TR*(wy+1));
    			v2 = vec2(len*1.5f*(wx+1), len*TR*wy);
    			} else {
    				v1 = vec2(len*1.5f*wx, len*TR*wy);
    				v2 = vec2(len*1.5f*(wx+1), len*TR*(wy+1));
    			}
    	}
    	float s1 = sqrt( pow(v1.x-x, 2) + pow(v1.y-y, 2) );
    	float s2 = sqrt( pow(v2.x-x, 2) + pow(v2.y-y, 2) );
    	if(s1 < s2)
    		vn = v1;
    	else
    		vn = v2;
    	vec4	mid = texture2DRect(colorTex0, vn);
    	float a = atan((x-vn.x)/(y-vn.y));//夹角
    	vec2 area1 = vec2(vn.x, vn.y-len/TR/2);
    	vec2 area2 = vec2(vn.x+len/2, vn.y-len/TR/4);
    	vec2 area3 = vec2(vn.x+len/2, vn.y+len/TR/4);
    	vec2 area4 = vec2(vn.x, vn.y+len/TR/2);
    	vec2 area5 = vec2(vn.x-len/2, vn.y+len/TR/4);
    	vec2 area6 = vec2(vn.x-len/2, vn.y-len/TR/4);
    	if(a>=PI6 && a<PI6*3)
    		vn = area1;
    	else if(a>=PI6*3 && a<PI6*5)
    		vn = area2;
    	else if((a>=PI6*5 && a<=PI6*6) || (a<-PI6*5 && a>-PI6*6))
    		vn = area3;
    	else if(a<-PI6*3 && a>=-PI6*5)
    		vn = area4;
    	else if(a<=-PI6 && a>-PI6*3)
    		vn = area5;
    	else if(a>-PI6 && a<PI6)
    		vn = area6;
    	vec4  color = texture2DRect(colorTex0, vn);
    	gl_FragColor = color;
    }

    其中len为传入到shader中六边形的单边长,也是三角形的单边长。TR其实是√3/2。而PI6明显就是PI/6,对应的是30度。

    其实核心思想就是判断属于哪个三角形。

    效果如下:


    同样的,实时改变len的值,图就能动起来:


    依旧很炫,^_^.

    openframeworks中主要代码:

    #include "testApp.h"
    
    //--------------------------------------------------------------
    void testApp::setup(){
    	img.loadImage("bg.jpg");
    
    	fbo.allocate(640, 480);
    
    	shader.load("triangle.vert", "triangle.frag");
    	len = 100.0f;
    	bAdd = false;
    }
    
    //--------------------------------------------------------------
    void testApp::update(){
    	if(len < 10.0f)
    		bAdd = true;
    	if(len > 100.0f)
    		bAdd = false;
    	len += bAdd ? (0.05f):(-0.05f);
    }
    
    //--------------------------------------------------------------
    void testApp::draw(){
    	ofEnableAlphaBlending();
    
    	fbo.begin();
    	img.draw(0, 0, 640, 480);
    	fbo.end();
    
    	shader.begin();
    	shader.setUniform1f("len", len);
    	shader.setUniformTexture("colorTex0", fbo.getTextureReference(), 0);
    	fbo.draw(0, 0, 640, 480);
    	shader.end();
    
    	ofDisableAlphaBlending();
    }


    OK,有兴趣的可以试试。

  • 相关阅读:
    WINCE6.0 error C2220: warning treated as error问题解决
    GPRS连接失败问题
    wince下sourcessources.cmnMakefile.def的相关作用
    IMX515开发备忘
    WINCE补丁包下载地址
    IMX51+WINCE6.0平台缩写意义
    喵哈哈村的魔法考试 Round #1 (Div.2) ABCD
    Codeforces Round #402 (Div. 2) D
    Codeforces Round #402 (Div. 2) C
    Codeforces Round #402 (Div. 2) B
  • 原文地址:https://www.cnblogs.com/riasky/p/3465028.html
Copyright © 2011-2022 走看看