游戏中的捏脸系统

本文介绍了游戏中的捏脸系统实现方式,包括骨骼动画和变形动画两种技术。骨骼动画通过绑定骨骼到面部网格实现脸部细节调整;变形动画则通过混合极端模型参数生成新的面部形状。此外,还讨论了面部纹理的捏制以及如何使用语音控制口型动画。代码段展示了编辑器中相关功能的实现,包括时间线操作、属性编辑和图形渲染等。
摘要由CSDN通过智能技术生成

        游戏中的捏脸系统一般有两种实现方式,一种是用骨骼动画来实现,另一种是使用变形动画(morph)来实现。
        用骨骼动画实现捏脸要求在面部每个细节部位绑定若干骨骼,通过移动骨骼带动面部网格顶点移动,网格顶点的移动再反馈到另外一套用于表情动画的骨骼蒙皮中。
        用变形动画实现捏脸要求先制作若干极端情况下的脸型模型,通过调节参数(权重)来混合这些极端模型,产生新的面部网格顶点。面部网格顶点生成后可以反馈到骨骼蒙皮中用于表情动画,也可以继续使用变形动画的方式和代表表情的极端模型相混合来产生表情动画。

        关于使用变形动画方式实现时如何生成极端情况下的脸型模型,通过观察原始数据可知,每个极端模型长相如同妖魔鬼怪毫无规律可言,让美术人员直接制作估计是不现实的。
        所以首先要确定好各调节参数之间的联动关系,比如将嘴部变宽时,下颌和鼻子底部也会相应的变宽。第二步美术人员制作单一参数下的极端模型。第三步联立方程组,将模型看做未知数,使用算法求解出图示的妖魔鬼怪极端模型。最后检验和微调。
    
         捏脸的另一种表现形式是捏制面部纹理,比如眉毛胡子的浓淡、嘴唇颜色、眉毛高低等,这些并不需要网格模型做变动,仅通过变化纹理即可实现。纹理的捏制和变形动画类似,也是通过若干极端状态下的纹理根据参数混合而来。
     
        关于使用语音控制口型动画,先将语音转换成对应的音节流,比如借助开源项目rhubarb-lip-sync导出口型数据,然后key出表情帧即可。
    

 

 

编辑器部分代码:

class CtrlFile;
class FimFile;
class TrigonFile;
class Express;
class FgFile;
class ExpressFrameHead;
class ExpressFrameLine;
class FaceEditorGui:public EditorDlgBase
{
public:
	FaceEditorGui();
	~FaceEditorGui();
	virtual bool OnWake();
	virtual bool OnSleep();
	virtual const char* GetTypeName();
	static  const char* DlgName();
	virtual void        Update();
	virtual void        Render();
	virtual bool ProcButtonUp       (GuiButtonCtrl    *ctrl);
	virtual bool ProcButtonDown     (GuiButtonCtrl    *ctrl);
	virtual bool ProcProgressUpdate (GuiProgressBarCtrl*ctrl);
	virtual bool ProcDragIconUp     (GuiDragIconCtrl  *ctrl);
	virtual bool ProcTabUp          (GuiTabCtrl       *ctrl);
	virtual bool ProcKeyUp          (int key);
	//virtual bool OnDropFiles(int filenum,/*const*/ char** filenames);

	virtual void OpenFile(const char* fileName,bool listFile=false);
	virtual void SaveFile(const char* fileName);

private:
	int  OnTimeLine_LeftDown(const char* args);
	int  OnTimeLine_RightDown(const char* args);
	int  OnTimeLine_Event(const char* args);
	void OnRightMenu(const char* args);

	void PropertyFaceGeo(bool bSend=true);
	void PropertyFaceTex(bool bSend=true);
	void PropertyFaceExpress(bool bSend=true);

	void RandomPropertyFaceGeo();
	void RandomPropertyFaceTex();
	void RandomPropertyFaceExpress();
	void ZeroPropertyFaceGeo();
	void ZeroPropertyFaceTex();
	void ZeroPropertyFaceExpress();

	void ReGenGeo();
	void ReGenTex();

//private:
public:
	GuiTabCtrl*         m_tabFacegen;
	GuiControl*         m_ctrlCanvans;
	RectF               m_rectCanvans;
	TexturePtr          m_texCanvans;

	CtrlFile*    m_ctlFile;
	FimFile*     m_fimFile;
#define TestTrigonFileNum 8
	TrigonFile*  m_trigonFile[TestTrigonFileNum];
	Express*     m_express;
	Express*     m_animExpress;
	FgFile*      m_fgFile;

	//动画
	ExpressFrameLine* m_frameLine;
	ExpressFrameHead* m_frameHead;

	//遗传
	FgFile*      m_fgFileInherit[8];

	//变形
	FgFile*      m_fgFileMorph[3];

	//照片适配

};


//========================================================
//  @Date:     2016.05
//  @File:     SourceLib/Gui/FaceEditorGui.cpp
//  @Brief:     FaceEditorGui
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================
 
#include "General/Pch.h"
#include "General/General.h"
#include "General/StringUtil.h"
#include "General/CallBack.h"
#include "General/Window.h"
#include "General/Option.h"
#include "Gui/GuiControlMisc.h"
#include "Gui/GuiDialogMisc.h"
#include "Gui/GuiMgr.h"
#include "Render/Camera.h"
#include "Render/MC_Misc.h"
#include "Render/RendDriver.h"
#include "Render/FaceGen.h"
#include "General/Pce.h"

using namespace RendSys;

FaceEditorGui::FaceEditorGui()
{
}

FaceEditorGui::~FaceEditorGui()
{
}

bool FaceEditorGui::OnWake()
{
	EditorDlgBase::OnWake();
	SubCtrlState("Menu.combox_view.contentGroup.menu_propertybox",GCS_CLICK);

	MAPCTRL(m_tabFacegen,"splitFrameAll.EditPannel.tableFacegen");
	MAPCTRL(m_propertyBox ,"splitFrameAll.EditPannel.scrollBar_property.contentGroup.list_ctrlBox");
	MAPCTRL(m_timeline    ,"timeLine");
	MAPCTRL(m_ctrlCanvans,"splitFrameAll.EditCanvans");

	G_TextureMgr->AddTexture(m_texCanvans,"data/gui/editorgui/paintBack.png");

	if (m_timeline)
	{
		m_timeline->CallBack()->Add("MouseDown","",this,&FaceEditorGui::OnTimeLine_LeftDown);
		m_timeline->CallBack()->Add("RightMouseDown","",this,&FaceEditorGui::OnTimeLine_RightDown);
		m_timeline->CallBack()->Add("TimeLineEvent","",this,&FaceEditorGui::OnTimeLine_Event);
	}

	SubCtrlVisible("toolbaricon_play.play",true);
	SubCtrlVisible("toolbaricon_play.pause",false);
	//==================^_^
	CameraCtrlerTarget* ctrler = new CameraCtrlerTarget;
	ctrler->SetDistToTar(300);
	ctrler->SetTarPos(vec3(0,0,0));
	G_Camera->PushCtrler(ctrler);
	G_Camera->SetEuler(0,-30,0);
	//==================^_^

	m_ctlFile = new CtrlFile;
	m_fimFile = new FimFile;
	for (int i=0;i<TestTrigonFileNum;i++)
	{
		m_trigonFile[i] = new TrigonFile;
	}
	m_express = new Express;
	m_animExpress = new Express;
	m_fgFile = new FgFile;

	//动画
	m_frameHead = new ExpressFrameHead(NULL);
	m_frameLine = new ExpressFrameLine;

	m_ctlFile->LoadFromFile("data/。。。");
	m_fimFile->LoadFromFile("data/。。。");

	m_fgFile->LoadFromFile("data/。。。");

	//m_trigonFile[0]->LoadFromFile("data/。。。");
	//m_trigonFile[0]->LoadFromFile("data/。。。");
	m_trigonFile[0]->LoadFromFile("data/。。。");
	m_trigonFile[1]->LoadFromFile("data/。。。");
	m_trigonFile[2]->LoadFromFile("data/。。。");
	m_trigonFile[3]->LoadFromFile("data/。。。");
	m_trigonFile[4]->LoadFromFile("data/。。。");
	m_trigonFile[5]->LoadFromFile("data/。。。");
	m_trigonFile[6]->LoadFromFile("data/。。。");
	m_trigonFile[7]->LoadFromFile("data/。。。");

	for (int i=0;i<TestTrigonFileNum;i++)
	{
		m_trigonFile[i]->GenTex(m_fgFile);
		m_trigonFile[i]->GenMesh(m_fgFile);
	}

	PropertyFaceGeo();

	{
		//自动产生表情
		int ExpressNum = 40;
		m_frameLine->m_keyFrameNum = ExpressNum*2;
		m_frameLine->m_maxTimeFrame = m_frameLine->m_keyFrameNum*30;
		m_frameLine->m_keyFrames = new ExpressFrame[ExpressNum*2];

		for (int i=0;i<ExpressNum*2;i++)
		{
			m_frameLine->m_keyFrames[i].m_timeFrame = i*30;
		}
		for (int i=0;i<ExpressNum;i++)
		{
			ExpressFrame* frame = &m_frameLine->m_keyFrames[i*2+1];
			frame->m_express.m_differenceMorphWeights[i] = 1500;
		}

		m_frameHead->SetFrameLine(m_frameLine);
		m_frameHead->SetPause(true);

		m_timeline->SetEditFrameLine(m_frameLine);
		m_timeline->SetEditPlayHead(m_frameHead);
	}

	return true;
}

bool FaceEditorGui::OnSleep()
{
	G_Camera->PopCtrler();
	SafeDelete(m_ctlFile);
	SafeDelete(m_fimFile);
	for (int i=0;i<TestTrigonFileNum;i++)
	{
		SafeDelete(m_trigonFile[i]);
	}
	SafeDelete(m_express);
	SafeDelete(m_animExpress);
	SafeDelete(m_fgFile);
	SafeDelete(m_frameHead);
	SafeDelete(m_frameLine);
	return true;
}


void FaceEditorGui::OpenFile(const char* fileName,bool listFile)
{
	if (fileName==NULL || strlen(fileName)>=MAX_PATH)
	{
		return;
	}
	m_fileName = fileName;
}


void FaceEditorGui::SaveFile(const char* fileName)
{

}


//timeline自处理右键 回传:创建、清除、拷贝、剪切、粘贴关键帧(空白关键帧、补间、标签、动作)信息?
int  FaceEditorGui::OnTimeLine_LeftDown(const char* args)
{
	int frameStart, frameEnd;
	m_timeline->GetSelectedFrame(frameStart, frameEnd);
	m_frameHead->GotoFrame(frameStart);
	m_frameHead->SetPause(true);
	SubCtrlVisible("toolbaricon_play.play",true);
	SubCtrlVisible("toolbaricon_play.pause",false);
	char buf[256];
	sprintf(buf,"frame%d - %d",frameStart,frameEnd);
	m_statusText->SetText(buf);
	return 0;
}

int  FaceEditorGui::OnTimeLine_RightDown(const char* args)
{
	//RightMenu* rightMenu = G_GuiMgr->GetGui<RightMenu>();
	//G_GuiMgr->PushGui(rightMenu,GL_DIALOG);
	//if (rightMenu)
	//{rightMenu->ClearMenu();
	//	rightMenu->CallBack()->EraseParmCommand("onButtonDown");
	//	rightMenu->CallBack()->Add("onButtonDown","",this,&SceneEditorGui::OnRightMenu);
	//	rightMenu->AddMenu("cut",M2U("剪切(T)").c_str())
	//		->AddMenu("copy",M2U("拷贝(C)").c_str())
	//		->AddMenu("paste",M2U("粘贴(P)").c_str())
	//		->AddMenu("undo",M2U("撤销(U)").c_str())
	//		->AddMenu("refresh",M2U("刷新(E)").c_str())
	//		->AddMenu("property",M2U("属性(R)").c_str());
	//	rightMenu->AdjustRect();
	//}
	return 0;
}
int  FaceEditorGui::OnTimeLine_Event(const char* args)
{
	GuiTimeLineCtrl::Event* event_ = (GuiTimeLineCtrl::Event*)args;
	//	char buf[256];
	//	sprintf(buf,"key%d - %d",keyStart,keyEnd);
	m_statusText->SetText(event_->dsc.c_str());
	return 0;
}

void FaceEditorGui::OnRightMenu(const char* args)
{
	String name = args;
	if (name == "cut")
	{
	}
	else if (name == "copy")
	{
	}
}

bool FaceEditorGui::ProcKeyUp(int key)
{
	EditorDlgBase::ProcKeyUp(key);
	return false;
}


bool FaceEditorGui::ProcButtonDown(GuiButtonCtrl* ctrl)
{
	if (!ctrl)
	{
		return true;
	}
	EditorDlgBase::ProcButtonDown(ctrl);
	//String path = ctrl->GetPath();
	String name = ctrl->GetIdName();
	if (name == "menu_new")
	{

	}
	else if (name == "menu_undo")
	{
	}
	else if (name == "ApplyProperty")
	{
		if (m_tabFacegen->GetCheckPos()==0)
		{
			PropertyFaceGeo(false);
		}
		else if (m_tabFacegen->GetCheckPos()==1)
		{
			PropertyFaceTex(false);
		}
		else if (m_tabFacegen->GetCheckPos()==2)
		{
			PropertyFaceExpress(false);
		}
	}	
	else if (name == "menu_propertybox")
	{
		GuiGroupCtrl* menu;
		MAPCTRL(menu,"Menu");
		if (ctrl->IsChildOf(menu))
		{
			bool visible = ctrl->GetState() == GCS_CLICK;
			SubCtrlVisible("splitFrameAll.EditPannel.scrollBar_property",visible);
		}
	}
	else if (name == "randomProperty")
	{
		if (m_tabFacegen->GetCheckPos()==0)
		{
			RandomPropertyFaceGeo();
		}
		else if (m_tabFacegen->GetCheckPos()==1)
		{
			RandomPropertyFaceTex();
		}
		else if (m_tabFacegen->GetCheckPos()==2)
		{
			RandomPropertyFaceExpress();
		}
	}
	else if (name == "zeroProperty")
	{
		if (m_tabFacegen->GetCheckPos()==0)
		{
			ZeroPropertyFaceGeo();
		}
		else if (m_tabFacegen->GetCheckPos()==1)
		{
			ZeroPropertyFaceTex();
		}
		else if (m_tabFacegen->GetCheckPos()==2)
		{
			ZeroPropertyFaceExpress();
		}
	}
	return true;
}

bool FaceEditorGui::ProcButtonUp(GuiButtonCtrl* ctrl)
{
	return true;
}

bool FaceEditorGui::ProcTabUp(GuiTabCtrl *ctrl)
{
	int curRadio = ctrl->GetCheckPos();
	if (curRadio == 0)
	{
		m_propertyBox->SetVisible(true);
		PropertyFaceGeo();
	}
	else if (curRadio == 1)
	{
		m_propertyBox->SetVisible(true);
		PropertyFaceTex();
	}
	else if (curRadio == 2)
	{
		m_propertyBox->SetVisible(true);
		PropertyFaceExpress();
	}
	else if (curRadio == 3)
	{
		m_propertyBox->SetVisible(false);
		PropertyFaceGeo();
	}
	else if (curRadio == 4)
	{
		m_propertyBox->SetVisible(false);
		PropertyFaceTex();
	}
	else if (curRadio == 5)
	{
		m_propertyBox->SetVisible(false);
		PropertyFaceExpress();
	}
	return true;
}

bool FaceEditorGui::ProcProgressUpdate(GuiProgressBarCtrl* ctrl)
{
	String name = ctrl->GetIdName();
	//if (name == "button_pause")
	{
		//
		if (m_tabFacegen->GetCheckPos()==0)
		{
			//PropertyFaceGeo(false);
			float pos = (ctrl->GetPos()-0.5f)*20000;
			m_ctlFile->ChangeLenearCtrlPos(m_propertyBox->GetCurItem(),pos,m_fgFile,CtrlFile::LGS);
			PropertyFaceGeo(true);
			ReGenGeo();
		}
		else if (m_tabFacegen->GetCheckPos()==1)
		{
			//PropertyFaceTex(false);
			float pos = (ctrl->GetPos()-0.5f)*20000;
			m_ctlFile->ChangeLenearCtrlPos(m_propertyBox->GetCurItem(),pos,m_fgFile,CtrlFile::LTS);
			PropertyFaceTex(true);
			ReGenTex();
		}
		else if (m_tabFacegen->GetCheckPos()==2)
		{
			PropertyFaceExpress(false);
			//float pos = (ctrl->GetPos()-0.5f)*20000;
			//m_express->ChangeLenearCtrlPos(m_propertyBox->GetCurItem(),pos,&m_fgFile,CtrlFile::LGS);
			//PropertyFaceExpress(true);
			//ReGenGeo();
		}
	}
	return true;
}

bool FaceEditorGui::ProcDragIconUp(GuiDragIconCtrl* ctrl)
{
	if (!ctrl)
	{
		return true;
	}
	EditorDlgBase::ProcDragIconUp(ctrl);
	String path = ctrl->GetPath();
	String name = ctrl->GetIdName();
	if(strstr(path.c_str(),"toolbaricon0"))
	{

	}
	else if (strstr(path.c_str(),"toolbaricon_play"))
	{
		if (m_timeline)
		{
			m_timeline->ProcDragIconUp(ctrl);
		}
	}
	return true;
}

void FaceEditorGui::PropertyFaceGeo(bool bSend)
{
	if (m_propertyBox)
	{
		m_ctlFile->CaculLinearCtrlPos(m_fgFile,CtrlFile::LGS);
		ListItemUpdater updater;
		updater.BeginUpdateItem(m_propertyBox,bSend,m_ctlFile->m_linearCtrlsGSNum);
		int i = 0;
		//for(int m=0;m<m_fgFile->m_symmetricGeoMorphNum;m++)
		//{
		//	//?不是对应的
		//	float temp = m_fgFile->m_symmetricGeoMorphWeights[m];
		//	updater.UpdateItem(i,m_ctlFile->m_linearCtrlsLGS[m%m_ctlFile->m_linearCtrlsGSNum].label.dsc,temp,-10000.0f,10000.0f);    i++;
		//	if (bSend==false)
		//	{
		//		m_fgFile->m_symmetricGeoMorphWeights[m] = temp;
		//	}
		//}
		for(int l=0;l<m_ctlFile->m_linearCtrlsGSNum;l++)
		{
			float temp = m_ctlFile->m_curLinearCtrlsPos[l];
			updater.UpdateItem(i,m_ctlFile->m_linearCtrlsLGS[l].label.dsc,temp,-10000.0f,10000.0f);    i++;
			if (bSend==false)
			{
				m_ctlFile->m_curLinearCtrlsPos[l] = temp;
			}
		}

		if (bSend==false)
		{
			ReGenGeo();
		}
	}
}


void FaceEditorGui::ReGenGeo()
{
	for (int i=0;i<TestTrigonFileNum;i++)
	{
		m_trigonFile[i]->GenMesh(m_fgFile);
		//重置表情
		m_trigonFile[i]->GenMesh(m_express);
	}
}


void FaceEditorGui::ReGenTex()
{
	for (int i=0;i<TestTrigonFileNum;i++)
	{
		m_trigonFile[i]->GenTex(m_fgFile);
	}

}

void FaceEditorGui::ZeroPropertyFaceGeo()
{
	if (m_propertyBox)
	{
		for (int d=0;d<m_fgFile->m_symmetricGeoMorphNum;d++)
		{
			m_fgFile->m_symmetricGeoMorphWeights[d] = 0;
		}
		PropertyFaceGeo(true);
		ReGenGeo();
	}
}
void FaceEditorGui::RandomPropertyFaceGeo()
{
	if (m_propertyBox)
	{
		for (int d=0;d<m_fgFile->m_symmetricGeoMorphNum;d++)
		{
			m_fgFile->m_symmetricGeoMorphWeights[d] = RandRange(-10000.0f,10000.0f);
		}
		PropertyFaceGeo(true);
		ReGenGeo();
	}
}
void FaceEditorGui::PropertyFaceTex(bool bSend)
{
	if (m_propertyBox)
	{
		m_ctlFile->CaculLinearCtrlPos(m_fgFile,CtrlFile::LTS);
		ListItemUpdater updater;
		updater.BeginUpdateItem(m_propertyBox,bSend,m_ctlFile->m_linearCtrlsTSNum);
		int i = 0;
		//for(int m=0;m<m_fgFile->m_symmetricTexMorphNum;m++)
		//{
		//	//?不是对应的
		//	float temp = m_fgFile->m_symmetricTexMorphWeights[m];
		//	updater.UpdateItem(i,m_ctlFile->m_linearCtrlsLTS[m%m_ctlFile->m_linearCtrlsTSNum].label.dsc,temp,-1000.0f,1000.0f);    i++;
		//	if (bSend==false)
		//	{
		//		m_fgFile->m_symmetricTexMorphWeights[m] = temp;
		//	}
		//}
		for(int l=0;l<m_ctlFile->m_linearCtrlsTSNum;l++)
		{
			float temp = m_ctlFile->m_curLinearCtrlsPos[l];
			updater.UpdateItem(i,m_ctlFile->m_linearCtrlsLTS[l].label.dsc,temp,-10000.0f,10000.0f);    i++;
			if (bSend==false)
			{
				m_ctlFile->m_curLinearCtrlsPos[l] = temp;
			}
		}

		if (bSend==false)
		{
			ReGenTex();
		}
	}
}

void FaceEditorGui::ZeroPropertyFaceTex()
{
	if (m_propertyBox)
	{
		for (int d=0;d<m_fgFile->m_symmetricTexMorphNum;d++)
		{
			m_fgFile->m_symmetricTexMorphWeights[d] = 0;
		}
		PropertyFaceTex(true);
		ReGenTex();
	}
}
void FaceEditorGui::RandomPropertyFaceTex()
{
	//if (m_propertyBox)
	//{
	//	bool bSend = true;
	//	ListItemUpdater updater;
	//	updater.BeginUpdateItem(m_propertyBox,bSend);
	//	int i = 0;
	//	for(int m=0;m<m_fgFile->m_symmetricTexMorphNum;m++)
	//	{
	//		float temp = RandRange(-1000.0f,1000.0f);
	//		updater.UpdateItem(i,m_ctlFile->m_linearCtrlsLTS[m%m_ctlFile->m_linearCtrlsTSNum].label.dsc,temp,-1000.0f,1000.0f);    i++;
	//	}

	//	m_ctlFile->CaculFg(&m_fgFile,CtrlFile::LTS);
	//	ReGenTex();
	//}
	if (m_propertyBox)
	{
		for (int d=0;d<m_fgFile->m_symmetricTexMorphNum;d++)
		{
			m_fgFile->m_symmetricTexMorphWeights[d] = RandRange(-10000.0f,10000.0f);
		}
		PropertyFaceTex(true);
		ReGenTex();
	}
}

void FaceEditorGui::PropertyFaceExpress(bool bSend)
{
	if (m_propertyBox)
	{
		ListItemUpdater updater;
		updater.BeginUpdateItem(m_propertyBox,bSend,m_trigonFile[0]->m_expressMorphNum);
		int i = 0;
		for(int m=0;m<m_trigonFile[0]->m_expressMorphNum;m++)
		{
			float temp = m_express->m_differenceMorphWeights[m];
			updater.UpdateItem(i,m_trigonFile[0]->m_expressMorph[m].label.dsc,temp,-100.0f,1000.0f);    i++;
			if (bSend==false)
			{
				m_express->m_differenceMorphWeights[m] = temp;
			}
		}

		if (bSend==false)
		{
			for (int i=0;i<TestTrigonFileNum;i++)
			{
				m_trigonFile[i]->GenMesh(m_express);
			}
		}
	}
}
void FaceEditorGui::ZeroPropertyFaceExpress()
{
	if (m_propertyBox)
	{
		bool bSend = true;
		ListItemUpdater updater;
		updater.BeginUpdateItem(m_propertyBox,bSend,m_trigonFile[0]->m_expressMorphNum);
		int i = 0;
		for(int m=0;m<m_trigonFile[0]->m_expressMorphNum;m++)
		{
			float temp = 0;
			updater.UpdateItem(i,m_trigonFile[0]->m_expressMorph[m].label.dsc,temp,-100.0f,1000.0f);    i++;
		}
		ReGenGeo();
	}
}
void FaceEditorGui::RandomPropertyFaceExpress()
{
	if (m_propertyBox)
	{
		bool bSend = true;
		ListItemUpdater updater;
		updater.BeginUpdateItem(m_propertyBox,bSend,m_trigonFile[0]->m_expressMorphNum);
		int i = 0;
		for(int m=0;m<m_trigonFile[0]->m_expressMorphNum;m++)
		{
			float temp = RandRange(-100.0f,1000.0f);
			updater.UpdateItem(i,m_trigonFile[0]->m_expressMorph[m].label.dsc,temp,-100.0f,1000.0f);    i++;
		}

		PropertyFaceExpress(false);
	}
}


void FaceEditorGui::Update()
{
	PROFILEFUN("FaceEditorGui::Update;",0.0f,ALWAYSHIDE);

	m_rectCanvans = m_ctrlCanvans->GetRectReal();
	vec2 off   = m_ctrlCanvans->GetOffset();
	m_rectCanvans.x += off.x;
	m_rectCanvans.y += off.y;

	//
	if (m_frameHead->IsPause()==false)
	{
		m_frameHead->Advance(-1);
		for (int i=0;i<TestTrigonFileNum;i++)
		{
			m_trigonFile[i]->GenMesh(&m_frameHead->m_mixFrame.m_express);
		}
	}
} 

void FaceEditorGui::Render()
{
	PROFILEFUN("FaceEditorGui::Render;",0.0f,ALWAYSHIDE);

	if (G_Option->m_renderTargetEnable)
	{
		G_RendDriver->GetRenderTarget(GuiTarget)->EndTarget();
		G_RendDriver->GetRenderTarget(SceneTarget)->BeginTarget();
		G_RendDriver->GetDepthBuffer(GuiDepthBuffer)->BeginBuffer();
		G_RendDriver->RendClear(RS_COLOR_BUFFER_BIT|RS_DEPTH_BUFFER_BIT|RS_STENCIL_BUFFER_BIT,Color(0.0f, 0.0f, 0.0f, 1.0f));
	}

	G_RendDriver->Color3f(1,1,1);
	G_RendDriver->ClearClipRect();
	m_texCanvans->Bind();
	G_RendDriver->RendTextureRect(m_rectCanvans);

	//float width = (G_Window->m_iWidth - rect.width)/2; //旋转将不在以模型为中心
	//G_Camera->SetTarPos(vec3(width*1,0,0));

	G_RendDriver->EndUI();
	G_RendDriver->SetViewPortf(m_rectCanvans.x/G_Window->m_iWidth,
		m_rectCanvans.y/G_Window->m_iHeight,
		m_rectCanvans.width /G_Window->m_iWidth,
		m_rectCanvans.height/G_Window->m_iHeight);
	G_RendDriver->Perspective();
	G_RendDriver->DefaultLight();
	G_RendDriver->SetRenderStateEnable(RS_LIGHT0,true);
	G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,false);
	G_RendDriver->BlendFunc(RS_SRC_ALPHA, RS_ONE_MINUS_SRC_ALPHA);
	G_RendDriver->Color3f(1,1,1);
	for (int i=0;i<TestTrigonFileNum;i++)
	{
		//if(i==3) continue;//m_trigonEyeGlasses.Rend();
		if (i==1)
		{
			G_RendDriver->DepthMask(false);
		}
		else
		{
			G_RendDriver->DepthMask(true);
		}
		m_trigonFile[i]->Rend();
	}
	G_RendDriver->SetViewPortf(0,0,1,1);
	if (G_Option->m_renderTargetEnable)
	{
		G_RendDriver->GetRenderTarget(SceneTarget)->EndTarget();
		G_RendDriver->GetRenderTarget(GuiTarget)->BeginTarget();
	}

	G_RendDriver->SetRenderStateEnable(RS_DEPTH_TEST,false);
	G_RendDriver->SetRenderStateEnable(RS_LIGHT0,false);
	G_RendDriver->SetRenderStateEnable(RS_TEXTURE_2D,true);
	G_RendDriver->BeginUI();
	GuiGroupCtrl::Render();
} 
const char* FaceEditorGui::GetTypeName()
{
	return "GuiGroupCtrl";
}
const char* FaceEditorGui::DlgName()
{
	return "FaceEditorGui";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值