3D模板阴影原理

1:先从3dsMax中导出一个简单的场景,一个园环,球,平面。

2:园环直接面向光源,园环对球体来说是一个光线的阻挡物,园环在它上面形成阴影,同时,园环和球体对平面来说是光线的阻挡物,所以,同时在其上面形成阴影。

3: 要产生模板阴影,先要找出在园环和球体上面面向光线的面,去除背向光线的面,通过测试光线同园环和球体上面每一个所组成的小角形的法线的夹角是否小于90度,即光线矢量同法线矢量的点积要大于零。

4:在余下的所有面向光线的面中,把每个面的每条边可以保存到一个Vector中,不过在保存之前,先把该条边同已保存在Vector中的每条边先进行逐一比较,如果,找到的这条边同它的两个顶点相同,但顺序相反,则取走在Vector中的这条边。
如找不到,则把该条边加入到Vector中,最后将得到一条(或两条)轮廓线(见图红色线)。

5: 把轮廓线上的每个点延着光线方向延长一定的长度(见黄线),黄线所构成的面(所谓的阴影体)同场景去作比较,即模板测试(stencil)
最后画出阴影部分和非阴影部分,这就是基本的原理。
[img]http://dl.iteye.com/upload/attachment/451558/b4597f32-83ad-36ec-b92e-b8c65473b6bc.png[/img]

[img]http://dl.iteye.com/upload/attachment/451560/84babb26-bae0-39eb-8ac8-7e8197a7fd46.png[/img]

[img]http://dl.iteye.com/upload/attachment/451563/d7ef0359-6c51-3382-b48a-e9173328ce36.png[/img]


import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
import java.io.File;
import java.nio.IntBuffer;
import java.util.Vector;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLJPanel;
import javax.media.opengl.glu.GLU;

public class Main extends javax.swing.JFrame implements GLEventListener{
private ThreeDSParser p;
Texture t;
int[] shadowVolume = new int[2];
int index = 0;
float ext = 2.2f;

public void init(GLAutoDrawable drawable){
p = new ThreeDSParser();
p.parseFile("D:/3dsfiles/simpleScene.3DS");


GL gl = drawable.getGL();

gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, new float[]{0.0f, .0f, 0f, 1.0f}, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, new float[]{1.0f, 1.0f, 1.0f, 1.0f}, 0);
gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, new float[]{1.0f, 1.0f, 1.0f, 1.0f}, 0);
gl.glLightf(GL.GL_LIGHT0, GL.GL_SHININESS, 60f);

gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, new float[]{.05f, .05f, .05f, 1.0f}, 0);
gl.glLightModeli(GL.GL_LIGHT_MODEL_COLOR_CONTROL,GL.GL_SEPARATE_SPECULAR_COLOR);

gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_LIGHT0);

gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LESS);
gl.glEnable(GL.GL_NORMALIZE);
gl.glShadeModel(GL.GL_SMOOTH);

gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

computeSilhouette(gl,0);
computeSilhouette(gl,2);
}

public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h){
GL gl = drawable.getGL();
GLU glu = new GLU();
gl.glViewport(x, y, w, h);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(p.camera[6], w/h, 0.1, 10000);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(p.camera[0], p.camera[1], p.camera[2], p.camera[3], p.camera[4], p.camera[5], 0, 0, 1);

}

public void display(GLAutoDrawable drawable){
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT );

gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, p.spot_position, 0);


//不写了颜色缓存,写了深度缓存,仅用作深度比较
gl.glColorMask( false, false, false, false );
renderScene(gl,0);

//模板测试时,不改变深度缓存
gl.glEnable( GL.GL_CULL_FACE );
gl.glEnable( GL.GL_STENCIL_TEST );
gl.glDepthMask( false );
gl.glStencilFunc( GL.GL_ALWAYS, 0, 0xffff );

/*去除阴影体的背面,保留前面同整个场景进行模板测试
*当过深度测试通过时,值加一GL.GL_INCR;否则不变GL.GL_KEEP
*/
gl.glCullFace( GL.GL_BACK );
gl.glStencilOp( GL.GL_KEEP, GL.GL_KEEP, GL.GL_INCR );
for(int i=0; i<shadowVolume.length; i++){
gl.glCallList(shadowVolume[i]);
}

/*去除阴影体的前面,保留背面同整个场景进行模板测试
*当过深度测试通过时,值减一GL.GL_DECR;否则不变GL.GL_KEEP
*/
gl.glCullFace( GL.GL_FRONT );
gl.glStencilOp( GL.GL_KEEP, GL.GL_KEEP, GL.GL_DECR );
for(int i=0; i<shadowVolume.length; i++){
gl.glCallList(shadowVolume[i]);
}

//恢复可写了颜色和深度缓存
gl.glDepthMask( true );
gl.glDepthFunc( GL.GL_LEQUAL );
gl.glColorMask( true, true, true, true );
gl.glStencilOp( GL.GL_KEEP, GL.GL_KEEP, GL.GL_KEEP );
gl.glCullFace( GL.GL_BACK );
gl.glDisable( GL.GL_CULL_FACE );

//在模板缓存值不等于参考值零处,画阴影部分
gl.glStencilFunc( GL.GL_NOTEQUAL, 0, 0xffff );
renderScene(gl,1);

//在模板缓存值等于参考值零处,画非阴影部分
gl.glStencilFunc( GL.GL_EQUAL, 0, 0xffff );
renderScene(gl,0);

gl.glDepthFunc( GL.GL_LESS );
gl.glDisable( GL.GL_STENCIL_TEST);


gl.glFlush();
}

public void renderScene(GL gl,float a){
for (int i=0; i<p.objs.size(); i++) {
Obj obj = p.objs.elementAt(i);

for (int j=0; j<obj.matNames.size(); j++){
String matName = obj.matNames.elementAt(j);
Material mat = p.nameMatHt.get(matName);

if(a == 0){
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, mat.ambient, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, mat.diffuse, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, mat.specular,0);
gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, mat.shininess);
}
else {
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, new float[]{0.0f, 0.0f,0.0f, 0.95f}, 0);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, new float[]{0.05f, 0.05f,0.05f, 1f}, 0);
}
IntBuffer indice = obj.indices.elementAt(j);

if(mat.texFileName == null) {
gl.glDisable(GL.GL_TEXTURE_2D);

gl.glBegin(GL.GL_TRIANGLES);
for (int k=0,l=0; k<indice.capacity(); k+=3,l++) {
int v1 = indice.get(k);
int v2 = indice.get(k+1);
int v3 = indice.get(k+2);


gl.glNormal3f(obj.normsBuff.get(3*v1),obj.normsBuff.get(3*v1 + 1),obj.normsBuff.get(3*v1 + 2));

gl.glVertex3f(obj.vertsBuff.get(3*v1),obj.vertsBuff.get(3*v1 + 1),obj.vertsBuff.get(3*v1 + 2));

gl.glNormal3f(obj.normsBuff.get(3*v2),obj.normsBuff.get(3*v2 + 1),obj.normsBuff.get(3*v2 + 2));

gl.glVertex3f(obj.vertsBuff.get(3*v2),obj.vertsBuff.get(3*v2 + 1),obj.vertsBuff.get(3*v2 + 2));

gl.glNormal3f(obj.normsBuff.get(3*v3),obj.normsBuff.get(3*v3 + 1),obj.normsBuff.get(3*v3 + 2));

gl.glVertex3f(obj.vertsBuff.get(3*v3),obj.vertsBuff.get(3*v3 + 1),obj.vertsBuff.get(3*v3 + 2));

}
gl.glEnd();
}
else {
gl.glEnable(GL.GL_TEXTURE_2D);

try {
t = TextureIO.newTexture(new File("d:/images/"+mat.texFileName), false);
t.setTexParameteri(GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
t.setTexParameteri(GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
t.setTexParameteri(GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
t.setTexParameteri(GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);
t.bind();
} catch (Exception e) {
e.printStackTrace();
}
gl.glBegin(GL.GL_TRIANGLES);
for (int k=0, l=0; k<indice.capacity(); k+=3,l++) {
int v1 = indice.get(k);
int v2 = indice.get(k+1);
int v3 = indice.get(k+2);

gl.glNormal3f(obj.normsBuff.get(3*v1),obj.normsBuff.get(3*v1 + 1),obj.normsBuff.get(3*v1 + 2));

float tx1 = (obj.texsBuff.get(2*v1) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty1 = 1.5f - (obj.texsBuff.get(2*v1 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx1, ty1);

gl.glVertex3f(obj.vertsBuff.get(3*v1),obj.vertsBuff.get(3*v1 + 1),obj.vertsBuff.get(3*v1 + 2));

gl.glNormal3f(obj.normsBuff.get(3*v2),obj.normsBuff.get(3*v2 + 1),obj.normsBuff.get(3*v2 + 2));

float tx2 = (obj.texsBuff.get(2*v2) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty2 = 1.5f - (obj.texsBuff.get(2*v2 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx2, ty2);

gl.glVertex3f(obj.vertsBuff.get(3*v2),obj.vertsBuff.get(3*v2 + 1),obj.vertsBuff.get(3*v2 + 2));

gl.glNormal3f(obj.normsBuff.get(3*v3),obj.normsBuff.get(3*v3 + 1),obj.normsBuff.get(3*v3 + 2));

float tx3 = (obj.texsBuff.get(2*v3) - mat.ou - 0.5f)*mat.tu + 0.5f;
float ty3 = 1.5f - (obj.texsBuff.get(2*v3 + 1) - mat.ov - 0.5f)*mat.tv;
gl.glTexCoord2f(tx3, ty3);

gl.glVertex3f(obj.vertsBuff.get(3*v3),obj.vertsBuff.get(3*v3 + 1),obj.vertsBuff.get(3*v3 + 2));

}
gl.glEnd();

}
}
}
}

public void computeSilhouette(GL gl, int objIndex){

Vector<Float> edges = new Vector<Float>();

//光线的方向
float[] lightDir = new float[3];
lightDir[0] = p.spot_position[0];
lightDir[1] = p.spot_position[1];
lightDir[2] = p.spot_position[2];

//导出模型全部顶点的索引
Obj obj = p.objs.elementAt(objIndex);
IntBuffer indices = obj.indices.elementAt(0);
for (int k=0,l=0; k<indices.capacity(); k+=3,l++) {

//取得每个三角形面的平面法线
float a = obj.planeNormsBuff.get(3*l);
float b = obj.planeNormsBuff.get(3*l + 1);
float c = obj.planeNormsBuff.get(3*l + 2);

//求得光线同法线的点积(夹角)
float ldotn = a*lightDir[0] + b*lightDir[1] + c*lightDir[2];

//通过判断点积来确定该面是否面向光源,背向光源去除。
if (ldotn<0) continue;

//分别取得三角形面的三条边
for (int i=0; i<3; i++){
int ev1 = indices.get(k+i);
int ev2 = i == 2 ? indices.get(k): indices.get(k+i+1);

//第一个顶点
float x1 = obj.vertsBuff.get(3*ev1);
float y1 = obj.vertsBuff.get(3*ev1 + 1);
float z1 = obj.vertsBuff.get(3*ev1 + 2);
//第二个顶点
float x2 = obj.vertsBuff.get(3*ev2);
float y2 = obj.vertsBuff.get(3*ev2 + 1);
float z2 = obj.vertsBuff.get(3*ev2 + 2);

//在edges Vector中寻找是否有顶点相同,但顺序相反的边。
int j=0;
for (; j<edges.size(); j+=6){
if (x1 == edges.elementAt(j+3)
&& y1 == edges.elementAt(j+4)
&& z1 == edges.elementAt(j+5)
&& x2 == edges.elementAt(j)
&& y2 == edges.elementAt(j+1)
&& z2 == edges.elementAt(j+2)){
break;
}
}

if (edges.isEmpty() || j == edges.size()) {
//没的找到,则放入该条边
edges.addElement(x1);
edges.addElement(y1);
edges.addElement(z1);
edges.addElement(x2);
edges.addElement(y2);
edges.addElement(z2);
} else {
//若找到,则取走Vector中顶点相同,但顺序相反的边
for (int h = 0; h<6; h++)
edges.removeElementAt(j);
}

}
}

//最终 edges Vector中是轮廓线的所有顶点


shadowVolume[index] = gl.glGenLists(1);
gl.glNewList(shadowVolume[index], GL.GL_COMPILE);
{

gl.glBegin( GL.GL_QUADS );
gl.glLineWidth(1f);
{
gl.glColor3f( 0.5f, 0.5f, 0.1f );

for (int i=0; i<edges.size(); i+=6) {
float x1 = edges.elementAt(i);
float y1 = edges.elementAt(i+1);
float z1 = edges.elementAt(i+2);
float x2 = edges.elementAt(i+3);
float y2 = edges.elementAt(i+4);
float z2 = edges.elementAt(i+5);

gl.glVertex3f(x1, y1, z1);

//把点延着光线方向延长一定的长度
float[] vExtended1 = extendVertex(x1, y1, z1, ext);
gl.glVertex3f( vExtended1[0], vExtended1[1], vExtended1[2] );

float[] vExtended2 = extendVertex(x2, y2, z2, ext);
gl.glVertex3f( vExtended2[0], vExtended2[1], vExtended2[2] );

gl.glVertex3f(x2, y2, z2);
}
}
gl.glEnd();

}
gl.glEndList();

index ++;
}

public float[] extendVertex( float x, float y, float z, float ext )
{
float[] lightDir = new float[3];

lightDir[0] = x - p.spot_position[0];
lightDir[1] = y - p.spot_position[1];
lightDir[2] = z - p.spot_position[2];

float[] newVert = new float[3];
newVert[0] = p.spot_position[0] + lightDir[0] * ext;
newVert[1] = p.spot_position[1] + lightDir[1] * ext;
newVert[2] = p.spot_position[2] + lightDir[2] * ext;

return newVert;
}

public void displayChanged(GLAutoDrawable gl, boolean modeChanged, boolean deviceChanged){ }
}


import com.sun.opengl.util.BufferUtil;
import java.awt.Color;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.util.Hashtable;
import java.util.Vector;

public class ThreeDSParser {
public int len = 0;
public Vector<Obj> objs = new Vector<Obj>();
public Hashtable<String,Material> nameMatHt = new Hashtable<String,Material>();
public Material curMat;
public Obj curObj;
public IntBuffer curIndices;
public FloatBuffer curTexsBuff;
public IntBuffer trimeshs;
public int numOfTrimesh;
public int numOfVertices;
public float[] camera = new float[9];
public float[] spot_position = new float[4];
public float[] spot_direction = new float[4];
public float maxCutoff , minCutoff;
public float[] lightColor = new float[4];
public float[][] material = new float[4][4];
public float ou, ov, tu=1f, tv=1f;


public ThreeDSParser(){}
public void parseFile(String filename){
try {
FileInputStream fis = new FileInputStream(filename);
FileChannel fc = fis.getChannel();
ByteBuffer bb = ByteBuffer.allocate((int)fc.size());
bb = bb.order(ByteOrder.LITTLE_ENDIAN);
bb.clear();
fc.read(bb);
bb.flip();

while (bb.hasRemaining()) {
int id = bb.getShort() &0xffff;
int length = bb.getInt();

switch(id) {
case 0x4d4d:
//---------------文件的头部---------------//
break;
case 0x3d3d:
//---------------编辑块头部----------------//
break;
case 0x4000:
//----------------对象头部-----------------//
//----------------6个字节的对象名称-------------//
curObj = new Obj();

byte[] b = new byte[6];
StringBuilder sb = new StringBuilder();
byte t = 0;
while((t=bb.get())!=0){
sb.append((char)t);
}

curObj.objName = sb.toString();
break;

case 0x4100:
break;
case 0x4110:
numOfVertices = bb.getShort();

//一个用于存放所有顶点的坐标x, y, z的数组
curObj.vertsBuff = BufferUtil.newFloatBuffer(3*numOfVertices);
curObj.vertsBuff.clear();

//一个用于存放顶点法线坐标的数组
curObj.normsBuff = BufferUtil.newFloatBuffer(3*numOfVertices);
curObj.normsBuff.clear();

for (int j=0;j<numOfVertices;j++){
//放入x坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);
//放入y坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);
//放入z坐标
curObj.vertsBuff.put(bb.getFloat());
curObj.normsBuff.put(0.0f);

}
curObj.vertsBuff.flip();
curObj.normsBuff.flip();
curObj.texsBuff = null;
break;
case 0x4120:
/*================面====================*/
numOfTrimesh = bb.getShort()&0xffff;
curObj.planeNormsBuff = BufferUtil.newFloatBuffer(3*numOfTrimesh);
curObj.planeNormsBuff.clear();
trimeshs = BufferUtil.newIntBuffer(3*numOfTrimesh);
trimeshs.clear();

for (int j=0; j<numOfTrimesh; j++) {
//面三个顶点A, B, C的索引
int ai = bb.getShort()&0xffff; //A
int bi = bb.getShort()&0xffff; //B
int ci = bb.getShort()&0xffff; //C

trimeshs.put(ai);
trimeshs.put(bi);
trimeshs.put(ci);

//面的三个点坐标用于计算面的法线
triNormalVector(ai,bi,ci);

//跳过下面一个2个字节的数据
bb.position(bb.position()+2);

}
curObj.planeNormsBuff.flip();
trimeshs.flip();

break;
case 0x4130:
//----------------面所使用的材质名称-------------------//
//---------------先读一个以0结束的字符串--------------//
//------接下来读2个字节的使用该材质的面数量------------//
//-------------再读2个字节的所有面的索引---------------//
StringBuilder sb2 = new StringBuilder();
byte t2 = 0;
while((t2=bb.get())!=0){
sb2.append((char)t2);
}
String materialName = sb2.toString().trim();

curObj.matNames.add(materialName);

int num = bb.getShort();
curIndices = BufferUtil.newIntBuffer(3*num);
curIndices.clear();

for (int j=0;j<num;j++) {
int i = bb.getShort();
int v1 = trimeshs.get(3*i);
int v2 = trimeshs.get(3*i + 1);
int v3 = trimeshs.get(3*i + 2);
curIndices.put(v1);
curIndices.put(v2);
curIndices.put(v3);

}
curIndices.flip();
curObj.indices.add(curIndices);

break;
case 0x4140:
//-----------------------项点纹理映射坐标----------------//

//-----------------------读取顶点数量---------------------//
numOfVertices = bb.getShort();

//-----------------------用于存放纹理坐标的内存-------------------//
curObj.texsBuff = BufferUtil.newFloatBuffer(2*numOfVertices);
curObj.texsBuff.clear();

//---------------------读纹理坐标--------------//
for (int j=0;j<numOfVertices;j++){
curObj.texsBuff.put(bb.getFloat());
curObj.texsBuff.put(bb.getFloat());
}
curObj.texsBuff.flip();
break;
case 0x4160:
objs.add(curObj);

bb.position(bb.position()+length-6);
break;
case 0xafff:
//-----------------材质头部-----------------//
curMat = new Material();
break;
case 0xa000:
//----------------材质的名称------------------//
b = new byte[length-6];
for (int j=0; j<length-6; j++) {
b[j] = bb.get();
}
String matName = new String(b,"gbk").trim();
if( nameMatHt.get(matName) == null )
nameMatHt.put(matName, curMat);

break;
case 0xa200:
//-------------------纹理头部-----------------//
break;
case 0xa300:
//-------------------纹理的文件名-------------//
b = new byte[length-6];
for (int j=0; j<length-6; j++) {
b[j] = bb.get();
}
curMat.texFileName = new String(b,"gbk").trim().toLowerCase();
break;
case 0xa353:
//---------------------纹理偏移值v--------------//
curMat.ov = bb.getFloat();

break;
case 0xa354:
//------------------纹理平铺u---------------------//
curMat.tu = bb.getFloat();

break;
case 0xa356:
//------------------纹理平铺v---------------------//
curMat.tv = bb.getFloat();

break;
case 0xa358:
//------------------纹理偏移值u---------------------//
curMat.ou = bb.getFloat();

break;
case 0xa010:
//--------------------环境光--------------------//
bb.position(bb.position()+6);
int ar = bb.get()&0xff;
int ag = bb.get()&0xff;
int ab = bb.get()&0xff;
curMat.ambient = new Color(ar,ag,ab, 255).getComponents(null);
break;
case 0xa020:
//---------------------漫射光------------------//
bb.position(bb.position()+6);
int dr = bb.get()&0xff;
int dg = bb.get()&0xff;
int db = bb.get()&0xff;
curMat.diffuse = new Color(dr,dg,db, 255).getComponents(null);

break;
case 0xa030:
//-------------高光反射----------------------//
bb.position(bb.position()+6);
int sr = bb.get()&0xff;
int sg = bb.get()&0xff;
int sbb = bb.get()&0xff;
curMat.specular = new Color(sr,sg,sbb, 255).getComponents(null);

break;
case 0xa041:
//-------------------光泽度--------------------//
bb.position(bb.position()+6);
curMat.shininess = bb.get()&0xff;
bb.position(bb.position()+1);
break;
case 0x4600:
//------------------光源的位置坐标-----------------//
spot_position[0] = bb.getFloat(); //光源的位置x
spot_position[1] = bb.getFloat(); //光源的位置y
spot_position[2] = bb.getFloat(); //光源的位置z
spot_position[3] = 1.0f;
break;
case 0x4610:
//------------------光源的目标位置坐标(xref,yref,zref)-----------------//
spot_direction[0] = bb.getFloat();
spot_direction[1] = bb.getFloat();
spot_direction[2] = bb.getFloat();

spot_direction[3] = 1.0f;
minCutoff = bb.getFloat()/2.0f; //截止角
maxCutoff = bb.getFloat()/2.0f;
bb.position(bb.position()+length-6-20);
break;
case 0x10:
//---------------光源的颜色------------------------//
new Color(bb.getFloat(),bb.getFloat(),bb.getFloat(),1.0f).getComponents(lightColor);
break;
case 0x4700:
camera[0] = bb.getFloat(); //观察点x0
camera[1] = bb.getFloat(); //观察点y0
camera[2] = bb.getFloat(); //观察点z0
camera[3] = bb.getFloat(); //瞄准点xref
camera[4] = bb.getFloat(); //瞄准点yref
camera[5] = bb.getFloat(); //瞄准点zref

//跳过下面一个4个字节的数据
bb.position(bb.position()+4);
camera[6] = bb.getFloat(); //相机的视角
break;
case 0x4720:
camera[7] = bb.getFloat(); //近点
camera[8] = bb.getFloat(); //远点
break;
default:
bb.position(bb.position()+length-6);

}
}
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
}

public void triNormalVector(int ai, int bi, int ci){
float[] v1 = new float[3];
float[] v2 = new float[3];
float[] v3 = new float[3];

v1[0] = curObj.vertsBuff.get(3*ci) - curObj.vertsBuff.get(3*bi);
v1[1] = curObj.vertsBuff.get(3*ci+1) - curObj.vertsBuff.get(3*bi+1);
v1[2] = curObj.vertsBuff.get(3*ci+2) - curObj.vertsBuff.get(3*bi+2);

v2[0] = curObj.vertsBuff.get(3*ai) - curObj.vertsBuff.get(3*bi);
v2[1] = curObj.vertsBuff.get(3*ai+1) - curObj.vertsBuff.get(3*bi+1);
v2[2] = curObj.vertsBuff.get(3*ai+2) - curObj.vertsBuff.get(3*bi+2);

v3[0] = v1[1]*v2[2] - v1[2]*v2[1];
v3[1] = v1[2]*v2[0] - v1[0]*v2[2];
v3[2] = v1[0]*v2[1] - v1[1]*v2[0];


curObj.planeNormsBuff.put(v3[0]);
curObj.planeNormsBuff.put(v3[1]);
curObj.planeNormsBuff.put(v3[2]);

//同原来这三个顶点的法向量进行矢量和

//a点的法线(x,y,z)
curObj.normsBuff.put(3*ai,curObj.normsBuff.get(3*ai)+v3[0]);
curObj.normsBuff.put(3*ai+1,curObj.normsBuff.get(3*ai+1)+v3[1]);
curObj.normsBuff.put(3*ai+2,curObj.normsBuff.get(3*ai+2)+v3[2]);

// b点的法线(x,y,z)
curObj.normsBuff.put(3*bi,curObj.normsBuff.get(3*bi)+v3[0]);
curObj.normsBuff.put(3*bi+1,curObj.normsBuff.get(3*bi+1)+v3[1]);
curObj.normsBuff.put(3*bi+2,curObj.normsBuff.get(3*bi+2)+v3[2]);

// c点的法线(x,y,z)
curObj.normsBuff.put(3*ci,curObj.normsBuff.get(3*ci)+v3[0]);
curObj.normsBuff.put(3*ci+1,curObj.normsBuff.get(3*ci+1)+v3[1]);
curObj.normsBuff.put(3*ci+2,curObj.normsBuff.get(3*ci+2)+v3[2]);

}


}





import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Vector;

public class Obj {
public String objName;
public Vector<String> matNames = new Vector<String>();
public FloatBuffer vertsBuff;
public FloatBuffer normsBuff;
public FloatBuffer texsBuff;
public Vector<IntBuffer> indices = new Vector<IntBuffer>();
public FloatBuffer planeNormsBuff;
}


public class Material {
public float[] ambient = new float[3];
public float[] diffuse = new float[3];
public float[] specular = new float[3];
public float shininess;
public String texFileName = null;
float ou = 0f;
float tu = 1.0f;
float ov = 0f;
float tv = 1.0f;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值