我有一个渲染圆环的任务。这是我第一次使用matlab,我已经设法挣扎着用一些可怕的kludged代码完成2/3部分。
分配的第一步是将一个圆圈渲染为一组20个点。我为此制作了:
circle(IMG)
然后下一步是旋转并平移该圆圈并绘制20次以表示圆环形状,所以我得到了这个:
torus points(IMG)
下一步是从顶点列表中渲染此圆环的三维表示。
我所拥有的是400x3矩阵中的顶点列表,如下所示:
7.66478245119846 -1.84059939326890 0.292371704722737
7.53434247103331 -1.79821687453702 0.573576436351046
7.32764268084884 -1.73105604149887 0.798635510047293
7.06491629627043 -1.64569106442929 0.945518575599317
6.77188080634298 -1.55047806205660 0.999847695156391
6.47722056651889 -1.45473714644104 0.956304755963036
... ... ...
其中每个后续的20行是另一个圆圈。
作业建议我使用冲浪功能来渲染这个但我无法弄清楚如何。我见过的所有例子都使用surf来表示由高度值扭曲的二维平面。这似乎不适合渲染这种三维形状。
我正在尝试的方法是构建一个面列表,然后使用补丁函数来渲染圆。每个圆的前2个点与下一个圆的相应2个点形成正方形,然后渲染。
使用类似的东西:
for i=1:400
face = [(i) (i+1) (i+21) (i+20)];
patch('Faces',face,'Vertices',torus_vertices,'FaceColor','r'); %Should do this at the end
end
我得到这样的东西:
3d Torus(IMG)
它扭曲,并且一些侧面和内侧面都搞砸了。我认为这可能与顶点在某个时刻翻转的顺序有关。
解决此问题的最佳方法是什么?如果可能的话,我想用冲浪功能来做。
Ex1.m
%Initial positions
position = [2 0 0];
normal = [0 1 0];
%Rotation matrix
rotate18 = [cos(todeg(18)) -sin(todeg(18)) 0;
sin(todeg(18)) cos(todeg(18)) 0;
0 0 1];
% translate along the x axis by 5
translate = [5 0 0];
%% iterate 20 times to get a list of all the vertices
taurus_vertices = zeros(0, 3);
for i=0:20
%rotate translation by 18 degrees
translate = translate * rotate18;
%translate
position = position + translate;
%rotate the normal so it faces the right direction
normal = normal * rotate18;
%Get vertices for the circle and append to vertices list
circle_vertices = circle_3D(1, position, normal);
taurus_vertices = cat(1, taurus_vertices, circle_vertices);
%translate back to original position
position = position - translate;
end
%scatter3(taurus_vertices(1:end, 1), taurus_vertices(1:end, 2), taurus_vertices(1:end, 3));
%% Render each face
for i=1:400
face = [(i) (i+1) (i+21) (i+20)];
patch('Faces',face,'Vertices',taurus_vertices,'FaceColor','r');
end
circle.m
function h_circle=circle_3D(r, M, n)
%% Prepare input parameters
if size(n,2)>size(n,1)
n=n';
end
if size(M,2)>size(M,1)
M=M';
end
%% Define unit vectors u and v
% u and v define a new coordinate system in a plane perpendicular to n
a=[1;0;0];
b=[0;1;0];
if isempty(find(cross(a,n), 1))==1
a=[0;0;1];
elseif isempty(find(cross(b,n), 1))==1
b=[0;0;1];
end
alpha=dot(n,a)/dot(n,n);
u=a-alpha*n;
v=cross(u,n);%b-beta*n-gamma*u;
u=u/sqrt(sum(u.*u));
v=v/sqrt(sum(v.*v));
%% Plot the circle
hold on
axis equal
degs = 0;
points = 0;
verts = zeros(20, 3);
for phi=0: pi()/180 : 2*pi()
degs=degs+1;
if (mod(degs,18) == 0 )
points = points + 1;
verts(points,1)=M(1,1)+r*cos(phi)*u(1,1)+r*sin(phi)*v(1,1);
verts(points,2)=M(2,1)+r*cos(phi)*u(2,1)+r*sin(phi)*v(2,1);
verts(points,3)=M(3,1)+r*cos(phi)*u(3,1)+r*sin(phi)*v(3,1);
end
end
h_circle= verts;
答案 0 :(得分:2)
你的问题对于trisurf是完美的 - 给定一组点,你需要构建一个连接网格的三元组。 对于您的问题,您可以使用:
%inner circle points and radius
N1=20;
r1=1;
%outer circle points and radius
N2=30;
r2=5;
%inner cicle angles
thC=linspace(0,2*pi*(1-1/N1),N1)';
%inner cicle points
xyzC=[r1*sin(thC), zeros(N1,1),r1*cos(thC)]';
%torus points
xyzT = zeros(3,N1*N2);
for i=1:N2
%circle transformation
thT = 2*pi*i/N2;
T = [1 0 0 r2*cos(thT); 0 1 0 r2*sin(thT);0 0 1 0]*[cos(thT) -sin(thT) 0 0;sin(thT) cos(thT) 0 0 ; 0 0 1 0; 0 0 0 1];
%add points
xyzT(:,(i-1)*N1+1:i*N1)=T*[xyzC ;ones(1,N1)];
end
%build patch triples
tri=[];
for i=1:N2
for j=1:N1
%get three points:
% jth from ith circle
% j+1th from ith circle
% jth from i+1th circle
tri(end+1,:)=[(i-1)*N1+j (i-1)*N1+j+1 i*N1+j];
%get three points:
% j+1th from ith circle
% j+1th from i+1th circle
% jth from i+1th circle
tri(end+1,:)=[ i*N1+j (i-1)*N1+j+1 i*N1+j+1];
end
end
tri=mod(tri-1,N1*N2)+1;
trisurf(tri,xyzT(1,:),xyzT(2,:),xyzT(3,:));axis equal
%fancy
shading interp
camlight left
并得到:
答案 1 :(得分:1)
谢谢你的例子。使用三角形而不是矩形来渲染圆环会更好,但截止时间就像一个小时之后,我设法使我当前的一个工作!
我弄清楚是什么导致了我的问题。旋转平移矩阵会对每个圆点的方向产生不利影响(它们不对齐),导致它扭曲。
在仔细查看笔记之后(这将是几年的在线笔记),我设法找到一些用于完全重写的扫描功能的伪代码。我现在在同一个点生成20个圆圈,并通过增加数量来围绕原点旋转每个圆圈。这导致了这个:
%% Settings
points = 20; %Number of points in each circle
circles = 20; %Number of circles making up the torus
radius = 1; %Radius of the circle
scale = 0.75; %Scale to apply to the whole torus
center = [2 0 0]; %Center point of the first circle to sweep into a torus
%% Create (circles+1) circles after the other in an array at point [2 0 0]
%The extra circle overlaps the first, this is to make face generation much
%simpler.
V = zeros(circles*points, 3);
for i=0:points:points*circles
for k=1:points
V(i+k,1) = center(1) + radius * cosd((k-1)*(360/points));
V(i+k,2) = center(2) + 0;
V(i+k,3) = center(3) + radius * sind((k-1)*(360/points));
end
end
%% Sweep the circles, rotate each circle 18 degrees more than the previous
for n=0:points:circles*points
%Calculate degrees for current circle
D = (n/points) * 360/circles;
%Create a Z-rotation matrix
Rz = [
cosd(D) sind(D) 0;
-sind(D) cosd(D) 0;
0 0 1;
];
%Rotate each point of the circle
for i=1:points
V(n+i, :) = Rz * V(n+i, :)';
end
end
%% Scale the torus
%Create a scalar matrix
S = [
scale 0 0;
0 scale 0;
0 0 scale
];
%Scale each point
for n=0:points:circles*points
for i=1:points
V(n+i, :) = S * V(n+i, :)';
end
end
%% Generate faces
F = zeros(circles*points, 4);
for n=1:points:circles*points
for k=1:points
%If it's an endface then have destination face vertices wrap around to the first face of the current circle
if(mod(k, points) == 0)
F((n-1)+k,2)= (n-1)+k+1 - points;
F((n-1)+k,3)= n+points+k - points;
else
%otherwise use the next faces starting vertices
F((n-1)+k,2)= (n-1)+k+1;
F((n-1)+k,3)= n+points+k;
end
%Set the points coming from the previous face
F((n-1)+k,1)= (n-1)+k;
F((n-1)+k,4)= n+points+k-1;
end
end
%% Render
%Configure renderer
axis equal;
hold on;
%Render points
scatter3(V(1:end, 1), V(1:end, 2), V(1:end, 3), 'MarkerEdgeColor', 'b');
%Render faces
patch('Faces', F, 'Vertices', V, 'FaceColor', 'g');
这使得: