用c#进行directx 3D编程:实现texture贴图的alpha通道

接触directX 3D已经有1个多月了。自己做的一个三维控件终于完成,不过还有些让人头痛的bug来修改.今天给大家写的是是现在3d里的texture贴图,并实现了其半透明效果。

在这个例子里,我绘制了一个矩形,贴上了一张带alpha通道的图片,并绘制了一个三角形,透过贴图可以看到此三角形。

例子的效果图如下:

用到的图片pic.bmp如下:

一,首先保证你机子上装了directx,没装的赶紧下载去装。

二,建立一个c#的windows应用程序,添加两个引用Microsoft.DirectX和Microsoft.DirectX.Direct3D;

三,form1.cs中代码为:

//--------------------------------------------------------
//  Copyright (C), 2000-2008, 黄博文(flysky).
//  Author: flysky      Version: 1.0        Date: 2008-8-13
//  Description: 实现维里的texture贴图,并实现了贴图的aplpha通道
//  Others:  主要绘制了一个矩形,并在此矩形上贴上一张半透明的图片,透过此贴图可以看到后面的三角形
//--------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.IO;

namespace TextureTest
{
    public partial class Form1 : Form
    {
        //绘图设备
        Device device = null;

        //材质
        Microsoft.DirectX.Direct3D.Texture texture;

        //要贴图的矩形框
        VertexBuffer rectangleVertexBuffer = null;

        //做映衬的三角形
        VertexBuffer triangleVertexBuffer = null;
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 初始化绘制by flysky
        /// </summary>
        /// <returns></returns>
        public bool InitializeGraphics()
        {
            try
            {
                // Now let's setup our D3D stuff
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed = true;
                presentParams.SwapEffect = SwapEffect.Discard;
                presentParams.EnableAutoDepthStencil = true;
                presentParams.AutoDepthStencilFormat = DepthFormat.D16;

                device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
                device.RenderState.ZBufferEnable = true;

                InitVertexBuffer();

                device.DeviceReset += new System.EventHandler(this.OnResetDevice);
                device.DeviceResizing += new CancelEventHandler(this.CancelResize);
                this.OnResetDevice(device, null);

               
                return true;
            }
            catch (DirectXException)
            {
                return false;
            }
        }

        /// <summary>
        /// 重置设备
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnResetDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            dev.RenderState.CullMode = Cull.None;

            //从文件中加载材质(大家可以选取其他的图片来比较效果,如果要实现半透明的话图片本身要是带alpha通道的)
            texture = TextureLoader.FromFile(dev, Application.StartupPath + @"\pic.bmp");
       
        }

        /// <summary>
        /// 尺寸大小改变
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CancelResize(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
        }

        /// <summary>
        /// 初始化顶点缓冲by flysky 2008-8-13
        /// </summary>
        private void InitVertexBuffer()
        {
            //初始化要贴图的矩形框顶点数据
            rectangleVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), 6, device, 0, CustomVertex.PositionNormalTextured.Format, Pool.Default);

            //构造个点,以构成贴图的矩形表面
            CustomVertex.PositionNormalTextured[] verts = (CustomVertex.PositionNormalTextured[])rectangleVertexBuffer.Lock(0, 0);

            //设置每个点的位置,法线,和Tu,Tv分量.Tu分量是贴图的宽度位置(将贴图的整个宽度看做为,Tu取值在和之间),Tv分量是选取贴图的高度位置(将贴图的整个高度看做为,Tv取值在和之间)
            verts[0].Position = new Vector3(-20, -20, -20);
            verts[0].Normal = new Vector3(-20, -20, -21);
            verts[0].Tu = 0.0f;
            verts[0].Tv = 1.0f;

            verts[1].Position = new Vector3(-20, 20, -20);
            verts[1].Normal = new Vector3(-20, 20, -21);
            verts[1].Tu = 0.0f;
            verts[1].Tv = 0.0f;

            verts[2].Position = new Vector3(20, 20, -20);
            verts[2].Normal = new Vector3(20, 20, -21);
            verts[2].Tu = 1.0f;
            verts[2].Tv = 0.0f;

            verts[3].Position = new Vector3(20, -20, -20);
            verts[3].Normal = new Vector3(20, -20, -21);
            verts[3].Tu = 1.0f;
            verts[3].Tv = 1.0f;

            verts[4].Position = new Vector3(-20, -20, -20);
            verts[4].Normal = new Vector3(-20, -20, -21);
            verts[4].Tu = 0.0f;
            verts[4].Tv = 1.0f;

            verts[5].Position = new Vector3(20, 20, -20);
            verts[5].Normal = new Vector3(20, 20, -21);
            verts[5].Tu = 1.0f;
            verts[5].Tv = 0.0f;

            rectangleVertexBuffer.Unlock();

           //初始化做映衬的三角形的顶点数据
            triangleVertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), 3, device, 0, CustomVertex.PositionColored.Format, Pool.Default);
            CustomVertex.PositionColored[] vertxs = (CustomVertex.PositionColored[])triangleVertexBuffer.Lock(0, 0);
            vertxs[0].Position = new Vector3(-10, -10, 0);
            vertxs[1].Position = new Vector3(-10, 10, 0);
            vertxs[2].Position = new Vector3(10, 10, 0);
            for (int i = 0; i < 3; i++)
            {
                vertxs[i].Color = Color.Red.ToArgb();
            }
            triangleVertexBuffer.Unlock();
        }

        public void Render()
        {
            if (device == null)
                return;

            device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, System.Drawing.Color.Blue, 1.0f, 0);

            SetupCamera();
            device.BeginScene();

            device.RenderState.Lighting = false;

            device.SetStreamSource(0, triangleVertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

            //开启设备的alpha通道,设置混合模式
            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.DestinationBlend = Blend.InvSourceAlpha;

            //设置材质
              device.SetTexture(0, texture);

            //设置材质的属性
            device.TextureState[0].ColorOperation = TextureOperation.Modulate;
            device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;

            //设置材质的alpha通道属性
            device.TextureState[0].AlphaOperation = TextureOperation.Modulate;
            device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
            device.TextureState[0].AlphaArgument2 = TextureArgument.Diffuse;

            device.SetStreamSource(0, rectangleVertexBuffer, 0);
            device.VertexFormat = CustomVertex.PositionNormalTextured.Format;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);

            //将材质置空并关闭alpha通道
            device.SetTexture(0, null);
            device.RenderState.AlphaBlendEnable = false;


            device.EndScene();
            device.Present();
        }

        //重载绘制函数
        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            this.Render(); // Render on painting
        }

        /// <summary>
        /// 设置摄像机的位置
        /// </summary>
        private void SetupCamera()
        {
            //设置世界矩阵,根据系统运行时间而变化
            device.Transform.World = Matrix.RotationX((float)Math.Sin(Environment.TickCount / 1000.0f));
            //设置摄像机的位置,它在z轴上-50处,看着原点,y轴为正方向
            device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 0.0f, -50f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));

            //设置摄像机的视界,角度为度,看的最近为,看的最远处为.不再这个视界中的影像都不会被显示
            device.Transform.Projection = Matrix.PerspectiveFovLH(((float)(float)Math.PI / 2), 1.0f, 10.0f, 200.0f);
        }

    }
}

四,program.cs中的代码为:

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace TextureTest
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            using (Form1 frm = new Form1())
            {
                if (!frm.InitializeGraphics()) // Initialize Direct3D
                {
                    MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");
                    return;
                }
                frm.Show();

                // While the form is still valid, render and process messages
                while (frm.Created)
                {
                    frm.Render();
                    Application.DoEvents(); //处理当前在消息队列中的所有 Windows 消息
                }
            }
        }
    }
}

这个例子的参考价值还是很高的哦,大家要看仔细。

原文地址:https://www.cnblogs.com/top5/p/1584955.html