Skip to content

Commit 76e671d

Browse files
committed
fix normal calculation; add another demo; other fixes
1 parent 2c63672 commit 76e671d

File tree

7 files changed

+305
-137
lines changed

7 files changed

+305
-137
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ featuring a wall clock.
6060
of a series of dots following a path like marching ants. Shows some of the functionality of graphics paths.
6161
* [demos/pathtube.html](https://peteroupc.github.io/html3dutil/demos/pathtube.html) - Demo
6262
of a tube formed by a path curve.
63+
* [demos/pathshapes.html](https://peteroupc.github.io/html3dutil/demos/pathshapes.html) - Demo
64+
of 3D and 2D shapes generated by a 2D path.
6365

6466
### Curves and Surfaces
6567

demos/pathshapes.html

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<head>
2+
<meta charset=utf-8>
3+
<style>
4+
body { margin: 0px; }
5+
canvas { width:100%; height:100%; overflow: hidden; }
6+
</style>
7+
<script type="text/javascript" src="../glutil_min.js"></script>
8+
<script type="text/javascript" src="../extras/camera.js"></script>
9+
<script type="text/javascript" src="../extras/path.js"></script>
10+
<script type="text/javascript" src="../extras/curvetube.js"></script>
11+
<script type="text/javascript" src="../extras/frame.js"></script>
12+
<script type="text/javascript" src="demoutil.js"></script>
13+
<script src="https://peteroupc.github.io/colorpicker/cbox.js"></script>
14+
</head>
15+
<body>
16+
<p style="position:absolute;left:0;top:1em">
17+
<a href="javascript:sampleShape(0)">Plane</a>,
18+
<a href="javascript:sampleShape(1)">Extruded</a>,
19+
<a href="javascript:sampleShape(2)">Closed figure</a>,
20+
<a href="javascript:sampleShape(3)">Tube</a>
21+
<br>
22+
Color: <input type=color value="#E0E0E0" id=colorsetting>
23+
</p>
24+
<canvas id=canvas></canvas>
25+
<script id="demo">
26+
//<!--
27+
/*
28+
Written by Peter O. in 2015.
29+
30+
Any copyright is dedicated to the Public Domain.
31+
http://creativecommons.org/publicdomain/zero/1.0/
32+
If you like this, you should donate to Peter O.
33+
at: http://upokecenter.dreamhosters.com/articles/donate-now-2/
34+
*/
35+
36+
var path=new GraphicsPath()
37+
.moveTo(-1,1,0)
38+
.lineTo(0,1)
39+
.arcTo(1,1,1,0,1)
40+
.lineTo(1,-1)
41+
.lineTo(0,-1)
42+
.arcTo(-1,-1,-1,0,1)
43+
.closePath()
44+
45+
function pathClosedFigure(path, zBottom, zTop, flatness){
46+
var mesh=new Mesh()
47+
mesh.merge(extrudePath(path,zBottom,zTop,flatness))
48+
mesh.merge(pathFloor(path,zTop,flatness))
49+
mesh.merge(pathFloor(path,zBottom,flatness).reverseWinding().reverseNormals())
50+
return mesh
51+
}
52+
53+
function makeTubeFromPath(path,flatness,thickness,pathSection){
54+
var mesh=new Mesh()
55+
var curves=path.getCurves(flatness)
56+
var resolution=Math.ceil((curves.getLength()/flatness)/10)
57+
var curveSection=(pathSection) ? pathSection.getCurves(flatness) : null
58+
new SurfaceEval()
59+
.vertex(new CurveTube(curves,thickness,curveSection))
60+
.setAutoNormal(true)
61+
.evalSurface(mesh,Mesh.TRIANGLES,resolution,
62+
Math.ceil(2*thickness/flatness));
63+
return mesh
64+
}
65+
66+
function pathFloor(path, z, flatness){
67+
if(z==null)z=0
68+
var tris=path.getTriangles(flatness);
69+
var mesh=new Mesh().mode(Mesh.TRIANGLES)
70+
.normal3(0,0,1);
71+
for(var i=0;i<tris.length;i++){
72+
var tri=tris[i]
73+
mesh.vertex3(tri[0],tri[1],z)
74+
.vertex3(tri[2],tri[3],z)
75+
.vertex3(tri[4],tri[5],z)
76+
}
77+
return mesh
78+
}
79+
function extrudePath(path, zStart, zEnd, flatness){
80+
var lines=path.getLines(flatness)
81+
var mesh=new Mesh().mode(Mesh.TRIANGLES)
82+
var z1=Math.min(zStart,zEnd)
83+
var z2=Math.max(zStart,zEnd)
84+
for(var i=0;i<lines.length;i++){
85+
var line=lines[i]
86+
var dx=line[2]-line[0]
87+
var dy=line[3]-line[1]
88+
var dot=dx*dx+dy*dy
89+
if(dot==0)continue;
90+
mesh.vertex3(line[0],line[1],z1)
91+
.vertex3(line[0],line[1],z2)
92+
.vertex3(line[2],line[3],z1)
93+
.vertex3(line[2],line[3],z1)
94+
.vertex3(line[0],line[1],z2)
95+
.vertex3(line[2],line[3],z2)
96+
}
97+
mesh.recalcNormals()
98+
return mesh
99+
}
100+
function createSampleShape(index){
101+
switch(index){
102+
case 0:
103+
return pathFloor(path,0,0.01);
104+
case 1:
105+
return extrudePath(path,-0.2,0.2,0.01);
106+
case 2:
107+
return pathClosedFigure(path,-0.25,0.25,0.01);
108+
case 3:
109+
return makeTubeFromPath(path,0.01,0.1);
110+
default:
111+
return new Mesh();
112+
}
113+
}
114+
function sampleShape(num){
115+
if(shape)scene.removeShape(shape);
116+
var cs=document.getElementById("colorsetting").value
117+
scene.addShape(shape=scene.makeShape(createSampleShape(num)).setColor(cs))
118+
}
119+
// Create the 3D scene; find the HTML canvas and pass it
120+
// to Scene3D.
121+
var scene=new Scene3D(document.getElementById("canvas"));
122+
scene.setClearColor("white");
123+
var camera=new Camera(scene,45,1,1000).setDistance(5)
124+
.turnVertical(-90)
125+
var xyz=new ShapeGroup();
126+
var pc=new FrameCounterDiv(scene)
127+
var shape=null;
128+
var axisline=scene.makeShape(Meshes.createCapsule(0.005,10,6,4));
129+
var zaxis=axisline.copy().setColor("blue")
130+
var yaxis=axisline.copy().setColor("green");
131+
yaxis.getTransform().setOrientation(90,1,0,0);
132+
var xaxis=axisline.copy().setColor("red");
133+
xaxis.getTransform().setOrientation(90,0,1,0);
134+
document.getElementById("colorsetting").addEventListener("change",
135+
function(e){ if(shape)shape.setColor(e.target.value) });
136+
xyz.addShape(xaxis).addShape(yaxis).addShape(zaxis);
137+
scene.addShape(xyz);
138+
sampleShape(0);
139+
GLUtil.renderLoop(function(){
140+
pc.update();
141+
camera.update();
142+
scene.render();
143+
});
144+
//-->
145+
</script>
146+
</body>

demos/pathtube.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
return mesh
5757
}
5858

59-
function makeTubeFromPath(flatness,thickness){
59+
function makeTubeFromPath(path,flatness,thickness){
6060
var mesh=new Mesh()
6161
var curves=path.getCurves(flatness)
6262
var resolution=Math.ceil(curves.getLength()*2/3)
@@ -75,7 +75,7 @@
7575
scene.setDirectionalLight(0,[0,-3,1.2],[1,1,1])
7676
scene.setDirectionalLight(1,[0,3,1.2],[.6,.6,.6])
7777
var mesh=null
78-
mesh=makeTubeFromPath(0.2,2)
78+
mesh=makeTubeFromPath(path,0.2,2)
7979
scene.addShape(
8080
scene.makeShape(mesh).setColor("blue"))
8181
scene.addShape(

extras/curvetube.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ CurveTube.prototype.evaluate=function(u, v){
235235
var vpos=this.sweptCurve.evaluate(v);
236236
t1 = vpos[0];
237237
t2 = vpos[1];
238-
var t3=vpos[2];
239238
sx = sampleX+(-basisVectors[0]*t1+basisVectors[3]*t2)*this.thickness;
240239
sy = sampleY+(-basisVectors[1]*t1+basisVectors[4]*t2)*this.thickness;
241240
sz = sampleZ+(-basisVectors[2]*t1+basisVectors[5]*t2)*this.thickness;

extras/path.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ GraphicsPath._Curve.prototype.evaluate=function(u){
479479
if((partialLen>=segstart && partialLen<segend) ||
480480
(partialLen==segend && mid+1==this.segments.length)){
481481
var seginfo=seg[3]
482-
var t=(u==1) ? segend : (partialLen-segstart)/seg[1]
482+
var t=(u==1) ? 1.0 : (partialLen-segstart)/seg[1]
483483
if(seg[0]==GraphicsPath.LINE){
484484
var x=seginfo[1]+(seginfo[3]-seginfo[1])*t
485485
var y=seginfo[2]+(seginfo[4]-seginfo[2])*t

glutil-mesh.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ Mesh._recalcNormalsStart=function(vertices,uniqueVertices,faces,stride,offset,fl
9696
/** @private */
9797
Mesh._recalcNormalsFinish=function(vertices,uniqueVertices,faces,stride,offset,flat){
9898
var len;
99+
var dupverts=[]
100+
var dupvertcount=0
99101
if(!flat){
100102
// If smooth shading is requested, make sure
101103
// that every vertex with the same position has the
@@ -104,19 +106,37 @@ Mesh._recalcNormalsFinish=function(vertices,uniqueVertices,faces,stride,offset,f
104106
var v=uniqueVertices[key]
105107
if(v && v.constructor==Array && v.length>=2){
106108
var v0=v[0];
107-
// Add the normals of duplicate vertices
108-
// to the first vertex
109+
var avgx=vertices[v0]
110+
var avgy=vertices[v0+1]
111+
var avgz=vertices[v0+2]
112+
dupverts[0]=avgx
113+
dupverts[1]=avgy
114+
dupverts[2]=avgz
115+
dupvertcount=3
109116
for(var i=1;i<v.length;i++){
110-
vertices[v0]+=vertices[v[i]]
111-
vertices[v0+1]+=vertices[v[i]+1]
112-
vertices[v0+2]+=vertices[v[i]+2]
117+
var dupfound=false
118+
var nx=vertices[v[i]]
119+
var ny=vertices[v[i]+1]
120+
var nz=vertices[v[i]+2]
121+
for(var j=0;j<dupvertcount;j+=3){
122+
if(nx==dupverts[j] && ny==dupverts[j+1] && nz==dupverts[j+2]){
123+
dupfound=true
124+
break
125+
}
126+
}
127+
if(!dupfound){
128+
dupverts[dupvertcount++]=nx
129+
dupverts[dupvertcount++]=ny
130+
dupverts[dupvertcount++]=nz
131+
avgx+=nx
132+
avgy+=ny
133+
avgy+=nz
134+
}
113135
}
114-
// Propagate the first vertex's normal to the
115-
// other vertices
116-
for(var i=1;i<v.length;i++){
117-
vertices[v[i]]=vertices[v0]
118-
vertices[v[i]+1]=vertices[v0+1]
119-
vertices[v[i]+2]=vertices[v0+2]
136+
for(var i=0;i<v.length;i++){
137+
vertices[v[i]]=avgx
138+
vertices[v[i]+1]=avgy
139+
vertices[v[i]+2]=avgz
120140
}
121141
}
122142
}

0 commit comments

Comments
 (0)