TWO SHADERS(TEXTURE) EXEMPLE
Download two shaders exemple - Moussa Dembélé – www.mousman.com- mousman@hotmail.com
model made by David A. Swan (aka Birdman)
(contains 122 172 triangles)
Sorry, either Adobe flash is not installed or you do not have it enabled
We have seen in the previous exemple how to parse and display an object with one shader.
Here we are going to use two shaders.
One for the texture parts and another for the non texture parts.
The sources of this project are in the – two_shaders – directory.
There’s not a lot of changes between this project and the previous one.
The structure is the same.
The World.as class is almost the same, the only change is that this time I’ve used two lights,
and that they are moving and not the object.
And of course a new class is instantiated instead of FerrariMesh : BuickMesh.
BuickMesh.as :
from line 56 to 76 wavefront files and textures are embeded :
[Embed (source = "../lib/buick/buick.obj", mimeType = "application/octet-stream")] private var _objData:Class; [Embed (source = "../lib/buick/buick.mtl", mimeType = "application/octet-stream")] private var _mtlData:Class; //textures [Embed(source = "../lib/buick/WHITEW~1.JPG")] private var _texture0Class:Class; [Embed(source = "../lib/buick/BUICKB~2.JPG")] private var _texture1Class:Class; [Embed(source="../lib/buick/BUICKblock.jpg")] private var _texture2Class:Class; [Embed(source="../lib/buick/OldWood27BoH.JPG")] private var _texture3Class:Class; [Embed(source="../lib/buick/pennplate.jpg")] private var _texture4Class:Class; [Embed(source="../lib/buick/plate2.jpg")] private var _texture6Class:Class; [Embed(source="../lib/buick/woodie9.jpg")] private var _texture7Class:Class;
I could have used an xml to define the textures and to load them,
and I will probably add this functionnaly in a futur version, but for now….
As we are using an object with some parts using textures and some not, we’ll have to use
two shaders, one for textures parts and one for non-textured parts.
First we have to create the textures.
For that I’ve made a dedicated class : MTextureManager
MTextureManager :
This class is here to create and store the textures in a simple way.
to create and store the texture we use the addTexture() function.
there’s three parameters :
- id , an Id given to the texture in order to acces it later. When parsing, MMtlParser used by MObjParser will remove the extention of the image file define as texture in the mtl file,
so in order to automatically retrieve the texture associated to a mtl set , you should give the same name without extention to the iD.
- textureClass , the class used to embed the image
- withMip , a boolean value to use or not mip »mapping.
To pass directly a Bitmap to create the Texture use addTextureFromBitmap() function.
To get the Texture we then can use the getTextureById(id:String):Texture function.
that’s all.
This is done from line 111 to line 117 :
_textureManager.addTexture("WHITEW~1",_texture0Class); _textureManager.addTexture("BUICKB~2",_texture1Class); _textureManager.addTexture("BUICKblock",_texture2Class); _textureManager.addTexture("OldWood27BoH",_texture3Class); _textureManager.addTexture("pennplate",_texture4Class); _textureManager.addTexture("plate2", _texture6Class); _textureManager.addTexture("woodie9",_texture7Class);
in the setShader() function the shaders are defined :
private function setShaders():void { // definition and decalration of the shaders to use var shader:MPhong2LightsShader = new MPhong2LightsShader(); var textureShader:MPhong2LightsTextureShader = new MPhong2LightsTextureShader(); var writer:MVerticesBytesArrayWriter = new MVerticesBytesArrayWriter(); var textureWriter: MVerticesBytesArrayWriterWT = new MVerticesBytesArrayWriterWT(); // ShaderSets's container _shaderStore = new ShaderStore(); // a ShaderSet object contains a IMShader and a IMBytesArrayWriter var shaderSet:ShaderSet = new ShaderSet(ShaderType.DEFAULT_SHADER, shader, writer); _shaderStore.add(shaderSet); shaderSet = new ShaderSet(ShaderType.DEFAULT_TEXTURE_SHADER, textureShader, textureWriter); _shaderStore.add(shaderSet); }
In addition to the two shaders two byteArray writers are defined :
- MVerticesBytesArrayWriter
- MVerticesBytesArrayWriterWT
We have already used the first one with the previous exemple.
The second (MVerticesBytesArrayWriterWT) is another implement of IMBytesArrayWriter created for textures polygon groups.
Feel free to create implementations of this interface according to your needs.
In the setSaticConstants() we only have the ambiant light this time, as the others lights are moving.
The two other lights are now defined in the setFrameConstants().
Let’s see now the drawTriangle() function , this is here that most of the changes happen :
Remember in the pevious exemple we looped through objects and then through polygon groups.
We do the same here,
but now for each polygon group we have to choose which shader and program to use.
First we define the ambiant and specular material color as last time.
Then we check if we have a texture defined for the polygon group (line 285)
isTexture = ((mPolygonsGroup.mtlSet) && (mPolygonsGroup.mtlSet.isTexture));
If so we use the shader associated to the texture parts
shaderSet = _shaderStore.getShaderById(ShaderType.DEFAULT_TEXTURE_SHADER); //trace("getting texture " + mPolygonsGroup.mtlSet.ambiantTexture + " , " + mPolygonsGroup.mtlSet.diffuseTexture); var texture:Texture = _textureManager.getTextureById(mPolygonsGroup.mtlSet.diffuseTexture); _context3D.setTextureAt(0, texture);
and set the shader program associated as well
if(_currentProgram != shaderSet.program){ _currentProgram = shaderSet.program; _context3D.setProgram(_currentProgram); }
If there’s no texture we use the other ones (line 299 to 307).
else { //trace("no texture"); shaderSet = _shaderStore.getShaderById(ShaderType.DEFAULT_SHADER); _context3D.setTextureAt(0, null); if(_currentProgram != shaderSet.program){ _currentProgram = shaderSet.program; _context3D.setProgram(_currentProgram); } }
Because some parts also use alpha we have to manage this :
// if we have an alpha < 1 if(mPolygonsGroup.mtlSet && mPolygonsGroup.mtlSet.dissolved <1) _context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA); else _context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO);
Last thing to do ,as the two shaders don’t use the same structure, is to reset the setting of vertexBuffer :
shaderSet.shader.releaseActiveVertextBuffer(_context3D);
And that’s it !
The complete drawTriangle function :
public function drawTriangles():void { var shaderSet:ShaderSet; var nbIndex:int = 0; var iBuffer:int = 0; var buffer3D:VertexBuffer3D; var index3D:IndexBuffer3D; var object3Dset:MObject3D; var mPolygonsGroup:MPolygoneGroup3D; var polygonBufferSet :MPolygonGroupBuffers; var isTexture:Boolean; var color:Object; // ---------------------- // define the constantes wich are not dependant of groups // ---------------------- setFrameConstants(); // loop through the objects var oSize:int = _mesh.mObjects.length; for (var i:int = 0; i < oSize; i++ ) { object3Dset = _mesh.mObjects[i]; //trace("drawing object " + object3Dset.id); // if there is a shaderSet for this object if (_shaderStore.getShaderById(object3Dset.id)) { shaderSet = _shaderStore.getShaderById(object3Dset.id); } // loop through the groups var pgSize:int = object3Dset.polygonsGroups.length; for (var j:int = 0; j < pgSize; j++ ) { mPolygonsGroup = object3Dset.polygonsGroups[j]; //trace("drawing group " + mPolygonsGroup.id); // define the constantes setDefaultConstants(mPolygonsGroup.mtlSet); // if there is a shaderSet for this group if (_shaderStore.getShaderById(mPolygonsGroup.id)) { shaderSet = _shaderStore.getShaderById(mPolygonsGroup.id); } // if no shaderSet for this group or this object has been found if (!shaderSet) { isTexture = ((mPolygonsGroup.mtlSet) && (mPolygonsGroup.mtlSet.isTexture)); // set the texture if (isTexture) { shaderSet = _shaderStore.getShaderById(ShaderType.DEFAULT_TEXTURE_SHADER); //trace("getting texture " + mPolygonsGroup.mtlSet.ambiantTexture + " , " + mPolygonsGroup.mtlSet.diffuseTexture); var texture:Texture = _textureManager.getTextureById(mPolygonsGroup.mtlSet.diffuseTexture); _context3D.setTextureAt(0, texture); //trace("setting program " + shaderSet.program + "from : " + shaderSet.id); if(_currentProgram != shaderSet.program){ _currentProgram = shaderSet.program; _context3D.setProgram(_currentProgram); } } else { //trace("no texture"); shaderSet = _shaderStore.getShaderById(ShaderType.DEFAULT_SHADER); _context3D.setTextureAt(0, null); if(_currentProgram != shaderSet.program){ _currentProgram = shaderSet.program; _context3D.setProgram(_currentProgram); } } } // if we have an alpha < 1 if(mPolygonsGroup.mtlSet && mPolygonsGroup.mtlSet.dissolved <1) _context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA); else _context3D.setBlendFactors(Context3DBlendFactor.ONE, Context3DBlendFactor.ZERO); // loop through the buffers var pbSize:int = mPolygonsGroup.polygonBufferSet.length; for (var k:int = 0; k < pbSize; k++ ) { polygonBufferSet = mPolygonsGroup.polygonBufferSet[k]; buffer3D = polygonBufferSet.vertexBuffer; index3D = polygonBufferSet.indexBuffer; shaderSet.shader.setActiveVertextBuffer(_context3D, buffer3D); //trace("drawing triangles "); _context3D.drawTriangles(index3D, 0, -1); } if(shaderSet) shaderSet.shader.releaseActiveVertextBuffer(_context3D); shaderSet = null; } if(shaderSet) shaderSet.shader.releaseActiveVertextBuffer(_context3D); shaderSet = null; } }
We’ve seen how to use one shader, then two,
now in the next exemple wee’ll hox to use as many shaders as we want.
Go to next exemple
Any questions, any comments, don’t hesitate !