libgdx changing the texture on a pre textured model - opengl

I've exported a model from blender but I want some instances to use a different texture
if (x % 2 == 0) {
shipInstance.materials.clear();
shipInstance.materials.add(new Material());
shipInstance.materials.get(0).set(new TextureAttribute(TextureAttribute.Diffuse, enemyTexture));
unfortunately doesn't work!
In a similar way I want to be able to change things like shininess and smoothing
(I'm guessing you can change things like this that are using the default shader?)
I've also (later) tried this...
Material mat = shipInstance.materials.get(m);
for (Iterator<Attribute> ai = mat.iterator(); ai.hasNext();){
Attribute att=ai.next();
if (att.type==TextureAttribute.Diffuse) {
((TextureAttribute)att).textureDescription.set(enemyTexture,TextureFilter.Linear,TextureFilter.Linear,TextureWrap.ClampToEdge,TextureWrap.ClampToEdge);
}
}
amongst other things...

argh!
for(int m=0;m<shipInstance.materials.size;m++) {
Material mat = shipInstance.materials.get(m);
for (Iterator<Attribute> ai = mat.iterator(); ai.hasNext();){
Attribute att=ai.next();
if (att.type==TextureAttribute.Diffuse) {
((TextureAttribute)att).textureDescription.set(enemyTexture,TextureFilter.Linear,TextureFilter.Linear,TextureWrap.ClampToEdge,TextureWrap.ClampToEdge);
}
}
}
My mistake was to subtract 1 from materials.size !!! (the last material in the model happened to be the most obvious one, it was in many cases when I tried different things probably working (accept for the last material) DoH!!!

Related

model dont have tangent or binormal value fbxsdk directx

I'm using a translator, so please understand that I may be inexperienced. I'm currently trying to create a 3d model in dx12 using fbxsdk.
There is no problem with the modeling used in the current example code, but now the moment you use the 3d model on sites such as mixamo and turbo,
iTangentCnt or iBinormalCnt value is zero, so the program is not working.
Is this because there is no tangent and binormal in the model?
There is no value even if you use other models, so I am curious that models have no value. How did others solve this problem?
void CFBXLoader::GetTangent(FbxMesh* _pMesh, tContainer* _pContainer, int _iIdx , int _iVtxOrder){
int iTangentCnt = _pMesh->GetElementTangentCount();
if (1 != iTangentCnt)
assert(NULL);
FbxGeometryElementTangent* pTangent = _pMesh->GetElementTangent();
UINT iTangentIdx = 0;
if (pTangent->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
{
if (pTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
iTangentIdx = _iVtxOrder;
else
iTangentIdx = pTangent->GetIndexArray().GetAt(_iVtxOrder);
}
else if (pTangent->GetMappingMode() == FbxGeometryElement::eByControlPoint)
{
if (pTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
iTangentIdx = _iIdx;
else
iTangentIdx = pTangent->GetIndexArray().GetAt(_iIdx);
}
FbxVector4 vTangent = pTangent->GetDirectArray().GetAt(iTangentIdx);
_pContainer->vecTangent[_iIdx].x = (float)vTangent.mData[0];
_pContainer->vecTangent[_iIdx].y = (float)vTangent.mData[2];
_pContainer->vecTangent[_iIdx].z = (float)vTangent.mData[1];}
void CFBXLoader::GetBinormal(FbxMesh* _pMesh, tContainer* _pContainer, int _iIdx, int _iVtxOrder){
int iBinormalCnt = _pMesh->GetElementBinormalCount();
if (1 != iBinormalCnt)
assert(NULL);
FbxGeometryElementBinormal* pBinormal = _pMesh->GetElementBinormal();
UINT iBinormalIdx = 0;
if (pBinormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
{
if (pBinormal->GetReferenceMode() == FbxGeometryElement::eDirect)
iBinormalIdx = _iVtxOrder;
else
iBinormalIdx = pBinormal->GetIndexArray().GetAt(_iVtxOrder);
}
else if (pBinormal->GetMappingMode() == FbxGeometryElement::eByControlPoint)
{
if (pBinormal->GetReferenceMode() == FbxGeometryElement::eDirect)
iBinormalIdx = _iIdx;
else
iBinormalIdx = pBinormal->GetIndexArray().GetAt(_iIdx);
}
FbxVector4 vBinormal = pBinormal->GetDirectArray().GetAt(iBinormalIdx);
_pContainer->vecBinormal[_iIdx].x = (float)vBinormal.mData[0];
_pContainer->vecBinormal[_iIdx].y = (float)vBinormal.mData[2];
_pContainer->vecBinormal[_iIdx].z = (float)vBinormal.mData[1];
}
If your run-time scenario requires tangents/binormals to operate, then you need to handle the case of them not already being defined in the FBX. If the iBinormalCnt is 0, then you can generate tangents/binormals in your own program using the surface normal and texture coordinates.
Lengyel, Eric. "7.5 Tangent Space", Foundations of Game Engine Development: Volume 2 - Rendering, Terathon Software LLC (2019) link
Mittring, Martin. "Triangle Mesh Tangent Space Calculation". Shader X^4 Advanced Rendering Techniques, 2006
See DirectXMesh's ComputeTangentFrame function.
For an example of a complete model exporter using Autodesk FBX, see the DirectX SDK Sample Content Exporter.
Note another option for rendering with tangent space without exporting the tangent/binormals is to compute them in the pixel shader at render time. I use this technique in the DirectX Tool Kit.
Christian Schüler, "Normal Mapping without Precomputed Tangents", ShaderX 5, Chapter 2.6, pp. 131 – 140 and this blog post
If tangents and bitangents are not present in your fbx file (you still need normals and one set of texture coordinates to have it work), you can use the GenerateTangentsData of FbxMesh object to build them.
bool result = _pMesh->GenerateTangentsData(uvSetIndex, overwrite, ignoretangentflip);
you will want overwrite to false, and ignoretangentflip to false most of the times.
uvSetIndex will be 0 most times as well (unless you have multiple uv set on your model).

Weird artefact while rotating mesh uvs

I created a Unity sphere and applied standard material with albedo texture. Now I'm trying to rotate mesh uvs (it looks like this is the simpliest way to rotate the texture)
Here is the code
using UnityEngine;
public class GameController : MonoBehaviour
{
public GameObject player;
public float rotationValue;
void Start ()
{
Mesh mesh = player.GetComponent<MeshFilter>().mesh;
Vector2[] uvs = mesh.uv;
mesh.uv = changeUvs(uvs);
}
private Vector2[] changeUvs (Vector2[] originalUvs)
{
for (int i = 0; i < originalUvs.Length; i++)
{
originalUvs[i].x = originalUvs[i].x + rotationValue;
if (originalUvs[i].x > 1)
{
originalUvs[i].x = originalUvs[i].x - 1f;
}
}
return originalUvs;
}
}
This gives me this strange artifact. What am I doing wrong?
It can't be done the way you're trying to do it. Even if you go outside the [0,1] range as pleluron suggests there will be a line on the sphere where the texture interpolates from high to low, and you get the entire texture in a single band as you see now.
The way the original sphere solves the problem is by having a seam that is duplicated. One version has x 0 and the other one has x 1. You don't see it because the vertices are at the same location. If you want to solve the problem with uv trickery then the only option is to move the seam, which involves creating a new mesh.
Actually the simplest way to rotate the planet is by leaving the texture alone and just rotate the object! If this for some reason is not an option then go into the material and find the tiling and offset. If you're using the standard shader then make sure you use the top one, just below the emission checkbox. If you modify that X you get the effect you're trying to create with the script you posted.

cocos2d-x v3 c++ Drop shadow cocos2d::Sprite

As far as I've found out, cocos doesn't offer a simple filter handling like AS3 for example does.
My situation:
I want to add a realtime shadow to an cocos2d::Sprite.
For example I would like to do something like this (similar to AS3):
auto mySprite = Sprite::createWithSpriteFrameName("myCharacter.png");
DropShadowFilter* dropShadow = new DropShadowFilter();
dropShadow->distance = 0;
dropShadow->angle = 45;
dropShadow->color = 0x333333;
dropShadow->alpha = 1;
dropShadow->blurX = 10;
dropShadow->blurY = 10;
dropShadow->strength = 1;
dropShadow->quality = 15;
mySprite->addFilter(dropShadow);
This should add a shadow to my Sprite to achieve an result like this:
Adobe Drop Shadow Example
Could you help me please?
There isn't any built in support for shadows on Sprites in Cocos2D-X.
The best option, performance-wise, would be to place your shadows in your sprite images already, instead of calculating and drawing them in the code.
Another option is to sub-class Sprite and override the draw method so that you duplicate the sprite and apply your effects and draw it below the original.
One possible way to achieve that is with this snippet from this thread on the Cocos forum. I can't say that I completely follow what this code does with the GL transforms, but you can use this as a starting point to experiment.
void CMySprite::draw()
{
// is_shadow is true if this sprite is to be considered like a shadow sprite, false otherwise.#
if (is_shadow)
{
ccBlendFunc blend;
// Change the default blending factors to this one.
blend.src = GL_SRC_ALPHA;
blend.dst = GL_ONE;
setBlendFunc( blend );
// Change the blending equation to thi in order to subtract from the values already written in the frame buffer
// the ones of the sprite.
glBlendEquationOES(GL_FUNC_REVERSE_SUBTRACT_OES);
}
CCSprite::draw();
if (is_shadow)
{
// The default blending function of cocos2d-x is GL_FUNC_ADD.
glBlendEquationOES(GL_FUNC_ADD_OES);
}
}

Removeable lightsources like Minecraft

I have succeded with making lightsources like the ones in Minecraft and it came with a very good result. I have used the cellular automata method to create the following light.
But say I got 2 or more lightsources near each other and I want to remove one of them.
Can you recommend a way to recalculate only the affected tiles?
Here is a image showing one lightsource. http://i.stack.imgur.com/E0dqR.png
Below is my code for calculating a light source and all of its neighbors tiles.
void World::processNeighborLight(Tile *pCurrent, int pLightLevel, int *pIterationCount)
{
*pIterationCount += 1; // Just to keep track of how many iterations were made.
pCurrent->updateLight(pLightLevel);
int newLight = pLightLevel - 1;
if (newLight <= 0) return;
Tile *N = pCurrent->getRelative(sf::Vector2i(0, -1));
Tile *E = pCurrent->getRelative(sf::Vector2i(1, 0));
Tile *S = pCurrent->getRelative(sf::Vector2i(0, 1));
Tile *W = pCurrent->getRelative(sf::Vector2i(-1, 0));
if (N->getLightLevel() < newLight)
{
N->updateLight(newLight);
processNeighborLight(N, newLight, pIterationCount);
}
if (E->getLightLevel() < newLight)
{
E->updateLight(newLight);
processNeighborLight(E, newLight, pIterationCount);
}
if (S->getLightLevel() < newLight)
{
S->updateLight(newLight);
processNeighborLight(S, newLight, pIterationCount);
}
if (W->getLightLevel() < newLight)
{
W->updateLight(newLight);
processNeighborLight(W, newLight, pIterationCount);
}
}
You could, rather than having each cell store a light level, have it store instead a collection of (lightsource, lightlevel) pairs (expensive?), and similarly have each light source store a collection of (cell, lightlevel) pairs (cheap!).
void KillLight (LightSource & kill_me)
{
// All we really do is iterate through each illuminated cell, and remove this lightsource from
// their list of light sources
for (auto i = kill_me.cells.begin(); i != kill_me.cells.end(); ++i)
{
// The cell contains some kind of collection that contains either a list of lightsources that hit it or <lightsource, illumination level>
// pairs. All we need to do is remove this light from that collection and recalculate the cell's light level
i->lights->erase (kill_me); // Note light sources must be comparable objects.
i->RecalculateMaxIllumination(); // The cell needs to figure out which of its sources is brightest now.
}
// And then handle other lightsource removal cleanup actions. Probably just have this method be called by
// ~LightSource()
}
If having each cell store a list of light sources hitting it is too expensive, the impact of having each light source remember which cells it illuminates is still cheap. I can think of alternate solutions, but they all involve some kind of mapping from a given light source to the set of all cells it illuminates.
This assumes, of course, that your light sources are relatively few in number compared to the number of cells, and no really crazy luminous light sources which illuminate tens of thousands of cells.

How do I set certain colors in an Opengl texture to transparent?

I am trying to create a library i can use to handle 2d rendering in Opengl (c++) i have it all figured out except I can't figure out how to set current colors transparent (ex. being able to set 255, 0, 255 to transparent) I realize from reading on the topic that I need to preprocess the texture and set that color's alpha value to 0 but I have no idea how to do this.
PS: I am using SOIL for loading textures if that helps.
I realize from reading on the topic that I need to preprocess the texture and set that color's alpha value to 0 but I have no idea how to do this.
for(y = 0; y < image.height; y++) for(x = 0; x < image.width; x++) {
if( image.data[x, y].rgb == colorkey ) {
image.data[x, y].alpha = 0.0;
} else {
image.data[x, y].alpha = 1.0;
}
}
/* ... */
upload_image_to_texture(image);
Firstly I would probably recommend you use alpha transparent textures rather than a color key/chroma key ones unless their is some specific reason not to (ie really low memory or your trying to use the Minecraft ones).
With that said, use shaders. In your fragment shader use the 'discard' keyword when the fragment color matches your color key. There's an official tutorial.