Houdini 里面实现科幻圆环面板的效果 -Tron
把之前做的一个procedural modeling的方法做个小结,目的是做出tron风格的圆盘界面。:
左边是目标效果 右边是实现效果
shawn老师的思路做了一下参考,这里讲一讲我的思路。
界面里面最小的元素组成是每个圆环的中的一个小扇形,那么基本的结构就是:
扇形 -> 圆环 -> 整个面板
1,扇形
扇形的做法比较简单,主要考虑的是扇形跨度,扇形最小半径和最大半径这三个参数,值得注意的是在houdini里面要做成一个完整封闭的扇形面,那么扇形上面的点排列必须是按时针顺序排列的,不然则会产生面有奇怪的扭转问题。
2,圆环
圆环里面主要判定最大最小的扇形长度以及空隙宽度,并在这个范围类循环生成新的扇形,如果所有的扇形和空隙长多超过了2π则结束这个圆环的创建
3,整个面板
在这个级别,主要是随机确定每个圆环的最小和最大半径,并确定在一个多大的高度空间内行程面板。
下面是代码,直接写在一个attrib wrangle 里面的detail级别就好了:
#define dao 6.28318530718
int segment(
float resolution;
float level;
float start_theta;
float end_theta;
float min_radius;
float max_radius;
){
int prim = addprim(geoself(),"poly");
//min_radius
float steps = start_theta;
while(1){
if(steps < end_theta){
vector next_pt = set(cos(steps)*min_radius, level, sin(steps)*min_radius);
int pt = addpoint(geoself(), next_pt);
addvertex(geoself(), prim, pt);
steps += resolution;
}else{
vector next_pt = set(cos(end_theta)*min_radius, level, sin(end_theta)*min_radius);
int pt = addpoint(geoself(), next_pt);
addvertex(geoself(), prim, pt);
steps = end_theta;
break;
}
}
//max_radius
while(1){
if(steps > start_theta){
vector next_pt = set(cos(steps)*max_radius, level, sin(steps)*max_radius);
int pt = addpoint(geoself(), next_pt);
addvertex(geoself(), prim, pt);
steps -= resolution;
}else{
vector next_pt = set(cos(start_theta)*max_radius, level, sin(start_theta)*max_radius);
int pt = addpoint(geoself(), next_pt);
addvertex(geoself(), prim, pt);
break;
}
}
return 1;
}
int circle(
int definition;
int step;
float level;
float min_radius;
float max_radius;
){
float total_length = 0;
float seg_length = 0;
float gap_length = 0;
int seg_num = 0;
float resolustion = dao / 181 * definition;
float seg_step = pow(rand(step*934),2)*2;
float gap_step = pow(rand(step*547),2)*0.5;
float min_seg = 0.01;
float max_seg = min_seg + seg_step ;
float min_gap = 0.002;
float max_gap = min_gap + gap_step;
float start_theta = 0;
float end_theta = 0;
int flag = 1;
while(flag){
seg_length = fit01(rand(seg_num*234), min_seg, max_seg);
gap_length = fit01(rand((seg_num+52)*25), min_gap, max_gap);
end_theta = start_theta + seg_length;
segment(resolustion, level, start_theta, end_theta, min_radius, max_radius);
total_length = total_length + seg_length + gap_length;
if (total_length > dao){
flag = 0;
}
seg_num++;
start_theta = total_length;
}
}
int tron(){
float max_level = 1;
float min_level = 0;
float max_R = 1.5;
float min_R = 0.8;
float max_width = 0.05;
float min_width = 0.001;
int max_num = 50;
for(int step = 0; step < max_num; step++){
float level = fit01(rand(step*234), min_level, max_level);
float min_radius = fit01(rand(step*344), min_R, max_R);
float width = fit01(rand(step*114), min_width, max_width);
float max_radius = min_radius + width;
circle(1, step, level, min_radius, max_radius);
}
}
tron();