(Unity) How to bake data (Vector3 and Color32) onto render textures? - unity3d

With the recent introduction of VFX Graph, attribute maps are being used to 'Set Position/Color from Map'.
In order to get an attribute map, one must bake position and color data into render textures. But there is no reference to how to do this that I could find or even on the Unity docs.
Any help on how to do this will be appreciated!

Most of the time you would want to use a Compute Shader to bake a list of points into your textures. I'd suggest you check these repositories for reference:
Bake Skinned Mesh Renderer Data into textures
https://github.com/keijiro/Smrvfx
Bake Kinect data into textures
https://github.com/roelkok/Kinect-VFX-Graph
Bake pointcloud data into texture:
https://github.com/keijiro/Pcx
Personally, I'm using these scripts which work for my purpose though I'm no expert in Compute Shaders:
public class FramePositionBaker
{
ComputeShader bakerShader;
RenderTexture VFXpositionMap;
RenderTexture inputPositionTexture;
private ComputeBuffer positionBuffer;
const int texSize = 256;
public FramePositionBaker(RenderTexture _VFXPositionMap)
{
inputPositionTexture = new RenderTexture(texSize, texSize, 0, RenderTextureFormat.ARGBFloat);
inputPositionTexture.enableRandomWrite = true;
inputPositionTexture.Create();
bakerShader = (ComputeShader)Resources.Load("FramePositionBaker");
if (bakerShader == null)
{
Debug.LogError("[FramePositionBaker] baking shader not found in any Resources folder");
}
VFXpositionMap = _VFXPositionMap;
}
public void BakeFrame(ref Vector3[] vertices)
{
int pointCount = vertices.Length;
positionBuffer = new ComputeBuffer(pointCount, 3 * sizeof(float));
positionBuffer.SetData(vertices);
//Debug.Log("Length " + vertices.Length);
bakerShader.SetInt("dim", texSize);
bakerShader.SetTexture(0, "PositionTexture", inputPositionTexture);
bakerShader.SetBuffer(0, "PositionBuffer", positionBuffer);
bakerShader.Dispatch(0, (texSize / 8) + 1, (texSize / 8) + 1, 1);
Graphics.CopyTexture(inputPositionTexture, VFXpositionMap);
positionBuffer.Dispose();
}
}
The compute shader:
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> PositionTexture;
uint dim;
Buffer<float3> PositionBuffer;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
// TODO: insert actual code here!
uint index = id.y * dim + id.x;
uint lastIndex = PositionBuffer.Length - 1;
// Trick for generating a pseudo-random number.
// Inspired by a similar trick in Keijiro's PCX repo (BakedPointCloud.cs).
// The points that are in excess because of the square texture, point randomly to a point in the texture.
// e.g. if (index > lastIndex) index = 0 generates excessive particles in the first position, resulting in a visible artifact.
//if (index > lastIndex) index = ( index * 132049U ) % lastIndex;
float3 pos;
if (index > lastIndex && lastIndex != 0) {
//pos = 0;
index = ( index * 132049U ) % lastIndex;
}
pos = PositionBuffer[index];
PositionTexture[id.xy] = float4 (pos.x, pos.y, pos.z, 1);
}

Related

Why does the scale value of the object change?

I'm trying to learn the Unity game engine. I'm trying to develop a mechanic. Objects are created from the object pool in a fixed location. However, when I make them child object of a different object and finish the process and deactivate them, the scale values ​​of the reconstructed objects change. Why is this happening?
private IEnumerator Create_Green_Pizzas(List<Transform> pizzas)
{
int pizzaCount = 0;
while (pizzaCount < pizzas.Count)
{
currentColumn++;
if (currentColumn >= columnCount)
{
currentRow++;
currentColumn = 0;
}
if (currentRow >= rowCount)
{
pizzaLevel++;
currentRow = 0;
currentColumn = 0;
}
for (int i = 0; i < pizzas.Count; i++)
{
if (!pizzas[i].gameObject.activeInHierarchy)
{
pizzas[i].gameObject.SetActive(true);
pizzas[i].parent = pizzasParent;
pizzas[i].rotation = transform.rotation;
pizzas[i].position = initialSlotPosition + new Vector3(((pizzas[i].lossyScale.x) * currentColumn), (pizzaLevel * pizzas[i].lossyScale.y), ((-pizzas[i].lossyScale.z) * currentRow));
pizzas[i].GetComponent<MeshRenderer>().material.color = Color.green;
_player.collectableGreenPizzas.Add(pizzas[i]);
pizzaCount++;
yield return new WaitForSeconds(0.5f);
break;
}
}
}
}
Setting gameobject's the parent might be the cause, so instead of:
pizzas[i].parent = pizzasParent;
try instead:
pizzas[i].SetParent(pizzasParent, true);
You can find more info about this method Here
If a GameObject has a parent, they become part of the parent's referential, their transform is now a local transform that depends on the parent's transform.
This means that if a child transform has a scale of (1, 1, 1), has the same scale as its parent.
Here's a small clip that illustrates this, two sphere that are the same size while they both have a different scale.
However you can force the GameObject to preserve its coordinates and scale using this line :
child.SetParent(parent, true);

AR camera distance measurement

I have a question about AR(Augmented Reality).
I want to know how to show the distance information(like centermeter...) between AR camera and target object. (Using Smartphone)
Can I do that in Unity ? Should I use AR Foundation? and with ARcore? How to write code?
I tried finding some relative code(below), but it seems just like Printing information between object and object, nothing about "AR camera"...
var other : Transform;
if (other) {
var dist = Vector3.Distance(other.position, transform.position);
print ("Distance to other: " + dist);
}
Thank again!
Here is how to do it Unity and AR Foundation 4.1.
This example script prints the depth in meters at the depth texture's center and works both with ARCore and ARKit:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;
public class GetDepthOfCenterPixel : MonoBehaviour {
// assign this field in inspector
[SerializeField] AROcclusionManager manager = null;
IEnumerator Start() {
while (ARSession.state < ARSessionState.SessionInitializing) {
// manager.descriptor.supportsEnvironmentDepthImage will return a correct value if ARSession.state >= ARSessionState.SessionInitializing
yield return null;
}
if (!manager.descriptor.supportsEnvironmentDepthImage) {
Debug.LogError("!manager.descriptor.supportsEnvironmentDepthImage");
yield break;
}
while (true) {
if (manager.TryAcquireEnvironmentDepthCpuImage(out var cpuImage) && cpuImage.valid) {
using (cpuImage) {
Assert.IsTrue(cpuImage.planeCount == 1);
var plane = cpuImage.GetPlane(0);
var dataLength = plane.data.Length;
var pixelStride = plane.pixelStride;
var rowStride = plane.rowStride;
Assert.AreEqual(0, dataLength % rowStride, "dataLength should be divisible by rowStride without a remainder");
Assert.AreEqual(0, rowStride % pixelStride, "rowStride should be divisible by pixelStride without a remainder");
var numOfRows = dataLength / rowStride;
var centerRowIndex = numOfRows / 2;
var centerPixelIndex = rowStride / (pixelStride * 2);
var centerPixelData = plane.data.GetSubArray(centerRowIndex * rowStride + centerPixelIndex * pixelStride, pixelStride);
var depthInMeters = convertPixelDataToDistanceInMeters(centerPixelData.ToArray(), cpuImage.format);
print($"depth texture size: ({cpuImage.width},{cpuImage.height}), pixelStride: {pixelStride}, rowStride: {rowStride}, pixel pos: ({centerPixelIndex}, {centerRowIndex}), depthInMeters of the center pixel: {depthInMeters}");
}
}
yield return null;
}
}
float convertPixelDataToDistanceInMeters(byte[] data, XRCpuImage.Format format) {
switch (format) {
case XRCpuImage.Format.DepthUint16:
return BitConverter.ToUInt16(data, 0) / 1000f;
case XRCpuImage.Format.DepthFloat32:
return BitConverter.ToSingle(data, 0);
default:
throw new Exception($"Format not supported: {format}");
}
}
}
I'm working on AR depth image as well and the basic idea is:
Acquire an image using API, normally it's in format Depth16;
Split the image into shortbuffers, as Depth16 means each pixel is 16 bits;
Get the distance value, which is stored in the lower 13 bits of each shortbuffer, you can do this by doing (shortbuffer & 0x1ff), then you can have the distance for each pixel, normally it's in millimeters.
By doing this through all the pixels, you can create a depth image and store it as jpg or other formats, here's the sample code of using AR Engine to get the distance:
try (Image depthImage = arFrame.acquireDepthImage()) {
int imwidth = depthImage.getWidth();
int imheight = depthImage.getHeight();
Image.Plane plane = depthImage.getPlanes()[0];
ShortBuffer shortDepthBuffer = plane.getBuffer().asShortBuffer();
File sdCardFile = Environment.getExternalStorageDirectory();
Log.i(TAG, "The storage path is " + sdCardFile);
File file = new File(sdCardFile, "RawdepthImage.jpg");
Bitmap disBitmap = Bitmap.createBitmap(imwidth, imheight, Bitmap.Config.RGB_565);
for (int i = 0; i < imheight; i++) {
for (int j = 0; j < imwidth; j++) {
int index = (i * imwidth + j) ;
shortDepthBuffer.position(index);
short depthSample = shortDepthBuffer.get();
short depthRange = (short) (depthSample & 0x1FFF);
//If you only want the distance value, here it is
byte value = (byte) depthRange;
byte value = (byte) depthRange ;
disBitmap.setPixel(j, i, Color.rgb(value, value, value));
}
}
//I rotate the image for a better view
Matrix matrix = new Matrix();
matrix.setRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(disBitmap, 0, 0, imwidth, imheight, matrix, true);
try {
FileOutputStream out = new FileOutputStream(file);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
MainActivity.num++;
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
While the answers are great, they may be too complicated and advanced for this question, which is about the distance between the ARCamera and another object, and not about the depth of pixels and their occlusion.
transform.position gives you the position of whatever game object you attach the script to in the hierarchy. So attach the script to the ARCamera object. And obviously, other should be the target object.
Alternately, you can get references to the two game objects using inspector variables or GetComponent
/raycasting should be in update/
Ray ray = new Ray(cam.transform.position, cam.transform.forward);
if (Physics.Raycast(ray, out info, 50f, layerMaskAR))//50 meters detection range bcs of 50f
{
distanca.text = string.Format("{0}: {1:N2}m", info.collider.name, info.distance, 2);
}
This is func that does it what u need with this is ofc on UI txt element and layer assigne to object/prefab.
int layerMaskAR = 1 << 6; (here u see 6 bcs 6th is my custom layer ,,layerMaskAR,,)
This is ray cating on to objects in only this layer rest object are ignored(if u dont want to ignore anything remove layerMask from raycast and it will print out name of anything with collider).
Totally doable by this line of code
Vector3.Distance(gameObject.transform.position, Camera.main.transform.position)

How to modify a Texture pixels from a compute shader in unity?

I stumbled upon a strange problem in vuforia.When i request a camera image using CameraDevice.GetCameraImage(mypixelformat), the image returned is both flipped sideways and rotated 180 deg. Because of this, to obtain a normal image i have to first rotate the image and then flip it sideways.The approach i am using is simply iterating over pixels of the image and modifying them.This approach is very poor performance wise.Below is the code:
Texture2D image;
CameraDevice cameraDevice = Vuforia.CameraDevice.Instance;
Vuforia.Image vufImage = cameraDevice.GetCameraImage(pixelFormat);
image = new Texture2D(vufImage.Width, vufImage.Height);
vufImage.CopyToTexture(image);
Color32[] colors = image.GetPixels32();
System.Array.Reverse(colors, 0, colors.Length); //rotate 180deg
image.SetPixels32(colors); //apply rotation
image = FlipTexture(image); //flip sideways
//***** THE FLIP TEXTURE METHOD *******//
private Texture2D FlipTexture(Texture2D original, bool upSideDown = false)
{
Texture2D flipped = new Texture2D(original.width, original.height);
int width = original.width;
int height = original.height;
for (int col = 0; col < width; col++)
{
for (int row = 0; row < height; row++)
{
if (upSideDown)
{
flipped.SetPixel(row, (width - 1) - col, original.GetPixel(row, col));
}
else
{
flipped.SetPixel((width - 1) - col, row, original.GetPixel(col, row));
}
}
}
flipped.Apply();
return flipped;
}
To improve the performance i want to somehow schedule these pixel operations on the GPU, i have heard that a compute shader can be used, but i have no idea where to start.Can someone please help me write the same operations in a compute shader so that the GPU can handle them, Thankyou!.
The whole compute shader are new for me too, but i took the occasion to research it a little bit for myself too. The following works for flipping a texture vertically (rotating and flipping horizontally should be just a vertical flip).
Someone might have a more elaborate solution for you, but maybe this is enough to get you started.
The Compute shader code:
#pragma kernel CSMain
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
Texture2D<float4> ImageInput;
float2 flip;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
flip = float2(512 , 1024) - id.xy ;
Result[id.xy] = float4(ImageInput[flip].x, ImageInput[flip].y, ImageInput[flip].z, 1.0);
}
and called from any script:
public void FlipImage()
{
int kernelHandle = shader.FindKernel("CSMain");
RenderTexture tex = new RenderTexture(512, 1024, 24);
tex.enableRandomWrite = true;
tex.Create();
shader.SetTexture(kernelHandle, "Result", tex);
shader.SetTexture(kernelHandle, "ImageInput", myTexture);
shader.Dispatch(kernelHandle, 512/8 , 1024 / 8, 1);
RenderTexture.active = tex;
result.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
result.Apply();
}
This takes an input Texture2D, flips it in the shader, applies it to a RenderTexture and to a Texture2D, whatever you need.
Note that the image sizes are hardcoded in my instance and should be replaced by whatever size you need. (for within the shader use shader.SetInt(); )

Tiling atlas textures correctly with a custom shader in Unity

This is a bit complicated, but it boils down to be quite a simple problem, I hope. So here is how it goes: I am using Unity to generate a map gameobject during runtime from a bsp file which has a whole bunch of vertices, faces, uvs, texture references, and so on. The meshes created come out exactly as they should be, and all the textures come out fine. There is one problem though, there are so many meshes created with so many materials leading to many draw calls making the program slow. So I searched on a way to reduce the draw calls and I found a solution. Combine all the meshes into one big mesh and create a texture atlas by combining all the textures used. Combining the meshes works fine and combining the textures comes out great as well. Then I faced the problem of uv mapping. So I found a solution from the NVidia white paper to make a custom shader which uses the tex2d function to interpolate the texel from the texture using the uv positions with their derivatives. I think this would have worked, but my meshes have really weird triangles and I think they are ruining this solution. In the images below you can see the difference when the meshes are combined from when they are separate:
Combined Meshes with Changed UVs and Custom Shader
Separate Meshes with original UVs
This is the code I am using in the shader to set the color of the model:
o.Albedo = tex2D (_MainTex, IN.uv2_BlendTex, ddx(IN.uv_MainTex), ddy(IN.uv_MainTex)).rgb;
As you can see, I have added a second UV which is the non-tiled version of the original UV. I do that by using the frac() function, but in the C# code rather than in the shader. Since the textures can be different sizes, I had to calculate the UV before getting to the shader because I have access to the texture sizes at that time.
Here is the code I used to calculate the 2 UVs:
Rect surfaceTextureRect = uvReMappers[textureIndex];
Mesh surfaceMesh = allFaces[i].mesh;
Vector2[] atlasTiledUVs = new Vector2[surfaceMesh.uv.Length];
Vector2[] atlasClampedUVs = new Vector2[surfaceMesh.uv.Length];
for (int j = 0; j < atlasClampedUVs.Length; j++)
{
Vector2 clampedUV = new Vector2((surfaceMesh.uv[j].x - Mathf.Floor(surfaceMesh.uv[j].x)), (surfaceMesh.uv[j].y - Mathf.Floor(surfaceMesh.uv[j].y)));
float atlasClampedX = (clampedUV.x * surfaceTextureRect.width) + surfaceTextureRect.x;
float atlasClampedY = (clampedUV.y * surfaceTextureRect.height) + surfaceTextureRect.y;
atlasTiledUVs[j] = new Vector2((surfaceMesh.uv[j].x * surfaceTextureRect.width) + surfaceTextureRect.x, (surfaceMesh.uv[j].y * surfaceTextureRect.height) + surfaceTextureRect.y);
atlasClampedUVs[j] = new Vector2(atlasClampedX, atlasClampedY);
if (i < 10) { Debug.Log(i + " Original: " + surfaceMesh.uv[j] + " ClampedUV: " + clampedUV); }
}
surfaceMesh.uv = atlasTiledUVs;
surfaceMesh.uv2 = atlasClampedUVs;
The array uvReMappers is an array of Rect created when using the Texture2D function PackTextures().
Sorry for taking so long, but here is my question: Why do the textures come out contorted. Is it because the way the meshes are triangulated or is it because of the way I wrote the custom shader. And finally how can I fix it.
Thank you for your time. I am sorry for writing so much, but I have never posted a question before. I always find answers to almost all my problems online, but I have been searching for days on how to fix this problem. I feel it might be too specific to be able to find an answer for. I hope I have provided enough information.
I finally solved the problem! So it turns out I should not calculate the UVs before the shader. Instead I passed the information needed by the shader through the UVs so that it can calculate the new texel positions directly.
Here is the code before the shader:
Rect surfaceTextureRect = uvReMappers[textureIndex];
Mesh surfaceMesh = allFaces[i].mesh;
Vector2[] atlasTexturePosition = new Vector2[surfaceMesh.uv.Length];
Vector2[] atlasTextureSize = new Vector2[surfaceMesh.uv.Length];
for (int j = 0; j < atlasTexturePosition.Length; j++)
{
atlasTexturePosition[j] = new Vector2(surfaceTextureRect.x, surfaceTextureRect.y);
atlasTextureSize[j] = new Vector2(surfaceTextureRect.width, surfaceTextureRect.height);
}
surfaceMesh.uv2 = atlasTexturePosition;
surfaceMesh.uv3 = atlasTextureSize;
Here is the shader code:
tex2D(_MainTex, float2((frac(IN.uv.x) * IN.uv3.x) + IN.uv2.x, (frac(IN.uv.y) * IN.uv3.y) + IN.uv2.y));
I took a different approach and created a texture atlas on the cpu, from there UV mapping was just like normal UV mapping all I had to do was assign a texture to the vertex info from my atlas ...
My scenario is a custom voxel engine that can handle anything from minecraft to rendering voxel based planets and I haven't found a scenario it can't handle yet.
Here's my code for the atlas ...
using UnityEngine;
using Voxels.Objects;
namespace Engine.MeshGeneration.Texturing
{
/// <summary>
/// Packed texture set to be used for mapping texture info on
/// dynamically generated meshes.
/// </summary>
public class TextureAtlas
{
/// <summary>
/// Texture definitions within the atlas.
/// </summary>
public TextureDef[] Textures { get; set; }
public TextureAtlas()
{
SetupTextures();
}
protected virtual void SetupTextures()
{
// default for bas atlas is a material with a single texture in the atlas
Textures = new TextureDef[]
{
new TextureDef
{
VoxelType = 0,
Faces = new[] { Face.Top, Face.Bottom, Face.Left, Face.Right, Face.Front, Face.Back },
Bounds = new[] {
new Vector2(0,1),
new Vector2(1, 1),
new Vector2(1,0),
new Vector2(0, 0)
}
}
};
}
public static TextureDef[] GenerateTextureSet(IntVector2 textureSizeInPixels, IntVector2 atlasSizeInPixels)
{
int x = atlasSizeInPixels.X / textureSizeInPixels.X;
int z = atlasSizeInPixels.Z / textureSizeInPixels.Z;
int i = 0;
var result = new TextureDef[x * z];
var uvSize = new Vector2(1f / ((float)x), 1f / ((float)z));
for (int tx = 0; tx < x; tx++)
for (int tz = 0; tz < z; tz++)
{
// for perf, types are limited to 255 (1 byte)
if(i < 255)
{
result[i] = new TextureDef
{
VoxelType = (byte)i,
Faces = new[] { Face.Top, Face.Bottom, Face.Left, Face.Right, Face.Front, Face.Back },
Bounds = new[] {
new Vector2(tx * uvSize.x, (tz + 1f) * uvSize.y),
new Vector2((tx + 1f) * uvSize.x, (tz + 1f) * uvSize.y),
new Vector2((tx + 1f) * uvSize.x, tz * uvSize.y),
new Vector2(tx * uvSize.x, tz * uvSize.y)
}
};
i++;
}
else
break;
}
return result;
}
}
}
And for a texture definition within the atlas ...
using UnityEngine;
using Voxels.Objects;
namespace Engine.MeshGeneration.Texturing
{
/// <summary>
/// Represents an area within the atlas texture
/// from which a single texture can be pulled.
/// </summary>
public class TextureDef
{
/// <summary>
/// The voxel block type to use this texture for.
/// </summary>
public byte VoxelType { get; set; }
/// <summary>
/// Faces this texture should be applied to on voxels of the above type.
/// </summary>
public Face[] Faces { get; set; }
/// <summary>
/// Atlas start ref
/// </summary>
public Vector2[] Bounds { get; set; }
}
}
For custom scenarios where I need direct control of the UV mappings I inherit texture atlas and then override the SetupTextures() method but in pretty much all cases for me I create atlases where the textures are all the same size so simply calling GenerateTextureSet will do the uv mapping calculations I believe you need.
The UV coords for a given face of a given voxel type are then ...
IEnumerable<Vector2> UVCoords(byte voxelType, Face face, TextureAtlas atlas)
{
return atlas.Textures
.Where(a => a.VoxelType == voxelType && a.Faces.Contains(face))
.First()
.Bounds;
}
In your case you probably have a different way to map to the texture of choice from your pack but essentially the combination of a face and type in my case are what determine the uv mapping set I want.
This then allows you to use your mesh with any standard shader instead of relying on custom shader logic.
You have to turn the passed in TEXCOORD0 from a percentage of the image space to a pixel value, use the modulus to figure out which pixel it is on the tiled texture, and then turn it back into a percentage of the image.
Here's the code:
You need the 2D variables _MainTex and _PatternTex to be defined.
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float modFunction(float number, float divisor){
//2018-05-24: copied from an answer by Nicol Bolas: https://stackoverflow.com/questions/35155598/unable-to-use-in-glsl
return (number - (divisor * floor(number/divisor)));
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 curColor = tex2D(_MainTex, i.uv);
fixed4 pattern = tex2D(_PatternTex,
float2(
modFunction(i.uv.x*_MainTex_TexelSize.z,_PatternTex_TexelSize.z) *_PatternTex_TexelSize.x,
modFunction(i.uv.y*_MainTex_TexelSize.w,_PatternTex_TexelSize.w) *_PatternTex_TexelSize.y
)
);
fixed4 col = curColor * pattern;
col.rgb *= col.a;
return col;
}

Multiple textures doesn't show

I'm a newbie of DirectX10. Now I'm developing a Direct10 application. It mixes two textures which are filled manually according to user's input. The current implementation is
Create two empty textures with usage D3D10_USAGE_STAGING.
Create two resource shader view to bind to the pixel shader because the shader needs it.
Copy the textures to the GPU memory by calling CopyResource.
Now the problem is that I can only see the first texture but I don't see the second. It looks to me that the binding doesn't work for the second texture.
I don't know what's wrong with it. Can anyone here shed me a light on it?
Thanks,
Marshall
The class COverlayTexture takes responsible for creating the texture, creating resource view, fill the texture with the mapped bitmap from another applicaiton and bind the resource view to the pixel shader.
HRESULT COverlayTexture::Initialize(VOID)
{
D3D10_TEXTURE2D_DESC texDesStaging;
texDesStaging.Width = m_width;
texDesStaging.Height = m_height;
texDesStaging.Usage = D3D10_USAGE_STAGING;
texDesStaging.BindFlags = 0;
texDesStaging.ArraySize = 1;
texDesStaging.MipLevels = 1;
texDesStaging.SampleDesc.Count = 1;
texDesStaging.SampleDesc.Quality = 0;
texDesStaging.MiscFlags = 0;
texDesStaging.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texDesStaging.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
HR( m_Device->CreateTexture2D( &texDesStaging, NULL, &m_pStagingResource ) );
D3D10_TEXTURE2D_DESC texDesShader;
texDesShader.Width = m_width;
texDesShader.Height = m_height;
texDesShader.BindFlags = D3D10_BIND_SHADER_RESOURCE;
texDesShader.ArraySize = 1;
texDesShader.MipLevels = 1;
texDesShader.SampleDesc.Count = 1;
texDesShader.SampleDesc.Quality = 0;
texDesShader.MiscFlags = 0;
texDesShader.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texDesShader.Usage = D3D10_USAGE_DEFAULT;
texDesShader.CPUAccessFlags = 0;
HR( m_Device->CreateTexture2D( &texDesShader, NULL, &m_pShaderResource ) );
D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
ZeroMemory( &viewDesc, sizeof( viewDesc ) );
viewDesc.Format = texDesShader.Format;
viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
viewDesc.Texture2D.MipLevels = texDesShader.MipLevels;
HR( m_Device->CreateShaderResourceView( m_pShaderResource, &viewDesc, &m_pShaderResourceView ) );
}
HRESULT COverlayTexture::Render(VOID)
{
m_Device->PSSetShaderResources(0, 1, m_pShaderResourceView);
D3D10_MAPPED_TEXTURE2D lockedRect;
m_pStagingResource->Map( 0, D3D10_MAP_WRITE, 0, &lockedRect );
// Fill in the texture with the bitmap mapped from shared memory view
m_pStagingResource->Unmap(0);
m_Device->CopyResource(m_pShaderResource, m_pStagingResource);
}
I use two instances of the class COverlayTexture each of which fills its own bitmap to its texture respectively and renders with sequence COverlayTexture[1] then COverlayTexture[0].
COverlayTexture* pOverlayTexture[2];
for( int i = 1; i < 0; i++)
{
pOverlayTexture[i]->Render()
}
The blend state setting in the FX file is definedas below:
BlendState AlphaBlend
{
AlphaToCoverageEnable = FALSE;
BlendEnable[0] = TRUE;
SrcBlend = SRC_ALPHA;
DestBlend = INV_SRC_ALPHA;
BlendOp = ADD;
BlendOpAlpha = ADD;
SrcBlendAlpha = ONE;
DestBlendAlpha = ZERO;
RenderTargetWriteMask[0] = 0x0f;
};
The pixel shader in the FX file is defined as below:
Texture2D txDiffuse;
float4 PS(PS_INPUT input) : SV_Target
{
float4 ret = txDiffuse.Sample(samLinear, input.Tex);
return ret;
}
Thanks again.
Edit for Paulo:
Thanks a lot, Paulo. The problem is that which instance of the object should be bound to alpha texture or diffuse texture. As testing, I bind the COverlayTexture[0] to the alpha and COverlayTexture[1] to the diffuse texture.
Texture2D txDiffuse[2];
float4 PS(PS_INPUT input) : SV_Target
{
float4 ret = txDiffuse[1].Sample(samLinear, input.Tex);
float alpha = txDiffuse[0].Sample(samLinear, input.Tex).x;
return float4(ret.xyz, alpha);
}
I called the PSSetShaderResources for the two resource views.
g_pShaderResourceViews[0] = overlay[0].m_pShaderResourceView;
g_pShaderResourceViews[1] = overlay[1].m_pShaderResourceView;
m_Device->PSSetShaderResources(0, 2, g_pShaderResourceViews);
The result is that i don't see anything. I also tried the channel x,y,z,w.
Post some more code.
I'm not sure how you mean to mix these two textures. If you want to mix them in the pixel shader you need to sample both of them then add them (or whatever operation you required) toghether.
How do you add the textures toghether? By setting a ID3D11BlendState or in the pixel shader?
EDIT:
You don't need two textures in every class: if you want to write to your texture your usage should be D3D10_USAGE_DYNAMIC. When you do this, you can also have this texture as your shader resource so you don't need to do the m_Device->CopyResource(m_pShaderResource, m_pStagingResource); step.
Since you're using alpha blending you must control the alpha value output in the pixel shader (the w component of the float4 that the pixel shader returns).
Bind both textures to your pixel shader and use one textures value as the alpha components:
Texture2D txDiffuse;
Texture2D txAlpha;
float4 PS(PS_INPUT input) : SV_Target
{
float4 ret = txDiffuse.Sample(samLinear, input.Tex);
float alpha=txAlpha.Sample(samLinear,input.Tex).x; // Choose the proper channel
return float4(ret.xyz,alpha); // Alpha is the 4th component
}